diff options
209 files changed, 4046 insertions, 3138 deletions
diff --git a/Documentation/ABI/stable/sysfs-bus-usb b/Documentation/ABI/stable/sysfs-bus-usb index 2be603c52a24..a6b685724740 100644 --- a/Documentation/ABI/stable/sysfs-bus-usb +++ b/Documentation/ABI/stable/sysfs-bus-usb @@ -37,8 +37,8 @@ Description: that the USB device has been connected to the machine. This file is read-only. Users: - PowerTOP <power@bughost.org> - http://www.lesswatts.org/projects/powertop/ + PowerTOP <powertop@lists.01.org> + https://01.org/powertop/ What: /sys/bus/usb/device/.../power/active_duration Date: January 2008 @@ -57,8 +57,8 @@ Description: will give an integer percentage. Note that this does not account for counter wrap. Users: - PowerTOP <power@bughost.org> - http://www.lesswatts.org/projects/powertop/ + PowerTOP <powertop@lists.01.org> + https://01.org/powertop/ What: /sys/bus/usb/devices/<busnum>-<port[.port]>...:<config num>-<interface num>/supports_autosuspend Date: January 2008 diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power index 9d43e7670841..efe449bdf811 100644 --- a/Documentation/ABI/testing/sysfs-devices-power +++ b/Documentation/ABI/testing/sysfs-devices-power @@ -1,6 +1,6 @@ What: /sys/devices/.../power/ Date: January 2009 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/devices/.../power directory contains attributes allowing the user space to check and modify some power @@ -8,7 +8,7 @@ Description: What: /sys/devices/.../power/wakeup Date: January 2009 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/devices/.../power/wakeup attribute allows the user space to check if the device is enabled to wake up the system @@ -34,7 +34,7 @@ Description: What: /sys/devices/.../power/control Date: January 2009 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/devices/.../power/control attribute allows the user space to control the run-time power management of the device. @@ -53,7 +53,7 @@ Description: What: /sys/devices/.../power/async Date: January 2009 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/devices/.../async attribute allows the user space to enable or diasble the device's suspend and resume callbacks to @@ -79,7 +79,7 @@ Description: What: /sys/devices/.../power/wakeup_count Date: September 2010 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/devices/.../wakeup_count attribute contains the number of signaled wakeup events associated with the device. This @@ -88,7 +88,7 @@ Description: What: /sys/devices/.../power/wakeup_active_count Date: September 2010 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/devices/.../wakeup_active_count attribute contains the number of times the processing of wakeup events associated with @@ -98,7 +98,7 @@ Description: What: /sys/devices/.../power/wakeup_abort_count Date: February 2012 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/devices/.../wakeup_abort_count attribute contains the number of times the processing of a wakeup event associated with @@ -109,7 +109,7 @@ Description: What: /sys/devices/.../power/wakeup_expire_count Date: February 2012 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/devices/.../wakeup_expire_count attribute contains the number of times a wakeup event associated with the device has @@ -119,7 +119,7 @@ Description: What: /sys/devices/.../power/wakeup_active Date: September 2010 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/devices/.../wakeup_active attribute contains either 1, or 0, depending on whether or not a wakeup event associated with @@ -129,7 +129,7 @@ Description: What: /sys/devices/.../power/wakeup_total_time_ms Date: September 2010 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/devices/.../wakeup_total_time_ms attribute contains the total time of processing wakeup events associated with the @@ -139,7 +139,7 @@ Description: What: /sys/devices/.../power/wakeup_max_time_ms Date: September 2010 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/devices/.../wakeup_max_time_ms attribute contains the maximum time of processing a single wakeup event associated @@ -149,7 +149,7 @@ Description: What: /sys/devices/.../power/wakeup_last_time_ms Date: September 2010 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/devices/.../wakeup_last_time_ms attribute contains the value of the monotonic clock corresponding to the time of @@ -160,7 +160,7 @@ Description: What: /sys/devices/.../power/wakeup_prevent_sleep_time_ms Date: February 2012 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/devices/.../wakeup_prevent_sleep_time_ms attribute contains the total time the device has been preventing @@ -189,7 +189,7 @@ Description: What: /sys/devices/.../power/pm_qos_latency_us Date: March 2012 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/devices/.../power/pm_qos_resume_latency_us attribute contains the PM QoS resume latency limit for the given device, @@ -207,7 +207,7 @@ Description: What: /sys/devices/.../power/pm_qos_no_power_off Date: September 2012 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/devices/.../power/pm_qos_no_power_off attribute is used for manipulating the PM QoS "no power off" flag. If @@ -222,7 +222,7 @@ Description: What: /sys/devices/.../power/pm_qos_remote_wakeup Date: September 2012 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/devices/.../power/pm_qos_remote_wakeup attribute is used for manipulating the PM QoS "remote wakeup required" diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power index 217772615d02..205a73878441 100644 --- a/Documentation/ABI/testing/sysfs-power +++ b/Documentation/ABI/testing/sysfs-power @@ -1,6 +1,6 @@ What: /sys/power/ Date: August 2006 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/power directory will contain files that will provide a unified interface to the power management @@ -8,7 +8,7 @@ Description: What: /sys/power/state Date: August 2006 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/power/state file controls the system power state. Reading from this file returns what states are supported, @@ -22,7 +22,7 @@ Description: What: /sys/power/disk Date: September 2006 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/power/disk file controls the operating mode of the suspend-to-disk mechanism. Reading from this file returns @@ -67,7 +67,7 @@ Description: What: /sys/power/image_size Date: August 2006 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/power/image_size file controls the size of the image created by the suspend-to-disk mechanism. It can be written a @@ -84,7 +84,7 @@ Description: What: /sys/power/pm_trace Date: August 2006 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/power/pm_trace file controls the code which saves the last PM event point in the RTC across reboots, so that you can @@ -133,7 +133,7 @@ Description: What: /sys/power/pm_async Date: January 2009 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/power/pm_async file controls the switch allowing the user space to enable or disable asynchronous suspend and resume @@ -146,7 +146,7 @@ Description: What: /sys/power/wakeup_count Date: July 2010 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/power/wakeup_count file allows user space to put the system into a sleep state while taking into account the @@ -161,7 +161,7 @@ Description: What: /sys/power/reserved_size Date: May 2011 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/power/reserved_size file allows user space to control the amount of memory reserved for allocations made by device @@ -175,7 +175,7 @@ Description: What: /sys/power/autosleep Date: April 2012 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/power/autosleep file can be written one of the strings returned by reads from /sys/power/state. If that happens, a @@ -192,7 +192,7 @@ Description: What: /sys/power/wake_lock Date: February 2012 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/power/wake_lock file allows user space to create wakeup source objects and activate them on demand (if one of @@ -219,7 +219,7 @@ Description: What: /sys/power/wake_unlock Date: February 2012 -Contact: Rafael J. Wysocki <rjw@sisk.pl> +Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/power/wake_unlock file allows user space to deactivate wakeup sources created with the help of /sys/power/wake_lock. diff --git a/Documentation/acpi/dsdt-override.txt b/Documentation/acpi/dsdt-override.txt index febbb1ba4d23..784841caa6e6 100644 --- a/Documentation/acpi/dsdt-override.txt +++ b/Documentation/acpi/dsdt-override.txt @@ -4,4 +4,4 @@ CONFIG_ACPI_CUSTOM_DSDT builds the image into the kernel. When to use this method is described in detail on the Linux/ACPI home page: -http://www.lesswatts.org/projects/acpi/overridingDSDT.php +https://01.org/linux-acpi/documentation/overriding-dsdt diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt deleted file mode 100644 index eb2469365593..000000000000 --- a/Documentation/devicetree/bindings/memory.txt +++ /dev/null @@ -1,168 +0,0 @@ -*** Memory binding *** - -The /memory node provides basic information about the address and size -of the physical memory. This node is usually filled or updated by the -bootloader, depending on the actual memory configuration of the given -hardware. - -The memory layout is described by the following node: - -/ { - #address-cells = <(n)>; - #size-cells = <(m)>; - memory { - device_type = "memory"; - reg = <(baseaddr1) (size1) - (baseaddr2) (size2) - ... - (baseaddrN) (sizeN)>; - }; - ... -}; - -A memory node follows the typical device tree rules for "reg" property: -n: number of cells used to store base address value -m: number of cells used to store size value -baseaddrX: defines a base address of the defined memory bank -sizeX: the size of the defined memory bank - - -More than one memory bank can be defined. - - -*** Reserved memory regions *** - -In /memory/reserved-memory node one can create child nodes describing -particular reserved (excluded from normal use) memory regions. Such -memory regions are usually designed for the special usage by various -device drivers. A good example are contiguous memory allocations or -memory sharing with other operating system on the same hardware board. -Those special memory regions might depend on the board configuration and -devices used on the target system. - -Parameters for each memory region can be encoded into the device tree -with the following convention: - -[(label):] (name) { - compatible = "linux,contiguous-memory-region", "reserved-memory-region"; - reg = <(address) (size)>; - (linux,default-contiguous-region); -}; - -compatible: one or more of: - - "linux,contiguous-memory-region" - enables binding of this - region to Contiguous Memory Allocator (special region for - contiguous memory allocations, shared with movable system - memory, Linux kernel-specific). - - "reserved-memory-region" - compatibility is defined, given - region is assigned for exclusive usage for by the respective - devices. - -reg: standard property defining the base address and size of - the memory region - -linux,default-contiguous-region: property indicating that the region - is the default region for all contiguous memory - allocations, Linux specific (optional) - -It is optional to specify the base address, so if one wants to use -autoconfiguration of the base address, '0' can be specified as a base -address in the 'reg' property. - -The /memory/reserved-memory node must contain the same #address-cells -and #size-cells value as the root node. - - -*** Device node's properties *** - -Once regions in the /memory/reserved-memory node have been defined, they -may be referenced by other device nodes. Bindings that wish to reference -memory regions should explicitly document their use of the following -property: - -memory-region = <&phandle_to_defined_region>; - -This property indicates that the device driver should use the memory -region pointed by the given phandle. - - -*** Example *** - -This example defines a memory consisting of 4 memory banks. 3 contiguous -regions are defined for Linux kernel, one default of all device drivers -(named contig_mem, placed at 0x72000000, 64MiB), one dedicated to the -framebuffer device (labelled display_mem, placed at 0x78000000, 8MiB) -and one for multimedia processing (labelled multimedia_mem, placed at -0x77000000, 64MiB). 'display_mem' region is then assigned to fb@12300000 -device for DMA memory allocations (Linux kernel drivers will use CMA is -available or dma-exclusive usage otherwise). 'multimedia_mem' is -assigned to scaler@12500000 and codec@12600000 devices for contiguous -memory allocations when CMA driver is enabled. - -The reason for creating a separate region for framebuffer device is to -match the framebuffer base address to the one configured by bootloader, -so once Linux kernel drivers starts no glitches on the displayed boot -logo appears. Scaller and codec drivers should share the memory -allocations. - -/ { - #address-cells = <1>; - #size-cells = <1>; - - /* ... */ - - memory { - reg = <0x40000000 0x10000000 - 0x50000000 0x10000000 - 0x60000000 0x10000000 - 0x70000000 0x10000000>; - - reserved-memory { - #address-cells = <1>; - #size-cells = <1>; - - /* - * global autoconfigured region for contiguous allocations - * (used only with Contiguous Memory Allocator) - */ - contig_region@0 { - compatible = "linux,contiguous-memory-region"; - reg = <0x0 0x4000000>; - linux,default-contiguous-region; - }; - - /* - * special region for framebuffer - */ - display_region: region@78000000 { - compatible = "linux,contiguous-memory-region", "reserved-memory-region"; - reg = <0x78000000 0x800000>; - }; - - /* - * special region for multimedia processing devices - */ - multimedia_region: region@77000000 { - compatible = "linux,contiguous-memory-region"; - reg = <0x77000000 0x4000000>; - }; - }; - }; - - /* ... */ - - fb0: fb@12300000 { - status = "okay"; - memory-region = <&display_region>; - }; - - scaler: scaler@12500000 { - status = "okay"; - memory-region = <&multimedia_region>; - }; - - codec: codec@12600000 { - status = "okay"; - memory-region = <&multimedia_region>; - }; -}; diff --git a/Documentation/devicetree/bindings/sound/cs42l73.txt b/Documentation/devicetree/bindings/sound/cs42l73.txt new file mode 100644 index 000000000000..80ae910dbf6c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs42l73.txt @@ -0,0 +1,22 @@ +CS42L73 audio CODEC + +Required properties: + + - compatible : "cirrus,cs42l73" + + - reg : the I2C address of the device for I2C + +Optional properties: + + - reset_gpio : a GPIO spec for the reset pin. + - chgfreq : Charge Pump Frequency values 0x00-0x0F + + +Example: + +codec: cs42l73@4a { + compatible = "cirrus,cs42l73"; + reg = <0x4a>; + reset_gpio = <&gpio 10 0>; + chgfreq = <0x05>; +};
\ No newline at end of file diff --git a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt new file mode 100644 index 000000000000..865178d5cdf3 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt @@ -0,0 +1,42 @@ +* Texas Instruments SoC audio setups with TLV320AIC3X Codec + +Required properties: +- compatible : "ti,da830-evm-audio" : forDM365/DA8xx/OMAPL1x/AM33xx +- ti,model : The user-visible name of this sound complex. +- ti,audio-codec : The phandle of the TLV320AIC3x audio codec +- ti,mcasp-controller : The phandle of the McASP controller +- ti,codec-clock-rate : The Codec Clock rate (in Hz) applied to the Codec +- ti,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 codec's pins, and the jacks on the board: + + Board connectors: + + * Headphone Jack + * Line Out + * Mic Jack + * Line In + + +Example: + +sound { + compatible = "ti,da830-evm-audio"; + ti,model = "DA830 EVM"; + ti,audio-codec = <&tlv320aic3x>; + ti,mcasp-controller = <&mcasp1>; + ti,codec-clock-rate = <12000000>; + ti,audio-routing = + "Headphone Jack", "HPLOUT", + "Headphone Jack", "HPROUT", + "Line Out", "LLOUT", + "Line Out", "RLOUT", + "MIC3L", "Mic Bias 2V", + "MIC3R", "Mic Bias 2V", + "Mic Bias 2V", "Mic Jack", + "LINE1L", "Line In", + "LINE2L", "Line In", + "LINE1R", "Line In", + "LINE2R", "Line In"; +}; diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt index 374e145c2ef1..ed785b3f67be 100644 --- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt +++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt @@ -4,17 +4,25 @@ Required properties: - compatible : "ti,dm646x-mcasp-audio" : for DM646x platforms "ti,da830-mcasp-audio" : for both DA830 & DA850 platforms - "ti,omap2-mcasp-audio" : for OMAP2 platforms (TI81xx, AM33xx) - -- reg : Should contain McASP registers offset and length -- interrupts : Interrupt number for McASP -- op-mode : I2S/DIT ops mode. -- tdm-slots : Slots for TDM operation. -- num-serializer : Serializers used by McASP. -- serial-dir : A list of serializer pin mode. The list number should be equal - to "num-serializer" parameter. Each entry is a number indication - serializer pin direction. (0 - INACTIVE, 1 - TX, 2 - RX) + "ti,am33xx-mcasp-audio" : for AM33xx platforms (AM33xx, TI81xx) +- reg : Should contain reg specifiers for the entries in the reg-names property. +- reg-names : Should contain: + * "mpu" for the main registers (required). For compatibility with + existing software, it is recommended this is the first entry. + * "dat" for separate data port register access (optional). +- op-mode : I2S/DIT ops mode. 0 for I2S mode. 1 for DIT mode used for S/PDIF, + IEC60958-1, and AES-3 formats. +- tdm-slots : Slots for TDM operation. Indicates number of channels transmitted + or received over one serializer. +- serial-dir : A list of serializer configuration. Each entry is a number + indication for serializer pin direction. + (0 - INACTIVE, 1 - TX, 2 - RX) +- dmas: two element list of DMA controller phandles and DMA request line + ordered pairs. +- dma-names: identifier string for each DMA request line in the dmas property. + These strings correspond 1:1 with the ordered pairs in dmas. The dma + identifiers must be "rx" and "tx". Optional properties: @@ -23,18 +31,23 @@ Optional properties: - rx-num-evt : FIFO levels. - sram-size-playback : size of sram to be allocated during playback - sram-size-capture : size of sram to be allocated during capture +- interrupts : Interrupt numbers for McASP, currently not used by the driver +- interrupt-names : Known interrupt names are "tx" and "rx" +- pinctrl-0: Should specify pin control group used for this controller. +- pinctrl-names: Should contain only one value - "default", for more details + please refer to pinctrl-bindings.txt + Example: mcasp0: mcasp0@1d00000 { compatible = "ti,da830-mcasp-audio"; - #address-cells = <1>; - #size-cells = <0>; reg = <0x100000 0x3000>; - interrupts = <82 83>; + reg-names "mpu"; + interrupts = <82>, <83>; + interrupts-names = "tx", "rx"; op-mode = <0>; /* MCASP_IIS_MODE */ tdm-slots = <2>; - num-serializer = <16>; serial-dir = < 0 0 0 0 /* 0: INACTIVE, 1: TX, 2: RX */ 0 0 0 0 diff --git a/Documentation/sound/alsa/soc/DPCM.txt b/Documentation/sound/alsa/soc/DPCM.txt new file mode 100644 index 000000000000..aa8546f2d144 --- /dev/null +++ b/Documentation/sound/alsa/soc/DPCM.txt @@ -0,0 +1,380 @@ +Dynamic PCM +=========== + +1. Description +============== + +Dynamic PCM allows an ALSA PCM device to digitally route its PCM audio to +various digital endpoints during the PCM stream runtime. e.g. PCM0 can route +digital audio to I2S DAI0, I2S DAI1 or PDM DAI2. This is useful for on SoC DSP +drivers that expose several ALSA PCMs and can route to multiple DAIs. + +The DPCM runtime routing is determined by the ALSA mixer settings in the same +way as the analog signal is routed in an ASoC codec driver. DPCM uses a DAPM +graph representing the DSP internal audio paths and uses the mixer settings to +determine the patch used by each ALSA PCM. + +DPCM re-uses all the existing component codec, platform and DAI drivers without +any modifications. + + +Phone Audio System with SoC based DSP +------------------------------------- + +Consider the following phone audio subsystem. This will be used in this +document for all examples :- + +| Front End PCMs | SoC DSP | Back End DAIs | Audio devices | + + ************* +PCM0 <------------> * * <----DAI0-----> Codec Headset + * * +PCM1 <------------> * * <----DAI1-----> Codec Speakers + * DSP * +PCM2 <------------> * * <----DAI2-----> MODEM + * * +PCM3 <------------> * * <----DAI3-----> BT + * * + * * <----DAI4-----> DMIC + * * + * * <----DAI5-----> FM + ************* + +This diagram shows a simple smart phone audio subsystem. It supports Bluetooth, +FM digital radio, Speakers, Headset Jack, digital microphones and cellular +modem. This sound card exposes 4 DSP front end (FE) ALSA PCM devices and +supports 6 back end (BE) DAIs. Each FE PCM can digitally route audio data to any +of the BE DAIs. The FE PCM devices can also route audio to more than 1 BE DAI. + + + +Example - DPCM Switching playback from DAI0 to DAI1 +--------------------------------------------------- + +Audio is being played to the Headset. After a while the user removes the headset +and audio continues playing on the speakers. + +Playback on PCM0 to Headset would look like :- + + ************* +PCM0 <============> * * <====DAI0=====> Codec Headset + * * +PCM1 <------------> * * <----DAI1-----> Codec Speakers + * DSP * +PCM2 <------------> * * <----DAI2-----> MODEM + * * +PCM3 <------------> * * <----DAI3-----> BT + * * + * * <----DAI4-----> DMIC + * * + * * <----DAI5-----> FM + ************* + +The headset is removed from the jack by user so the speakers must now be used :- + + ************* +PCM0 <============> * * <----DAI0-----> Codec Headset + * * +PCM1 <------------> * * <====DAI1=====> Codec Speakers + * DSP * +PCM2 <------------> * * <----DAI2-----> MODEM + * * +PCM3 <------------> * * <----DAI3-----> BT + * * + * * <----DAI4-----> DMIC + * * + * * <----DAI5-----> FM + ************* + +The audio driver processes this as follows :- + + 1) Machine driver receives Jack removal event. + + 2) Machine driver OR audio HAL disables the Headset path. + + 3) DPCM runs the PCM trigger(stop), hw_free(), shutdown() operations on DAI0 + for headset since the path is now disabled. + + 4) Machine driver or audio HAL enables the speaker path. + + 5) DPCM runs the PCM ops for startup(), hw_params(), prepapre() and + trigger(start) for DAI1 Speakers since the path is enabled. + +In this example, the machine driver or userspace audio HAL can alter the routing +and then DPCM will take care of managing the DAI PCM operations to either bring +the link up or down. Audio playback does not stop during this transition. + + + +DPCM machine driver +=================== + +The DPCM enabled ASoC machine driver is similar to normal machine drivers +except that we also have to :- + + 1) Define the FE and BE DAI links. + + 2) Define any FE/BE PCM operations. + + 3) Define widget graph connections. + + +1 FE and BE DAI links +--------------------- + +| Front End PCMs | SoC DSP | Back End DAIs | Audio devices | + + ************* +PCM0 <------------> * * <----DAI0-----> Codec Headset + * * +PCM1 <------------> * * <----DAI1-----> Codec Speakers + * DSP * +PCM2 <------------> * * <----DAI2-----> MODEM + * * +PCM3 <------------> * * <----DAI3-----> BT + * * + * * <----DAI4-----> DMIC + * * + * * <----DAI5-----> FM + ************* + +For the example above we have to define 4 FE DAI links and 6 BE DAI links. The +FE DAI links are defined as follows :- + +static struct snd_soc_dai_link machine_dais[] = { + { + .name = "PCM0 System", + .stream_name = "System Playback", + .cpu_dai_name = "System Pin", + .platform_name = "dsp-audio", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + }, + .....< other FE and BE DAI links here > +}; + +This FE DAI link is pretty similar to a regular DAI link except that we also +set the DAI link to a DPCM FE with the "dynamic = 1". The supported FE stream +directions should also be set with the "dpcm_playback" and "dpcm_capture" +flags. There is also an option to specify the ordering of the trigger call for +each FE. This allows the ASoC core to trigger the DSP before or after the other +components (as some DSPs have strong requirements for the ordering DAI/DSP +start and stop sequences). + +The FE DAI above sets the codec and code DAIs to dummy devices since the BE is +dynamic and will change depending on runtime config. + +The BE DAIs are configured as follows :- + +static struct snd_soc_dai_link machine_dais[] = { + .....< FE DAI links here > + { + .name = "Codec Headset", + .cpu_dai_name = "ssp-dai.0", + .platform_name = "snd-soc-dummy", + .no_pcm = 1, + .codec_name = "rt5640.0-001c", + .codec_dai_name = "rt5640-aif1", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = hswult_ssp0_fixup, + .ops = &haswell_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + .....< other BE DAI links here > +}; + +This BE DAI link connects DAI0 to the codec (in this case RT5460 AIF1). It sets +the "no_pcm" flag to mark it has a BE and sets flags for supported stream +directions using "dpcm_playback" and "dpcm_capture" above. + +The BE has also flags set for ignoreing suspend and PM down time. This allows +the BE to work in a hostless mode where the host CPU is not transferring data +like a BT phone call :- + + ************* +PCM0 <------------> * * <----DAI0-----> Codec Headset + * * +PCM1 <------------> * * <----DAI1-----> Codec Speakers + * DSP * +PCM2 <------------> * * <====DAI2=====> MODEM + * * +PCM3 <------------> * * <====DAI3=====> BT + * * + * * <----DAI4-----> DMIC + * * + * * <----DAI5-----> FM + ************* + +This allows the host CPU to sleep whilst the DSP, MODEM DAI and the BT DAI are +still in operation. + +A BE DAI link can also set the codec to a dummy device if the code is a device +that is managed externally. + +Likewise a BE DAI can also set a dummy cpu DAI if the CPU DAI is managed by the +DSP firmware. + + +2 FE/BE PCM operations +---------------------- + +The BE above also exports some PCM operations and a "fixup" callback. The fixup +callback is used by the machine driver to (re)configure the DAI based upon the +FE hw params. i.e. the DSP may perform SRC or ASRC from the FE to BE. + +e.g. DSP converts all FE hw params to run at fixed rate of 48k, 16bit, stereo for +DAI0. This means all FE hw_params have to be fixed in the machine driver for +DAI0 so that the DAI is running at desired configuration regardless of the FE +configuration. + +static int dai0_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + /* The DSP will covert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set DAI0 to 16 bit */ + snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - + SNDRV_PCM_HW_PARAM_FIRST_MASK], + SNDRV_PCM_FORMAT_S16_LE); + return 0; +} + +The other PCM operation are the same as for regular DAI links. Use as necessary. + + +3 Widget graph connections +-------------------------- + +The BE DAI links will normally be connected to the graph at initialisation time +by the ASoC DAPM core. However, if the BE codec or BE DAI is a dummy then this +has to be set explicitly in the driver :- + +/* BE for codec Headset - DAI0 is dummy and managed by DSP FW */ +{"DAI0 CODEC IN", NULL, "AIF1 Capture"}, +{"AIF1 Playback", NULL, "DAI0 CODEC OUT"}, + + +Writing a DPCM DSP driver +========================= + +The DPCM DSP driver looks much like a standard platform class ASoC driver +combined with elements from a codec class driver. A DSP platform driver must +implement :- + + 1) Front End PCM DAIs - i.e. struct snd_soc_dai_driver. + + 2) DAPM graph showing DSP audio routing from FE DAIs to BEs. + + 3) DAPM widgets from DSP graph. + + 4) Mixers for gains, routing, etc. + + 5) DMA configuration. + + 6) BE AIF widgets. + +Items 6 is important for routing the audio outside of the DSP. AIF need to be +defined for each BE and each stream direction. e.g for BE DAI0 above we would +have :- + +SND_SOC_DAPM_AIF_IN("DAI0 RX", NULL, 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_OUT("DAI0 TX", NULL, 0, SND_SOC_NOPM, 0, 0), + +The BE AIF are used to connect the DSP graph to the graphs for the other +component drivers (e.g. codec graph). + + +Hostless PCM streams +==================== + +A hostless PCM stream is a stream that is not routed through the host CPU. An +example of this would be a phone call from handset to modem. + + + ************* +PCM0 <------------> * * <----DAI0-----> Codec Headset + * * +PCM1 <------------> * * <====DAI1=====> Codec Speakers/Mic + * DSP * +PCM2 <------------> * * <====DAI2=====> MODEM + * * +PCM3 <------------> * * <----DAI3-----> BT + * * + * * <----DAI4-----> DMIC + * * + * * <----DAI5-----> FM + ************* + +In this case the PCM data is routed via the DSP. The host CPU in this use case +is only used for control and can sleep during the runtime of the stream. + +The host can control the hostless link either by :- + + 1) Configuring the link as a CODEC <-> CODEC style link. In this case the link + is enabled or disabled by the state of the DAPM graph. This usually means + there is a mixer control that can be used to connect or disconnect the path + between both DAIs. + + 2) Hostless FE. This FE has a virtual connection to the BE DAI links on the DAPM + graph. Control is then carried out by the FE as regualar PCM operations. + This method gives more control over the DAI links, but requires much more + userspace code to control the link. Its recommended to use CODEC<->CODEC + unless your HW needs more fine grained sequencing of the PCM ops. + + +CODEC <-> CODEC link +-------------------- + +This DAI link is enabled when DAPM detects a valid path within the DAPM graph. +The machine driver sets some additional parameters to the DAI link i.e. + +static const struct snd_soc_pcm_stream dai_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 dais[] = { + < ... more DAI links above ... > + { + .name = "MODEM", + .stream_name = "MODEM", + .cpu_dai_name = "dai2", + .codec_dai_name = "modem-aif1", + .codec_name = "modem", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .params = &dai_params, + } + < ... more DAI links here ... > + +These parameters are used to configure the DAI hw_params() when DAPM detects a +valid path and then calls the PCM operations to start the link. DAPM will also +call the appropriate PCM operations to disable the DAI when the path is no +longer valid. + + +Hostless FE +----------- + +The DAI link(s) are enabled by a FE that does not read or write any PCM data. +This means creating a new FE that is connected with a virtual path to both +DAI links. The DAI links will be started when the FE PCM is started and stopped +when the FE PCM is stopped. Note that the FE PCM cannot read or write data in +this configuration. + + diff --git a/Documentation/sound/alsa/soc/codec.txt b/Documentation/sound/alsa/soc/codec.txt index bce23a4a7875..db5f9c9ae149 100644 --- a/Documentation/sound/alsa/soc/codec.txt +++ b/Documentation/sound/alsa/soc/codec.txt @@ -1,22 +1,23 @@ -ASoC Codec Driver -================= +ASoC Codec Class Driver +======================= -The codec driver is generic and hardware independent code that configures the -codec to provide audio capture and playback. It should contain no code that is -specific to the target platform or machine. All platform and machine specific -code should be added to the platform and machine drivers respectively. +The codec class driver is generic and hardware independent code that configures +the codec, FM, MODEM, BT or external DSP to provide audio capture and playback. +It should contain no code that is specific to the target platform or machine. +All platform and machine specific code should be added to the platform and +machine drivers respectively. -Each codec driver *must* provide the following features:- +Each codec class driver *must* provide the following features:- 1) Codec DAI and PCM configuration - 2) Codec control IO - using I2C, 3 Wire(SPI) or both APIs + 2) Codec control IO - using RegMap API 3) Mixers and audio controls 4) Codec audio operations + 5) DAPM description. + 6) DAPM event handler. Optionally, codec drivers can also provide:- - 5) DAPM description. - 6) DAPM event handler. 7) DAC Digital mute control. Its probably best to use this guide in conjunction with the existing codec @@ -64,26 +65,9 @@ struct snd_soc_dai_driver wm8731_dai = { 2 - Codec control IO -------------------- The codec can usually be controlled via an I2C or SPI style interface -(AC97 combines control with data in the DAI). The codec drivers provide -functions to read and write the codec registers along with supplying a -register cache:- - - /* IO control data and register cache */ - void *control_data; /* codec control (i2c/3wire) data */ - void *reg_cache; - -Codec read/write should do any data formatting and call the hardware -read write below to perform the IO. These functions are called by the -core and ALSA when performing DAPM or changing the mixer:- - - unsigned int (*read)(struct snd_soc_codec *, unsigned int); - int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); - -Codec hardware IO functions - usually points to either the I2C, SPI or AC97 -read/write:- - - hw_write_t hw_write; - hw_read_t hw_read; +(AC97 combines control with data in the DAI). The codec driver should use the +Regmap API for all codec IO. Please see include/linux/regmap.h and existing +codec drivers for example regmap usage. 3 - Mixers and audio controls @@ -127,7 +111,7 @@ Defines a stereo enumerated control 4 - Codec Audio Operations -------------------------- -The codec driver also supports the following ALSA operations:- +The codec driver also supports the following ALSA PCM operations:- /* SoC audio ops */ struct snd_soc_ops { diff --git a/Documentation/sound/alsa/soc/dapm.txt b/Documentation/sound/alsa/soc/dapm.txt index 05bf5a0eee41..7dfd88ce31ac 100644 --- a/Documentation/sound/alsa/soc/dapm.txt +++ b/Documentation/sound/alsa/soc/dapm.txt @@ -21,7 +21,7 @@ level power systems. There are 4 power domains within DAPM - 1. Codec domain - VREF, VMID (core codec and audio power) + 1. Codec bias domain - VREF, VMID (core codec and audio power) Usually controlled at codec probe/remove and suspend/resume, although can be set at stream time if power is not needed for sidetone, etc. @@ -63,14 +63,22 @@ Audio DAPM widgets fall into a number of types:- o Line - Line Input/Output (and optional Jack) o Speaker - Speaker o Supply - Power or clock supply widget used by other widgets. + o Regulator - External regulator that supplies power to audio components. + o Clock - External clock that supplies clock to audio componnents. + o AIF IN - Audio Interface Input (with TDM slot mask). + o AIF OUT - Audio Interface Output (with TDM slot mask). + o Siggen - Signal Generator. + o DAI IN - Digital Audio Interface Input. + o DAI OUT - Digital Audio Interface Output. + o DAI Link - DAI Link between two DAI structures */ o Pre - Special PRE widget (exec before all others) o Post - Special POST widget (exec after all others) (Widgets are defined in include/sound/soc-dapm.h) -Widgets are usually added in the codec driver and the machine driver. There are -convenience macros defined in soc-dapm.h that can be used to quickly build a -list of widgets of the codecs and machines DAPM widgets. +Widgets can be added to the sound card by any of the component driver types. +There are convenience macros defined in soc-dapm.h that can be used to quickly +build a list of widgets of the codecs and machines DAPM widgets. Most widgets have a name, register, shift and invert. Some widgets have extra parameters for stream name and kcontrols. @@ -80,11 +88,13 @@ parameters for stream name and kcontrols. ------------------------- Stream Widgets relate to the stream power domain and only consist of ADCs -(analog to digital converters) and DACs (digital to analog converters). +(analog to digital converters), DACs (digital to analog converters), +AIF IN and AIF OUT. Stream widgets have the following format:- SND_SOC_DAPM_DAC(name, stream name, reg, shift, invert), +SND_SOC_DAPM_AIF_IN(name, stream, slot, reg, shift, invert) NOTE: the stream name must match the corresponding stream name in your codec snd_soc_codec_dai. @@ -94,6 +104,11 @@ e.g. stream widgets for HiFi playback and capture SND_SOC_DAPM_DAC("HiFi DAC", "HiFi Playback", REG, 3, 1), SND_SOC_DAPM_ADC("HiFi ADC", "HiFi Capture", REG, 2, 1), +e.g. stream widgets for AIF + +SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), + 2.2 Path Domain Widgets ----------------------- @@ -121,12 +136,14 @@ If you dont want the mixer elements prefixed with the name of the mixer widget, you can use SND_SOC_DAPM_MIXER_NAMED_CTL instead. the parameters are the same as for SND_SOC_DAPM_MIXER. -2.3 Platform/Machine domain Widgets ------------------------------------ + +2.3 Machine domain Widgets +-------------------------- Machine widgets are different from codec widgets in that they don't have a codec register bit associated with them. A machine widget is assigned to each -machine audio component (non codec) that can be independently powered. e.g. +machine audio component (non codec or DSP) that can be independently +powered. e.g. o Speaker Amp o Microphone Bias @@ -146,12 +163,12 @@ static int spitz_mic_bias(struct snd_soc_dapm_widget* w, int event) SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias), -2.4 Codec Domain ----------------- +2.4 Codec (BIAS) Domain +----------------------- -The codec power domain has no widgets and is handled by the codecs DAPM event -handler. This handler is called when the codec powerstate is changed wrt to any -stream event or by kernel PM events. +The codec bias power domain has no widgets and is handled by the codecs DAPM +event handler. This handler is called when the codec powerstate is changed wrt +to any stream event or by kernel PM events. 2.5 Virtual Widgets @@ -169,15 +186,16 @@ After all the widgets have been defined, they can then be added to the DAPM subsystem individually with a call to snd_soc_dapm_new_control(). -3. Codec Widget Interconnections -================================ +3. Codec/DSP Widget Interconnections +==================================== -Widgets are connected to each other within the codec and machine by audio paths -(called interconnections). Each interconnection must be defined in order to -create a map of all audio paths between widgets. +Widgets are connected to each other within the codec, platform and machine by +audio paths (called interconnections). Each interconnection must be defined in +order to create a map of all audio paths between widgets. -This is easiest with a diagram of the codec (and schematic of the machine audio -system), as it requires joining widgets together via their audio signal paths. +This is easiest with a diagram of the codec or DSP (and schematic of the machine +audio system), as it requires joining widgets together via their audio signal +paths. e.g., from the WM8731 output mixer (wm8731.c) @@ -247,16 +265,9 @@ machine and includes the codec. e.g. o Mic Jack o Codec Pins -When a codec pin is NC it can be marked as not used with a call to - -snd_soc_dapm_set_endpoint(codec, "Widget Name", 0); - -The last argument is 0 for inactive and 1 for active. This way the pin and its -input widget will never be powered up and consume power. - -This also applies to machine widgets. e.g. if a headphone is connected to a -jack then the jack can be marked active. If the headphone is removed, then -the headphone jack can be marked inactive. +Endpoints are added to the DAPM graph so that their usage can be determined in +order to save power. e.g. NC codecs pins will be switched OFF, unconnected +jacks can also be switched OFF. 5 DAPM Widget Events diff --git a/Documentation/sound/alsa/soc/machine.txt b/Documentation/sound/alsa/soc/machine.txt index d50c14df3411..74056dba52be 100644 --- a/Documentation/sound/alsa/soc/machine.txt +++ b/Documentation/sound/alsa/soc/machine.txt @@ -1,8 +1,10 @@ ASoC Machine Driver =================== -The ASoC machine (or board) driver is the code that glues together the platform -and codec drivers. +The ASoC machine (or board) driver is the code that glues together all the +component drivers (e.g. codecs, platforms and DAIs). It also describes the +relationships between each componnent which include audio paths, GPIOs, +interrupts, clocking, jacks and voltage regulators. The machine driver can contain codec and platform specific code. It registers the audio subsystem with the kernel as a platform device and is represented by diff --git a/Documentation/sound/alsa/soc/platform.txt b/Documentation/sound/alsa/soc/platform.txt index d57efad37e0a..3a08a2c9150c 100644 --- a/Documentation/sound/alsa/soc/platform.txt +++ b/Documentation/sound/alsa/soc/platform.txt @@ -1,9 +1,9 @@ ASoC Platform Driver ==================== -An ASoC platform driver can be divided into audio DMA and SoC DAI configuration -and control. The platform drivers only target the SoC CPU and must have no board -specific code. +An ASoC platform driver class can be divided into audio DMA drivers, SoC DAI +drivers and DSP drivers. The platform drivers only target the SoC CPU and must +have no board specific code. Audio DMA ========= @@ -64,3 +64,16 @@ Each SoC DAI driver must provide the following features:- 5) Suspend and resume (optional) Please see codec.txt for a description of items 1 - 4. + + +SoC DSP Drivers +=============== + +Each SoC DSP driver usually supplies the following features :- + + 1) DAPM graph + 2) Mixer controls + 3) DMA IO to/from DSP buffers (if applicable) + 4) Definition of DSP front end (FE) PCM devices. + +Please see DPCM.txt for a description of item 4. diff --git a/MAINTAINERS b/MAINTAINERS index 8a0cbf3cf2c8..a7c34ef3509d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -237,11 +237,11 @@ F: drivers/platform/x86/acer-wmi.c ACPI M: Len Brown <lenb@kernel.org> -M: Rafael J. Wysocki <rjw@sisk.pl> +M: Rafael J. Wysocki <rjw@rjwysocki.net> L: linux-acpi@vger.kernel.org -W: http://www.lesswatts.org/projects/acpi/ -Q: http://patchwork.kernel.org/project/linux-acpi/list/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux +W: https://01.org/linux-acpi +Q: https://patchwork.kernel.org/project/linux-acpi/list/ +T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm S: Supported F: drivers/acpi/ F: drivers/pnp/pnpacpi/ @@ -256,21 +256,21 @@ F: drivers/pci/*/*/*acpi* ACPI FAN DRIVER M: Zhang Rui <rui.zhang@intel.com> L: linux-acpi@vger.kernel.org -W: http://www.lesswatts.org/projects/acpi/ +W: https://01.org/linux-acpi S: Supported F: drivers/acpi/fan.c ACPI THERMAL DRIVER M: Zhang Rui <rui.zhang@intel.com> L: linux-acpi@vger.kernel.org -W: http://www.lesswatts.org/projects/acpi/ +W: https://01.org/linux-acpi S: Supported F: drivers/acpi/*thermal* ACPI VIDEO DRIVER M: Zhang Rui <rui.zhang@intel.com> L: linux-acpi@vger.kernel.org -W: http://www.lesswatts.org/projects/acpi/ +W: https://01.org/linux-acpi S: Supported F: drivers/acpi/video.c @@ -2300,7 +2300,7 @@ S: Maintained F: drivers/net/ethernet/ti/cpmac.c CPU FREQUENCY DRIVERS -M: Rafael J. Wysocki <rjw@sisk.pl> +M: Rafael J. Wysocki <rjw@rjwysocki.net> M: Viresh Kumar <viresh.kumar@linaro.org> L: cpufreq@vger.kernel.org L: linux-pm@vger.kernel.org @@ -2331,7 +2331,7 @@ S: Maintained F: drivers/cpuidle/cpuidle-big_little.c CPUIDLE DRIVERS -M: Rafael J. Wysocki <rjw@sisk.pl> +M: Rafael J. Wysocki <rjw@rjwysocki.net> M: Daniel Lezcano <daniel.lezcano@linaro.org> L: linux-pm@vger.kernel.org S: Maintained @@ -3553,7 +3553,7 @@ F: fs/freevxfs/ FREEZER M: Pavel Machek <pavel@ucw.cz> -M: "Rafael J. Wysocki" <rjw@sisk.pl> +M: "Rafael J. Wysocki" <rjw@rjwysocki.net> L: linux-pm@vger.kernel.org S: Supported F: Documentation/power/freezing-of-tasks.txt @@ -3624,6 +3624,12 @@ L: linux-scsi@vger.kernel.org S: Odd Fixes (e.g., new signatures) F: drivers/scsi/fdomain.* +GCOV BASED KERNEL PROFILING +M: Peter Oberparleiter <oberpar@linux.vnet.ibm.com> +S: Maintained +F: kernel/gcov/ +F: Documentation/gcov.txt + GDT SCSI DISK ARRAY CONTROLLER DRIVER M: Achim Leubner <achim_leubner@adaptec.com> L: linux-scsi@vger.kernel.org @@ -3889,7 +3895,7 @@ F: drivers/video/hgafb.c HIBERNATION (aka Software Suspend, aka swsusp) M: Pavel Machek <pavel@ucw.cz> -M: "Rafael J. Wysocki" <rjw@sisk.pl> +M: "Rafael J. Wysocki" <rjw@rjwysocki.net> L: linux-pm@vger.kernel.org S: Supported F: arch/x86/power/ @@ -4339,7 +4345,7 @@ F: drivers/video/i810/ INTEL MENLOW THERMAL DRIVER M: Sujith Thomas <sujith.thomas@intel.com> L: platform-driver-x86@vger.kernel.org -W: http://www.lesswatts.org/projects/acpi/ +W: https://01.org/linux-acpi S: Supported F: drivers/platform/x86/intel_menlow.c @@ -8095,7 +8101,7 @@ F: drivers/sh/ SUSPEND TO RAM M: Len Brown <len.brown@intel.com> M: Pavel Machek <pavel@ucw.cz> -M: "Rafael J. Wysocki" <rjw@sisk.pl> +M: "Rafael J. Wysocki" <rjw@rjwysocki.net> L: linux-pm@vger.kernel.org S: Supported F: Documentation/power/ @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 12 SUBLEVEL = 0 -EXTRAVERSION = -rc5 +EXTRAVERSION = -rc6 NAME = One Giant Leap for Frogkind # *DOCUMENTATION* diff --git a/arch/arm/common/mcpm_entry.c b/arch/arm/common/mcpm_entry.c index 370236dd1a03..990250965f2c 100644 --- a/arch/arm/common/mcpm_entry.c +++ b/arch/arm/common/mcpm_entry.c @@ -51,7 +51,8 @@ void mcpm_cpu_power_down(void) { phys_reset_t phys_reset; - BUG_ON(!platform_ops); + if (WARN_ON_ONCE(!platform_ops || !platform_ops->power_down)) + return; BUG_ON(!irqs_disabled()); /* @@ -93,7 +94,8 @@ void mcpm_cpu_suspend(u64 expected_residency) { phys_reset_t phys_reset; - BUG_ON(!platform_ops); + if (WARN_ON_ONCE(!platform_ops || !platform_ops->suspend)) + return; BUG_ON(!irqs_disabled()); /* Very similar to mcpm_cpu_power_down() */ diff --git a/arch/arm/common/sharpsl_param.c b/arch/arm/common/sharpsl_param.c index d56c932580eb..025f6ce38596 100644 --- a/arch/arm/common/sharpsl_param.c +++ b/arch/arm/common/sharpsl_param.c @@ -15,6 +15,7 @@ #include <linux/module.h> #include <linux/string.h> #include <asm/mach/sharpsl_param.h> +#include <asm/memory.h> /* * Certain hardware parameters determined at the time of device manufacture, @@ -25,8 +26,10 @@ */ #ifdef CONFIG_ARCH_SA1100 #define PARAM_BASE 0xe8ffc000 +#define param_start(x) (void *)(x) #else #define PARAM_BASE 0xa0000a00 +#define param_start(x) __va(x) #endif #define MAGIC_CHG(a,b,c,d) ( ( d << 24 ) | ( c << 16 ) | ( b << 8 ) | a ) @@ -41,7 +44,7 @@ EXPORT_SYMBOL(sharpsl_param); void sharpsl_save_param(void) { - memcpy(&sharpsl_param, (void *)PARAM_BASE, sizeof(struct sharpsl_param_info)); + memcpy(&sharpsl_param, param_start(PARAM_BASE), sizeof(struct sharpsl_param_info)); if (sharpsl_param.comadj_keyword != COMADJ_MAGIC) sharpsl_param.comadj=-1; diff --git a/arch/arm/include/asm/Kbuild b/arch/arm/include/asm/Kbuild index d3db39860b9c..59ceae8f3c95 100644 --- a/arch/arm/include/asm/Kbuild +++ b/arch/arm/include/asm/Kbuild @@ -31,5 +31,4 @@ generic-y += termbits.h generic-y += termios.h generic-y += timex.h generic-y += trace_clock.h -generic-y += types.h generic-y += unaligned.h diff --git a/arch/arm/include/asm/mcpm.h b/arch/arm/include/asm/mcpm.h index 0f7b7620e9a5..fc82a88f5b69 100644 --- a/arch/arm/include/asm/mcpm.h +++ b/arch/arm/include/asm/mcpm.h @@ -76,8 +76,11 @@ int mcpm_cpu_power_up(unsigned int cpu, unsigned int cluster); * * This must be called with interrupts disabled. * - * This does not return. Re-entry in the kernel is expected via - * mcpm_entry_point. + * On success this does not return. Re-entry in the kernel is expected + * via mcpm_entry_point. + * + * This will return if mcpm_platform_register() has not been called + * previously in which case the caller should take appropriate action. */ void mcpm_cpu_power_down(void); @@ -98,8 +101,11 @@ void mcpm_cpu_power_down(void); * * This must be called with interrupts disabled. * - * This does not return. Re-entry in the kernel is expected via - * mcpm_entry_point. + * On success this does not return. Re-entry in the kernel is expected + * via mcpm_entry_point. + * + * This will return if mcpm_platform_register() has not been called + * previously in which case the caller should take appropriate action. */ void mcpm_cpu_suspend(u64 expected_residency); diff --git a/arch/arm/include/asm/syscall.h b/arch/arm/include/asm/syscall.h index f1d96d4e8092..73ddd7239b33 100644 --- a/arch/arm/include/asm/syscall.h +++ b/arch/arm/include/asm/syscall.h @@ -57,6 +57,9 @@ static inline void syscall_get_arguments(struct task_struct *task, unsigned int i, unsigned int n, unsigned long *args) { + if (n == 0) + return; + if (i + n > SYSCALL_MAX_ARGS) { unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i; unsigned int n_bad = n + i - SYSCALL_MAX_ARGS; @@ -81,6 +84,9 @@ static inline void syscall_set_arguments(struct task_struct *task, unsigned int i, unsigned int n, const unsigned long *args) { + if (n == 0) + return; + if (i + n > SYSCALL_MAX_ARGS) { pr_warning("%s called with max args %d, handling only %d\n", __func__, i + n, SYSCALL_MAX_ARGS); diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 2c7cc1e03473..476de57dcef2 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -487,7 +487,26 @@ __fixup_smp: mrc p15, 0, r0, c0, c0, 5 @ read MPIDR and r0, r0, #0xc0000000 @ multiprocessing extensions and teq r0, #0x80000000 @ not part of a uniprocessor system? - moveq pc, lr @ yes, assume SMP + bne __fixup_smp_on_up @ no, assume UP + + @ Core indicates it is SMP. Check for Aegis SOC where a single + @ Cortex-A9 CPU is present but SMP operations fault. + mov r4, #0x41000000 + orr r4, r4, #0x0000c000 + orr r4, r4, #0x00000090 + teq r3, r4 @ Check for ARM Cortex-A9 + movne pc, lr @ Not ARM Cortex-A9, + + @ If a future SoC *does* use 0x0 as the PERIPH_BASE, then the + @ below address check will need to be #ifdef'd or equivalent + @ for the Aegis platform. + mrc p15, 4, r0, c15, c0 @ get SCU base address + teq r0, #0x0 @ '0' on actual UP A9 hardware + beq __fixup_smp_on_up @ So its an A9 UP + ldr r0, [r0, #4] @ read SCU Config + and r0, r0, #0x3 @ number of CPUs + teq r0, #0x0 @ is 1? + movne pc, lr __fixup_smp_on_up: adr r0, 1f diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index f5e1a8471714..1272ed202dde 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1232,7 +1232,8 @@ __iommu_create_mapping(struct device *dev, struct page **pages, size_t size) break; len = (j - i) << PAGE_SHIFT; - ret = iommu_map(mapping->domain, iova, phys, len, 0); + ret = iommu_map(mapping->domain, iova, phys, len, + IOMMU_READ|IOMMU_WRITE); if (ret < 0) goto fail; iova += len; @@ -1431,6 +1432,27 @@ static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt, GFP_KERNEL); } +static int __dma_direction_to_prot(enum dma_data_direction dir) +{ + int prot; + + switch (dir) { + case DMA_BIDIRECTIONAL: + prot = IOMMU_READ | IOMMU_WRITE; + break; + case DMA_TO_DEVICE: + prot = IOMMU_READ; + break; + case DMA_FROM_DEVICE: + prot = IOMMU_WRITE; + break; + default: + prot = 0; + } + + return prot; +} + /* * Map a part of the scatter-gather list into contiguous io address space */ @@ -1444,6 +1466,7 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg, int ret = 0; unsigned int count; struct scatterlist *s; + int prot; size = PAGE_ALIGN(size); *handle = DMA_ERROR_CODE; @@ -1460,7 +1483,9 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg, !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs)) __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir); - ret = iommu_map(mapping->domain, iova, phys, len, 0); + prot = __dma_direction_to_prot(dir); + + ret = iommu_map(mapping->domain, iova, phys, len, prot); if (ret < 0) goto fail; count += len >> PAGE_SHIFT; @@ -1665,19 +1690,7 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *p if (dma_addr == DMA_ERROR_CODE) return dma_addr; - switch (dir) { - case DMA_BIDIRECTIONAL: - prot = IOMMU_READ | IOMMU_WRITE; - break; - case DMA_TO_DEVICE: - prot = IOMMU_READ; - break; - case DMA_FROM_DEVICE: - prot = IOMMU_WRITE; - break; - default: - prot = 0; - } + prot = __dma_direction_to_prot(dir); ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len, prot); if (ret < 0) diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index febaee7ca57b..18ec4c504abf 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -17,7 +17,6 @@ #include <linux/nodemask.h> #include <linux/initrd.h> #include <linux/of_fdt.h> -#include <linux/of_reserved_mem.h> #include <linux/highmem.h> #include <linux/gfp.h> #include <linux/memblock.h> @@ -379,8 +378,6 @@ void __init arm_memblock_init(struct meminfo *mi, if (mdesc->reserve) mdesc->reserve(); - early_init_dt_scan_reserved_mem(); - /* * reserve memory for DMA contigouos allocations, * must come from DMA area inside low memory diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 145d703227bf..f67e839f06c8 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1033,6 +1033,7 @@ config X86_REBOOTFIXUPS config MICROCODE tristate "CPU microcode loading support" + depends on CPU_SUP_AMD || CPU_SUP_INTEL select FW_LOADER ---help--- diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 1191ac1c9d25..a419814cea57 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -113,7 +113,7 @@ static int __init early_get_pnodeid(void) break; case UV3_HUB_PART_NUMBER: case UV3_HUB_PART_NUMBER_X: - uv_min_hub_revision_id += UV3_HUB_REVISION_BASE - 1; + uv_min_hub_revision_id += UV3_HUB_REVISION_BASE; break; } diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 697b93af02dd..a0e2a8a80c94 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -775,11 +775,22 @@ void __init kvm_spinlock_init(void) if (!kvm_para_has_feature(KVM_FEATURE_PV_UNHALT)) return; - printk(KERN_INFO "KVM setup paravirtual spinlock\n"); + pv_lock_ops.lock_spinning = PV_CALLEE_SAVE(kvm_lock_spinning); + pv_lock_ops.unlock_kick = kvm_unlock_kick; +} + +static __init int kvm_spinlock_init_jump(void) +{ + if (!kvm_para_available()) + return 0; + if (!kvm_para_has_feature(KVM_FEATURE_PV_UNHALT)) + return 0; static_key_slow_inc(¶virt_ticketlocks_enabled); + printk(KERN_INFO "KVM setup paravirtual spinlock\n"); - pv_lock_ops.lock_spinning = PV_CALLEE_SAVE(kvm_lock_spinning); - pv_lock_ops.unlock_kick = kvm_unlock_kick; + return 0; } +early_initcall(kvm_spinlock_init_jump); + #endif /* CONFIG_PARAVIRT_SPINLOCKS */ diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index d1e4777b4e75..31d04758b76f 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -278,6 +278,15 @@ static void __init xen_smp_prepare_boot_cpu(void) old memory can be recycled */ make_lowmem_page_readwrite(xen_initial_gdt); +#ifdef CONFIG_X86_32 + /* + * Xen starts us with XEN_FLAT_RING1_DS, but linux code + * expects __USER_DS + */ + loadsegment(ds, __USER_DS); + loadsegment(es, __USER_DS); +#endif + xen_filter_cpu_maps(); xen_setup_vcpu_info_placement(); } diff --git a/block/partitions/efi.c b/block/partitions/efi.c index 1eb09ee5311b..a8287b49d062 100644 --- a/block/partitions/efi.c +++ b/block/partitions/efi.c @@ -222,11 +222,16 @@ check_hybrid: * the disk size. * * Hybrid MBRs do not necessarily comply with this. + * + * Consider a bad value here to be a warning to support dd'ing + * an image from a smaller disk to a larger disk. */ if (ret == GPT_MBR_PROTECTIVE) { sz = le32_to_cpu(mbr->partition_record[part].size_in_lba); if (sz != (uint32_t) total_sectors - 1 && sz != 0xFFFFFFFF) - ret = 0; + pr_debug("GPT: mbr size in lba (%u) different than whole disk (%u).\n", + sz, min_t(uint32_t, + total_sectors - 1, 0xFFFFFFFF)); } done: return ret; diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 22327e6a7236..6efe2ac6902f 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -24,7 +24,7 @@ menuconfig ACPI are configured, ACPI is used. The project home page for the Linux ACPI subsystem is here: - <http://www.lesswatts.org/projects/acpi/> + <https://01.org/linux-acpi> Linux support for ACPI is based on Intel Corporation's ACPI Component Architecture (ACPI CA). For more information on the @@ -123,9 +123,9 @@ config ACPI_BUTTON default y help This driver handles events on the power, sleep, and lid buttons. - A daemon reads /proc/acpi/event and perform user-defined actions - such as shutting down the system. This is necessary for - software-controlled poweroff. + A daemon reads events from input devices or via netlink and + performs user-defined actions such as shutting down the system. + This is necessary for software-controlled poweroff. To compile this driver as a module, choose M here: the module will be called button. diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 59d3202f6b36..a94383d1f350 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -1025,60 +1025,4 @@ void acpi_dev_pm_detach(struct device *dev, bool power_off) } } EXPORT_SYMBOL_GPL(acpi_dev_pm_detach); - -/** - * acpi_dev_pm_add_dependent - Add physical device depending for PM. - * @handle: Handle of ACPI device node. - * @depdev: Device depending on that node for PM. - */ -void acpi_dev_pm_add_dependent(acpi_handle handle, struct device *depdev) -{ - struct acpi_device_physical_node *dep; - struct acpi_device *adev; - - if (!depdev || acpi_bus_get_device(handle, &adev)) - return; - - mutex_lock(&adev->physical_node_lock); - - list_for_each_entry(dep, &adev->power_dependent, node) - if (dep->dev == depdev) - goto out; - - dep = kzalloc(sizeof(*dep), GFP_KERNEL); - if (dep) { - dep->dev = depdev; - list_add_tail(&dep->node, &adev->power_dependent); - } - - out: - mutex_unlock(&adev->physical_node_lock); -} -EXPORT_SYMBOL_GPL(acpi_dev_pm_add_dependent); - -/** - * acpi_dev_pm_remove_dependent - Remove physical device depending for PM. - * @handle: Handle of ACPI device node. - * @depdev: Device depending on that node for PM. - */ -void acpi_dev_pm_remove_dependent(acpi_handle handle, struct device *depdev) -{ - struct acpi_device_physical_node *dep; - struct acpi_device *adev; - - if (!depdev || acpi_bus_get_device(handle, &adev)) - return; - - mutex_lock(&adev->physical_node_lock); - - list_for_each_entry(dep, &adev->power_dependent, node) - if (dep->dev == depdev) { - list_del(&dep->node); - kfree(dep); - break; - } - - mutex_unlock(&adev->physical_node_lock); -} -EXPORT_SYMBOL_GPL(acpi_dev_pm_remove_dependent); #endif /* CONFIG_PM */ diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 0dbe5cdf3396..c2ad391d8041 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -59,16 +59,9 @@ ACPI_MODULE_NAME("power"); #define ACPI_POWER_RESOURCE_STATE_ON 0x01 #define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF -struct acpi_power_dependent_device { - struct list_head node; - struct acpi_device *adev; - struct work_struct work; -}; - struct acpi_power_resource { struct acpi_device device; struct list_head list_node; - struct list_head dependent; char *name; u32 system_level; u32 order; @@ -233,32 +226,6 @@ static int acpi_power_get_list_state(struct list_head *list, int *state) return 0; } -static void acpi_power_resume_dependent(struct work_struct *work) -{ - struct acpi_power_dependent_device *dep; - struct acpi_device_physical_node *pn; - struct acpi_device *adev; - int state; - - dep = container_of(work, struct acpi_power_dependent_device, work); - adev = dep->adev; - if (acpi_power_get_inferred_state(adev, &state)) - return; - - if (state > ACPI_STATE_D0) - return; - - mutex_lock(&adev->physical_node_lock); - - list_for_each_entry(pn, &adev->physical_node_list, node) - pm_request_resume(pn->dev); - - list_for_each_entry(pn, &adev->power_dependent, node) - pm_request_resume(pn->dev); - - mutex_unlock(&adev->physical_node_lock); -} - static int __acpi_power_on(struct acpi_power_resource *resource) { acpi_status status = AE_OK; @@ -283,14 +250,8 @@ static int acpi_power_on_unlocked(struct acpi_power_resource *resource) resource->name)); } else { result = __acpi_power_on(resource); - if (result) { + if (result) resource->ref_count--; - } else { - struct acpi_power_dependent_device *dep; - - list_for_each_entry(dep, &resource->dependent, node) - schedule_work(&dep->work); - } } return result; } @@ -390,52 +351,6 @@ static int acpi_power_on_list(struct list_head *list) return result; } -static void acpi_power_add_dependent(struct acpi_power_resource *resource, - struct acpi_device *adev) -{ - struct acpi_power_dependent_device *dep; - - mutex_lock(&resource->resource_lock); - - list_for_each_entry(dep, &resource->dependent, node) - if (dep->adev == adev) - goto out; - - dep = kzalloc(sizeof(*dep), GFP_KERNEL); - if (!dep) - goto out; - - dep->adev = adev; - INIT_WORK(&dep->work, acpi_power_resume_dependent); - list_add_tail(&dep->node, &resource->dependent); - - out: - mutex_unlock(&resource->resource_lock); -} - -static void acpi_power_remove_dependent(struct acpi_power_resource *resource, - struct acpi_device *adev) -{ - struct acpi_power_dependent_device *dep; - struct work_struct *work = NULL; - - mutex_lock(&resource->resource_lock); - - list_for_each_entry(dep, &resource->dependent, node) - if (dep->adev == adev) { - list_del(&dep->node); - work = &dep->work; - break; - } - - mutex_unlock(&resource->resource_lock); - - if (work) { - cancel_work_sync(work); - kfree(dep); - } -} - static struct attribute *attrs[] = { NULL, }; @@ -524,8 +439,6 @@ static void acpi_power_expose_hide(struct acpi_device *adev, void acpi_power_add_remove_device(struct acpi_device *adev, bool add) { - struct acpi_device_power_state *ps; - struct acpi_power_resource_entry *entry; int state; if (adev->wakeup.flags.valid) @@ -535,16 +448,6 @@ void acpi_power_add_remove_device(struct acpi_device *adev, bool add) if (!adev->power.flags.power_resources) return; - ps = &adev->power.states[ACPI_STATE_D0]; - list_for_each_entry(entry, &ps->resources, node) { - struct acpi_power_resource *resource = entry->resource; - - if (add) - acpi_power_add_dependent(resource, adev); - else - acpi_power_remove_dependent(resource, adev); - } - for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++) acpi_power_expose_hide(adev, &adev->power.states[state].resources, @@ -882,7 +785,6 @@ int acpi_add_power_resource(acpi_handle handle) acpi_init_device_object(device, handle, ACPI_BUS_TYPE_POWER, ACPI_STA_DEFAULT); mutex_init(&resource->resource_lock); - INIT_LIST_HEAD(&resource->dependent); INIT_LIST_HEAD(&resource->list_node); resource->name = device->pnp.bus_id; strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); @@ -936,8 +838,10 @@ void acpi_resume_power_resources(void) mutex_lock(&resource->resource_lock); result = acpi_power_get_state(resource->device.handle, &state); - if (result) + if (result) { + mutex_unlock(&resource->resource_lock); continue; + } if (state == ACPI_POWER_RESOURCE_STATE_OFF && resource->ref_count) { diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 407ad13cac2f..fee8a297c7d9 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -999,7 +999,6 @@ int acpi_device_add(struct acpi_device *device, INIT_LIST_HEAD(&device->wakeup_list); INIT_LIST_HEAD(&device->physical_node_list); mutex_init(&device->physical_node_lock); - INIT_LIST_HEAD(&device->power_dependent); new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL); if (!new_bus_id) { diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 4ba8b0405572..ab714d2ad978 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -1035,17 +1035,3 @@ void ata_acpi_on_disable(struct ata_device *dev) { ata_acpi_clear_gtf(dev); } - -void ata_scsi_acpi_bind(struct ata_device *dev) -{ - acpi_handle handle = ata_dev_acpi_handle(dev); - if (handle) - acpi_dev_pm_add_dependent(handle, &dev->sdev->sdev_gendev); -} - -void ata_scsi_acpi_unbind(struct ata_device *dev) -{ - acpi_handle handle = ata_dev_acpi_handle(dev); - if (handle) - acpi_dev_pm_remove_dependent(handle, &dev->sdev->sdev_gendev); -} diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 97a0cef12959..db6dfcfa3e2e 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3679,7 +3679,6 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) if (!IS_ERR(sdev)) { dev->sdev = sdev; scsi_device_put(sdev); - ata_scsi_acpi_bind(dev); } else { dev->sdev = NULL; } @@ -3767,8 +3766,6 @@ static void ata_scsi_remove_dev(struct ata_device *dev) struct scsi_device *sdev; unsigned long flags; - ata_scsi_acpi_unbind(dev); - /* Alas, we need to grab scan_mutex to ensure SCSI device * state doesn't change underneath us and thus * scsi_device_get() always succeeds. The mutex locking can diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index eeeb77845d48..45b5ab3a95d5 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -121,8 +121,6 @@ extern void ata_acpi_set_state(struct ata_port *ap, pm_message_t state); extern void ata_acpi_bind_port(struct ata_port *ap); extern void ata_acpi_bind_dev(struct ata_device *dev); extern acpi_handle ata_dev_acpi_handle(struct ata_device *dev); -extern void ata_scsi_acpi_bind(struct ata_device *dev); -extern void ata_scsi_acpi_unbind(struct ata_device *dev); #else static inline void ata_acpi_dissociate(struct ata_host *host) { } static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; } @@ -133,8 +131,6 @@ static inline void ata_acpi_set_state(struct ata_port *ap, pm_message_t state) { } static inline void ata_acpi_bind_port(struct ata_port *ap) {} static inline void ata_acpi_bind_dev(struct ata_device *dev) {} -static inline void ata_scsi_acpi_bind(struct ata_device *dev) {} -static inline void ata_scsi_acpi_unbind(struct ata_device *dev) {} #endif /* libata-scsi.c */ diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 9e59f6535c44..bece691cb5d9 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -333,8 +333,10 @@ store_mem_state(struct device *dev, online_type = ONLINE_KEEP; else if (!strncmp(buf, "offline", min_t(int, count, 7))) online_type = -1; - else - return -EINVAL; + else { + ret = -EINVAL; + goto err; + } switch (online_type) { case ONLINE_KERNEL: @@ -357,6 +359,7 @@ store_mem_state(struct device *dev, ret = -EINVAL; /* should never happen */ } +err: unlock_device_hotplug(); if (ret) diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 57f777835d97..6873b4ce03f9 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -44,7 +44,6 @@ struct regmap_format { struct regmap_async { struct list_head list; - struct work_struct cleanup; struct regmap *map; void *work_buf; }; @@ -64,9 +63,11 @@ struct regmap { void *bus_context; const char *name; + bool async; spinlock_t async_lock; wait_queue_head_t async_waitq; struct list_head async_list; + struct list_head async_free; int async_ret; #ifdef CONFIG_DEBUG_FS @@ -218,7 +219,7 @@ bool regcache_set_val(struct regmap *map, void *base, unsigned int idx, int regcache_lookup_reg(struct regmap *map, unsigned int reg); int _regmap_raw_write(struct regmap *map, unsigned int reg, - const void *val, size_t val_len, bool async); + const void *val, size_t val_len); void regmap_async_complete_cb(struct regmap_async *async, int ret); diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index d6c2d691b6e8..a36112af494c 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -631,8 +631,7 @@ static int regcache_sync_block_raw_flush(struct regmap *map, const void **data, map->cache_bypass = 1; - ret = _regmap_raw_write(map, base, *data, count * val_bytes, - false); + ret = _regmap_raw_write(map, base, *data, count * val_bytes); map->cache_bypass = 0; diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 7d689a15c500..0503d868ff8c 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -42,15 +42,6 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg, static int _regmap_bus_raw_write(void *context, unsigned int reg, unsigned int val); -static void async_cleanup(struct work_struct *work) -{ - struct regmap_async *async = container_of(work, struct regmap_async, - cleanup); - - kfree(async->work_buf); - kfree(async); -} - bool regmap_reg_in_ranges(unsigned int reg, const struct regmap_range *ranges, unsigned int nranges) @@ -465,6 +456,7 @@ struct regmap *regmap_init(struct device *dev, spin_lock_init(&map->async_lock); INIT_LIST_HEAD(&map->async_list); + INIT_LIST_HEAD(&map->async_free); init_waitqueue_head(&map->async_waitq); if (config->read_flag_mask || config->write_flag_mask) { @@ -942,12 +934,22 @@ EXPORT_SYMBOL_GPL(regmap_reinit_cache); */ void regmap_exit(struct regmap *map) { + struct regmap_async *async; + regcache_exit(map); regmap_debugfs_exit(map); regmap_range_exit(map); if (map->bus && map->bus->free_context) map->bus->free_context(map->bus_context); kfree(map->work_buf); + while (!list_empty(&map->async_free)) { + async = list_first_entry_or_null(&map->async_free, + struct regmap_async, + list); + list_del(&async->list); + kfree(async->work_buf); + kfree(async); + } kfree(map); } EXPORT_SYMBOL_GPL(regmap_exit); @@ -1039,7 +1041,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg, } int _regmap_raw_write(struct regmap *map, unsigned int reg, - const void *val, size_t val_len, bool async) + const void *val, size_t val_len) { struct regmap_range_node *range; unsigned long flags; @@ -1091,7 +1093,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, dev_dbg(map->dev, "Writing window %d/%zu\n", win_residue, val_len / map->format.val_bytes); ret = _regmap_raw_write(map, reg, val, win_residue * - map->format.val_bytes, async); + map->format.val_bytes); if (ret != 0) return ret; @@ -1114,21 +1116,42 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, u8[0] |= map->write_flag_mask; - if (async && map->bus->async_write) { - struct regmap_async *async = map->bus->async_alloc(); - if (!async) - return -ENOMEM; + /* + * Essentially all I/O mechanisms will be faster with a single + * buffer to write. Since register syncs often generate raw + * writes of single registers optimise that case. + */ + if (val != work_val && val_len == map->format.val_bytes) { + memcpy(work_val, val, map->format.val_bytes); + val = work_val; + } + + if (map->async && map->bus->async_write) { + struct regmap_async *async; trace_regmap_async_write_start(map->dev, reg, val_len); - async->work_buf = kzalloc(map->format.buf_size, - GFP_KERNEL | GFP_DMA); - if (!async->work_buf) { - kfree(async); - return -ENOMEM; + spin_lock_irqsave(&map->async_lock, flags); + async = list_first_entry_or_null(&map->async_free, + struct regmap_async, + list); + if (async) + list_del(&async->list); + spin_unlock_irqrestore(&map->async_lock, flags); + + if (!async) { + async = map->bus->async_alloc(); + if (!async) + return -ENOMEM; + + async->work_buf = kzalloc(map->format.buf_size, + GFP_KERNEL | GFP_DMA); + if (!async->work_buf) { + kfree(async); + return -ENOMEM; + } } - INIT_WORK(&async->cleanup, async_cleanup); async->map = map; /* If the caller supplied the value we can use it safely. */ @@ -1152,11 +1175,8 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, ret); spin_lock_irqsave(&map->async_lock, flags); - list_del(&async->list); + list_move(&async->list, &map->async_free); spin_unlock_irqrestore(&map->async_lock, flags); - - kfree(async->work_buf); - kfree(async); } return ret; @@ -1253,7 +1273,7 @@ static int _regmap_bus_raw_write(void *context, unsigned int reg, map->work_buf + map->format.reg_bytes + map->format.pad_bytes, - map->format.val_bytes, false); + map->format.val_bytes); } static inline void *_regmap_map_get_context(struct regmap *map) @@ -1318,6 +1338,37 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val) EXPORT_SYMBOL_GPL(regmap_write); /** + * regmap_write_async(): Write a value to a single register asynchronously + * + * @map: Register map to write to + * @reg: Register to write to + * @val: Value to be written + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val) +{ + int ret; + + if (reg % map->reg_stride) + return -EINVAL; + + map->lock(map->lock_arg); + + map->async = true; + + ret = _regmap_write(map, reg, val); + + map->async = false; + + map->unlock(map->lock_arg); + + return ret; +} +EXPORT_SYMBOL_GPL(regmap_write_async); + +/** * regmap_raw_write(): Write raw values to one or more registers * * @map: Register map to write to @@ -1345,7 +1396,7 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, map->lock(map->lock_arg); - ret = _regmap_raw_write(map, reg, val, val_len, false); + ret = _regmap_raw_write(map, reg, val, val_len); map->unlock(map->lock_arg); @@ -1426,8 +1477,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, return ret; } } else { - ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count, - false); + ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count); } if (val_bytes != 1) @@ -1473,7 +1523,11 @@ int regmap_raw_write_async(struct regmap *map, unsigned int reg, map->lock(map->lock_arg); - ret = _regmap_raw_write(map, reg, val, val_len, true); + map->async = true; + + ret = _regmap_raw_write(map, reg, val, val_len); + + map->async = false; map->unlock(map->lock_arg); @@ -1788,6 +1842,41 @@ int regmap_update_bits(struct regmap *map, unsigned int reg, EXPORT_SYMBOL_GPL(regmap_update_bits); /** + * regmap_update_bits_async: Perform a read/modify/write cycle on the register + * map asynchronously + * + * @map: Register map to update + * @reg: Register to update + * @mask: Bitmask to change + * @val: New value for bitmask + * + * With most buses the read must be done synchronously so this is most + * useful for devices with a cache which do not need to interact with + * the hardware to determine the current register value. + * + * Returns zero for success, a negative number on error. + */ +int regmap_update_bits_async(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val) +{ + bool change; + int ret; + + map->lock(map->lock_arg); + + map->async = true; + + ret = _regmap_update_bits(map, reg, mask, val, &change); + + map->async = false; + + map->unlock(map->lock_arg); + + return ret; +} +EXPORT_SYMBOL_GPL(regmap_update_bits_async); + +/** * regmap_update_bits_check: Perform a read/modify/write cycle on the * register map and report if updated * @@ -1812,6 +1901,43 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg, } EXPORT_SYMBOL_GPL(regmap_update_bits_check); +/** + * regmap_update_bits_check_async: Perform a read/modify/write cycle on the + * register map asynchronously and report if + * updated + * + * @map: Register map to update + * @reg: Register to update + * @mask: Bitmask to change + * @val: New value for bitmask + * @change: Boolean indicating if a write was done + * + * With most buses the read must be done synchronously so this is most + * useful for devices with a cache which do not need to interact with + * the hardware to determine the current register value. + * + * Returns zero for success, a negative number on error. + */ +int regmap_update_bits_check_async(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val, + bool *change) +{ + int ret; + + map->lock(map->lock_arg); + + map->async = true; + + ret = _regmap_update_bits(map, reg, mask, val, change); + + map->async = false; + + map->unlock(map->lock_arg); + + return ret; +} +EXPORT_SYMBOL_GPL(regmap_update_bits_check_async); + void regmap_async_complete_cb(struct regmap_async *async, int ret) { struct regmap *map = async->map; @@ -1820,8 +1946,7 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret) trace_regmap_async_io_complete(map->dev); spin_lock(&map->async_lock); - - list_del(&async->list); + list_move(&async->list, &map->async_free); wake = list_empty(&map->async_list); if (ret != 0) @@ -1829,8 +1954,6 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret) spin_unlock(&map->async_lock); - schedule_work(&async->cleanup); - if (wake) wake_up(&map->async_waitq); } diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c index 06189e55b4e5..94c280d36e8b 100644 --- a/drivers/char/tpm/xen-tpmfront.c +++ b/drivers/char/tpm/xen-tpmfront.c @@ -10,6 +10,7 @@ #include <linux/errno.h> #include <linux/err.h> #include <linux/interrupt.h> +#include <xen/xen.h> #include <xen/events.h> #include <xen/interface/io/tpmif.h> #include <xen/grant_table.h> diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 32b3479a2405..badf6206b2b2 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -383,6 +383,7 @@ static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max) static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate) { int max_perf, min_perf; + u64 val; intel_pstate_get_min_max(cpu, &min_perf, &max_perf); @@ -394,11 +395,11 @@ static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate) trace_cpu_frequency(pstate * 100000, cpu->cpu); cpu->pstate.current_pstate = pstate; + val = pstate << 8; if (limits.no_turbo) - wrmsrl(MSR_IA32_PERF_CTL, BIT(32) | (pstate << 8)); - else - wrmsrl(MSR_IA32_PERF_CTL, pstate << 8); + val |= (u64)1 << 32; + wrmsrl(MSR_IA32_PERF_CTL, val); } static inline void intel_pstate_pstate_increase(struct cpudata *cpu, int steps) @@ -637,8 +638,8 @@ static int intel_pstate_cpu_exit(struct cpufreq_policy *policy) static int intel_pstate_cpu_init(struct cpufreq_policy *policy) { - int rc, min_pstate, max_pstate; struct cpudata *cpu; + int rc; rc = intel_pstate_init_cpu(policy->cpu); if (rc) @@ -652,9 +653,8 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy) else policy->policy = CPUFREQ_POLICY_POWERSAVE; - intel_pstate_get_min_max(cpu, &min_pstate, &max_pstate); - policy->min = min_pstate * 100000; - policy->max = max_pstate * 100000; + policy->min = cpu->pstate.min_pstate * 100000; + policy->max = cpu->pstate.turbo_pstate * 100000; /* cpuinfo and default policy values */ policy->cpuinfo.min_freq = cpu->pstate.min_pstate * 100000; diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c index 8a72b0c555f8..15631f92ab7d 100644 --- a/drivers/cpufreq/s3c64xx-cpufreq.c +++ b/drivers/cpufreq/s3c64xx-cpufreq.c @@ -166,7 +166,7 @@ static void __init s3c64xx_cpufreq_config_regulator(void) if (freq->frequency == CPUFREQ_ENTRY_INVALID) continue; - dvfs = &s3c64xx_dvfs_table[freq->index]; + dvfs = &s3c64xx_dvfs_table[freq->driver_data]; found = 0; for (i = 0; i < count; i++) { diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c index 2d9ca6055e5e..41b5913ddabe 100644 --- a/drivers/gpio/gpio-lynxpoint.c +++ b/drivers/gpio/gpio-lynxpoint.c @@ -248,14 +248,15 @@ static void lp_gpio_irq_handler(unsigned irq, struct irq_desc *desc) struct lp_gpio *lg = irq_data_get_irq_handler_data(data); struct irq_chip *chip = irq_data_get_irq_chip(data); u32 base, pin, mask; - unsigned long reg, pending; + unsigned long reg, ena, pending; unsigned virq; /* check from GPIO controller which pin triggered the interrupt */ for (base = 0; base < lg->chip.ngpio; base += 32) { reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); + ena = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); - while ((pending = inl(reg))) { + while ((pending = (inl(reg) & inl(ena)))) { pin = __ffs(pending); mask = BIT(pin); /* Clear before handling so we don't lose an edge */ diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 86ef3461ec06..0dee0e0c247a 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -136,7 +136,7 @@ static struct gpio_desc *gpio_to_desc(unsigned gpio) */ static int desc_to_gpio(const struct gpio_desc *desc) { - return desc->chip->base + gpio_chip_hwgpio(desc); + return desc - &gpio_desc[0]; } @@ -1398,7 +1398,7 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) int status = -EPROBE_DEFER; unsigned long flags; - if (!desc || !desc->chip) { + if (!desc) { pr_warn("%s: invalid GPIO\n", __func__); return -EINVAL; } @@ -1406,6 +1406,8 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) spin_lock_irqsave(&gpio_lock, flags); chip = desc->chip; + if (chip == NULL) + goto done; if (!try_module_get(chip->owner)) goto done; diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index a7b30be86ae0..52605c0ea3a6 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c @@ -525,8 +525,10 @@ static int adf4350_probe(struct spi_device *spi) } indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (indio_dev == NULL) - return -ENOMEM; + if (indio_dev == NULL) { + ret = -ENOMEM; + goto error_disable_clk; + } st = iio_priv(indio_dev); diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 2710f7245c3b..2db7dcd826b9 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -477,6 +477,9 @@ void iio_disable_all_buffers(struct iio_dev *indio_dev) indio_dev->currentmode = INDIO_DIRECT_MODE; if (indio_dev->setup_ops->postdisable) indio_dev->setup_ops->postdisable(indio_dev); + + if (indio_dev->available_scan_masks == NULL) + kfree(indio_dev->active_scan_mask); } int iio_update_buffers(struct iio_dev *indio_dev, diff --git a/drivers/infiniband/hw/amso1100/c2_ae.c b/drivers/infiniband/hw/amso1100/c2_ae.c index d5d1929753e4..cedda25232be 100644 --- a/drivers/infiniband/hw/amso1100/c2_ae.c +++ b/drivers/infiniband/hw/amso1100/c2_ae.c @@ -141,7 +141,7 @@ static const char *to_qp_state_str(int state) return "C2_QP_STATE_ERROR"; default: return "<invalid QP state>"; - }; + } } void c2_ae_event(struct c2_dev *c2dev, u32 mq_index) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 3f831de9a4d8..b1a6cb3a2809 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -164,6 +164,7 @@ int mlx5_vector2eqn(struct mlx5_ib_dev *dev, int vector, int *eqn, int *irqn) static int alloc_comp_eqs(struct mlx5_ib_dev *dev) { struct mlx5_eq_table *table = &dev->mdev.priv.eq_table; + char name[MLX5_MAX_EQ_NAME]; struct mlx5_eq *eq, *n; int ncomp_vec; int nent; @@ -180,11 +181,10 @@ static int alloc_comp_eqs(struct mlx5_ib_dev *dev) goto clean; } - snprintf(eq->name, MLX5_MAX_EQ_NAME, "mlx5_comp%d", i); + snprintf(name, MLX5_MAX_EQ_NAME, "mlx5_comp%d", i); err = mlx5_create_map_eq(&dev->mdev, eq, i + MLX5_EQ_VEC_COMP_BASE, nent, 0, - eq->name, - &dev->mdev.priv.uuari.uars[0]); + name, &dev->mdev.priv.uuari.uars[0]); if (err) { kfree(eq); goto clean; @@ -301,9 +301,8 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, props->max_srq_sge = max_rq_sg - 1; props->max_fast_reg_page_list_len = (unsigned int)-1; props->local_ca_ack_delay = dev->mdev.caps.local_ca_ack_delay; - props->atomic_cap = dev->mdev.caps.flags & MLX5_DEV_CAP_FLAG_ATOMIC ? - IB_ATOMIC_HCA : IB_ATOMIC_NONE; - props->masked_atomic_cap = IB_ATOMIC_HCA; + props->atomic_cap = IB_ATOMIC_NONE; + props->masked_atomic_cap = IB_ATOMIC_NONE; props->max_pkeys = be16_to_cpup((__be16 *)(out_mad->data + 28)); props->max_mcast_grp = 1 << dev->mdev.caps.log_max_mcg; props->max_mcast_qp_attach = dev->mdev.caps.max_qp_mcg; @@ -1006,6 +1005,11 @@ static void mlx5_ib_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event, ibev.device = &ibdev->ib_dev; ibev.element.port_num = port; + if (port < 1 || port > ibdev->num_ports) { + mlx5_ib_warn(ibdev, "warning: event on port %d\n", port); + return; + } + if (ibdev->ib_active) ib_dispatch_event(&ibev); } diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index bd41df95b6f0..3453580b1eb2 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -42,6 +42,10 @@ enum { DEF_CACHE_SIZE = 10, }; +enum { + MLX5_UMR_ALIGN = 2048 +}; + static __be64 *mr_align(__be64 *ptr, int align) { unsigned long mask = align - 1; @@ -61,13 +65,11 @@ static int order2idx(struct mlx5_ib_dev *dev, int order) static int add_keys(struct mlx5_ib_dev *dev, int c, int num) { - struct device *ddev = dev->ib_dev.dma_device; struct mlx5_mr_cache *cache = &dev->cache; struct mlx5_cache_ent *ent = &cache->ent[c]; struct mlx5_create_mkey_mbox_in *in; struct mlx5_ib_mr *mr; int npages = 1 << ent->order; - int size = sizeof(u64) * npages; int err = 0; int i; @@ -83,21 +85,6 @@ static int add_keys(struct mlx5_ib_dev *dev, int c, int num) } mr->order = ent->order; mr->umred = 1; - mr->pas = kmalloc(size + 0x3f, GFP_KERNEL); - if (!mr->pas) { - kfree(mr); - err = -ENOMEM; - goto out; - } - mr->dma = dma_map_single(ddev, mr_align(mr->pas, 0x40), size, - DMA_TO_DEVICE); - if (dma_mapping_error(ddev, mr->dma)) { - kfree(mr->pas); - kfree(mr); - err = -ENOMEM; - goto out; - } - in->seg.status = 1 << 6; in->seg.xlt_oct_size = cpu_to_be32((npages + 1) / 2); in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); @@ -108,8 +95,6 @@ static int add_keys(struct mlx5_ib_dev *dev, int c, int num) sizeof(*in)); if (err) { mlx5_ib_warn(dev, "create mkey failed %d\n", err); - dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE); - kfree(mr->pas); kfree(mr); goto out; } @@ -129,11 +114,9 @@ out: static void remove_keys(struct mlx5_ib_dev *dev, int c, int num) { - struct device *ddev = dev->ib_dev.dma_device; struct mlx5_mr_cache *cache = &dev->cache; struct mlx5_cache_ent *ent = &cache->ent[c]; struct mlx5_ib_mr *mr; - int size; int err; int i; @@ -149,14 +132,10 @@ static void remove_keys(struct mlx5_ib_dev *dev, int c, int num) ent->size--; spin_unlock(&ent->lock); err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr); - if (err) { + if (err) mlx5_ib_warn(dev, "failed destroy mkey\n"); - } else { - size = ALIGN(sizeof(u64) * (1 << mr->order), 0x40); - dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE); - kfree(mr->pas); + else kfree(mr); - } } } @@ -408,13 +387,12 @@ static void free_cached_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr) static void clean_keys(struct mlx5_ib_dev *dev, int c) { - struct device *ddev = dev->ib_dev.dma_device; struct mlx5_mr_cache *cache = &dev->cache; struct mlx5_cache_ent *ent = &cache->ent[c]; struct mlx5_ib_mr *mr; - int size; int err; + cancel_delayed_work(&ent->dwork); while (1) { spin_lock(&ent->lock); if (list_empty(&ent->head)) { @@ -427,14 +405,10 @@ static void clean_keys(struct mlx5_ib_dev *dev, int c) ent->size--; spin_unlock(&ent->lock); err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr); - if (err) { + if (err) mlx5_ib_warn(dev, "failed destroy mkey\n"); - } else { - size = ALIGN(sizeof(u64) * (1 << mr->order), 0x40); - dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE); - kfree(mr->pas); + else kfree(mr); - } } } @@ -540,13 +514,15 @@ int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev) int i; dev->cache.stopped = 1; - destroy_workqueue(dev->cache.wq); + flush_workqueue(dev->cache.wq); mlx5_mr_cache_debugfs_cleanup(dev); for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) clean_keys(dev, i); + destroy_workqueue(dev->cache.wq); + return 0; } @@ -675,10 +651,12 @@ static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem, int page_shift, int order, int access_flags) { struct mlx5_ib_dev *dev = to_mdev(pd->device); + struct device *ddev = dev->ib_dev.dma_device; struct umr_common *umrc = &dev->umrc; struct ib_send_wr wr, *bad; struct mlx5_ib_mr *mr; struct ib_sge sg; + int size = sizeof(u64) * npages; int err; int i; @@ -697,7 +675,22 @@ static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem, if (!mr) return ERR_PTR(-EAGAIN); - mlx5_ib_populate_pas(dev, umem, page_shift, mr_align(mr->pas, 0x40), 1); + mr->pas = kmalloc(size + MLX5_UMR_ALIGN - 1, GFP_KERNEL); + if (!mr->pas) { + err = -ENOMEM; + goto error; + } + + mlx5_ib_populate_pas(dev, umem, page_shift, + mr_align(mr->pas, MLX5_UMR_ALIGN), 1); + + mr->dma = dma_map_single(ddev, mr_align(mr->pas, MLX5_UMR_ALIGN), size, + DMA_TO_DEVICE); + if (dma_mapping_error(ddev, mr->dma)) { + kfree(mr->pas); + err = -ENOMEM; + goto error; + } memset(&wr, 0, sizeof(wr)); wr.wr_id = (u64)(unsigned long)mr; @@ -718,6 +711,9 @@ static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem, wait_for_completion(&mr->done); up(&umrc->sem); + dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE); + kfree(mr->pas); + if (mr->status != IB_WC_SUCCESS) { mlx5_ib_warn(dev, "reg umr failed\n"); err = -EFAULT; diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 045f8cdbd303..5659ea880741 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -203,7 +203,7 @@ static int sq_overhead(enum ib_qp_type qp_type) switch (qp_type) { case IB_QPT_XRC_INI: - size = sizeof(struct mlx5_wqe_xrc_seg); + size += sizeof(struct mlx5_wqe_xrc_seg); /* fall through */ case IB_QPT_RC: size += sizeof(struct mlx5_wqe_ctrl_seg) + @@ -211,20 +211,23 @@ static int sq_overhead(enum ib_qp_type qp_type) sizeof(struct mlx5_wqe_raddr_seg); break; + case IB_QPT_XRC_TGT: + return 0; + case IB_QPT_UC: - size = sizeof(struct mlx5_wqe_ctrl_seg) + + size += sizeof(struct mlx5_wqe_ctrl_seg) + sizeof(struct mlx5_wqe_raddr_seg); break; case IB_QPT_UD: case IB_QPT_SMI: case IB_QPT_GSI: - size = sizeof(struct mlx5_wqe_ctrl_seg) + + size += sizeof(struct mlx5_wqe_ctrl_seg) + sizeof(struct mlx5_wqe_datagram_seg); break; case MLX5_IB_QPT_REG_UMR: - size = sizeof(struct mlx5_wqe_ctrl_seg) + + size += sizeof(struct mlx5_wqe_ctrl_seg) + sizeof(struct mlx5_wqe_umr_ctrl_seg) + sizeof(struct mlx5_mkey_seg); break; @@ -270,7 +273,8 @@ static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr, return wqe_size; if (wqe_size > dev->mdev.caps.max_sq_desc_sz) { - mlx5_ib_dbg(dev, "\n"); + mlx5_ib_dbg(dev, "wqe_size(%d) > max_sq_desc_sz(%d)\n", + wqe_size, dev->mdev.caps.max_sq_desc_sz); return -EINVAL; } @@ -280,9 +284,15 @@ static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr, wq_size = roundup_pow_of_two(attr->cap.max_send_wr * wqe_size); qp->sq.wqe_cnt = wq_size / MLX5_SEND_WQE_BB; + if (qp->sq.wqe_cnt > dev->mdev.caps.max_wqes) { + mlx5_ib_dbg(dev, "wqe count(%d) exceeds limits(%d)\n", + qp->sq.wqe_cnt, dev->mdev.caps.max_wqes); + return -ENOMEM; + } qp->sq.wqe_shift = ilog2(MLX5_SEND_WQE_BB); qp->sq.max_gs = attr->cap.max_send_sge; - qp->sq.max_post = 1 << ilog2(wq_size / wqe_size); + qp->sq.max_post = wq_size / wqe_size; + attr->cap.max_send_wr = qp->sq.max_post; return wq_size; } @@ -1280,6 +1290,11 @@ static enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_Q MLX5_QP_OPTPAR_Q_KEY, [MLX5_QP_ST_MLX] = MLX5_QP_OPTPAR_PKEY_INDEX | MLX5_QP_OPTPAR_Q_KEY, + [MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH | + MLX5_QP_OPTPAR_RRE | + MLX5_QP_OPTPAR_RAE | + MLX5_QP_OPTPAR_RWE | + MLX5_QP_OPTPAR_PKEY_INDEX, }, }, [MLX5_QP_STATE_RTR] = { @@ -1314,6 +1329,11 @@ static enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_Q [MLX5_QP_STATE_RTS] = { [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY, [MLX5_QP_ST_MLX] = MLX5_QP_OPTPAR_Q_KEY, + [MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_RWE, + [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_RNR_TIMEOUT | + MLX5_QP_OPTPAR_RWE | + MLX5_QP_OPTPAR_RAE | + MLX5_QP_OPTPAR_RRE, }, }, }; @@ -1651,29 +1671,6 @@ static __always_inline void set_raddr_seg(struct mlx5_wqe_raddr_seg *rseg, rseg->reserved = 0; } -static void set_atomic_seg(struct mlx5_wqe_atomic_seg *aseg, struct ib_send_wr *wr) -{ - if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) { - aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap); - aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add); - } else if (wr->opcode == IB_WR_MASKED_ATOMIC_FETCH_AND_ADD) { - aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add); - aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add_mask); - } else { - aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add); - aseg->compare = 0; - } -} - -static void set_masked_atomic_seg(struct mlx5_wqe_masked_atomic_seg *aseg, - struct ib_send_wr *wr) -{ - aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap); - aseg->swap_add_mask = cpu_to_be64(wr->wr.atomic.swap_mask); - aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add); - aseg->compare_mask = cpu_to_be64(wr->wr.atomic.compare_add_mask); -} - static void set_datagram_seg(struct mlx5_wqe_datagram_seg *dseg, struct ib_send_wr *wr) { @@ -2063,28 +2060,11 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, case IB_WR_ATOMIC_CMP_AND_SWP: case IB_WR_ATOMIC_FETCH_AND_ADD: - set_raddr_seg(seg, wr->wr.atomic.remote_addr, - wr->wr.atomic.rkey); - seg += sizeof(struct mlx5_wqe_raddr_seg); - - set_atomic_seg(seg, wr); - seg += sizeof(struct mlx5_wqe_atomic_seg); - - size += (sizeof(struct mlx5_wqe_raddr_seg) + - sizeof(struct mlx5_wqe_atomic_seg)) / 16; - break; - case IB_WR_MASKED_ATOMIC_CMP_AND_SWP: - set_raddr_seg(seg, wr->wr.atomic.remote_addr, - wr->wr.atomic.rkey); - seg += sizeof(struct mlx5_wqe_raddr_seg); - - set_masked_atomic_seg(seg, wr); - seg += sizeof(struct mlx5_wqe_masked_atomic_seg); - - size += (sizeof(struct mlx5_wqe_raddr_seg) + - sizeof(struct mlx5_wqe_masked_atomic_seg)) / 16; - break; + mlx5_ib_warn(dev, "Atomic operations are not supported yet\n"); + err = -ENOSYS; + *bad_wr = wr; + goto out; case IB_WR_LOCAL_INV: next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL; diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index 84d297afd6a9..0aa478bc291a 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c @@ -295,7 +295,7 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, mlx5_vfree(in); if (err) { mlx5_ib_dbg(dev, "create SRQ failed, err %d\n", err); - goto err_srq; + goto err_usr_kern_srq; } mlx5_ib_dbg(dev, "create SRQ with srqn 0x%x\n", srq->msrq.srqn); @@ -316,6 +316,8 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, err_core: mlx5_core_destroy_srq(&dev->mdev, &srq->msrq); + +err_usr_kern_srq: if (pd->uobject) destroy_srq_user(pd, srq); else diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c index 7c9d35f39d75..690201738993 100644 --- a/drivers/infiniband/hw/mthca/mthca_eq.c +++ b/drivers/infiniband/hw/mthca/mthca_eq.c @@ -357,7 +357,7 @@ static int mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq) mthca_warn(dev, "Unhandled event %02x(%02x) on EQ %d\n", eqe->type, eqe->subtype, eq->eqn); break; - }; + } set_eqe_hw(eqe); ++eq->cons_index; diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c index 4ed8235d2d36..50219ab2279d 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c @@ -150,7 +150,7 @@ enum ib_qp_state get_ibqp_state(enum ocrdma_qp_state qps) return IB_QPS_SQE; case OCRDMA_QPS_ERR: return IB_QPS_ERR; - }; + } return IB_QPS_ERR; } @@ -171,7 +171,7 @@ static enum ocrdma_qp_state get_ocrdma_qp_state(enum ib_qp_state qps) return OCRDMA_QPS_SQE; case IB_QPS_ERR: return OCRDMA_QPS_ERR; - }; + } return OCRDMA_QPS_ERR; } @@ -1982,7 +1982,7 @@ int ocrdma_mbx_create_qp(struct ocrdma_qp *qp, struct ib_qp_init_attr *attrs, break; default: return -EINVAL; - }; + } cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_CREATE_QP, sizeof(*cmd)); if (!cmd) diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c index 56e004940f18..0ce7674621ea 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c @@ -531,7 +531,7 @@ static void ocrdma_event_handler(struct ocrdma_dev *dev, u32 event) case BE_DEV_DOWN: ocrdma_close(dev); break; - }; + } } static struct ocrdma_driver ocrdma_drv = { diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c index 6e982bb43c31..69f1d1221a6b 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c @@ -141,7 +141,7 @@ static inline void get_link_speed_and_width(struct ocrdma_dev *dev, /* Unsupported */ *ib_speed = IB_SPEED_SDR; *ib_width = IB_WIDTH_1X; - }; + } } @@ -2331,7 +2331,7 @@ static enum ib_wc_status ocrdma_to_ibwc_err(u16 status) default: ibwc_status = IB_WC_GENERAL_ERR; break; - }; + } return ibwc_status; } @@ -2370,7 +2370,7 @@ static void ocrdma_update_wc(struct ocrdma_qp *qp, struct ib_wc *ibwc, pr_err("%s() invalid opcode received = 0x%x\n", __func__, hdr->cw & OCRDMA_WQE_OPCODE_MASK); break; - }; + } } static void ocrdma_set_cqe_status_flushed(struct ocrdma_qp *qp, diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index 4caa8e6d59d7..2d2b1b7588d7 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c @@ -269,6 +269,14 @@ static chunk_t area_location(struct pstore *ps, chunk_t area) return NUM_SNAPSHOT_HDR_CHUNKS + ((ps->exceptions_per_area + 1) * area); } +static void skip_metadata(struct pstore *ps) +{ + uint32_t stride = ps->exceptions_per_area + 1; + chunk_t next_free = ps->next_free; + if (sector_div(next_free, stride) == NUM_SNAPSHOT_HDR_CHUNKS) + ps->next_free++; +} + /* * Read or write a metadata area. Remembering to skip the first * chunk which holds the header. @@ -502,6 +510,8 @@ static int read_exceptions(struct pstore *ps, ps->current_area--; + skip_metadata(ps); + return 0; } @@ -616,8 +626,6 @@ static int persistent_prepare_exception(struct dm_exception_store *store, struct dm_exception *e) { struct pstore *ps = get_info(store); - uint32_t stride; - chunk_t next_free; sector_t size = get_dev_size(dm_snap_cow(store->snap)->bdev); /* Is there enough room ? */ @@ -630,10 +638,8 @@ static int persistent_prepare_exception(struct dm_exception_store *store, * Move onto the next free pending, making sure to take * into account the location of the metadata chunks. */ - stride = (ps->exceptions_per_area + 1); - next_free = ++ps->next_free; - if (sector_div(next_free, stride) == 1) - ps->next_free++; + ps->next_free++; + skip_metadata(ps); atomic_inc(&ps->pending_count); return 0; diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 2a9b100c4825..dbbf8ee3f592 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -158,8 +158,6 @@ int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val) { int ret; - BUG_ON(!mutex_is_locked(&mc13xxx->lock)); - if (offset > MC13XXX_NUMREGS) return -EINVAL; @@ -172,8 +170,6 @@ EXPORT_SYMBOL(mc13xxx_reg_read); int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val) { - BUG_ON(!mutex_is_locked(&mc13xxx->lock)); - dev_vdbg(mc13xxx->dev, "[0x%02x] <- 0x%06x\n", offset, val); if (offset > MC13XXX_NUMREGS || val > 0xffffff) @@ -186,7 +182,6 @@ EXPORT_SYMBOL(mc13xxx_reg_write); int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset, u32 mask, u32 val) { - BUG_ON(!mutex_is_locked(&mc13xxx->lock)); BUG_ON(val & ~mask); dev_vdbg(mc13xxx->dev, "[0x%02x] <- 0x%06x (mask: 0x%06x)\n", offset, val, mask); diff --git a/drivers/mfd/mc13xxx-spi.c b/drivers/mfd/mc13xxx-spi.c index 77189daadf1e..5f14ef6693c2 100644 --- a/drivers/mfd/mc13xxx-spi.c +++ b/drivers/mfd/mc13xxx-spi.c @@ -94,10 +94,15 @@ static int mc13xxx_spi_write(void *context, const void *data, size_t count) { struct device *dev = context; struct spi_device *spi = to_spi_device(dev); + const char *reg = data; if (count != 4) return -ENOTSUPP; + /* include errata fix for spi audio problems */ + if (*reg == MC13783_AUDIO_CODEC || *reg == MC13783_AUDIO_DAC) + spi_write(spi, data, count); + return spi_write(spi, data, count); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 5472cbd34028..6ca30739625f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -180,28 +180,32 @@ static int verify_block_sig(struct mlx5_cmd_prot_block *block) return 0; } -static void calc_block_sig(struct mlx5_cmd_prot_block *block, u8 token) +static void calc_block_sig(struct mlx5_cmd_prot_block *block, u8 token, + int csum) { block->token = token; - block->ctrl_sig = ~xor8_buf(block->rsvd0, sizeof(*block) - sizeof(block->data) - 2); - block->sig = ~xor8_buf(block, sizeof(*block) - 1); + if (csum) { + block->ctrl_sig = ~xor8_buf(block->rsvd0, sizeof(*block) - + sizeof(block->data) - 2); + block->sig = ~xor8_buf(block, sizeof(*block) - 1); + } } -static void calc_chain_sig(struct mlx5_cmd_msg *msg, u8 token) +static void calc_chain_sig(struct mlx5_cmd_msg *msg, u8 token, int csum) { struct mlx5_cmd_mailbox *next = msg->next; while (next) { - calc_block_sig(next->buf, token); + calc_block_sig(next->buf, token, csum); next = next->next; } } -static void set_signature(struct mlx5_cmd_work_ent *ent) +static void set_signature(struct mlx5_cmd_work_ent *ent, int csum) { ent->lay->sig = ~xor8_buf(ent->lay, sizeof(*ent->lay)); - calc_chain_sig(ent->in, ent->token); - calc_chain_sig(ent->out, ent->token); + calc_chain_sig(ent->in, ent->token, csum); + calc_chain_sig(ent->out, ent->token, csum); } static void poll_timeout(struct mlx5_cmd_work_ent *ent) @@ -539,8 +543,7 @@ static void cmd_work_handler(struct work_struct *work) lay->type = MLX5_PCI_CMD_XPORT; lay->token = ent->token; lay->status_own = CMD_OWNER_HW; - if (!cmd->checksum_disabled) - set_signature(ent); + set_signature(ent, !cmd->checksum_disabled); dump_command(dev, ent, 1); ktime_get_ts(&ent->ts1); @@ -773,8 +776,6 @@ static int mlx5_copy_from_msg(void *to, struct mlx5_cmd_msg *from, int size) copy = min_t(int, size, MLX5_CMD_DATA_BLOCK_SIZE); block = next->buf; - if (xor8_buf(block, sizeof(*block)) != 0xff) - return -EINVAL; memcpy(to, block->data, copy); to += copy; @@ -1361,6 +1362,7 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev) goto err_map; } + cmd->checksum_disabled = 1; cmd->max_reg_cmds = (1 << cmd->log_sz) - 1; cmd->bitmask = (1 << cmd->max_reg_cmds) - 1; @@ -1510,7 +1512,7 @@ int mlx5_cmd_status_to_err(struct mlx5_outbox_hdr *hdr) case MLX5_CMD_STAT_BAD_SYS_STATE_ERR: return -EIO; case MLX5_CMD_STAT_BAD_RES_ERR: return -EINVAL; case MLX5_CMD_STAT_RES_BUSY: return -EBUSY; - case MLX5_CMD_STAT_LIM_ERR: return -EINVAL; + case MLX5_CMD_STAT_LIM_ERR: return -ENOMEM; case MLX5_CMD_STAT_BAD_RES_STATE_ERR: return -EINVAL; case MLX5_CMD_STAT_IX_ERR: return -EINVAL; case MLX5_CMD_STAT_NO_RES_ERR: return -EAGAIN; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index 443cc4d7b024..2231d93cc7ad 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c @@ -366,9 +366,11 @@ int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx, goto err_in; } + snprintf(eq->name, MLX5_MAX_EQ_NAME, "%s@pci:%s", + name, pci_name(dev->pdev)); eq->eqn = out.eq_number; err = request_irq(table->msix_arr[vecidx].vector, mlx5_msix_handler, 0, - name, eq); + eq->name, eq); if (err) goto err_eq; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index b47739b0b5f6..bc0f5fb66e24 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -165,9 +165,7 @@ static int handle_hca_cap(struct mlx5_core_dev *dev) struct mlx5_cmd_set_hca_cap_mbox_in *set_ctx = NULL; struct mlx5_cmd_query_hca_cap_mbox_in query_ctx; struct mlx5_cmd_set_hca_cap_mbox_out set_out; - struct mlx5_profile *prof = dev->profile; u64 flags; - int csum = 1; int err; memset(&query_ctx, 0, sizeof(query_ctx)); @@ -197,20 +195,14 @@ static int handle_hca_cap(struct mlx5_core_dev *dev) memcpy(&set_ctx->hca_cap, &query_out->hca_cap, sizeof(set_ctx->hca_cap)); - if (prof->mask & MLX5_PROF_MASK_CMDIF_CSUM) { - csum = !!prof->cmdif_csum; - flags = be64_to_cpu(set_ctx->hca_cap.flags); - if (csum) - flags |= MLX5_DEV_CAP_FLAG_CMDIF_CSUM; - else - flags &= ~MLX5_DEV_CAP_FLAG_CMDIF_CSUM; - - set_ctx->hca_cap.flags = cpu_to_be64(flags); - } - if (dev->profile->mask & MLX5_PROF_MASK_QP_SIZE) set_ctx->hca_cap.log_max_qp = dev->profile->log_max_qp; + flags = be64_to_cpu(query_out->hca_cap.flags); + /* disable checksum */ + flags &= ~MLX5_DEV_CAP_FLAG_CMDIF_CSUM; + + set_ctx->hca_cap.flags = cpu_to_be64(flags); memset(&set_out, 0, sizeof(set_out)); set_ctx->hca_cap.log_uar_page_sz = cpu_to_be16(PAGE_SHIFT - 12); set_ctx->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_SET_HCA_CAP); @@ -225,9 +217,6 @@ static int handle_hca_cap(struct mlx5_core_dev *dev) if (err) goto query_ex; - if (!csum) - dev->cmd.checksum_disabled = 1; - query_ex: kfree(query_out); kfree(set_ctx); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c index 3a2408d44820..7b12acf210f8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c @@ -90,6 +90,10 @@ struct mlx5_manage_pages_outbox { __be64 pas[0]; }; +enum { + MAX_RECLAIM_TIME_MSECS = 5000, +}; + static int insert_page(struct mlx5_core_dev *dev, u64 addr, struct page *page, u16 func_id) { struct rb_root *root = &dev->priv.page_root; @@ -279,6 +283,9 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages, int err; int i; + if (nclaimed) + *nclaimed = 0; + memset(&in, 0, sizeof(in)); outlen = sizeof(*out) + npages * sizeof(out->pas[0]); out = mlx5_vzalloc(outlen); @@ -388,20 +395,25 @@ static int optimal_reclaimed_pages(void) int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev) { - unsigned long end = jiffies + msecs_to_jiffies(5000); + unsigned long end = jiffies + msecs_to_jiffies(MAX_RECLAIM_TIME_MSECS); struct fw_page *fwp; struct rb_node *p; + int nclaimed = 0; int err; do { p = rb_first(&dev->priv.page_root); if (p) { fwp = rb_entry(p, struct fw_page, rb_node); - err = reclaim_pages(dev, fwp->func_id, optimal_reclaimed_pages(), NULL); + err = reclaim_pages(dev, fwp->func_id, + optimal_reclaimed_pages(), + &nclaimed); if (err) { mlx5_core_warn(dev, "failed reclaiming pages (%d)\n", err); return err; } + if (nclaimed) + end = jiffies + msecs_to_jiffies(MAX_RECLAIM_TIME_MSECS); } if (time_after(jiffies, end)) { mlx5_core_warn(dev, "FW did not return all pages. giving up...\n"); diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 9d2009a9004d..78cc76053328 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -74,10 +74,4 @@ config OF_MTD depends on MTD def_bool y -config OF_RESERVED_MEM - depends on OF_FLATTREE && (DMA_CMA || (HAVE_GENERIC_DMA_COHERENT && HAVE_MEMBLOCK)) - def_bool y - help - Initialization code for DMA reserved memory - endmenu # OF diff --git a/drivers/of/Makefile b/drivers/of/Makefile index ed9660adad77..efd05102c405 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -9,4 +9,3 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o obj-$(CONFIG_OF_PCI) += of_pci.o obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o obj-$(CONFIG_OF_MTD) += of_mtd.o -obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o diff --git a/drivers/of/base.c b/drivers/of/base.c index 865d3f66c86b..7d4c70f859e3 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -303,10 +303,8 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) struct device_node *cpun, *cpus; cpus = of_find_node_by_path("/cpus"); - if (!cpus) { - pr_warn("Missing cpus node, bailing out\n"); + if (!cpus) return NULL; - } for_each_child_of_node(cpus, cpun) { if (of_node_cmp(cpun->type, "cpu")) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 229dd9d69e18..a4fa9ad31b8f 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -18,7 +18,6 @@ #include <linux/string.h> #include <linux/errno.h> #include <linux/slab.h> -#include <linux/random.h> #include <asm/setup.h> /* for COMMAND_LINE_SIZE */ #ifdef CONFIG_PPC @@ -803,14 +802,3 @@ void __init unflatten_device_tree(void) } #endif /* CONFIG_OF_EARLY_FLATTREE */ - -/* Feed entire flattened device tree into the random pool */ -static int __init add_fdt_randomness(void) -{ - if (initial_boot_params) - add_device_randomness(initial_boot_params, - be32_to_cpu(initial_boot_params->totalsize)); - - return 0; -} -core_initcall(add_fdt_randomness); diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c deleted file mode 100644 index 0fe40c7d6904..000000000000 --- a/drivers/of/of_reserved_mem.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Device tree based initialization code for reserved memory. - * - * Copyright (c) 2013 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * Author: Marek Szyprowski <m.szyprowski@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 optional) any later version of the license. - */ - -#include <linux/memblock.h> -#include <linux/err.h> -#include <linux/of.h> -#include <linux/of_fdt.h> -#include <linux/of_platform.h> -#include <linux/mm.h> -#include <linux/sizes.h> -#include <linux/mm_types.h> -#include <linux/dma-contiguous.h> -#include <linux/dma-mapping.h> -#include <linux/of_reserved_mem.h> - -#define MAX_RESERVED_REGIONS 16 -struct reserved_mem { - phys_addr_t base; - unsigned long size; - struct cma *cma; - char name[32]; -}; -static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS]; -static int reserved_mem_count; - -static int __init fdt_scan_reserved_mem(unsigned long node, const char *uname, - int depth, void *data) -{ - struct reserved_mem *rmem = &reserved_mem[reserved_mem_count]; - phys_addr_t base, size; - int is_cma, is_reserved; - unsigned long len; - const char *status; - __be32 *prop; - - is_cma = IS_ENABLED(CONFIG_DMA_CMA) && - of_flat_dt_is_compatible(node, "linux,contiguous-memory-region"); - is_reserved = of_flat_dt_is_compatible(node, "reserved-memory-region"); - - if (!is_reserved && !is_cma) { - /* ignore node and scan next one */ - return 0; - } - - status = of_get_flat_dt_prop(node, "status", &len); - if (status && strcmp(status, "okay") != 0) { - /* ignore disabled node nad scan next one */ - return 0; - } - - prop = of_get_flat_dt_prop(node, "reg", &len); - if (!prop || (len < (dt_root_size_cells + dt_root_addr_cells) * - sizeof(__be32))) { - pr_err("Reserved mem: node %s, incorrect \"reg\" property\n", - uname); - /* ignore node and scan next one */ - return 0; - } - base = dt_mem_next_cell(dt_root_addr_cells, &prop); - size = dt_mem_next_cell(dt_root_size_cells, &prop); - - if (!size) { - /* ignore node and scan next one */ - return 0; - } - - pr_info("Reserved mem: found %s, memory base %lx, size %ld MiB\n", - uname, (unsigned long)base, (unsigned long)size / SZ_1M); - - if (reserved_mem_count == ARRAY_SIZE(reserved_mem)) - return -ENOSPC; - - rmem->base = base; - rmem->size = size; - strlcpy(rmem->name, uname, sizeof(rmem->name)); - - if (is_cma) { - struct cma *cma; - if (dma_contiguous_reserve_area(size, base, 0, &cma) == 0) { - rmem->cma = cma; - reserved_mem_count++; - if (of_get_flat_dt_prop(node, - "linux,default-contiguous-region", - NULL)) - dma_contiguous_set_default(cma); - } - } else if (is_reserved) { - if (memblock_remove(base, size) == 0) - reserved_mem_count++; - else - pr_err("Failed to reserve memory for %s\n", uname); - } - - return 0; -} - -static struct reserved_mem *get_dma_memory_region(struct device *dev) -{ - struct device_node *node; - const char *name; - int i; - - node = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!node) - return NULL; - - name = kbasename(node->full_name); - for (i = 0; i < reserved_mem_count; i++) - if (strcmp(name, reserved_mem[i].name) == 0) - return &reserved_mem[i]; - return NULL; -} - -/** - * of_reserved_mem_device_init() - assign reserved memory region to given device - * - * This function assign memory region pointed by "memory-region" device tree - * property to the given device. - */ -void of_reserved_mem_device_init(struct device *dev) -{ - struct reserved_mem *region = get_dma_memory_region(dev); - if (!region) - return; - - if (region->cma) { - dev_set_cma_area(dev, region->cma); - pr_info("Assigned CMA %s to %s device\n", region->name, - dev_name(dev)); - } else { - if (dma_declare_coherent_memory(dev, region->base, region->base, - region->size, DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) != 0) - pr_info("Declared reserved memory %s to %s device\n", - region->name, dev_name(dev)); - } -} - -/** - * of_reserved_mem_device_release() - release reserved memory device structures - * - * This function releases structures allocated for memory region handling for - * the given device. - */ -void of_reserved_mem_device_release(struct device *dev) -{ - struct reserved_mem *region = get_dma_memory_region(dev); - if (!region && !region->cma) - dma_release_declared_memory(dev); -} - -/** - * early_init_dt_scan_reserved_mem() - create reserved memory regions - * - * This function grabs memory from early allocator for device exclusive use - * defined in device tree structures. It should be called by arch specific code - * once the early allocator (memblock) has been activated and all other - * subsystems have already allocated/reserved memory. - */ -void __init early_init_dt_scan_reserved_mem(void) -{ - of_scan_flat_dt_by_path("/memory/reserved-memory", - fdt_scan_reserved_mem, NULL); -} diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 9b439ac63d8e..f6dcde220821 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -21,7 +21,6 @@ #include <linux/of_device.h> #include <linux/of_irq.h> #include <linux/of_platform.h> -#include <linux/of_reserved_mem.h> #include <linux/platform_device.h> const struct of_device_id of_default_bus_match_table[] = { @@ -219,8 +218,6 @@ static struct platform_device *of_platform_device_create_pdata( dev->dev.bus = &platform_bus_type; dev->dev.platform_data = platform_data; - of_reserved_mem_device_init(&dev->dev); - /* We do not fill the DMA ops for platform devices by default. * This is currently the responsibility of the platform code * to do such, possibly using a device notifier @@ -228,7 +225,6 @@ static struct platform_device *of_platform_device_create_pdata( if (of_device_add(dev) != 0) { platform_device_put(dev); - of_reserved_mem_device_release(&dev->dev); return NULL; } diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 0b7d23b4ad95..be12fbfcae10 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -994,14 +994,16 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) /* * This bridge should have been registered as a hotplug function - * under its parent, so the context has to be there. If not, we - * are in deep goo. + * under its parent, so the context should be there, unless the + * parent is going to be handled by pciehp, in which case this + * bridge is not interesting to us either. */ mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(handle); - if (WARN_ON(!context)) { + if (!context) { mutex_unlock(&acpiphp_context_lock); put_device(&bus->dev); + pci_dev_put(bridge->pci_dev); kfree(bridge); return; } diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index a0ebbc9ce5cd..042aa077b5b3 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1912,9 +1912,6 @@ static int serial_imx_probe_dt(struct imx_port *sport, sport->devdata = of_id->data; - if (of_device_is_stdout_path(np)) - add_preferred_console(imx_reg.cons->name, sport->port.line, 0); - return 0; } #else diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 93b697a0de65..15ad6fcda88b 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -561,12 +561,13 @@ static int vt8500_serial_probe(struct platform_device *pdev) if (!mmres || !irqres) return -ENODEV; - if (np) + if (np) { port = of_alias_get_id(np, "serial"); if (port >= VT8500_MAX_PORTS) port = -1; - else + } else { port = -1; + } if (port < 0) { /* calculate the port id */ diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 6f96795dd20c..64d7a6d9a1ad 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -100,8 +100,10 @@ static void host_stop(struct ci_hdrc *ci) { struct usb_hcd *hcd = ci->hcd; - usb_remove_hcd(hcd); - usb_put_hcd(hcd); + if (hcd) { + usb_remove_hcd(hcd); + usb_put_hcd(hcd); + } if (ci->platdata->reg_vbus) regulator_disable(ci->platdata->reg_vbus); } diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 5b44cd47da5b..01fe36273f3b 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -97,6 +97,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* Alcor Micro Corp. Hub */ { USB_DEVICE(0x058f, 0x9254), .driver_info = USB_QUIRK_RESET_RESUME }, + /* MicroTouch Systems touchscreen */ + { USB_DEVICE(0x0596, 0x051e), .driver_info = USB_QUIRK_RESET_RESUME }, + /* appletouch */ { USB_DEVICE(0x05ac, 0x021a), .driver_info = USB_QUIRK_RESET_RESUME }, @@ -130,6 +133,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* Broadcom BCM92035DGROM BT dongle */ { USB_DEVICE(0x0a5c, 0x2021), .driver_info = USB_QUIRK_RESET_RESUME }, + /* MAYA44USB sound device */ + { USB_DEVICE(0x0a92, 0x0091), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Action Semiconductor flash disk */ { USB_DEVICE(0x10d6, 0x2200), .driver_info = USB_QUIRK_STRING_FETCH_255 }, diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 2c76ef1320ea..08ef2829a7e2 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -799,7 +799,7 @@ void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev) * switchable ports. */ pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN, - cpu_to_le32(ports_available)); + ports_available); pci_read_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN, &ports_available); @@ -821,7 +821,7 @@ void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev) * host. */ pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, - cpu_to_le32(ports_available)); + ports_available); pci_read_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, &ports_available); diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 773a6b28c4f1..e8b4c56dcf62 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1157,18 +1157,6 @@ int xhci_bus_suspend(struct usb_hcd *hcd) t1 = xhci_port_state_to_neutral(t1); if (t1 != t2) xhci_writel(xhci, t2, port_array[port_index]); - - if (hcd->speed != HCD_USB3) { - /* enable remote wake up for USB 2.0 */ - __le32 __iomem *addr; - u32 tmp; - - /* Get the port power control register address. */ - addr = port_array[port_index] + PORTPMSC; - tmp = xhci_readl(xhci, addr); - tmp |= PORT_RWE; - xhci_writel(xhci, tmp, addr); - } } hcd->state = HC_STATE_SUSPENDED; bus_state->next_statechange = jiffies + msecs_to_jiffies(10); @@ -1247,20 +1235,6 @@ int xhci_bus_resume(struct usb_hcd *hcd) xhci_ring_device(xhci, slot_id); } else xhci_writel(xhci, temp, port_array[port_index]); - - if (hcd->speed != HCD_USB3) { - /* disable remote wake up for USB 2.0 */ - __le32 __iomem *addr; - u32 tmp; - - /* Add one to the port status register address to get - * the port power control register address. - */ - addr = port_array[port_index] + PORTPMSC; - tmp = xhci_readl(xhci, addr); - tmp &= ~PORT_RWE; - xhci_writel(xhci, tmp, addr); - } } (void) xhci_readl(xhci, &xhci->op_regs->command); diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 236c3aabe940..b8dffd59eb25 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -35,6 +35,9 @@ #define PCI_VENDOR_ID_ETRON 0x1b6f #define PCI_DEVICE_ID_ASROCK_P67 0x7023 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 + static const char hcd_name[] = "xhci_hcd"; /* called after powerup, by probe or system-pm "wakeup" */ @@ -69,6 +72,14 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) "QUIRK: Fresco Logic xHC needs configure" " endpoint cmd after reset endpoint"); } + if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK && + pdev->revision == 0x4) { + xhci->quirks |= XHCI_SLOW_SUSPEND; + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "QUIRK: Fresco Logic xHC revision %u" + "must be suspended extra slowly", + pdev->revision); + } /* Fresco Logic confirms: all revisions of this chip do not * support MSI, even though some of them claim to in their PCI * capabilities. @@ -110,6 +121,15 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_SPURIOUS_REBOOT; xhci->quirks |= XHCI_AVOID_BEI; } + if (pdev->vendor == PCI_VENDOR_ID_INTEL && + (pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI)) { + /* Workaround for occasional spurious wakeups from S5 (or + * any other sleep) on Haswell machines with LPT and LPT-LP + * with the new Intel BIOS + */ + xhci->quirks |= XHCI_SPURIOUS_WAKEUP; + } if (pdev->vendor == PCI_VENDOR_ID_ETRON && pdev->device == PCI_DEVICE_ID_ASROCK_P67) { xhci->quirks |= XHCI_RESET_ON_RESUME; @@ -217,6 +237,11 @@ static void xhci_pci_remove(struct pci_dev *dev) usb_put_hcd(xhci->shared_hcd); } usb_hcd_pci_remove(dev); + + /* Workaround for spurious wakeups at shutdown with HSW */ + if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) + pci_set_power_state(dev, PCI_D3hot); + kfree(xhci); } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 1e36dbb48366..6e0d886bcce5 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -730,6 +730,9 @@ void xhci_shutdown(struct usb_hcd *hcd) spin_lock_irq(&xhci->lock); xhci_halt(xhci); + /* Workaround for spurious wakeups at shutdown with HSW */ + if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) + xhci_reset(xhci); spin_unlock_irq(&xhci->lock); xhci_cleanup_msix(xhci); @@ -737,6 +740,10 @@ void xhci_shutdown(struct usb_hcd *hcd) xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_shutdown completed - status = %x", xhci_readl(xhci, &xhci->op_regs->status)); + + /* Yet another workaround for spurious wakeups at shutdown with HSW */ + if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) + pci_set_power_state(to_pci_dev(hcd->self.controller), PCI_D3hot); } #ifdef CONFIG_PM @@ -839,6 +846,7 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci) int xhci_suspend(struct xhci_hcd *xhci) { int rc = 0; + unsigned int delay = XHCI_MAX_HALT_USEC; struct usb_hcd *hcd = xhci_to_hcd(xhci); u32 command; @@ -861,8 +869,12 @@ int xhci_suspend(struct xhci_hcd *xhci) command = xhci_readl(xhci, &xhci->op_regs->command); command &= ~CMD_RUN; xhci_writel(xhci, command, &xhci->op_regs->command); + + /* Some chips from Fresco Logic need an extraordinary delay */ + delay *= (xhci->quirks & XHCI_SLOW_SUSPEND) ? 10 : 1; + if (xhci_handshake(xhci, &xhci->op_regs->status, - STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC)) { + STS_HALT, STS_HALT, delay)) { xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n"); spin_unlock_irq(&xhci->lock); return -ETIMEDOUT; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 289fbfbae746..941d5f59e4dc 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1548,6 +1548,8 @@ struct xhci_hcd { #define XHCI_COMP_MODE_QUIRK (1 << 14) #define XHCI_AVOID_BEI (1 << 15) #define XHCI_PLAT (1 << 16) +#define XHCI_SLOW_SUSPEND (1 << 17) +#define XHCI_SPURIOUS_WAKEUP (1 << 18) unsigned int num_active_eps; unsigned int limit_active_eps; /* There are two roothubs to keep track of bus suspend info for */ diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index e2b21c1d9c40..ba5f70f92888 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -246,6 +246,6 @@ config USB_EZUSB_FX2 config USB_HSIC_USB3503 tristate "USB3503 HSIC to USB20 Driver" depends on I2C - select REGMAP + select REGMAP_I2C help This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver. diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 18e877ffe7b7..cd70cc886171 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -922,6 +922,52 @@ static void musb_generic_disable(struct musb *musb) } /* + * Program the HDRC to start (enable interrupts, dma, etc.). + */ +void musb_start(struct musb *musb) +{ + void __iomem *regs = musb->mregs; + u8 devctl = musb_readb(regs, MUSB_DEVCTL); + + dev_dbg(musb->controller, "<== devctl %02x\n", devctl); + + /* Set INT enable registers, enable interrupts */ + musb->intrtxe = musb->epmask; + musb_writew(regs, MUSB_INTRTXE, musb->intrtxe); + musb->intrrxe = musb->epmask & 0xfffe; + musb_writew(regs, MUSB_INTRRXE, musb->intrrxe); + musb_writeb(regs, MUSB_INTRUSBE, 0xf7); + + musb_writeb(regs, MUSB_TESTMODE, 0); + + /* put into basic highspeed mode and start session */ + musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE + | MUSB_POWER_HSENAB + /* ENSUSPEND wedges tusb */ + /* | MUSB_POWER_ENSUSPEND */ + ); + + musb->is_active = 0; + devctl = musb_readb(regs, MUSB_DEVCTL); + devctl &= ~MUSB_DEVCTL_SESSION; + + /* session started after: + * (a) ID-grounded irq, host mode; + * (b) vbus present/connect IRQ, peripheral mode; + * (c) peripheral initiates, using SRP + */ + if (musb->port_mode != MUSB_PORT_MODE_HOST && + (devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) { + musb->is_active = 1; + } else { + devctl |= MUSB_DEVCTL_SESSION; + } + + musb_platform_enable(musb); + musb_writeb(regs, MUSB_DEVCTL, devctl); +} + +/* * Make the HDRC stop (disable interrupts, etc.); * reversible by musb_start * called on gadget driver unregister diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 65f3917b4fc5..1c5bf75ee8ff 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -503,6 +503,7 @@ static inline void musb_configure_ep0(struct musb *musb) extern const char musb_driver_name[]; extern void musb_stop(struct musb *musb); +extern void musb_start(struct musb *musb); extern void musb_write_fifo(struct musb_hw_ep *ep, u16 len, const u8 *src); extern void musb_read_fifo(struct musb_hw_ep *ep, u16 len, u8 *dst); diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index b19ed213ab85..3671898a4535 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1853,11 +1853,14 @@ static int musb_gadget_start(struct usb_gadget *g, musb->gadget_driver = driver; spin_lock_irqsave(&musb->lock, flags); + musb->is_active = 1; otg_set_peripheral(otg, &musb->g); musb->xceiv->state = OTG_STATE_B_IDLE; spin_unlock_irqrestore(&musb->lock, flags); + musb_start(musb); + /* REVISIT: funcall to other code, which also * handles power budgeting ... this way also * ensures HdrcStart is indirectly called. diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index a523950c2b32..d1d6b83aabca 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -44,52 +44,6 @@ #include "musb_core.h" -/* -* Program the HDRC to start (enable interrupts, dma, etc.). -*/ -static void musb_start(struct musb *musb) -{ - void __iomem *regs = musb->mregs; - u8 devctl = musb_readb(regs, MUSB_DEVCTL); - - dev_dbg(musb->controller, "<== devctl %02x\n", devctl); - - /* Set INT enable registers, enable interrupts */ - musb->intrtxe = musb->epmask; - musb_writew(regs, MUSB_INTRTXE, musb->intrtxe); - musb->intrrxe = musb->epmask & 0xfffe; - musb_writew(regs, MUSB_INTRRXE, musb->intrrxe); - musb_writeb(regs, MUSB_INTRUSBE, 0xf7); - - musb_writeb(regs, MUSB_TESTMODE, 0); - - /* put into basic highspeed mode and start session */ - musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE - | MUSB_POWER_HSENAB - /* ENSUSPEND wedges tusb */ - /* | MUSB_POWER_ENSUSPEND */ - ); - - musb->is_active = 0; - devctl = musb_readb(regs, MUSB_DEVCTL); - devctl &= ~MUSB_DEVCTL_SESSION; - - /* session started after: - * (a) ID-grounded irq, host mode; - * (b) vbus present/connect IRQ, peripheral mode; - * (c) peripheral initiates, using SRP - */ - if (musb->port_mode != MUSB_PORT_MODE_HOST && - (devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) { - musb->is_active = 1; - } else { - devctl |= MUSB_DEVCTL_SESSION; - } - - musb_platform_enable(musb); - musb_writeb(regs, MUSB_DEVCTL, devctl); -} - static void musb_port_suspend(struct musb *musb, bool do_suspend) { struct usb_otg *otg = musb->xceiv->otg; diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 80a7104d5ddb..acaee066b99a 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -451,6 +451,10 @@ static void option_instat_callback(struct urb *urb); #define CHANGHONG_VENDOR_ID 0x2077 #define CHANGHONG_PRODUCT_CH690 0x7001 +/* Inovia */ +#define INOVIA_VENDOR_ID 0x20a6 +#define INOVIA_SEW858 0x1105 + /* some devices interfaces need special handling due to a number of reasons */ enum option_blacklist_reason { OPTION_BLACKLIST_NONE = 0, @@ -689,6 +693,222 @@ static const struct usb_device_id option_ids[] = { { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7A) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7B) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x02) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x03) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x04) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x05) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x06) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x10) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x12) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x13) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x14) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x15) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x17) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x18) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x19) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x31) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x32) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x33) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x34) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x35) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x36) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x48) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x49) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x61) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x62) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x63) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x64) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x65) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x66) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x78) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x79) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x02) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x03) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x04) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x05) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x06) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x10) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x12) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x13) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x14) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x15) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x17) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x18) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x19) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x31) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x32) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x33) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x34) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x35) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x36) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x48) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x49) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x61) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x62) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x63) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x64) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x65) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x66) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x78) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x79) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x02) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x03) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x04) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x05) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x06) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x10) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x12) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x13) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x14) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x15) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x17) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x18) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x19) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x31) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x32) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x33) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x34) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x35) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x36) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x48) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x49) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x61) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x62) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x63) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x64) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x65) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x66) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x78) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x79) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x02) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x03) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x04) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x05) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x06) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x10) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x12) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x13) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x14) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x15) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x17) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x18) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x19) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x31) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x32) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x33) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x34) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x35) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x36) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x48) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x49) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4C) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x61) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x62) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x63) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x64) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x65) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x66) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6D) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6E) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6F) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x78) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x79) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7A) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7B) }, + { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7C) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) }, @@ -1257,7 +1477,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) }, { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD145) }, - { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD200) }, + { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD200), + .driver_info = (kernel_ulong_t)&net_intf6_blacklist + }, { USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */ { USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730 LTE USB modem.*/ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM600) }, @@ -1345,6 +1567,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */ { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */ + { USB_DEVICE(INOVIA_VENDOR_ID, INOVIA_SEW858) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 760b78560f67..c9a35697ebe9 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -190,6 +190,7 @@ static struct usb_device_id ti_id_table_combined[] = { { 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(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) }, { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, { } /* terminator */ }; diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 94d75edef77f..18509e6c21ab 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -211,8 +211,11 @@ static int slave_configure(struct scsi_device *sdev) /* * Many devices do not respond properly to READ_CAPACITY_16. * Tell the SCSI layer to try READ_CAPACITY_10 first. + * However some USB 3.0 drive enclosures return capacity + * modulo 2TB. Those must use READ_CAPACITY_16 */ - sdev->try_rc_10_first = 1; + if (!(us->fflags & US_FL_NEEDS_CAP16)) + sdev->try_rc_10_first = 1; /* assume SPC3 or latter devices support sense size > 18 */ if (sdev->scsi_level > SCSI_SPC_2) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index c015f2c16729..de32cfa5bfa6 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1925,6 +1925,13 @@ UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by Oliver Neukum <oneukum@suse.com> */ +UNUSUAL_DEV( 0x174c, 0x55aa, 0x0100, 0x0100, + "ASMedia", + "AS2105", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_NEEDS_CAP16), + /* Reported by Jesse Feddema <jdfeddema@gmail.com> */ UNUSUAL_DEV( 0x177f, 0x0400, 0x0000, 0x0000, "Yarvik", diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index a9807dea3887..4fb7a8f83c8a 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -545,6 +545,8 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, long npage; int ret = 0, prot = 0; uint64_t mask; + struct vfio_dma *dma = NULL; + unsigned long pfn; end = map->iova + map->size; @@ -587,8 +589,6 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, } for (iova = map->iova; iova < end; iova += size, vaddr += size) { - struct vfio_dma *dma = NULL; - unsigned long pfn; long i; /* Pin a contiguous chunk of memory */ @@ -597,16 +597,15 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, if (npage <= 0) { WARN_ON(!npage); ret = (int)npage; - break; + goto out; } /* Verify pages are not already mapped */ for (i = 0; i < npage; i++) { if (iommu_iova_to_phys(iommu->domain, iova + (i << PAGE_SHIFT))) { - vfio_unpin_pages(pfn, npage, prot, true); ret = -EBUSY; - break; + goto out_unpin; } } @@ -616,8 +615,7 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, if (ret) { if (ret != -EBUSY || map_try_harder(iommu, iova, pfn, npage, prot)) { - vfio_unpin_pages(pfn, npage, prot, true); - break; + goto out_unpin; } } @@ -672,9 +670,8 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, dma = kzalloc(sizeof(*dma), GFP_KERNEL); if (!dma) { iommu_unmap(iommu->domain, iova, size); - vfio_unpin_pages(pfn, npage, prot, true); ret = -ENOMEM; - break; + goto out_unpin; } dma->size = size; @@ -685,16 +682,21 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, } } - if (ret) { - struct vfio_dma *tmp; - iova = map->iova; - size = map->size; - while ((tmp = vfio_find_dma(iommu, iova, size))) { - int r = vfio_remove_dma_overlap(iommu, iova, - &size, tmp); - if (WARN_ON(r || !size)) - break; - } + WARN_ON(ret); + mutex_unlock(&iommu->lock); + return ret; + +out_unpin: + vfio_unpin_pages(pfn, npage, prot, true); + +out: + iova = map->iova; + size = map->size; + while ((dma = vfio_find_dma(iommu, iova, size))) { + int r = vfio_remove_dma_overlap(iommu, iova, + &size, dma); + if (WARN_ON(r || !size)) + break; } mutex_unlock(&iommu->lock); diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index c7c64f18773d..fa932c2f7d97 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -613,6 +613,9 @@ static int w1_bus_notify(struct notifier_block *nb, unsigned long action, sl = dev_to_w1_slave(dev); fops = sl->family->fops; + if (!fops) + return 0; + switch (action) { case BUS_NOTIFY_ADD_DEVICE: /* if the family driver needs to initialize something... */ @@ -713,7 +716,10 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) atomic_set(&sl->refcnt, 0); init_completion(&sl->released); + /* slave modules need to be loaded in a context with unlocked mutex */ + mutex_unlock(&dev->mutex); request_module("w1-family-0x%0x", rn->family); + mutex_lock(&dev->mutex); spin_lock(&w1_flock); f = w1_family_registered(rn->family); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index b0ef7b07b1b3..51e3afa78354 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6437,6 +6437,7 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len, if (btrfs_extent_readonly(root, disk_bytenr)) goto out; + btrfs_release_path(path); /* * look for other files referencing this extent, if we diff --git a/fs/buffer.c b/fs/buffer.c index 4d7433534f5c..6024877335ca 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1005,9 +1005,19 @@ grow_dev_page(struct block_device *bdev, sector_t block, struct buffer_head *bh; sector_t end_block; int ret = 0; /* Will call free_more_memory() */ + gfp_t gfp_mask; - page = find_or_create_page(inode->i_mapping, index, - (mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS)|__GFP_MOVABLE); + gfp_mask = mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS; + gfp_mask |= __GFP_MOVABLE; + /* + * XXX: __getblk_slow() can not really deal with failure and + * will endlessly loop on improvised global reclaim. Prefer + * looping in the allocator rather than here, at least that + * code knows what it's doing. + */ + gfp_mask |= __GFP_NOFAIL; + + page = find_or_create_page(inode->i_mapping, index, gfp_mask); if (!page) return ret; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index a16b4e58bcc6..77fc5e181077 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -120,14 +120,16 @@ cifs_read_super(struct super_block *sb) { struct inode *inode; struct cifs_sb_info *cifs_sb; + struct cifs_tcon *tcon; int rc = 0; cifs_sb = CIFS_SB(sb); + tcon = cifs_sb_master_tcon(cifs_sb); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIXACL) sb->s_flags |= MS_POSIXACL; - if (cifs_sb_master_tcon(cifs_sb)->ses->capabilities & CAP_LARGE_FILES) + if (tcon->ses->capabilities & tcon->ses->server->vals->cap_large_files) sb->s_maxbytes = MAX_LFS_FILESIZE; else sb->s_maxbytes = MAX_NON_LFS; @@ -147,7 +149,7 @@ cifs_read_super(struct super_block *sb) goto out_no_root; } - if (cifs_sb_master_tcon(cifs_sb)->nocase) + if (tcon->nocase) sb->s_d_op = &cifs_ci_dentry_ops; else sb->s_d_op = &cifs_dentry_ops; diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index a630475e421c..08f9dfb1a894 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -1491,15 +1491,30 @@ struct file_notify_information { __u8 FileName[0]; } __attribute__((packed)); -struct reparse_data { - __u32 ReparseTag; - __u16 ReparseDataLength; +/* For IO_REPARSE_TAG_SYMLINK */ +struct reparse_symlink_data { + __le32 ReparseTag; + __le16 ReparseDataLength; __u16 Reserved; - __u16 SubstituteNameOffset; - __u16 SubstituteNameLength; - __u16 PrintNameOffset; - __u16 PrintNameLength; - __u32 Flags; + __le16 SubstituteNameOffset; + __le16 SubstituteNameLength; + __le16 PrintNameOffset; + __le16 PrintNameLength; + __le32 Flags; + char PathBuffer[0]; +} __attribute__((packed)); + +/* For IO_REPARSE_TAG_NFS */ +#define NFS_SPECFILE_LNK 0x00000000014B4E4C +#define NFS_SPECFILE_CHR 0x0000000000524843 +#define NFS_SPECFILE_BLK 0x00000000004B4C42 +#define NFS_SPECFILE_FIFO 0x000000004F464946 +#define NFS_SPECFILE_SOCK 0x000000004B434F53 +struct reparse_posix_data { + __le32 ReparseTag; + __le16 ReparseDataLength; + __u16 Reserved; + __le64 InodeType; /* LNK, FIFO, CHR etc. */ char PathBuffer[0]; } __attribute__((packed)); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 4baf35949b51..ccd31ab815d4 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -3088,7 +3088,8 @@ CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, bool is_unicode; unsigned int sub_len; char *sub_start; - struct reparse_data *reparse_buf; + struct reparse_symlink_data *reparse_buf; + struct reparse_posix_data *posix_buf; __u32 data_offset, data_count; char *end_of_smb; @@ -3137,20 +3138,47 @@ CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, goto qreparse_out; } end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount; - reparse_buf = (struct reparse_data *) + reparse_buf = (struct reparse_symlink_data *) ((char *)&pSMBr->hdr.Protocol + data_offset); if ((char *)reparse_buf >= end_of_smb) { rc = -EIO; goto qreparse_out; } - if ((reparse_buf->PathBuffer + reparse_buf->PrintNameOffset + - reparse_buf->PrintNameLength) > end_of_smb) { + if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) { + cifs_dbg(FYI, "NFS style reparse tag\n"); + posix_buf = (struct reparse_posix_data *)reparse_buf; + + if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) { + cifs_dbg(FYI, "unsupported file type 0x%llx\n", + le64_to_cpu(posix_buf->InodeType)); + rc = -EOPNOTSUPP; + goto qreparse_out; + } + is_unicode = true; + sub_len = le16_to_cpu(reparse_buf->ReparseDataLength); + if (posix_buf->PathBuffer + sub_len > end_of_smb) { + cifs_dbg(FYI, "reparse buf beyond SMB\n"); + rc = -EIO; + goto qreparse_out; + } + *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer, + sub_len, is_unicode, nls_codepage); + goto qreparse_out; + } else if (reparse_buf->ReparseTag != + cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) { + rc = -EOPNOTSUPP; + goto qreparse_out; + } + + /* Reparse tag is NTFS symlink */ + sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) + + reparse_buf->PathBuffer; + sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength); + if (sub_start + sub_len > end_of_smb) { cifs_dbg(FYI, "reparse buf beyond SMB\n"); rc = -EIO; goto qreparse_out; } - sub_start = reparse_buf->SubstituteNameOffset + reparse_buf->PathBuffer; - sub_len = reparse_buf->SubstituteNameLength; if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) is_unicode = true; else diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index af847e1cf1c1..651a5279607b 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -780,7 +780,9 @@ static const struct { ERRDOS, ERRnoaccess, 0xc0000290}, { ERRDOS, ERRbadfunc, 0xc000029c}, { ERRDOS, ERRsymlink, NT_STATUS_STOPPED_ON_SYMLINK}, { - ERRDOS, ERRinvlevel, 0x007c0001}, }; + ERRDOS, ERRinvlevel, 0x007c0001}, { + 0, 0, 0 } +}; /***************************************************************************** Print an error message from the status code diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 352358de1d7e..e87387dbf39f 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -500,9 +500,9 @@ select_sectype(struct TCP_Server_Info *server, enum securityEnum requested) return NTLMv2; if (global_secflags & CIFSSEC_MAY_NTLM) return NTLM; - /* Fallthrough */ default: - return Unspecified; + /* Fallthrough to attempt LANMAN authentication next */ + break; } case CIFS_NEGFLAVOR_LANMAN: switch (requested) { diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index eba0efde66d7..edccb5252462 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -687,6 +687,10 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses) else return -EIO; + /* no need to send SMB logoff if uid already closed due to reconnect */ + if (ses->need_reconnect) + goto smb2_session_already_dead; + rc = small_smb2_init(SMB2_LOGOFF, NULL, (void **) &req); if (rc) return rc; @@ -701,6 +705,8 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses) * No tcon so can't do * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]); */ + +smb2_session_already_dead: return rc; } diff --git a/fs/cifs/smbfsctl.h b/fs/cifs/smbfsctl.h index d952ee48f4dc..a4b2391fe66e 100644 --- a/fs/cifs/smbfsctl.h +++ b/fs/cifs/smbfsctl.h @@ -97,9 +97,23 @@ #define FSCTL_QUERY_NETWORK_INTERFACE_INFO 0x001401FC /* BB add struct */ #define FSCTL_SRV_READ_HASH 0x001441BB /* BB add struct */ +/* See FSCC 2.1.2.5 */ #define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003 #define IO_REPARSE_TAG_HSM 0xC0000004 #define IO_REPARSE_TAG_SIS 0x80000007 +#define IO_REPARSE_TAG_HSM2 0x80000006 +#define IO_REPARSE_TAG_DRIVER_EXTENDER 0x80000005 +/* Used by the DFS filter. See MS-DFSC */ +#define IO_REPARSE_TAG_DFS 0x8000000A +/* Used by the DFS filter See MS-DFSC */ +#define IO_REPARSE_TAG_DFSR 0x80000012 +#define IO_REPARSE_TAG_FILTER_MANAGER 0x8000000B +/* See section MS-FSCC 2.1.2.4 */ +#define IO_REPARSE_TAG_SYMLINK 0xA000000C +#define IO_REPARSE_TAG_DEDUP 0x80000013 +#define IO_REPARSE_APPXSTREAM 0xC0000014 +/* NFS symlinks, Win 8/SMB3 and later */ +#define IO_REPARSE_TAG_NFS 0x80000014 /* fsctl flags */ /* If Flags is set to this value, the request is an FSCTL not ioctl request */ diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 6fdcb1b4a106..800b938e4061 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -410,8 +410,13 @@ static int wait_for_free_request(struct TCP_Server_Info *server, const int timeout, const int optype) { - return wait_for_free_credits(server, timeout, - server->ops->get_credits_field(server, optype)); + int *val; + + val = server->ops->get_credits_field(server, optype); + /* Since an echo is already inflight, no need to wait to send another */ + if (*val <= 0 && optype == CIFS_ECHO_OP) + return -EAGAIN; + return wait_for_free_credits(server, timeout, val); } static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 1194b1f0f839..f8cde46de9cd 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -1783,7 +1783,7 @@ retry: d_tmpfile(dentry, inode); err = ext3_orphan_add(handle, inode); if (err) - goto err_drop_inode; + goto err_unlock_inode; mark_inode_dirty(inode); unlock_new_inode(inode); } @@ -1791,10 +1791,9 @@ retry: if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) goto retry; return err; -err_drop_inode: +err_unlock_inode: ext3_journal_stop(handle); unlock_new_inode(inode); - iput(inode); return err; } diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 1bec5a5c1e45..5a0408d7b114 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -2319,7 +2319,7 @@ retry: d_tmpfile(dentry, inode); err = ext4_orphan_add(handle, inode); if (err) - goto err_drop_inode; + goto err_unlock_inode; mark_inode_dirty(inode); unlock_new_inode(inode); } @@ -2328,10 +2328,9 @@ retry: if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) goto retry; return err; -err_drop_inode: +err_unlock_inode: ext4_journal_stop(handle); unlock_new_inode(inode); - iput(inode); return err; } diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 9f8ef9b7674d..8eaa1ba793fc 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -288,10 +288,14 @@ static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma) static unsigned long proc_reg_get_unmapped_area(struct file *file, unsigned long orig_addr, unsigned long len, unsigned long pgoff, unsigned long flags) { struct proc_dir_entry *pde = PDE(file_inode(file)); - int rv = -EIO; - unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); + unsigned long rv = -EIO; + unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long) = NULL; if (use_pde(pde)) { - get_unmapped_area = pde->proc_fops->get_unmapped_area; +#ifdef CONFIG_MMU + get_unmapped_area = current->mm->get_unmapped_area; +#endif + if (pde->proc_fops->get_unmapped_area) + get_unmapped_area = pde->proc_fops->get_unmapped_area; if (get_unmapped_area) rv = get_unmapped_area(file, orig_addr, len, pgoff, flags); unuse_pde(pde); diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 7366e9d63cee..390bdab01c3c 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -941,6 +941,8 @@ static void pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm, frame = pte_pfn(pte); flags = PM_PRESENT; page = vm_normal_page(vma, addr, pte); + if (pte_soft_dirty(pte)) + flags2 |= __PM_SOFT_DIRTY; } else if (is_swap_pte(pte)) { swp_entry_t entry; if (pte_swp_soft_dirty(pte)) @@ -960,7 +962,7 @@ static void pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm, if (page && !PageAnon(page)) flags |= PM_FILE; - if ((vma->vm_flags & VM_SOFTDIRTY) || pte_soft_dirty(pte)) + if ((vma->vm_flags & VM_SOFTDIRTY)) flags2 |= __PM_SOFT_DIRTY; *pme = make_pme(PM_PFRAME(frame) | PM_STATUS2(pm->v2, flags2) | flags); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 02e113bb8b7d..d9019821aa60 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -311,7 +311,6 @@ struct acpi_device { unsigned int physical_node_count; struct list_head physical_node_list; struct mutex physical_node_lock; - struct list_head power_dependent; void (*remove)(struct acpi_device *); }; @@ -456,8 +455,6 @@ acpi_status acpi_add_pm_notifier(struct acpi_device *adev, acpi_status acpi_remove_pm_notifier(struct acpi_device *adev, acpi_notify_handler handler); int acpi_pm_device_sleep_state(struct device *, int *, int); -void acpi_dev_pm_add_dependent(acpi_handle handle, struct device *depdev); -void acpi_dev_pm_remove_dependent(acpi_handle handle, struct device *depdev); #else static inline acpi_status acpi_add_pm_notifier(struct acpi_device *adev, acpi_notify_handler handler, @@ -478,10 +475,6 @@ static inline int acpi_pm_device_sleep_state(struct device *d, int *p, int m) return (m >= ACPI_STATE_D0 && m <= ACPI_STATE_D3_COLD) ? m : ACPI_STATE_D0; } -static inline void acpi_dev_pm_add_dependent(acpi_handle handle, - struct device *depdev) {} -static inline void acpi_dev_pm_remove_dependent(acpi_handle handle, - struct device *depdev) {} #endif #ifdef CONFIG_PM_RUNTIME diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index ecc82b37c4cc..b3e7a667e03c 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -137,47 +137,24 @@ extern void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, extern void mem_cgroup_replace_page_cache(struct page *oldpage, struct page *newpage); -/** - * mem_cgroup_toggle_oom - toggle the memcg OOM killer for the current task - * @new: true to enable, false to disable - * - * Toggle whether a failed memcg charge should invoke the OOM killer - * or just return -ENOMEM. Returns the previous toggle state. - * - * NOTE: Any path that enables the OOM killer before charging must - * call mem_cgroup_oom_synchronize() afterward to finalize the - * OOM handling and clean up. - */ -static inline bool mem_cgroup_toggle_oom(bool new) +static inline void mem_cgroup_oom_enable(void) { - bool old; - - old = current->memcg_oom.may_oom; - current->memcg_oom.may_oom = new; - - return old; + WARN_ON(current->memcg_oom.may_oom); + current->memcg_oom.may_oom = 1; } -static inline void mem_cgroup_enable_oom(void) +static inline void mem_cgroup_oom_disable(void) { - bool old = mem_cgroup_toggle_oom(true); - - WARN_ON(old == true); -} - -static inline void mem_cgroup_disable_oom(void) -{ - bool old = mem_cgroup_toggle_oom(false); - - WARN_ON(old == false); + WARN_ON(!current->memcg_oom.may_oom); + current->memcg_oom.may_oom = 0; } static inline bool task_in_memcg_oom(struct task_struct *p) { - return p->memcg_oom.in_memcg_oom; + return p->memcg_oom.memcg; } -bool mem_cgroup_oom_synchronize(void); +bool mem_cgroup_oom_synchronize(bool wait); #ifdef CONFIG_MEMCG_SWAP extern int do_swap_account; @@ -402,16 +379,11 @@ static inline void mem_cgroup_end_update_page_stat(struct page *page, { } -static inline bool mem_cgroup_toggle_oom(bool new) -{ - return false; -} - -static inline void mem_cgroup_enable_oom(void) +static inline void mem_cgroup_oom_enable(void) { } -static inline void mem_cgroup_disable_oom(void) +static inline void mem_cgroup_oom_disable(void) { } @@ -420,7 +392,7 @@ static inline bool task_in_memcg_oom(struct task_struct *p) return false; } -static inline bool mem_cgroup_oom_synchronize(void) +static inline bool mem_cgroup_oom_synchronize(bool wait) { return false; } diff --git a/include/linux/mfd/mc13xxx.h b/include/linux/mfd/mc13xxx.h index 41ed59276c00..67c17b5a6f44 100644 --- a/include/linux/mfd/mc13xxx.h +++ b/include/linux/mfd/mc13xxx.h @@ -41,6 +41,13 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode, unsigned int channel, u8 ato, bool atox, unsigned int *sample); +#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 MC13XXX_IRQ_ADCDONE 0 #define MC13XXX_IRQ_ADCBISDONE 1 #define MC13XXX_IRQ_TS 2 diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index 68029b30c3dc..5eb4e31af22b 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -181,7 +181,7 @@ enum { MLX5_DEV_CAP_FLAG_TLP_HINTS = 1LL << 39, MLX5_DEV_CAP_FLAG_SIG_HAND_OVER = 1LL << 40, MLX5_DEV_CAP_FLAG_DCT = 1LL << 41, - MLX5_DEV_CAP_FLAG_CMDIF_CSUM = 1LL << 46, + MLX5_DEV_CAP_FLAG_CMDIF_CSUM = 3LL << 46, }; enum { @@ -417,7 +417,7 @@ struct mlx5_init_seg { struct health_buffer health; __be32 rsvd2[884]; __be32 health_counter; - __be32 rsvd3[1023]; + __be32 rsvd3[1019]; __be64 ieee1588_clk; __be32 ieee1588_clk_type; __be32 clr_intx; diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 8888381fc150..6b8c496572c8 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -82,7 +82,7 @@ enum { }; enum { - MLX5_MAX_EQ_NAME = 20 + MLX5_MAX_EQ_NAME = 32 }; enum { @@ -747,8 +747,7 @@ static inline u32 mlx5_idx_to_mkey(u32 mkey_idx) enum { MLX5_PROF_MASK_QP_SIZE = (u64)1 << 0, - MLX5_PROF_MASK_CMDIF_CSUM = (u64)1 << 1, - MLX5_PROF_MASK_MR_CACHE = (u64)1 << 2, + MLX5_PROF_MASK_MR_CACHE = (u64)1 << 1, }; enum { @@ -758,7 +757,6 @@ enum { struct mlx5_profile { u64 mask; u32 log_max_qp; - int cmdif_csum; struct { int size; int limit; diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h deleted file mode 100644 index c84128255814..000000000000 --- a/include/linux/of_reserved_mem.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __OF_RESERVED_MEM_H -#define __OF_RESERVED_MEM_H - -#ifdef CONFIG_OF_RESERVED_MEM -void of_reserved_mem_device_init(struct device *dev); -void of_reserved_mem_device_release(struct device *dev); -void early_init_dt_scan_reserved_mem(void); -#else -static inline void of_reserved_mem_device_init(struct device *dev) { } -static inline void of_reserved_mem_device_release(struct device *dev) { } -static inline void early_init_dt_scan_reserved_mem(void) { } -#endif - -#endif /* __OF_RESERVED_MEM_H */ diff --git a/include/linux/platform_data/davinci_asp.h b/include/linux/platform_data/davinci_asp.h index 8db5ae03b6e3..689a856b86f9 100644 --- a/include/linux/platform_data/davinci_asp.h +++ b/include/linux/platform_data/davinci_asp.h @@ -84,6 +84,8 @@ struct snd_platform_data { u8 version; u8 txnumevt; u8 rxnumevt; + int tx_dma_channel; + int rx_dma_channel; }; enum { diff --git a/include/linux/regmap.h b/include/linux/regmap.h index a10380bfbeac..114565befbd2 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -374,6 +374,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config); struct regmap *dev_get_regmap(struct device *dev, const char *name); int regmap_write(struct regmap *map, unsigned int reg, unsigned int val); +int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val); int regmap_raw_write(struct regmap *map, unsigned int reg, const void *val, size_t val_len); int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, @@ -387,9 +388,14 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, size_t val_count); int regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val); +int regmap_update_bits_async(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val); int regmap_update_bits_check(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, bool *change); +int regmap_update_bits_check_async(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val, + bool *change); int regmap_get_val_bytes(struct regmap *map); int regmap_async_complete(struct regmap *map); bool regmap_can_raw_write(struct regmap *map); @@ -527,6 +533,13 @@ static inline int regmap_write(struct regmap *map, unsigned int reg, return -EINVAL; } +static inline int regmap_write_async(struct regmap *map, unsigned int reg, + unsigned int val) +{ + WARN_ONCE(1, "regmap API is disabled"); + return -EINVAL; +} + static inline int regmap_raw_write(struct regmap *map, unsigned int reg, const void *val, size_t val_len) { @@ -576,6 +589,14 @@ static inline int regmap_update_bits(struct regmap *map, unsigned int reg, return -EINVAL; } +static inline int regmap_update_bits_async(struct regmap *map, + unsigned int reg, + unsigned int mask, unsigned int val) +{ + WARN_ONCE(1, "regmap API is disabled"); + return -EINVAL; +} + static inline int regmap_update_bits_check(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, @@ -585,6 +606,16 @@ static inline int regmap_update_bits_check(struct regmap *map, return -EINVAL; } +static inline int regmap_update_bits_check_async(struct regmap *map, + unsigned int reg, + unsigned int mask, + unsigned int val, + bool *change) +{ + WARN_ONCE(1, "regmap API is disabled"); + return -EINVAL; +} + static inline int regmap_get_val_bytes(struct regmap *map) { WARN_ONCE(1, "regmap API is disabled"); diff --git a/include/linux/sched.h b/include/linux/sched.h index 6682da36b293..e27baeeda3f4 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1394,11 +1394,10 @@ struct task_struct { } memcg_batch; unsigned int memcg_kmem_skip_account; struct memcg_oom_info { + struct mem_cgroup *memcg; + gfp_t gfp_mask; + int order; unsigned int may_oom:1; - unsigned int in_memcg_oom:1; - unsigned int oom_locked:1; - int wakeups; - struct mem_cgroup *wait_on_memcg; } memcg_oom; #endif #ifdef CONFIG_UPROBES diff --git a/include/linux/usb/usb_phy_gen_xceiv.h b/include/linux/usb/usb_phy_gen_xceiv.h index f9a7e7bc925b..11d85b9c1b08 100644 --- a/include/linux/usb/usb_phy_gen_xceiv.h +++ b/include/linux/usb/usb_phy_gen_xceiv.h @@ -12,7 +12,7 @@ struct usb_phy_gen_xceiv_platform_data { unsigned int needs_reset:1; }; -#if IS_ENABLED(CONFIG_NOP_USB_XCEIV) +#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE)) /* sometimes transceivers are accessed only through e.g. ULPI */ extern void usb_nop_xceiv_register(void); extern void usb_nop_xceiv_unregister(void); diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h index bf99cd01be20..630356866030 100644 --- a/include/linux/usb_usual.h +++ b/include/linux/usb_usual.h @@ -66,7 +66,9 @@ US_FLAG(INITIAL_READ10, 0x00100000) \ /* Initial READ(10) (and others) must be retried */ \ US_FLAG(WRITE_CACHE, 0x00200000) \ - /* Write Cache status is not available */ + /* Write Cache status is not available */ \ + US_FLAG(NEEDS_CAP16, 0x00400000) + /* cannot handle READ_CAPACITY_10 */ #define US_FLAG(name, value) US_FL_##name = value , enum { US_DO_ALL_FLAGS }; diff --git a/include/sound/cs42l73.h b/include/sound/cs42l73.h new file mode 100644 index 000000000000..f354be4cdc9e --- /dev/null +++ b/include/sound/cs42l73.h @@ -0,0 +1,22 @@ +/* + * linux/sound/cs42l73.h -- Platform data for CS42L73 + * + * 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 __CS42L73_H +#define __CS42L73_H + +struct cs42l73_platform_data { + /* RST GPIO */ + unsigned int reset_gpio; + unsigned int chgfreq; + int jack_detection; + unsigned int mclk_freq; +}; + +#endif /* __CS42L73_H */ diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index f11c35cd5532..15017311f2e9 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -61,6 +61,8 @@ struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream) * @slave_id: Slave requester id for the DMA channel. * @filter_data: Custom DMA channel filter data, this will usually be used when * requesting the DMA channel. + * @chan_name: Custom channel name to use when requesting DMA channel. + * @fifo_size: FIFO size of the DAI controller in bytes */ struct snd_dmaengine_dai_dma_data { dma_addr_t addr; @@ -68,6 +70,8 @@ struct snd_dmaengine_dai_dma_data { u32 maxburst; unsigned int slave_id; void *filter_data; + const char *chan_name; + unsigned int fifo_size; }; void snd_dmaengine_pcm_set_config_from_dai_data( @@ -96,6 +100,10 @@ void snd_dmaengine_pcm_set_config_from_dai_data( * playback. */ #define SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX BIT(3) +/* + * The PCM streams have custom channel names specified. + */ +#define SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME BIT(4) /** * struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h index fe66533e9b7a..fb0a312bcb81 100644 --- a/include/sound/rcar_snd.h +++ b/include/sound/rcar_snd.h @@ -68,6 +68,7 @@ struct rsnd_scu_platform_info { * * A : generation */ +#define RSND_GEN_MASK (0xF << 0) #define RSND_GEN1 (1 << 0) /* fixme */ #define RSND_GEN2 (2 << 0) /* fixme */ diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index ae9a227d35d3..800c101bb096 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -105,6 +105,8 @@ int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, unsigned int freq_in, unsigned int freq_out); +int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio); + /* Digital Audio interface formatting */ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt); @@ -131,6 +133,7 @@ struct snd_soc_dai_ops { int (*set_pll)(struct snd_soc_dai *dai, int pll_id, int source, unsigned int freq_in, unsigned int freq_out); int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div); + int (*set_bclk_ratio)(struct snd_soc_dai *dai, unsigned int ratio); /* * DAI format configuration @@ -166,6 +169,13 @@ struct snd_soc_dai_ops { struct snd_soc_dai *); int (*prepare)(struct snd_pcm_substream *, struct snd_soc_dai *); + /* + * NOTE: Commands passed to the trigger function are not necessarily + * compatible with the current state of the dai. For example this + * sequence of commands is possible: START STOP STOP. + * So do not unconditionally use refcounting functions in the trigger + * function, e.g. clk_enable/disable. + */ int (*trigger)(struct snd_pcm_substream *, int, struct snd_soc_dai *); int (*bespoke_trigger)(struct snd_pcm_substream *, int, @@ -276,6 +286,13 @@ static inline void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai, dai->capture_dma_data = data; } +static inline void snd_soc_dai_init_dma_data(struct snd_soc_dai *dai, + void *playback, void *capture) +{ + dai->playback_dma_data = playback; + dai->capture_dma_data = capture; +} + static inline void snd_soc_dai_set_drvdata(struct snd_soc_dai *dai, void *data) { diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 27a72d5d4b00..2037c45adfe6 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -286,6 +286,8 @@ struct device; .info = snd_soc_info_volsw, \ .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 1) } +#define SOC_DAPM_SINGLE_VIRT(xname, max) \ + SOC_DAPM_SINGLE(xname, SND_SOC_NOPM, 0, max, 0) #define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_volsw, \ @@ -300,6 +302,8 @@ struct device; .tlv.p = (tlv_array), \ .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } +#define SOC_DAPM_SINGLE_TLV_VIRT(xname, max, tlv_array) \ + SOC_DAPM_SINGLE(xname, SND_SOC_NOPM, 0, max, 0, tlv_array) #define SOC_DAPM_ENUM(xname, xenum) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_enum_double, \ diff --git a/include/sound/soc.h b/include/sound/soc.h index d22cb0a06feb..1f741cb24f33 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -13,6 +13,7 @@ #ifndef __LINUX_SND_SOC_H #define __LINUX_SND_SOC_H +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/types.h> #include <linux/notifier.h> @@ -330,7 +331,6 @@ struct soc_enum; struct snd_soc_jack; struct snd_soc_jack_zone; struct snd_soc_jack_pin; -struct snd_soc_cache_ops; #include <sound/soc-dapm.h> #include <sound/soc-dpcm.h> @@ -348,10 +348,6 @@ enum snd_soc_control_type { SND_SOC_REGMAP, }; -enum snd_soc_compress_type { - SND_SOC_FLAT_COMPRESSION = 1, -}; - enum snd_soc_pcm_subclass { SND_SOC_PCM_CLASS_PCM = 0, SND_SOC_PCM_CLASS_BE = 1, @@ -369,6 +365,7 @@ int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source, int snd_soc_register_card(struct snd_soc_card *card); int snd_soc_unregister_card(struct snd_soc_card *card); +int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card); int snd_soc_suspend(struct device *dev); int snd_soc_resume(struct device *dev); int snd_soc_poweroff(struct device *dev); @@ -386,6 +383,9 @@ void snd_soc_unregister_codec(struct device *dev); int snd_soc_register_component(struct device *dev, const struct snd_soc_component_driver *cmpnt_drv, struct snd_soc_dai_driver *dai_drv, int num_dai); +int devm_snd_soc_register_component(struct device *dev, + const struct snd_soc_component_driver *cmpnt_drv, + struct snd_soc_dai_driver *dai_drv, int num_dai); void snd_soc_unregister_component(struct device *dev); int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, unsigned int reg); @@ -403,12 +403,6 @@ int snd_soc_cache_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value); int snd_soc_cache_read(struct snd_soc_codec *codec, unsigned int reg, unsigned int *value); -int snd_soc_default_volatile_register(struct snd_soc_codec *codec, - unsigned int reg); -int snd_soc_default_readable_register(struct snd_soc_codec *codec, - unsigned int reg); -int snd_soc_default_writable_register(struct snd_soc_codec *codec, - unsigned int reg); int snd_soc_platform_read(struct snd_soc_platform *platform, unsigned int reg); int snd_soc_platform_write(struct snd_soc_platform *platform, @@ -542,22 +536,6 @@ 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 - * readable, writable or volatile. - * - * @reg: the register number - * @read: whether this register is readable - * @write: whether this register is writable - * @vol: whether this register is volatile - */ -struct snd_soc_reg_access { - u16 reg; - u16 read; - u16 write; - u16 vol; -}; - -/** * struct snd_soc_jack_pin - Describes a pin to update based on jack detection * * @pin: name of the pin to update @@ -657,17 +635,26 @@ struct snd_soc_compr_ops { int (*trigger)(struct snd_compr_stream *); }; -/* SoC cache ops */ -struct snd_soc_cache_ops { +/* component interface */ +struct snd_soc_component_driver { + const char *name; + + /* DT */ + int (*of_xlate_dai_name)(struct snd_soc_component *component, + struct of_phandle_args *args, + const char **dai_name); +}; + +struct snd_soc_component { const char *name; - enum snd_soc_compress_type id; - int (*init)(struct snd_soc_codec *codec); - int (*exit)(struct snd_soc_codec *codec); - int (*read)(struct snd_soc_codec *codec, unsigned int reg, - unsigned int *value); - int (*write)(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value); - int (*sync)(struct snd_soc_codec *codec); + int id; + struct device *dev; + struct list_head list; + + struct snd_soc_dai_driver *dai_drv; + int num_dai; + + const struct snd_soc_component_driver *driver; }; /* SoC Audio Codec device */ @@ -683,8 +670,6 @@ struct snd_soc_codec { struct list_head list; struct list_head card_list; int num_dai; - enum snd_soc_compress_type compress_type; - size_t reg_size; /* reg_cache_size * reg_word_size */ int (*volatile_register)(struct snd_soc_codec *, unsigned int); int (*readable_register)(struct snd_soc_codec *, unsigned int); int (*writable_register)(struct snd_soc_codec *, unsigned int); @@ -708,13 +693,13 @@ struct snd_soc_codec { unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int); unsigned int (*read)(struct snd_soc_codec *, unsigned int); int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); - int (*bulk_write_raw)(struct snd_soc_codec *, unsigned int, const void *, size_t); void *reg_cache; - const void *reg_def_copy; - const struct snd_soc_cache_ops *cache_ops; struct mutex cache_rw_mutex; int val_bytes; + /* component */ + struct snd_soc_component component; + /* dapm */ struct snd_soc_dapm_context dapm; unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */ @@ -733,6 +718,7 @@ struct snd_soc_codec_driver { int (*remove)(struct snd_soc_codec *); int (*suspend)(struct snd_soc_codec *); int (*resume)(struct snd_soc_codec *); + struct snd_soc_component_driver component_driver; /* Default control and setup, added after probe() is run */ const struct snd_kcontrol_new *controls; @@ -760,9 +746,6 @@ struct snd_soc_codec_driver { short reg_cache_step; short reg_word_size; const void *reg_cache_default; - short reg_access_size; - const struct snd_soc_reg_access *reg_access_default; - enum snd_soc_compress_type compress_type; /* codec bias level */ int (*set_bias_level)(struct snd_soc_codec *, @@ -849,20 +832,6 @@ struct snd_soc_platform { #endif }; -struct snd_soc_component_driver { - const char *name; -}; - -struct snd_soc_component { - const char *name; - int id; - int num_dai; - struct device *dev; - struct list_head list; - - const struct snd_soc_component_driver *driver; -}; - struct snd_soc_dai_link { /* config - must be set by machine driver */ const char *name; /* Codec name */ @@ -944,12 +913,6 @@ struct snd_soc_codec_conf { * associated per device */ const char *name_prefix; - - /* - * set this to the desired compression type if you want to - * override the one supplied in codec->driver->compress_type - */ - enum snd_soc_compress_type compress_type; }; struct snd_soc_aux_dev { @@ -1088,7 +1051,8 @@ struct snd_soc_pcm_runtime { /* mixer control */ struct soc_mixer_control { int min, max, platform_max; - unsigned int reg, rreg, shift, rshift; + int reg, rreg; + unsigned int shift, rshift; unsigned int invert:1; unsigned int autodisable:1; }; @@ -1121,8 +1085,6 @@ struct soc_enum { unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg); unsigned int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val); -unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec, - unsigned int reg, const void *data, size_t len); /* device driver data */ @@ -1201,6 +1163,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname); unsigned int snd_soc_of_parse_daifmt(struct device_node *np, const char *prefix); +int snd_soc_of_get_dai_name(struct device_node *of_node, + const char **dai_name); #include <sound/soc-dai.h> diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h index 5fc2dcdd21cd..03996b2bb04f 100644 --- a/include/trace/events/asoc.h +++ b/include/trace/events/asoc.h @@ -14,6 +14,7 @@ struct snd_soc_codec; struct snd_soc_platform; struct snd_soc_card; struct snd_soc_dapm_widget; +struct snd_soc_dapm_path; /* * Log register events diff --git a/ipc/sem.c b/ipc/sem.c index 8c4f59b0204a..db9d241af133 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -1282,6 +1282,12 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum, sem_lock(sma, NULL, -1); + if (sma->sem_perm.deleted) { + sem_unlock(sma, -1); + rcu_read_unlock(); + return -EIDRM; + } + curr = &sma->sem_base[semnum]; ipc_assert_locked_object(&sma->sem_perm); @@ -1336,12 +1342,14 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, int i; sem_lock(sma, NULL, -1); + if (sma->sem_perm.deleted) { + err = -EIDRM; + goto out_unlock; + } if(nsems > SEMMSL_FAST) { if (!ipc_rcu_getref(sma)) { - sem_unlock(sma, -1); - rcu_read_unlock(); err = -EIDRM; - goto out_free; + goto out_unlock; } sem_unlock(sma, -1); rcu_read_unlock(); @@ -1354,10 +1362,8 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, rcu_read_lock(); sem_lock_and_putref(sma); if (sma->sem_perm.deleted) { - sem_unlock(sma, -1); - rcu_read_unlock(); err = -EIDRM; - goto out_free; + goto out_unlock; } } for (i = 0; i < sma->sem_nsems; i++) @@ -1375,8 +1381,8 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, struct sem_undo *un; if (!ipc_rcu_getref(sma)) { - rcu_read_unlock(); - return -EIDRM; + err = -EIDRM; + goto out_rcu_wakeup; } rcu_read_unlock(); @@ -1404,10 +1410,8 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, rcu_read_lock(); sem_lock_and_putref(sma); if (sma->sem_perm.deleted) { - sem_unlock(sma, -1); - rcu_read_unlock(); err = -EIDRM; - goto out_free; + goto out_unlock; } for (i = 0; i < nsems; i++) @@ -1431,6 +1435,10 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, goto out_rcu_wakeup; sem_lock(sma, NULL, -1); + if (sma->sem_perm.deleted) { + err = -EIDRM; + goto out_unlock; + } curr = &sma->sem_base[semnum]; switch (cmd) { @@ -1836,6 +1844,10 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, if (error) goto out_rcu_wakeup; + error = -EIDRM; + locknum = sem_lock(sma, sops, nsops); + if (sma->sem_perm.deleted) + goto out_unlock_free; /* * semid identifiers are not unique - find_alloc_undo may have * allocated an undo structure, it was invalidated by an RMID @@ -1843,8 +1855,6 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, * This case can be detected checking un->semid. The existence of * "un" itself is guaranteed by rcu. */ - error = -EIDRM; - locknum = sem_lock(sma, sops, nsops); if (un && un->semid == -1) goto out_unlock_free; @@ -2057,6 +2067,12 @@ void exit_sem(struct task_struct *tsk) } sem_lock(sma, NULL, -1); + /* exit_sem raced with IPC_RMID, nothing to do */ + if (sma->sem_perm.deleted) { + sem_unlock(sma, -1); + rcu_read_unlock(); + continue; + } un = __lookup_undo(ulp, semid); if (un == NULL) { /* exit_sem raced with IPC_RMID+semget() that created diff --git a/ipc/util.c b/ipc/util.c index fdb8ae740775..7684f41bce76 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -17,12 +17,27 @@ * Pavel Emelianov <xemul@openvz.org> * * General sysv ipc locking scheme: - * when doing ipc id lookups, take the ids->rwsem - * rcu_read_lock() - * obtain the ipc object (kern_ipc_perm) - * perform security, capabilities, auditing and permission checks, etc. - * acquire the ipc lock (kern_ipc_perm.lock) throught ipc_lock_object() - * perform data updates (ie: SET, RMID, LOCK/UNLOCK commands) + * rcu_read_lock() + * obtain the ipc object (kern_ipc_perm) by looking up the id in an idr + * tree. + * - perform initial checks (capabilities, auditing and permission, + * etc). + * - perform read-only operations, such as STAT, INFO commands. + * acquire the ipc lock (kern_ipc_perm.lock) through + * ipc_lock_object() + * - perform data updates, such as SET, RMID commands and + * mechanism-specific operations (semop/semtimedop, + * msgsnd/msgrcv, shmat/shmdt). + * drop the ipc lock, through ipc_unlock_object(). + * rcu_read_unlock() + * + * The ids->rwsem must be taken when: + * - creating, removing and iterating the existing entries in ipc + * identifier sets. + * - iterating through files under /proc/sysvipc/ + * + * Note that sems have a special fast path that avoids kern_ipc_perm.lock - + * see sem_lock(). */ #include <linux/mm.h> diff --git a/lib/percpu-refcount.c b/lib/percpu-refcount.c index 7deeb6297a48..1a53d497a8c5 100644 --- a/lib/percpu-refcount.c +++ b/lib/percpu-refcount.c @@ -53,6 +53,7 @@ int percpu_ref_init(struct percpu_ref *ref, percpu_ref_func_t *release) ref->release = release; return 0; } +EXPORT_SYMBOL_GPL(percpu_ref_init); /** * percpu_ref_cancel_init - cancel percpu_ref_init() @@ -84,6 +85,7 @@ void percpu_ref_cancel_init(struct percpu_ref *ref) free_percpu(ref->pcpu_count); } } +EXPORT_SYMBOL_GPL(percpu_ref_cancel_init); static void percpu_ref_kill_rcu(struct rcu_head *rcu) { @@ -156,3 +158,4 @@ void percpu_ref_kill_and_confirm(struct percpu_ref *ref, call_rcu_sched(&ref->rcu, percpu_ref_kill_rcu); } +EXPORT_SYMBOL_GPL(percpu_ref_kill_and_confirm); diff --git a/mm/filemap.c b/mm/filemap.c index 1e6aec4a2d2e..ae4846ff4849 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1616,7 +1616,6 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) struct inode *inode = mapping->host; pgoff_t offset = vmf->pgoff; struct page *page; - bool memcg_oom; pgoff_t size; int ret = 0; @@ -1625,11 +1624,7 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return VM_FAULT_SIGBUS; /* - * Do we have something in the page cache already? Either - * way, try readahead, but disable the memcg OOM killer for it - * as readahead is optional and no errors are propagated up - * the fault stack. The OOM killer is enabled while trying to - * instantiate the faulting page individually below. + * Do we have something in the page cache already? */ page = find_get_page(mapping, offset); if (likely(page) && !(vmf->flags & FAULT_FLAG_TRIED)) { @@ -1637,14 +1632,10 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) * We found the page, so try async readahead before * waiting for the lock. */ - memcg_oom = mem_cgroup_toggle_oom(false); do_async_mmap_readahead(vma, ra, file, page, offset); - mem_cgroup_toggle_oom(memcg_oom); } else if (!page) { /* No page in the page cache at all */ - memcg_oom = mem_cgroup_toggle_oom(false); do_sync_mmap_readahead(vma, ra, file, offset); - mem_cgroup_toggle_oom(memcg_oom); count_vm_event(PGMAJFAULT); mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT); ret = VM_FAULT_MAJOR; diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 7489884682d8..610e3df2768a 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2697,6 +2697,7 @@ void __split_huge_page_pmd(struct vm_area_struct *vma, unsigned long address, mmun_start = haddr; mmun_end = haddr + HPAGE_PMD_SIZE; +again: mmu_notifier_invalidate_range_start(mm, mmun_start, mmun_end); spin_lock(&mm->page_table_lock); if (unlikely(!pmd_trans_huge(*pmd))) { @@ -2719,7 +2720,14 @@ void __split_huge_page_pmd(struct vm_area_struct *vma, unsigned long address, split_huge_page(page); put_page(page); - BUG_ON(pmd_trans_huge(*pmd)); + + /* + * We don't always have down_write of mmap_sem here: a racing + * do_huge_pmd_wp_page() might have copied-on-write to another + * huge page before our split_huge_page() got the anon_vma lock. + */ + if (unlikely(pmd_trans_huge(*pmd))) + goto again; } void split_huge_page_pmd_mm(struct mm_struct *mm, unsigned long address, diff --git a/mm/hugetlb.c b/mm/hugetlb.c index b49579c7f2a5..0b7656e804d1 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -653,6 +653,7 @@ static void free_huge_page(struct page *page) BUG_ON(page_count(page)); BUG_ON(page_mapcount(page)); restore_reserve = PagePrivate(page); + ClearPagePrivate(page); spin_lock(&hugetlb_lock); hugetlb_cgroup_uncharge_page(hstate_index(h), @@ -695,8 +696,22 @@ static void prep_compound_gigantic_page(struct page *page, unsigned long order) /* we rely on prep_new_huge_page to set the destructor */ set_compound_order(page, order); __SetPageHead(page); + __ClearPageReserved(page); for (i = 1; i < nr_pages; i++, p = mem_map_next(p, page, i)) { __SetPageTail(p); + /* + * For gigantic hugepages allocated through bootmem at + * boot, it's safer to be consistent with the not-gigantic + * hugepages and clear the PG_reserved bit from all tail pages + * too. Otherwse drivers using get_user_pages() to access tail + * pages may get the reference counting wrong if they see + * PG_reserved set on a tail page (despite the head page not + * having PG_reserved set). Enforcing this consistency between + * head and tail pages allows drivers to optimize away a check + * on the head page when they need know if put_page() is needed + * after get_user_pages(). + */ + __ClearPageReserved(p); set_page_count(p, 0); p->first_page = page; } @@ -1329,9 +1344,9 @@ static void __init gather_bootmem_prealloc(void) #else page = virt_to_page(m); #endif - __ClearPageReserved(page); WARN_ON(page_count(page) != 1); prep_compound_huge_page(page, h->order); + WARN_ON(PageReserved(page)); prep_new_huge_page(h, page, page_to_nid(page)); /* * If we had gigantic hugepages allocated at boot time, we need diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 1c52ddbc839b..34d3ca9572d6 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -866,6 +866,7 @@ static unsigned long mem_cgroup_read_events(struct mem_cgroup *memcg, unsigned long val = 0; int cpu; + get_online_cpus(); for_each_online_cpu(cpu) val += per_cpu(memcg->stat->events[idx], cpu); #ifdef CONFIG_HOTPLUG_CPU @@ -873,6 +874,7 @@ static unsigned long mem_cgroup_read_events(struct mem_cgroup *memcg, val += memcg->nocpu_base.events[idx]; spin_unlock(&memcg->pcp_counter_lock); #endif + put_online_cpus(); return val; } @@ -2159,110 +2161,59 @@ static void memcg_oom_recover(struct mem_cgroup *memcg) memcg_wakeup_oom(memcg); } -/* - * try to call OOM killer - */ static void mem_cgroup_oom(struct mem_cgroup *memcg, gfp_t mask, int order) { - bool locked; - int wakeups; - if (!current->memcg_oom.may_oom) return; - - current->memcg_oom.in_memcg_oom = 1; - /* - * As with any blocking lock, a contender needs to start - * listening for wakeups before attempting the trylock, - * otherwise it can miss the wakeup from the unlock and sleep - * indefinitely. This is just open-coded because our locking - * is so particular to memcg hierarchies. + * We are in the middle of the charge context here, so we + * don't want to block when potentially sitting on a callstack + * that holds all kinds of filesystem and mm locks. + * + * Also, the caller may handle a failed allocation gracefully + * (like optional page cache readahead) and so an OOM killer + * invocation might not even be necessary. + * + * That's why we don't do anything here except remember the + * OOM context and then deal with it at the end of the page + * fault when the stack is unwound, the locks are released, + * and when we know whether the fault was overall successful. */ - wakeups = atomic_read(&memcg->oom_wakeups); - mem_cgroup_mark_under_oom(memcg); - - locked = mem_cgroup_oom_trylock(memcg); - - if (locked) - mem_cgroup_oom_notify(memcg); - - if (locked && !memcg->oom_kill_disable) { - mem_cgroup_unmark_under_oom(memcg); - mem_cgroup_out_of_memory(memcg, mask, order); - mem_cgroup_oom_unlock(memcg); - /* - * There is no guarantee that an OOM-lock contender - * sees the wakeups triggered by the OOM kill - * uncharges. Wake any sleepers explicitely. - */ - memcg_oom_recover(memcg); - } else { - /* - * A system call can just return -ENOMEM, but if this - * is a page fault and somebody else is handling the - * OOM already, we need to sleep on the OOM waitqueue - * for this memcg until the situation is resolved. - * Which can take some time because it might be - * handled by a userspace task. - * - * However, this is the charge context, which means - * that we may sit on a large call stack and hold - * various filesystem locks, the mmap_sem etc. and we - * don't want the OOM handler to deadlock on them - * while we sit here and wait. Store the current OOM - * context in the task_struct, then return -ENOMEM. - * At the end of the page fault handler, with the - * stack unwound, pagefault_out_of_memory() will check - * back with us by calling - * mem_cgroup_oom_synchronize(), possibly putting the - * task to sleep. - */ - current->memcg_oom.oom_locked = locked; - current->memcg_oom.wakeups = wakeups; - css_get(&memcg->css); - current->memcg_oom.wait_on_memcg = memcg; - } + css_get(&memcg->css); + current->memcg_oom.memcg = memcg; + current->memcg_oom.gfp_mask = mask; + current->memcg_oom.order = order; } /** * mem_cgroup_oom_synchronize - complete memcg OOM handling + * @handle: actually kill/wait or just clean up the OOM state * - * This has to be called at the end of a page fault if the the memcg - * OOM handler was enabled and the fault is returning %VM_FAULT_OOM. + * This has to be called at the end of a page fault if the memcg OOM + * handler was enabled. * - * Memcg supports userspace OOM handling, so failed allocations must + * Memcg supports userspace OOM handling where failed allocations must * sleep on a waitqueue until the userspace task resolves the * situation. Sleeping directly in the charge context with all kinds * of locks held is not a good idea, instead we remember an OOM state * in the task and mem_cgroup_oom_synchronize() has to be called at - * the end of the page fault to put the task to sleep and clean up the - * OOM state. + * the end of the page fault to complete the OOM handling. * * Returns %true if an ongoing memcg OOM situation was detected and - * finalized, %false otherwise. + * completed, %false otherwise. */ -bool mem_cgroup_oom_synchronize(void) +bool mem_cgroup_oom_synchronize(bool handle) { + struct mem_cgroup *memcg = current->memcg_oom.memcg; struct oom_wait_info owait; - struct mem_cgroup *memcg; + bool locked; /* OOM is global, do not handle */ - if (!current->memcg_oom.in_memcg_oom) - return false; - - /* - * We invoked the OOM killer but there is a chance that a kill - * did not free up any charges. Everybody else might already - * be sleeping, so restart the fault and keep the rampage - * going until some charges are released. - */ - memcg = current->memcg_oom.wait_on_memcg; if (!memcg) - goto out; + return false; - if (test_thread_flag(TIF_MEMDIE) || fatal_signal_pending(current)) - goto out_memcg; + if (!handle) + goto cleanup; owait.memcg = memcg; owait.wait.flags = 0; @@ -2271,13 +2222,25 @@ bool mem_cgroup_oom_synchronize(void) INIT_LIST_HEAD(&owait.wait.task_list); prepare_to_wait(&memcg_oom_waitq, &owait.wait, TASK_KILLABLE); - /* Only sleep if we didn't miss any wakeups since OOM */ - if (atomic_read(&memcg->oom_wakeups) == current->memcg_oom.wakeups) + mem_cgroup_mark_under_oom(memcg); + + locked = mem_cgroup_oom_trylock(memcg); + + if (locked) + mem_cgroup_oom_notify(memcg); + + if (locked && !memcg->oom_kill_disable) { + mem_cgroup_unmark_under_oom(memcg); + finish_wait(&memcg_oom_waitq, &owait.wait); + mem_cgroup_out_of_memory(memcg, current->memcg_oom.gfp_mask, + current->memcg_oom.order); + } else { schedule(); - finish_wait(&memcg_oom_waitq, &owait.wait); -out_memcg: - mem_cgroup_unmark_under_oom(memcg); - if (current->memcg_oom.oom_locked) { + mem_cgroup_unmark_under_oom(memcg); + finish_wait(&memcg_oom_waitq, &owait.wait); + } + + if (locked) { mem_cgroup_oom_unlock(memcg); /* * There is no guarantee that an OOM-lock contender @@ -2286,10 +2249,9 @@ out_memcg: */ memcg_oom_recover(memcg); } +cleanup: + current->memcg_oom.memcg = NULL; css_put(&memcg->css); - current->memcg_oom.wait_on_memcg = NULL; -out: - current->memcg_oom.in_memcg_oom = 0; return true; } @@ -2703,6 +2665,9 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm, || fatal_signal_pending(current))) goto bypass; + if (unlikely(task_in_memcg_oom(current))) + goto bypass; + /* * We always charge the cgroup the mm_struct belongs to. * The mm_struct's mem_cgroup changes on task migration if the @@ -2801,6 +2766,8 @@ done: return 0; nomem: *ptr = NULL; + if (gfp_mask & __GFP_NOFAIL) + return 0; return -ENOMEM; bypass: *ptr = root_mem_cgroup; diff --git a/mm/memory.c b/mm/memory.c index ca0003947115..1311f26497e6 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -837,6 +837,8 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm, */ make_migration_entry_read(&entry); pte = swp_entry_to_pte(entry); + if (pte_swp_soft_dirty(*src_pte)) + pte = pte_swp_mksoft_dirty(pte); set_pte_at(src_mm, addr, src_pte, pte); } } @@ -3863,15 +3865,21 @@ int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, * space. Kernel faults are handled more gracefully. */ if (flags & FAULT_FLAG_USER) - mem_cgroup_enable_oom(); + mem_cgroup_oom_enable(); ret = __handle_mm_fault(mm, vma, address, flags); - if (flags & FAULT_FLAG_USER) - mem_cgroup_disable_oom(); - - if (WARN_ON(task_in_memcg_oom(current) && !(ret & VM_FAULT_OOM))) - mem_cgroup_oom_synchronize(); + if (flags & FAULT_FLAG_USER) { + mem_cgroup_oom_disable(); + /* + * The task may have entered a memcg OOM situation but + * if the allocation error was handled gracefully (no + * VM_FAULT_OOM), there is no need to kill anything. + * Just clean up the OOM state peacefully. + */ + if (task_in_memcg_oom(current) && !(ret & VM_FAULT_OOM)) + mem_cgroup_oom_synchronize(false); + } return ret; } diff --git a/mm/migrate.c b/mm/migrate.c index a26bccd44ccb..7a7325ee1d08 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -161,6 +161,8 @@ static int remove_migration_pte(struct page *new, struct vm_area_struct *vma, get_page(new); pte = pte_mkold(mk_pte(new, vma->vm_page_prot)); + if (pte_swp_soft_dirty(*ptep)) + pte = pte_mksoft_dirty(pte); if (is_write_migration_entry(entry)) pte = pte_mkwrite(pte); #ifdef CONFIG_HUGETLB_PAGE diff --git a/mm/mprotect.c b/mm/mprotect.c index 94722a4d6b43..a3af058f68e4 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -94,13 +94,16 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd, swp_entry_t entry = pte_to_swp_entry(oldpte); if (is_write_migration_entry(entry)) { + pte_t newpte; /* * A protection check is difficult so * just be safe and disable write */ make_migration_entry_read(&entry); - set_pte_at(mm, addr, pte, - swp_entry_to_pte(entry)); + newpte = swp_entry_to_pte(entry); + if (pte_swp_soft_dirty(oldpte)) + newpte = pte_swp_mksoft_dirty(newpte); + set_pte_at(mm, addr, pte, newpte); } pages++; } diff --git a/mm/mremap.c b/mm/mremap.c index 91b13d6a16d4..0843feb66f3d 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -25,7 +25,6 @@ #include <asm/uaccess.h> #include <asm/cacheflush.h> #include <asm/tlbflush.h> -#include <asm/pgalloc.h> #include "internal.h" @@ -63,10 +62,8 @@ static pmd_t *alloc_new_pmd(struct mm_struct *mm, struct vm_area_struct *vma, return NULL; pmd = pmd_alloc(mm, pud, addr); - if (!pmd) { - pud_free(mm, pud); + if (!pmd) return NULL; - } VM_BUG_ON(pmd_trans_huge(*pmd)); diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 314e9d274381..6738c47f1f72 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -680,7 +680,7 @@ void pagefault_out_of_memory(void) { struct zonelist *zonelist; - if (mem_cgroup_oom_synchronize()) + if (mem_cgroup_oom_synchronize(true)) return; zonelist = node_zonelist(first_online_node, GFP_KERNEL); diff --git a/mm/page-writeback.c b/mm/page-writeback.c index f5236f804aa6..63807583d8e8 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -1210,11 +1210,11 @@ static unsigned long dirty_poll_interval(unsigned long dirty, return 1; } -static long bdi_max_pause(struct backing_dev_info *bdi, - unsigned long bdi_dirty) +static unsigned long bdi_max_pause(struct backing_dev_info *bdi, + unsigned long bdi_dirty) { - long bw = bdi->avg_write_bandwidth; - long t; + unsigned long bw = bdi->avg_write_bandwidth; + unsigned long t; /* * Limit pause time for small memory systems. If sleeping for too long @@ -1226,7 +1226,7 @@ static long bdi_max_pause(struct backing_dev_info *bdi, t = bdi_dirty / (1 + bw / roundup_pow_of_two(1 + HZ / 8)); t++; - return min_t(long, t, MAX_PAUSE); + return min_t(unsigned long, t, MAX_PAUSE); } static long bdi_min_pause(struct backing_dev_info *bdi, diff --git a/mm/slab_common.c b/mm/slab_common.c index a3443278ce3a..e2e98af703ea 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -56,6 +56,7 @@ static int kmem_cache_sanity_check(struct mem_cgroup *memcg, const char *name, continue; } +#if !defined(CONFIG_SLUB) || !defined(CONFIG_SLUB_DEBUG_ON) /* * For simplicity, we won't check this in the list of memcg * caches. We have control over memcg naming, and if there @@ -69,6 +70,7 @@ static int kmem_cache_sanity_check(struct mem_cgroup *memcg, const char *name, s = NULL; return -EINVAL; } +#endif } WARN_ON(strchr(name, ' ')); /* It confuses parsers */ diff --git a/mm/swapfile.c b/mm/swapfile.c index 3963fc24fcc1..de7c904e52e5 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1824,6 +1824,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) struct filename *pathname; int i, type, prev; int err; + unsigned int old_block_size; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1914,6 +1915,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) } swap_file = p->swap_file; + old_block_size = p->old_block_size; p->swap_file = NULL; p->max = 0; swap_map = p->swap_map; @@ -1938,7 +1940,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) inode = mapping->host; if (S_ISBLK(inode->i_mode)) { struct block_device *bdev = I_BDEV(inode); - set_blocksize(bdev, p->old_block_size); + set_blocksize(bdev, old_block_size); blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); } else { mutex_lock(&inode->i_mutex); diff --git a/mm/vmscan.c b/mm/vmscan.c index 53f2f82f83ae..eea668d9cff6 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -211,6 +211,7 @@ void unregister_shrinker(struct shrinker *shrinker) down_write(&shrinker_rwsem); list_del(&shrinker->list); up_write(&shrinker_rwsem); + kfree(shrinker->nr_deferred); } EXPORT_SYMBOL(unregister_shrinker); diff --git a/mm/zswap.c b/mm/zswap.c index 841e35f1db22..d93510c6aa2d 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -804,6 +804,10 @@ static void zswap_frontswap_invalidate_area(unsigned type) } tree->rbroot = RB_ROOT; spin_unlock(&tree->lock); + + zbud_destroy_pool(tree->pool); + kfree(tree); + zswap_trees[type] = NULL; } static struct zbud_ops zswap_zbud_ops = { diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 95c2b2689a03..7db9954f1af2 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -580,15 +580,13 @@ static struct aa_namespace *__next_namespace(struct aa_namespace *root, /* check if the next ns is a sibling, parent, gp, .. */ parent = ns->parent; - while (parent) { + while (ns != root) { mutex_unlock(&ns->lock); next = list_entry_next(ns, base.list); if (!list_entry_is_head(next, &parent->sub_ns, base.list)) { mutex_lock(&next->lock); return next; } - if (parent == root) - return NULL; ns = parent; parent = parent->parent; } diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 345bec07a27d..705c2879d3a9 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -610,6 +610,7 @@ void aa_free_profile(struct aa_profile *profile) aa_put_dfa(profile->policy.dfa); aa_put_replacedby(profile->replacedby); + kzfree(profile->hash); kzfree(profile); } diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index ac41e9cdc976..26ad4f0aade3 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -3531,7 +3531,7 @@ static int create_capture_mixers(struct hda_codec *codec) if (!multi) err = create_single_cap_vol_ctl(codec, n, vol, sw, inv_dmic); - else if (!multi_cap_vol) + else if (!multi_cap_vol && !inv_dmic) err = create_bind_cap_vol_ctl(codec, n, vol, sw); else err = create_multi_cap_vol_ctl(codec); diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 4f255dfee450..f59a321a6d6a 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -4845,6 +4845,7 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne if ((err = hdsp_get_iobox_version(hdsp)) < 0) return err; } + memset(&hdsp_version, 0, sizeof(hdsp_version)); hdsp_version.io_type = hdsp->io_type; hdsp_version.firmware_rev = hdsp->firmware_rev; if ((err = copy_to_user(argp, &hdsp_version, sizeof(hdsp_version)))) diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 61a64d281905..8b9e70105dd2 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,5 +1,5 @@ snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o -snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o +snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),) snd-soc-core-objs += soc-generic-dmaengine-pcm.o diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index 3109db7b9017..612e5801003f 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c @@ -50,7 +50,7 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, buf->area = dma_alloc_coherent(pcm->card->dev, size, &buf->addr, GFP_KERNEL); pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%zu\n", - (void *)buf->area, (void *)buf->addr, size); + (void *)buf->area, (void *)(long)buf->addr, size); if (!buf->area) return -ENOMEM; diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c index 7222380131ea..b4e36901a40b 100644 --- a/sound/soc/atmel/atmel_wm8904.c +++ b/sound/soc/atmel/atmel_wm8904.c @@ -12,7 +12,6 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> -#include <linux/pinctrl/consumer.h> #include <sound/soc.h> @@ -155,15 +154,8 @@ static int atmel_asoc_wm8904_probe(struct platform_device *pdev) struct snd_soc_card *card = &atmel_asoc_wm8904_card; struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink; struct clk *clk_src; - struct pinctrl *pinctrl; int id, ret; - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) { - dev_err(&pdev->dev, "failed to request pinctrl\n"); - return PTR_ERR(pinctrl); - } - card->dev = &pdev->dev; ret = atmel_asoc_wm8904_dt_init(pdev); if (ret) { diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 802717eccbd0..f15bff1548f8 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -37,6 +37,7 @@ #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/i2c.h> +#include <linux/of.h> #include <linux/atmel-ssc.h> diff --git a/sound/soc/cirrus/Kconfig b/sound/soc/cirrus/Kconfig index 2c20f01e1f7e..06f938deda15 100644 --- a/sound/soc/cirrus/Kconfig +++ b/sound/soc/cirrus/Kconfig @@ -1,6 +1,6 @@ config SND_EP93XX_SOC tristate "SoC Audio support for the Cirrus Logic EP93xx series" - depends on ARCH_EP93XX && SND_SOC + depends on (ARCH_EP93XX || COMPILE_TEST) && SND_SOC select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for codecs attached to diff --git a/sound/soc/cirrus/ep93xx-pcm.c b/sound/soc/cirrus/ep93xx-pcm.c index 0e9f56e0d4b2..cfe517e68009 100644 --- a/sound/soc/cirrus/ep93xx-pcm.c +++ b/sound/soc/cirrus/ep93xx-pcm.c @@ -57,9 +57,22 @@ static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param) return false; } +static struct dma_chan *ep93xx_compat_request_channel( + struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_substream *substream) +{ + struct snd_dmaengine_dai_dma_data *dma_data; + + dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + + return snd_dmaengine_pcm_request_channel(ep93xx_pcm_dma_filter, + dma_data); +} + static const struct snd_dmaengine_pcm_config ep93xx_dmaengine_pcm_config = { .pcm_hardware = &ep93xx_pcm_hardware, .compat_filter_fn = ep93xx_pcm_dma_filter, + .compat_request_channel = ep93xx_compat_request_channel, .prealloc_buffer_size = 131072, }; diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 259d1ac4492f..75d0ad5d2dcb 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -16,6 +16,7 @@ #include <linux/mfd/88pm860x.h> #include <linux/slab.h> #include <linux/delay.h> +#include <linux/regmap.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -140,6 +141,7 @@ struct pm860x_priv { unsigned int filter; struct snd_soc_codec *codec; struct i2c_client *i2c; + struct regmap *regmap; struct pm860x_chip *chip; struct pm860x_det det; @@ -269,48 +271,6 @@ static struct st_gain st_table[] = { { -86, 29, 0}, { -56, 30, 0}, { -28, 31, 0}, { 0, 0, 0}, }; -static int pm860x_volatile(unsigned int reg) -{ - BUG_ON(reg >= REG_CACHE_SIZE); - - switch (reg) { - case PM860X_AUDIO_SUPPLIES_2: - return 1; - } - - return 0; -} - -static unsigned int pm860x_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - unsigned char *cache = codec->reg_cache; - - BUG_ON(reg >= REG_CACHE_SIZE); - - if (pm860x_volatile(reg)) - return cache[reg]; - - reg += REG_CACHE_BASE; - - return pm860x_reg_read(codec->control_data, reg); -} - -static int pm860x_write_reg_cache(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) -{ - unsigned char *cache = codec->reg_cache; - - BUG_ON(reg >= REG_CACHE_SIZE); - - if (!pm860x_volatile(reg)) - cache[reg] = (unsigned char)value; - - reg += REG_CACHE_BASE; - - return pm860x_reg_write(codec->control_data, reg, value); -} - static int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1169,6 +1129,7 @@ static int pm860x_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, static int pm860x_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec); int data; switch (level) { @@ -1182,17 +1143,17 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec, if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { /* Enable Audio PLL & Audio section */ data = AUDIO_PLL | AUDIO_SECTION_ON; - pm860x_reg_write(codec->control_data, REG_MISC2, data); + pm860x_reg_write(pm860x->i2c, REG_MISC2, data); udelay(300); data = AUDIO_PLL | AUDIO_SECTION_RESET | AUDIO_SECTION_ON; - pm860x_reg_write(codec->control_data, REG_MISC2, data); + pm860x_reg_write(pm860x->i2c, REG_MISC2, data); } break; case SND_SOC_BIAS_OFF: data = AUDIO_PLL | AUDIO_SECTION_RESET | AUDIO_SECTION_ON; - pm860x_set_bits(codec->control_data, REG_MISC2, data, 0); + pm860x_set_bits(pm860x->i2c, REG_MISC2, data, 0); break; } codec->dapm.bias_level = level; @@ -1322,17 +1283,17 @@ int pm860x_hs_jack_detect(struct snd_soc_codec *codec, pm860x->det.lo_shrt = lo_shrt; if (det & SND_JACK_HEADPHONE) - pm860x_set_bits(codec->control_data, REG_HS_DET, + pm860x_set_bits(pm860x->i2c, REG_HS_DET, EN_HS_DET, EN_HS_DET); /* headset short detect */ if (hs_shrt) { data = CLR_SHORT_HS2 | CLR_SHORT_HS1; - pm860x_set_bits(codec->control_data, REG_SHORTS, data, data); + pm860x_set_bits(pm860x->i2c, REG_SHORTS, data, data); } /* Lineout short detect */ if (lo_shrt) { data = CLR_SHORT_LO2 | CLR_SHORT_LO1; - pm860x_set_bits(codec->control_data, REG_SHORTS, data, data); + pm860x_set_bits(pm860x->i2c, REG_SHORTS, data, data); } /* sync status */ @@ -1350,7 +1311,7 @@ int pm860x_mic_jack_detect(struct snd_soc_codec *codec, pm860x->det.mic_det = det; if (det & SND_JACK_MICROPHONE) - pm860x_set_bits(codec->control_data, REG_MIC_DET, + pm860x_set_bits(pm860x->i2c, REG_MIC_DET, MICDET_MASK, MICDET_MASK); /* sync status */ @@ -1366,7 +1327,7 @@ static int pm860x_probe(struct snd_soc_codec *codec) pm860x->codec = codec; - codec->control_data = pm860x->i2c; + codec->control_data = pm860x->regmap; for (i = 0; i < 4; i++) { ret = request_threaded_irq(pm860x->irq[i], NULL, @@ -1380,14 +1341,6 @@ static int pm860x_probe(struct snd_soc_codec *codec) pm860x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - ret = pm860x_bulk_read(codec->control_data, REG_CACHE_BASE, - REG_CACHE_SIZE, codec->reg_cache); - if (ret < 0) { - dev_err(codec->dev, "Failed to fill register cache: %d\n", - ret); - goto out; - } - return 0; out: @@ -1410,10 +1363,6 @@ static int pm860x_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_pm860x = { .probe = pm860x_probe, .remove = pm860x_remove, - .read = pm860x_read_reg_cache, - .write = pm860x_write_reg_cache, - .reg_cache_size = REG_CACHE_SIZE, - .reg_word_size = sizeof(u8), .set_bias_level = pm860x_set_bias_level, .controls = pm860x_snd_controls, @@ -1439,6 +1388,8 @@ static int pm860x_codec_probe(struct platform_device *pdev) pm860x->chip = chip; pm860x->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; + pm860x->regmap = (chip->id == CHIP_PM8607) ? chip->regmap + : chip->regmap_companion; platform_set_drvdata(pdev, pm860x); for (i = 0; i < 4; i++) { diff --git a/sound/soc/codecs/88pm860x-codec.h b/sound/soc/codecs/88pm860x-codec.h index 3364ba4a3607..f7282f4f4a79 100644 --- a/sound/soc/codecs/88pm860x-codec.h +++ b/sound/soc/codecs/88pm860x-codec.h @@ -12,67 +12,66 @@ #ifndef __88PM860X_H #define __88PM860X_H -/* The offset of these registers are 0xb0 */ -#define PM860X_PCM_IFACE_1 0x00 -#define PM860X_PCM_IFACE_2 0x01 -#define PM860X_PCM_IFACE_3 0x02 -#define PM860X_PCM_RATE 0x03 -#define PM860X_EC_PATH 0x04 -#define PM860X_SIDETONE_L_GAIN 0x05 -#define PM860X_SIDETONE_R_GAIN 0x06 -#define PM860X_SIDETONE_SHIFT 0x07 -#define PM860X_ADC_OFFSET_1 0x08 -#define PM860X_ADC_OFFSET_2 0x09 -#define PM860X_DMIC_DELAY 0x0a +#define PM860X_PCM_IFACE_1 0xb0 +#define PM860X_PCM_IFACE_2 0xb1 +#define PM860X_PCM_IFACE_3 0xb2 +#define PM860X_PCM_RATE 0xb3 +#define PM860X_EC_PATH 0xb4 +#define PM860X_SIDETONE_L_GAIN 0xb5 +#define PM860X_SIDETONE_R_GAIN 0xb6 +#define PM860X_SIDETONE_SHIFT 0xb7 +#define PM860X_ADC_OFFSET_1 0xb8 +#define PM860X_ADC_OFFSET_2 0xb9 +#define PM860X_DMIC_DELAY 0xba -#define PM860X_I2S_IFACE_1 0x0b -#define PM860X_I2S_IFACE_2 0x0c -#define PM860X_I2S_IFACE_3 0x0d -#define PM860X_I2S_IFACE_4 0x0e -#define PM860X_EQUALIZER_N0_1 0x0f -#define PM860X_EQUALIZER_N0_2 0x10 -#define PM860X_EQUALIZER_N1_1 0x11 -#define PM860X_EQUALIZER_N1_2 0x12 -#define PM860X_EQUALIZER_D1_1 0x13 -#define PM860X_EQUALIZER_D1_2 0x14 -#define PM860X_LOFI_GAIN_LEFT 0x15 -#define PM860X_LOFI_GAIN_RIGHT 0x16 -#define PM860X_HIFIL_GAIN_LEFT 0x17 -#define PM860X_HIFIL_GAIN_RIGHT 0x18 -#define PM860X_HIFIR_GAIN_LEFT 0x19 -#define PM860X_HIFIR_GAIN_RIGHT 0x1a -#define PM860X_DAC_OFFSET 0x1b -#define PM860X_OFFSET_LEFT_1 0x1c -#define PM860X_OFFSET_LEFT_2 0x1d -#define PM860X_OFFSET_RIGHT_1 0x1e -#define PM860X_OFFSET_RIGHT_2 0x1f -#define PM860X_ADC_ANA_1 0x20 -#define PM860X_ADC_ANA_2 0x21 -#define PM860X_ADC_ANA_3 0x22 -#define PM860X_ADC_ANA_4 0x23 -#define PM860X_ANA_TO_ANA 0x24 -#define PM860X_HS1_CTRL 0x25 -#define PM860X_HS2_CTRL 0x26 -#define PM860X_LO1_CTRL 0x27 -#define PM860X_LO2_CTRL 0x28 -#define PM860X_EAR_CTRL_1 0x29 -#define PM860X_EAR_CTRL_2 0x2a -#define PM860X_AUDIO_SUPPLIES_1 0x2b -#define PM860X_AUDIO_SUPPLIES_2 0x2c -#define PM860X_ADC_EN_1 0x2d -#define PM860X_ADC_EN_2 0x2e -#define PM860X_DAC_EN_1 0x2f -#define PM860X_DAC_EN_2 0x31 -#define PM860X_AUDIO_CAL_1 0x32 -#define PM860X_AUDIO_CAL_2 0x33 -#define PM860X_AUDIO_CAL_3 0x34 -#define PM860X_AUDIO_CAL_4 0x35 -#define PM860X_AUDIO_CAL_5 0x36 -#define PM860X_ANA_INPUT_SEL_1 0x37 -#define PM860X_ANA_INPUT_SEL_2 0x38 +#define PM860X_I2S_IFACE_1 0xbb +#define PM860X_I2S_IFACE_2 0xbc +#define PM860X_I2S_IFACE_3 0xbd +#define PM860X_I2S_IFACE_4 0xbe +#define PM860X_EQUALIZER_N0_1 0xbf +#define PM860X_EQUALIZER_N0_2 0xc0 +#define PM860X_EQUALIZER_N1_1 0xc1 +#define PM860X_EQUALIZER_N1_2 0xc2 +#define PM860X_EQUALIZER_D1_1 0xc3 +#define PM860X_EQUALIZER_D1_2 0xc4 +#define PM860X_LOFI_GAIN_LEFT 0xc5 +#define PM860X_LOFI_GAIN_RIGHT 0xc6 +#define PM860X_HIFIL_GAIN_LEFT 0xc7 +#define PM860X_HIFIL_GAIN_RIGHT 0xc8 +#define PM860X_HIFIR_GAIN_LEFT 0xc9 +#define PM860X_HIFIR_GAIN_RIGHT 0xca +#define PM860X_DAC_OFFSET 0xcb +#define PM860X_OFFSET_LEFT_1 0xcc +#define PM860X_OFFSET_LEFT_2 0xcd +#define PM860X_OFFSET_RIGHT_1 0xce +#define PM860X_OFFSET_RIGHT_2 0xcf +#define PM860X_ADC_ANA_1 0xd0 +#define PM860X_ADC_ANA_2 0xd1 +#define PM860X_ADC_ANA_3 0xd2 +#define PM860X_ADC_ANA_4 0xd3 +#define PM860X_ANA_TO_ANA 0xd4 +#define PM860X_HS1_CTRL 0xd5 +#define PM860X_HS2_CTRL 0xd6 +#define PM860X_LO1_CTRL 0xd7 +#define PM860X_LO2_CTRL 0xd8 +#define PM860X_EAR_CTRL_1 0xd9 +#define PM860X_EAR_CTRL_2 0xda +#define PM860X_AUDIO_SUPPLIES_1 0xdb +#define PM860X_AUDIO_SUPPLIES_2 0xdc +#define PM860X_ADC_EN_1 0xdd +#define PM860X_ADC_EN_2 0xde +#define PM860X_DAC_EN_1 0xdf +#define PM860X_DAC_EN_2 0xe1 +#define PM860X_AUDIO_CAL_1 0xe2 +#define PM860X_AUDIO_CAL_2 0xe3 +#define PM860X_AUDIO_CAL_3 0xe4 +#define PM860X_AUDIO_CAL_4 0xe5 +#define PM860X_AUDIO_CAL_5 0xe6 +#define PM860X_ANA_INPUT_SEL_1 0xe7 +#define PM860X_ANA_INPUT_SEL_2 0xe8 -#define PM860X_PCM_IFACE_4 0x39 -#define PM860X_I2S_IFACE_5 0x3a +#define PM860X_PCM_IFACE_4 0xe9 +#define PM860X_I2S_IFACE_5 0xea #define PM860X_SHORTS 0x3b #define PM860X_PLL_ADJ_1 0x3c diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 80555d7551e6..a0394a8f2257 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -126,6 +126,8 @@ struct ab8500_codec_drvdata_dbg { /* Private data for AB8500 device-driver */ struct ab8500_codec_drvdata { + struct regmap *regmap; + /* Sidetone */ long *sid_fir_values; enum sid_state sid_status; @@ -166,49 +168,35 @@ static inline const char *amic_type_str(enum amic_type type) */ /* Read a register from the audio-bank of AB8500 */ -static unsigned int ab8500_codec_read_reg(struct snd_soc_codec *codec, - unsigned int reg) +static int ab8500_codec_read_reg(void *context, unsigned int reg, + unsigned int *value) { + struct device *dev = context; int status; - unsigned int value = 0; u8 value8; - status = abx500_get_register_interruptible(codec->dev, AB8500_AUDIO, - reg, &value8); - if (status < 0) { - dev_err(codec->dev, - "%s: ERROR: Register (0x%02x:0x%02x) read failed (%d).\n", - __func__, (u8)AB8500_AUDIO, (u8)reg, status); - } else { - dev_dbg(codec->dev, - "%s: Read 0x%02x from register 0x%02x:0x%02x\n", - __func__, value8, (u8)AB8500_AUDIO, (u8)reg); - value = (unsigned int)value8; - } + status = abx500_get_register_interruptible(dev, AB8500_AUDIO, + reg, &value8); + *value = (unsigned int)value8; - return value; + return status; } /* Write to a register in the audio-bank of AB8500 */ -static int ab8500_codec_write_reg(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) +static int ab8500_codec_write_reg(void *context, unsigned int reg, + unsigned int value) { - int status; - - status = abx500_set_register_interruptible(codec->dev, AB8500_AUDIO, - reg, value); - if (status < 0) - dev_err(codec->dev, - "%s: ERROR: Register (%02x:%02x) write failed (%d).\n", - __func__, (u8)AB8500_AUDIO, (u8)reg, status); - else - dev_dbg(codec->dev, - "%s: Wrote 0x%02x into register %02x:%02x\n", - __func__, (u8)value, (u8)AB8500_AUDIO, (u8)reg); + struct device *dev = context; - return status; + return abx500_set_register_interruptible(dev, AB8500_AUDIO, + reg, value); } +static const struct regmap_config ab8500_codec_regmap = { + .reg_read = ab8500_codec_read_reg, + .reg_write = ab8500_codec_write_reg, +}; + /* * Controls - DAPM */ @@ -2485,9 +2473,13 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) dev_dbg(dev, "%s: Enter.\n", __func__); + snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); + /* Setup AB8500 according to board-settings */ pdata = dev_get_platdata(dev->parent); + codec->control_data = drvdata->regmap; + if (np) { if (!pdata) pdata = devm_kzalloc(dev, @@ -2532,12 +2524,10 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) } /* Override HW-defaults */ - ab8500_codec_write_reg(codec, - AB8500_ANACONF5, - BIT(AB8500_ANACONF5_HSAUTOEN)); - ab8500_codec_write_reg(codec, - AB8500_SHORTCIRCONF, - BIT(AB8500_SHORTCIRCONF_HSZCDDIS)); + snd_soc_write(codec, AB8500_ANACONF5, + BIT(AB8500_ANACONF5_HSAUTOEN)); + snd_soc_write(codec, AB8500_SHORTCIRCONF, + BIT(AB8500_SHORTCIRCONF_HSZCDDIS)); /* Add filter controls */ status = snd_soc_add_codec_controls(codec, ab8500_filter_controls, @@ -2567,9 +2557,6 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver ab8500_codec_driver = { .probe = ab8500_codec_probe, - .read = ab8500_codec_read_reg, - .write = ab8500_codec_write_reg, - .reg_word_size = sizeof(u8), .controls = ab8500_ctrls, .num_controls = ARRAY_SIZE(ab8500_ctrls), .dapm_widgets = ab8500_dapm_widgets, @@ -2592,6 +2579,15 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev) drvdata->anc_status = ANC_UNCONFIGURED; dev_set_drvdata(&pdev->dev, drvdata); + drvdata->regmap = devm_regmap_init(&pdev->dev, NULL, &pdev->dev, + &ab8500_codec_regmap); + if (IS_ERR(drvdata->regmap)) { + status = PTR_ERR(drvdata->regmap); + dev_err(&pdev->dev, "%s: Failed to allocate regmap: %d\n", + __func__, status); + return status; + } + dev_dbg(&pdev->dev, "%s: Register codec.\n", __func__); status = snd_soc_register_codec(&pdev->dev, &ab8500_codec_driver, ab8500_codec_dai, @@ -2606,7 +2602,7 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev) static int ab8500_codec_driver_remove(struct platform_device *pdev) { - dev_info(&pdev->dev, "%s Enter.\n", __func__); + dev_dbg(&pdev->dev, "%s Enter.\n", __func__); snd_soc_unregister_codec(&pdev->dev); diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 1aa10ddf3a61..59654b1e7f3f 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -32,6 +32,7 @@ struct adau1373_dai { }; struct adau1373 { + struct regmap *regmap; struct adau1373_dai dais[3]; }; @@ -73,7 +74,6 @@ struct adau1373 { #define ADAU1373_PLL_CTRL4(x) (0x2c + (x) * 7) #define ADAU1373_PLL_CTRL5(x) (0x2d + (x) * 7) #define ADAU1373_PLL_CTRL6(x) (0x2e + (x) * 7) -#define ADAU1373_PLL_CTRL7(x) (0x2f + (x) * 7) #define ADAU1373_HEADDECT 0x36 #define ADAU1373_ADC_DAC_STATUS 0x37 #define ADAU1373_ADC_CTRL 0x3c @@ -152,37 +152,172 @@ struct adau1373 { #define ADAU1373_EP_CTRL_MICBIAS1_OFFSET 4 #define ADAU1373_EP_CTRL_MICBIAS2_OFFSET 2 -static const uint8_t adau1373_default_regs[] = { - 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, /* 0x10 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, /* 0x30 */ - 0x00, 0x00, 0x00, 0x80, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x00, /* 0x40 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x78, 0x18, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, /* 0x80 */ - 0x00, 0xc0, 0x88, 0x7a, 0xdf, 0x20, 0x00, 0x00, - 0x78, 0x18, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, /* 0x90 */ - 0x00, 0xc0, 0x88, 0x7a, 0xdf, 0x20, 0x00, 0x00, - 0x78, 0x18, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, /* 0xa0 */ - 0x00, 0xc0, 0x88, 0x7a, 0xdf, 0x20, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, /* 0xe0 */ - 0x00, 0x1f, 0x0f, 0x00, 0x00, +static const struct reg_default adau1373_reg_defaults[] = { + { ADAU1373_INPUT_MODE, 0x00 }, + { ADAU1373_AINL_CTRL(0), 0x00 }, + { ADAU1373_AINR_CTRL(0), 0x00 }, + { ADAU1373_AINL_CTRL(1), 0x00 }, + { ADAU1373_AINR_CTRL(1), 0x00 }, + { ADAU1373_AINL_CTRL(2), 0x00 }, + { ADAU1373_AINR_CTRL(2), 0x00 }, + { ADAU1373_AINL_CTRL(3), 0x00 }, + { ADAU1373_AINR_CTRL(3), 0x00 }, + { ADAU1373_LLINE_OUT(0), 0x00 }, + { ADAU1373_RLINE_OUT(0), 0x00 }, + { ADAU1373_LLINE_OUT(1), 0x00 }, + { ADAU1373_RLINE_OUT(1), 0x00 }, + { ADAU1373_LSPK_OUT, 0x00 }, + { ADAU1373_RSPK_OUT, 0x00 }, + { ADAU1373_LHP_OUT, 0x00 }, + { ADAU1373_RHP_OUT, 0x00 }, + { ADAU1373_ADC_GAIN, 0x00 }, + { ADAU1373_LADC_MIXER, 0x00 }, + { ADAU1373_RADC_MIXER, 0x00 }, + { ADAU1373_LLINE1_MIX, 0x00 }, + { ADAU1373_RLINE1_MIX, 0x00 }, + { ADAU1373_LLINE2_MIX, 0x00 }, + { ADAU1373_RLINE2_MIX, 0x00 }, + { ADAU1373_LSPK_MIX, 0x00 }, + { ADAU1373_RSPK_MIX, 0x00 }, + { ADAU1373_LHP_MIX, 0x00 }, + { ADAU1373_RHP_MIX, 0x00 }, + { ADAU1373_EP_MIX, 0x00 }, + { ADAU1373_HP_CTRL, 0x00 }, + { ADAU1373_HP_CTRL2, 0x00 }, + { ADAU1373_LS_CTRL, 0x00 }, + { ADAU1373_EP_CTRL, 0x00 }, + { ADAU1373_MICBIAS_CTRL1, 0x00 }, + { ADAU1373_MICBIAS_CTRL2, 0x00 }, + { ADAU1373_OUTPUT_CTRL, 0x00 }, + { ADAU1373_PWDN_CTRL1, 0x00 }, + { ADAU1373_PWDN_CTRL2, 0x00 }, + { ADAU1373_PWDN_CTRL3, 0x00 }, + { ADAU1373_DPLL_CTRL(0), 0x00 }, + { ADAU1373_PLL_CTRL1(0), 0x00 }, + { ADAU1373_PLL_CTRL2(0), 0x00 }, + { ADAU1373_PLL_CTRL3(0), 0x00 }, + { ADAU1373_PLL_CTRL4(0), 0x00 }, + { ADAU1373_PLL_CTRL5(0), 0x00 }, + { ADAU1373_PLL_CTRL6(0), 0x02 }, + { ADAU1373_DPLL_CTRL(1), 0x00 }, + { ADAU1373_PLL_CTRL1(1), 0x00 }, + { ADAU1373_PLL_CTRL2(1), 0x00 }, + { ADAU1373_PLL_CTRL3(1), 0x00 }, + { ADAU1373_PLL_CTRL4(1), 0x00 }, + { ADAU1373_PLL_CTRL5(1), 0x00 }, + { ADAU1373_PLL_CTRL6(1), 0x02 }, + { ADAU1373_HEADDECT, 0x00 }, + { ADAU1373_ADC_CTRL, 0x00 }, + { ADAU1373_CLK_SRC_DIV(0), 0x00 }, + { ADAU1373_CLK_SRC_DIV(1), 0x00 }, + { ADAU1373_DAI(0), 0x0a }, + { ADAU1373_DAI(1), 0x0a }, + { ADAU1373_DAI(2), 0x0a }, + { ADAU1373_BCLKDIV(0), 0x00 }, + { ADAU1373_BCLKDIV(1), 0x00 }, + { ADAU1373_BCLKDIV(2), 0x00 }, + { ADAU1373_SRC_RATIOA(0), 0x00 }, + { ADAU1373_SRC_RATIOB(0), 0x00 }, + { ADAU1373_SRC_RATIOA(1), 0x00 }, + { ADAU1373_SRC_RATIOB(1), 0x00 }, + { ADAU1373_SRC_RATIOA(2), 0x00 }, + { ADAU1373_SRC_RATIOB(2), 0x00 }, + { ADAU1373_DEEMP_CTRL, 0x00 }, + { ADAU1373_SRC_DAI_CTRL(0), 0x08 }, + { ADAU1373_SRC_DAI_CTRL(1), 0x08 }, + { ADAU1373_SRC_DAI_CTRL(2), 0x08 }, + { ADAU1373_DIN_MIX_CTRL(0), 0x00 }, + { ADAU1373_DIN_MIX_CTRL(1), 0x00 }, + { ADAU1373_DIN_MIX_CTRL(2), 0x00 }, + { ADAU1373_DIN_MIX_CTRL(3), 0x00 }, + { ADAU1373_DIN_MIX_CTRL(4), 0x00 }, + { ADAU1373_DOUT_MIX_CTRL(0), 0x00 }, + { ADAU1373_DOUT_MIX_CTRL(1), 0x00 }, + { ADAU1373_DOUT_MIX_CTRL(2), 0x00 }, + { ADAU1373_DOUT_MIX_CTRL(3), 0x00 }, + { ADAU1373_DOUT_MIX_CTRL(4), 0x00 }, + { ADAU1373_DAI_PBL_VOL(0), 0x00 }, + { ADAU1373_DAI_PBR_VOL(0), 0x00 }, + { ADAU1373_DAI_PBL_VOL(1), 0x00 }, + { ADAU1373_DAI_PBR_VOL(1), 0x00 }, + { ADAU1373_DAI_PBL_VOL(2), 0x00 }, + { ADAU1373_DAI_PBR_VOL(2), 0x00 }, + { ADAU1373_DAI_RECL_VOL(0), 0x00 }, + { ADAU1373_DAI_RECR_VOL(0), 0x00 }, + { ADAU1373_DAI_RECL_VOL(1), 0x00 }, + { ADAU1373_DAI_RECR_VOL(1), 0x00 }, + { ADAU1373_DAI_RECL_VOL(2), 0x00 }, + { ADAU1373_DAI_RECR_VOL(2), 0x00 }, + { ADAU1373_DAC1_PBL_VOL, 0x00 }, + { ADAU1373_DAC1_PBR_VOL, 0x00 }, + { ADAU1373_DAC2_PBL_VOL, 0x00 }, + { ADAU1373_DAC2_PBR_VOL, 0x00 }, + { ADAU1373_ADC_RECL_VOL, 0x00 }, + { ADAU1373_ADC_RECR_VOL, 0x00 }, + { ADAU1373_DMIC_RECL_VOL, 0x00 }, + { ADAU1373_DMIC_RECR_VOL, 0x00 }, + { ADAU1373_VOL_GAIN1, 0x00 }, + { ADAU1373_VOL_GAIN2, 0x00 }, + { ADAU1373_VOL_GAIN3, 0x00 }, + { ADAU1373_HPF_CTRL, 0x00 }, + { ADAU1373_BASS1, 0x00 }, + { ADAU1373_BASS2, 0x00 }, + { ADAU1373_DRC(0) + 0x0, 0x78 }, + { ADAU1373_DRC(0) + 0x1, 0x18 }, + { ADAU1373_DRC(0) + 0x2, 0x00 }, + { ADAU1373_DRC(0) + 0x3, 0x00 }, + { ADAU1373_DRC(0) + 0x4, 0x00 }, + { ADAU1373_DRC(0) + 0x5, 0xc0 }, + { ADAU1373_DRC(0) + 0x6, 0x00 }, + { ADAU1373_DRC(0) + 0x7, 0x00 }, + { ADAU1373_DRC(0) + 0x8, 0x00 }, + { ADAU1373_DRC(0) + 0x9, 0xc0 }, + { ADAU1373_DRC(0) + 0xa, 0x88 }, + { ADAU1373_DRC(0) + 0xb, 0x7a }, + { ADAU1373_DRC(0) + 0xc, 0xdf }, + { ADAU1373_DRC(0) + 0xd, 0x20 }, + { ADAU1373_DRC(0) + 0xe, 0x00 }, + { ADAU1373_DRC(0) + 0xf, 0x00 }, + { ADAU1373_DRC(1) + 0x0, 0x78 }, + { ADAU1373_DRC(1) + 0x1, 0x18 }, + { ADAU1373_DRC(1) + 0x2, 0x00 }, + { ADAU1373_DRC(1) + 0x3, 0x00 }, + { ADAU1373_DRC(1) + 0x4, 0x00 }, + { ADAU1373_DRC(1) + 0x5, 0xc0 }, + { ADAU1373_DRC(1) + 0x6, 0x00 }, + { ADAU1373_DRC(1) + 0x7, 0x00 }, + { ADAU1373_DRC(1) + 0x8, 0x00 }, + { ADAU1373_DRC(1) + 0x9, 0xc0 }, + { ADAU1373_DRC(1) + 0xa, 0x88 }, + { ADAU1373_DRC(1) + 0xb, 0x7a }, + { ADAU1373_DRC(1) + 0xc, 0xdf }, + { ADAU1373_DRC(1) + 0xd, 0x20 }, + { ADAU1373_DRC(1) + 0xe, 0x00 }, + { ADAU1373_DRC(1) + 0xf, 0x00 }, + { ADAU1373_DRC(2) + 0x0, 0x78 }, + { ADAU1373_DRC(2) + 0x1, 0x18 }, + { ADAU1373_DRC(2) + 0x2, 0x00 }, + { ADAU1373_DRC(2) + 0x3, 0x00 }, + { ADAU1373_DRC(2) + 0x4, 0x00 }, + { ADAU1373_DRC(2) + 0x5, 0xc0 }, + { ADAU1373_DRC(2) + 0x6, 0x00 }, + { ADAU1373_DRC(2) + 0x7, 0x00 }, + { ADAU1373_DRC(2) + 0x8, 0x00 }, + { ADAU1373_DRC(2) + 0x9, 0xc0 }, + { ADAU1373_DRC(2) + 0xa, 0x88 }, + { ADAU1373_DRC(2) + 0xb, 0x7a }, + { ADAU1373_DRC(2) + 0xc, 0xdf }, + { ADAU1373_DRC(2) + 0xd, 0x20 }, + { ADAU1373_DRC(2) + 0xe, 0x00 }, + { ADAU1373_DRC(2) + 0xf, 0x00 }, + { ADAU1373_3D_CTRL1, 0x00 }, + { ADAU1373_3D_CTRL2, 0x00 }, + { ADAU1373_FDSP_SEL1, 0x00 }, + { ADAU1373_FDSP_SEL2, 0x00 }, + { ADAU1373_FDSP_SEL2, 0x00 }, + { ADAU1373_FDSP_SEL4, 0x00 }, + { ADAU1373_DIGMICCTRL, 0x00 }, + { ADAU1373_DIGEN, 0x00 }, }; static const unsigned int adau1373_out_tlv[] = { @@ -418,6 +553,7 @@ static int adau1373_pll_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; + struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); unsigned int pll_id = w->name[3] - '1'; unsigned int val; @@ -426,7 +562,7 @@ static int adau1373_pll_event(struct snd_soc_dapm_widget *w, else val = 0; - snd_soc_update_bits(codec, ADAU1373_PLL_CTRL6(pll_id), + regmap_update_bits(adau1373->regmap, ADAU1373_PLL_CTRL6(pll_id), ADAU1373_PLL_CTRL6_PLL_EN, val); if (SND_SOC_DAPM_EVENT_ON(event)) @@ -938,7 +1074,7 @@ static int adau1373_hw_params(struct snd_pcm_substream *substream, adau1373_dai->enable_src = (div != 0); - snd_soc_update_bits(codec, ADAU1373_BCLKDIV(dai->id), + regmap_update_bits(adau1373->regmap, ADAU1373_BCLKDIV(dai->id), ADAU1373_BCLKDIV_SR_MASK | ADAU1373_BCLKDIV_BCLK_MASK, (div << 2) | ADAU1373_BCLKDIV_64); @@ -959,7 +1095,7 @@ static int adau1373_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - return snd_soc_update_bits(codec, ADAU1373_DAI(dai->id), + return regmap_update_bits(adau1373->regmap, ADAU1373_DAI(dai->id), ADAU1373_DAI_WLEN_MASK, ctrl); } @@ -1016,7 +1152,7 @@ static int adau1373_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - snd_soc_update_bits(codec, ADAU1373_DAI(dai->id), + regmap_update_bits(adau1373->regmap, ADAU1373_DAI(dai->id), ~ADAU1373_DAI_WLEN_MASK, ctrl); return 0; @@ -1039,7 +1175,7 @@ static int adau1373_set_dai_sysclk(struct snd_soc_dai *dai, adau1373_dai->sysclk = freq; adau1373_dai->clk_src = clk_id; - snd_soc_update_bits(dai->codec, ADAU1373_BCLKDIV(dai->id), + regmap_update_bits(adau1373->regmap, ADAU1373_BCLKDIV(dai->id), ADAU1373_BCLKDIV_SOURCE, clk_id << 5); return 0; @@ -1120,6 +1256,7 @@ static struct snd_soc_dai_driver adau1373_dai_driver[] = { static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id, int source, unsigned int freq_in, unsigned int freq_out) { + struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); unsigned int dpll_div = 0; unsigned int x, r, n, m, i, j, mode; @@ -1187,36 +1324,36 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id, if (dpll_div) { dpll_div = 11 - dpll_div; - snd_soc_update_bits(codec, ADAU1373_PLL_CTRL6(pll_id), + regmap_update_bits(adau1373->regmap, ADAU1373_PLL_CTRL6(pll_id), ADAU1373_PLL_CTRL6_DPLL_BYPASS, 0); } else { - snd_soc_update_bits(codec, ADAU1373_PLL_CTRL6(pll_id), + regmap_update_bits(adau1373->regmap, ADAU1373_PLL_CTRL6(pll_id), ADAU1373_PLL_CTRL6_DPLL_BYPASS, ADAU1373_PLL_CTRL6_DPLL_BYPASS); } - snd_soc_write(codec, ADAU1373_DPLL_CTRL(pll_id), + regmap_write(adau1373->regmap, ADAU1373_DPLL_CTRL(pll_id), (source << 4) | dpll_div); - snd_soc_write(codec, ADAU1373_PLL_CTRL1(pll_id), (m >> 8) & 0xff); - snd_soc_write(codec, ADAU1373_PLL_CTRL2(pll_id), m & 0xff); - snd_soc_write(codec, ADAU1373_PLL_CTRL3(pll_id), (n >> 8) & 0xff); - snd_soc_write(codec, ADAU1373_PLL_CTRL4(pll_id), n & 0xff); - snd_soc_write(codec, ADAU1373_PLL_CTRL5(pll_id), + regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL1(pll_id), (m >> 8) & 0xff); + regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL2(pll_id), m & 0xff); + regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL3(pll_id), (n >> 8) & 0xff); + regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL4(pll_id), n & 0xff); + regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL5(pll_id), (r << 3) | (x << 1) | mode); /* Set sysclk to pll_rate / 4 */ - snd_soc_update_bits(codec, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09); + regmap_update_bits(adau1373->regmap, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09); return 0; } -static void adau1373_load_drc_settings(struct snd_soc_codec *codec, +static void adau1373_load_drc_settings(struct adau1373 *adau1373, unsigned int nr, uint8_t *drc) { unsigned int i; for (i = 0; i < ADAU1373_DRC_SIZE; ++i) - snd_soc_write(codec, ADAU1373_DRC(nr) + i, drc[i]); + regmap_write(adau1373->regmap, ADAU1373_DRC(nr) + i, drc[i]); } static bool adau1373_valid_micbias(enum adau1373_micbias_voltage micbias) @@ -1235,13 +1372,14 @@ static bool adau1373_valid_micbias(enum adau1373_micbias_voltage micbias) static int adau1373_probe(struct snd_soc_codec *codec) { + struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); struct adau1373_platform_data *pdata = codec->dev->platform_data; bool lineout_differential = false; unsigned int val; int ret; int i; - ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); + ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); if (ret) { dev_err(codec->dev, "failed to set cache I/O: %d\n", ret); return ret; @@ -1256,7 +1394,7 @@ static int adau1373_probe(struct snd_soc_codec *codec) return -EINVAL; for (i = 0; i < pdata->num_drc; ++i) { - adau1373_load_drc_settings(codec, i, + adau1373_load_drc_settings(adau1373, i, pdata->drc_setting[i]); } @@ -1268,18 +1406,18 @@ static int adau1373_probe(struct snd_soc_codec *codec) if (pdata->input_differential[i]) val |= BIT(i); } - snd_soc_write(codec, ADAU1373_INPUT_MODE, val); + regmap_write(adau1373->regmap, ADAU1373_INPUT_MODE, val); val = 0; if (pdata->lineout_differential) val |= ADAU1373_OUTPUT_CTRL_LDIFF; if (pdata->lineout_ground_sense) val |= ADAU1373_OUTPUT_CTRL_LNFBEN; - snd_soc_write(codec, ADAU1373_OUTPUT_CTRL, val); + regmap_write(adau1373->regmap, ADAU1373_OUTPUT_CTRL, val); lineout_differential = pdata->lineout_differential; - snd_soc_write(codec, ADAU1373_EP_CTRL, + regmap_write(adau1373->regmap, ADAU1373_EP_CTRL, (pdata->micbias1 << ADAU1373_EP_CTRL_MICBIAS1_OFFSET) | (pdata->micbias2 << ADAU1373_EP_CTRL_MICBIAS2_OFFSET)); } @@ -1289,7 +1427,7 @@ static int adau1373_probe(struct snd_soc_codec *codec) ARRAY_SIZE(adau1373_lineout2_controls)); } - snd_soc_write(codec, ADAU1373_ADC_CTRL, + regmap_write(adau1373->regmap, ADAU1373_ADC_CTRL, ADAU1373_ADC_CTRL_RESET_FORCE | ADAU1373_ADC_CTRL_PEAK_DETECT); return 0; @@ -1298,17 +1436,19 @@ static int adau1373_probe(struct snd_soc_codec *codec) static int adau1373_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); + switch (level) { case SND_SOC_BIAS_ON: break; case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: - snd_soc_update_bits(codec, ADAU1373_PWDN_CTRL3, + regmap_update_bits(adau1373->regmap, ADAU1373_PWDN_CTRL3, ADAU1373_PWDN_CTRL3_PWR_EN, ADAU1373_PWDN_CTRL3_PWR_EN); break; case SND_SOC_BIAS_OFF: - snd_soc_update_bits(codec, ADAU1373_PWDN_CTRL3, + regmap_update_bits(adau1373->regmap, ADAU1373_PWDN_CTRL3, ADAU1373_PWDN_CTRL3_PWR_EN, 0); break; } @@ -1324,17 +1464,49 @@ static int adau1373_remove(struct snd_soc_codec *codec) static int adau1373_suspend(struct snd_soc_codec *codec) { - return adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF); + struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); + int ret; + + ret = adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF); + regcache_cache_only(adau1373->regmap, true); + + return ret; } static int adau1373_resume(struct snd_soc_codec *codec) { + struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(adau1373->regmap, false); adau1373_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - snd_soc_cache_sync(codec); + regcache_sync(adau1373->regmap); return 0; } +static bool adau1373_register_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ADAU1373_SOFT_RESET: + case ADAU1373_ADC_DAC_STATUS: + return true; + default: + return false; + } +} + +static const struct regmap_config adau1373_regmap_config = { + .val_bits = 8, + .reg_bits = 8, + + .volatile_reg = adau1373_register_volatile, + .max_register = ADAU1373_SOFT_RESET, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = adau1373_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(adau1373_reg_defaults), +}; + static struct snd_soc_codec_driver adau1373_codec_driver = { .probe = adau1373_probe, .remove = adau1373_remove, @@ -1342,9 +1514,6 @@ static struct snd_soc_codec_driver adau1373_codec_driver = { .resume = adau1373_resume, .set_bias_level = adau1373_set_bias_level, .idle_bias_off = true, - .reg_cache_size = ARRAY_SIZE(adau1373_default_regs), - .reg_cache_default = adau1373_default_regs, - .reg_word_size = sizeof(uint8_t), .set_pll = adau1373_set_pll, @@ -1366,6 +1535,13 @@ static int adau1373_i2c_probe(struct i2c_client *client, if (!adau1373) return -ENOMEM; + adau1373->regmap = devm_regmap_init_i2c(client, + &adau1373_regmap_config); + if (IS_ERR(adau1373->regmap)) + return PTR_ERR(adau1373->regmap); + + regmap_write(adau1373->regmap, ADAU1373_SOFT_RESET, 0x00); + dev_set_drvdata(&client->dev, adau1373); ret = snd_soc_register_codec(&client->dev, &adau1373_codec_driver, diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index 15b012d0f226..14a7c169d004 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -115,22 +115,34 @@ #define ADAV80X_PLL_OUTE_SYSCLKPD(x) BIT(2 - (x)) -static u8 adav80x_default_regs[] = { - 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x01, 0x80, 0x26, 0x00, 0x00, - 0x02, 0x40, 0x20, 0x00, 0x09, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x92, 0xb1, 0x37, - 0x48, 0xd2, 0xfb, 0xca, 0xd2, 0x15, 0xe8, 0x29, 0xb9, 0x6a, 0xda, 0x2b, - 0xb7, 0xc0, 0x11, 0x65, 0x5c, 0xf6, 0xff, 0x8d, 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, 0xa5, 0x00, 0x00, - 0x00, 0xe8, 0x46, 0xe1, 0x5b, 0xd3, 0x43, 0x77, 0x93, 0xa7, 0x44, 0xee, - 0x32, 0x12, 0xc0, 0x11, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x3f, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, +static struct reg_default adav80x_reg_defaults[] = { + { ADAV80X_PLAYBACK_CTRL, 0x01 }, + { ADAV80X_AUX_IN_CTRL, 0x01 }, + { ADAV80X_REC_CTRL, 0x02 }, + { ADAV80X_AUX_OUT_CTRL, 0x01 }, + { ADAV80X_DPATH_CTRL1, 0xc0 }, + { ADAV80X_DPATH_CTRL2, 0x11 }, + { ADAV80X_DAC_CTRL1, 0x00 }, + { ADAV80X_DAC_CTRL2, 0x00 }, + { ADAV80X_DAC_CTRL3, 0x00 }, + { ADAV80X_DAC_L_VOL, 0xff }, + { ADAV80X_DAC_R_VOL, 0xff }, + { ADAV80X_PGA_L_VOL, 0x00 }, + { ADAV80X_PGA_R_VOL, 0x00 }, + { ADAV80X_ADC_CTRL1, 0x00 }, + { ADAV80X_ADC_CTRL2, 0x00 }, + { ADAV80X_ADC_L_VOL, 0xff }, + { ADAV80X_ADC_R_VOL, 0xff }, + { ADAV80X_PLL_CTRL1, 0x00 }, + { ADAV80X_PLL_CTRL2, 0x00 }, + { ADAV80X_ICLK_CTRL1, 0x00 }, + { ADAV80X_ICLK_CTRL2, 0x00 }, + { ADAV80X_PLL_CLK_SRC, 0x00 }, + { ADAV80X_PLL_OUTE, 0x00 }, }; struct adav80x { - enum snd_soc_control_type control_type; + struct regmap *regmap; enum adav80x_clk_src clk_src; unsigned int sysclk; @@ -298,7 +310,7 @@ static int adav80x_set_deemph(struct snd_soc_codec *codec) val = ADAV80X_DAC_CTRL2_DEEMPH_NONE; } - return snd_soc_update_bits(codec, ADAV80X_DAC_CTRL2, + return regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL2, ADAV80X_DAC_CTRL2_DEEMPH_MASK, val); } @@ -394,10 +406,11 @@ static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][0], + regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][0], ADAV80X_CAPTURE_MODE_MASK | ADAV80X_CAPTURE_MODE_MASTER, capture); - snd_soc_write(codec, adav80x_port_ctrl_regs[dai->id][1], playback); + regmap_write(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][1], + playback); adav80x->dai_fmt[dai->id] = fmt & SND_SOC_DAIFMT_FORMAT_MASK; @@ -407,6 +420,7 @@ static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) static int adav80x_set_adc_clock(struct snd_soc_codec *codec, unsigned int sample_rate) { + struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); unsigned int val; if (sample_rate <= 48000) @@ -414,7 +428,7 @@ static int adav80x_set_adc_clock(struct snd_soc_codec *codec, else val = ADAV80X_ADC_CTRL1_MODULATOR_64FS; - snd_soc_update_bits(codec, ADAV80X_ADC_CTRL1, + regmap_update_bits(adav80x->regmap, ADAV80X_ADC_CTRL1, ADAV80X_ADC_CTRL1_MODULATOR_MASK, val); return 0; @@ -423,6 +437,7 @@ static int adav80x_set_adc_clock(struct snd_soc_codec *codec, static int adav80x_set_dac_clock(struct snd_soc_codec *codec, unsigned int sample_rate) { + struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); unsigned int val; if (sample_rate <= 48000) @@ -430,7 +445,7 @@ static int adav80x_set_dac_clock(struct snd_soc_codec *codec, else val = ADAV80X_DAC_CTRL2_DIV2 | ADAV80X_DAC_CTRL2_INTERPOL_128FS; - snd_soc_update_bits(codec, ADAV80X_DAC_CTRL2, + regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL2, ADAV80X_DAC_CTRL2_DIV_MASK | ADAV80X_DAC_CTRL2_INTERPOL_MASK, val); @@ -440,6 +455,7 @@ static int adav80x_set_dac_clock(struct snd_soc_codec *codec, static int adav80x_set_capture_pcm_format(struct snd_soc_codec *codec, struct snd_soc_dai *dai, snd_pcm_format_t format) { + struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); unsigned int val; switch (format) { @@ -459,7 +475,7 @@ static int adav80x_set_capture_pcm_format(struct snd_soc_codec *codec, return -EINVAL; } - snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][0], + regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][0], ADAV80X_CAPTURE_WORD_LEN_MASK, val); return 0; @@ -491,7 +507,7 @@ static int adav80x_set_playback_pcm_format(struct snd_soc_codec *codec, return -EINVAL; } - snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][1], + regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][1], ADAV80X_PLAYBACK_MODE_MASK, val); return 0; @@ -554,8 +570,10 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec, ADAV80X_ICLK_CTRL1_ICLK2_SRC(clk_id); iclk_ctrl2 = ADAV80X_ICLK_CTRL2_ICLK1_SRC(clk_id); - snd_soc_write(codec, ADAV80X_ICLK_CTRL1, iclk_ctrl1); - snd_soc_write(codec, ADAV80X_ICLK_CTRL2, iclk_ctrl2); + regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL1, + iclk_ctrl1); + regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL2, + iclk_ctrl2); snd_soc_dapm_sync(&codec->dapm); } @@ -575,10 +593,12 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec, mask = ADAV80X_PLL_OUTE_SYSCLKPD(clk_id); if (freq == 0) { - snd_soc_update_bits(codec, ADAV80X_PLL_OUTE, mask, mask); + regmap_update_bits(adav80x->regmap, ADAV80X_PLL_OUTE, + mask, mask); adav80x->sysclk_pd[clk_id] = true; } else { - snd_soc_update_bits(codec, ADAV80X_PLL_OUTE, mask, 0); + regmap_update_bits(adav80x->regmap, ADAV80X_PLL_OUTE, + mask, 0); adav80x->sysclk_pd[clk_id] = false; } @@ -650,9 +670,9 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id, return -EINVAL; } - snd_soc_update_bits(codec, ADAV80X_PLL_CTRL1, ADAV80X_PLL_CTRL1_PLLDIV, - pll_ctrl1); - snd_soc_update_bits(codec, ADAV80X_PLL_CTRL2, + regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CTRL1, + ADAV80X_PLL_CTRL1_PLLDIV, pll_ctrl1); + regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CTRL2, ADAV80X_PLL_CTRL2_PLL_MASK(pll_id), pll_ctrl2); if (source != adav80x->pll_src) { @@ -661,7 +681,7 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id, else pll_src = ADAV80X_PLL_CLK_SRC_PLL_XIN(pll_id); - snd_soc_update_bits(codec, ADAV80X_PLL_CLK_SRC, + regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CLK_SRC, ADAV80X_PLL_CLK_SRC_PLL_MASK(pll_id), pll_src); adav80x->pll_src = source; @@ -675,6 +695,7 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id, static int adav80x_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); unsigned int mask = ADAV80X_DAC_CTRL1_PD; switch (level) { @@ -683,10 +704,12 @@ static int adav80x_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: - snd_soc_update_bits(codec, ADAV80X_DAC_CTRL1, mask, 0x00); + regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL1, mask, + 0x00); break; case SND_SOC_BIAS_OFF: - snd_soc_update_bits(codec, ADAV80X_DAC_CTRL1, mask, mask); + regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL1, mask, + mask); break; } @@ -780,7 +803,7 @@ static int adav80x_probe(struct snd_soc_codec *codec) int ret; struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - ret = snd_soc_codec_set_cache_io(codec, 7, 9, adav80x->control_type); + ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); if (ret) { dev_err(codec->dev, "failed to set cache I/O: %d\n", ret); return ret; @@ -791,23 +814,31 @@ static int adav80x_probe(struct snd_soc_codec *codec) snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2"); /* Power down S/PDIF receiver, since it is currently not supported */ - snd_soc_write(codec, ADAV80X_PLL_OUTE, 0x20); + regmap_write(adav80x->regmap, ADAV80X_PLL_OUTE, 0x20); /* Disable DAC zero flag */ - snd_soc_write(codec, ADAV80X_DAC_CTRL3, 0x6); + regmap_write(adav80x->regmap, ADAV80X_DAC_CTRL3, 0x6); return adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); } static int adav80x_suspend(struct snd_soc_codec *codec) { - return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF); + struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); + int ret; + + ret = adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF); + regcache_cache_only(adav80x->regmap, true); + + return ret; } static int adav80x_resume(struct snd_soc_codec *codec) { + struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(adav80x->regmap, false); adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - codec->cache_sync = 1; - snd_soc_cache_sync(codec); + regcache_sync(adav80x->regmap); return 0; } @@ -827,10 +858,6 @@ static struct snd_soc_codec_driver adav80x_codec_driver = { .set_pll = adav80x_set_pll, .set_sysclk = adav80x_set_sysclk, - .reg_word_size = sizeof(u8), - .reg_cache_size = ARRAY_SIZE(adav80x_default_regs), - .reg_cache_default = adav80x_default_regs, - .controls = adav80x_controls, .num_controls = ARRAY_SIZE(adav80x_controls), .dapm_widgets = adav80x_dapm_widgets, @@ -839,18 +866,21 @@ static struct snd_soc_codec_driver adav80x_codec_driver = { .num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes), }; -static int adav80x_bus_probe(struct device *dev, - enum snd_soc_control_type control_type) +static int adav80x_bus_probe(struct device *dev, struct regmap *regmap) { struct adav80x *adav80x; int ret; + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + adav80x = kzalloc(sizeof(*adav80x), GFP_KERNEL); if (!adav80x) return -ENOMEM; + dev_set_drvdata(dev, adav80x); - adav80x->control_type = control_type; + adav80x->regmap = regmap; ret = snd_soc_register_codec(dev, &adav80x_codec_driver, adav80x_dais, ARRAY_SIZE(adav80x_dais)); @@ -868,6 +898,19 @@ static int adav80x_bus_remove(struct device *dev) } #if defined(CONFIG_SPI_MASTER) +static const struct regmap_config adav80x_spi_regmap_config = { + .val_bits = 8, + .pad_bits = 1, + .reg_bits = 7, + .read_flag_mask = 0x01, + + .max_register = ADAV80X_PLL_OUTE, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = adav80x_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults), +}; + static const struct spi_device_id adav80x_spi_id[] = { { "adav801", 0 }, { } @@ -876,7 +919,8 @@ MODULE_DEVICE_TABLE(spi, adav80x_spi_id); static int adav80x_spi_probe(struct spi_device *spi) { - return adav80x_bus_probe(&spi->dev, SND_SOC_SPI); + return adav80x_bus_probe(&spi->dev, + devm_regmap_init_spi(spi, &adav80x_spi_regmap_config)); } static int adav80x_spi_remove(struct spi_device *spi) @@ -896,6 +940,18 @@ static struct spi_driver adav80x_spi_driver = { #endif #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +static const struct regmap_config adav80x_i2c_regmap_config = { + .val_bits = 8, + .pad_bits = 1, + .reg_bits = 7, + + .max_register = ADAV80X_PLL_OUTE, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = adav80x_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults), +}; + static const struct i2c_device_id adav80x_i2c_id[] = { { "adav803", 0 }, { } @@ -905,7 +961,8 @@ MODULE_DEVICE_TABLE(i2c, adav80x_i2c_id); static int adav80x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { - return adav80x_bus_probe(&client->dev, SND_SOC_I2C); + return adav80x_bus_probe(&client->dev, + devm_regmap_init_i2c(client, &adav80x_i2c_regmap_config)); } static int adav80x_i2c_remove(struct i2c_client *client) diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index 71059c07ae7b..b4819dcd4f4d 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -45,8 +45,6 @@ #define AK4104_TX_TXE (1 << 0) #define AK4104_TX_V (1 << 1) -#define DRV_NAME "ak4104-codec" - struct ak4104_private { struct regmap *regmap; }; @@ -291,12 +289,19 @@ static const struct of_device_id ak4104_of_match[] = { }; MODULE_DEVICE_TABLE(of, ak4104_of_match); +static const struct spi_device_id ak4104_id_table[] = { + { "ak4104", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, ak4104_id_table); + static struct spi_driver ak4104_spi_driver = { .driver = { - .name = DRV_NAME, + .name = "ak4104", .owner = THIS_MODULE, .of_match_table = ak4104_of_match, }, + .id_table = ak4104_id_table, .probe = ak4104_spi_probe, .remove = ak4104_spi_remove, }; diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 2d0378709702..21c35ed778cc 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -352,7 +352,6 @@ static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) */ default: return -EINVAL; - break; } snd_soc_update_bits(codec, MD_CTL1, DIF_MASK, data); @@ -405,7 +404,6 @@ static int ak4642_dai_hw_params(struct snd_pcm_substream *substream, break; default: return -EINVAL; - break; } snd_soc_update_bits(codec, MD_CTL2, FS_MASK, rate); diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 657808ba1418..6f05b17d1965 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1477,21 +1477,25 @@ static void arizona_enable_fll(struct arizona_fll *fll, { struct arizona *arizona = fll->arizona; int ret; + bool use_sync = false; /* * If we have both REFCLK and SYNCCLK then enable both, * otherwise apply the SYNCCLK settings to REFCLK. */ - if (fll->ref_src >= 0 && fll->ref_src != fll->sync_src) { + if (fll->ref_src >= 0 && fll->ref_freq && + fll->ref_src != fll->sync_src) { regmap_update_bits(arizona->regmap, fll->base + 5, ARIZONA_FLL1_OUTDIV_MASK, ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); arizona_apply_fll(arizona, fll->base, ref, fll->ref_src, false); - if (fll->sync_src >= 0) + if (fll->sync_src >= 0) { arizona_apply_fll(arizona, fll->base + 0x10, sync, fll->sync_src, true); + use_sync = true; + } } else if (fll->sync_src >= 0) { regmap_update_bits(arizona->regmap, fll->base + 5, ARIZONA_FLL1_OUTDIV_MASK, @@ -1511,7 +1515,7 @@ static void arizona_enable_fll(struct arizona_fll *fll, * Increase the bandwidth if we're not using a low frequency * sync source. */ - if (fll->sync_src >= 0 && fll->sync_freq > 100000) + if (use_sync && fll->sync_freq > 100000) regmap_update_bits(arizona->regmap, fll->base + 0x17, ARIZONA_FLL1_SYNC_BW, 0); else @@ -1526,8 +1530,7 @@ static void arizona_enable_fll(struct arizona_fll *fll, regmap_update_bits(arizona->regmap, fll->base + 1, ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); - if (fll->ref_src >= 0 && fll->sync_src >= 0 && - fll->ref_src != fll->sync_src) + if (use_sync) regmap_update_bits(arizona->regmap, fll->base + 0x11, ARIZONA_FLL1_SYNC_ENA, ARIZONA_FLL1_SYNC_ENA); @@ -1561,10 +1564,12 @@ int arizona_set_fll_refclk(struct arizona_fll *fll, int source, if (fll->ref_src == source && fll->ref_freq == Fref) return 0; - if (fll->fout && Fref > 0) { - ret = arizona_calc_fll(fll, &ref, Fref, fll->fout); - if (ret != 0) - return ret; + if (fll->fout) { + if (Fref > 0) { + ret = arizona_calc_fll(fll, &ref, Fref, fll->fout); + if (ret != 0) + return ret; + } if (fll->sync_src >= 0) { ret = arizona_calc_fll(fll, &sync, fll->sync_freq, diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index 23316c887b19..43737a27d79c 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -38,24 +38,6 @@ #include <sound/soc.h> #include <sound/initval.h> -static inline unsigned int cq93vc_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - struct davinci_vc *davinci_vc = codec->control_data; - - return readl(davinci_vc->base + reg); -} - -static inline int cq93vc_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - struct davinci_vc *davinci_vc = codec->control_data; - - writel(value, davinci_vc->base + reg); - - return 0; -} - static const struct snd_kcontrol_new cq93vc_snd_controls[] = { SOC_SINGLE("PGA Capture Volume", DAVINCI_VC_REG05, 0, 0x03, 0), SOC_SINGLE("Mono DAC Playback Volume", DAVINCI_VC_REG09, 0, 0x3f, 0), @@ -64,13 +46,15 @@ static const struct snd_kcontrol_new cq93vc_snd_controls[] = { static int cq93vc_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u8 reg = cq93vc_read(codec, DAVINCI_VC_REG09) & ~DAVINCI_VC_REG09_MUTE; + u8 reg; if (mute) - cq93vc_write(codec, DAVINCI_VC_REG09, - reg | DAVINCI_VC_REG09_MUTE); + reg = DAVINCI_VC_REG09_MUTE; else - cq93vc_write(codec, DAVINCI_VC_REG09, reg); + reg = 0; + + snd_soc_update_bits(codec, DAVINCI_VC_REG09, DAVINCI_VC_REG09_MUTE, + reg); return 0; } @@ -79,7 +63,7 @@ static int cq93vc_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 davinci_vc *davinci_vc = codec->control_data; + struct davinci_vc *davinci_vc = codec->dev->platform_data; switch (freq) { case 22579200: @@ -97,18 +81,18 @@ static int cq93vc_set_bias_level(struct snd_soc_codec *codec, { switch (level) { case SND_SOC_BIAS_ON: - cq93vc_write(codec, DAVINCI_VC_REG12, + snd_soc_write(codec, DAVINCI_VC_REG12, DAVINCI_VC_REG12_POWER_ALL_ON); break; case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: - cq93vc_write(codec, DAVINCI_VC_REG12, + snd_soc_write(codec, DAVINCI_VC_REG12, DAVINCI_VC_REG12_POWER_ALL_OFF); break; case SND_SOC_BIAS_OFF: /* force all power off */ - cq93vc_write(codec, DAVINCI_VC_REG12, + snd_soc_write(codec, DAVINCI_VC_REG12, DAVINCI_VC_REG12_POWER_ALL_OFF); break; } @@ -154,11 +138,9 @@ static int cq93vc_probe(struct snd_soc_codec *codec) struct davinci_vc *davinci_vc = codec->dev->platform_data; davinci_vc->cq93vc.codec = codec; - codec->control_data = davinci_vc; + codec->control_data = davinci_vc->regmap; - /* Set controls */ - snd_soc_add_codec_controls(codec, cq93vc_snd_controls, - ARRAY_SIZE(cq93vc_snd_controls)); + snd_soc_codec_set_cache_io(codec, 32, 32, SND_SOC_REGMAP); /* Off, with power on */ cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -174,12 +156,12 @@ static int cq93vc_remove(struct snd_soc_codec *codec) } static struct snd_soc_codec_driver soc_codec_dev_cq93vc = { - .read = cq93vc_read, - .write = cq93vc_write, .set_bias_level = cq93vc_set_bias_level, .probe = cq93vc_probe, .remove = cq93vc_remove, .resume = cq93vc_resume, + .controls = cq93vc_snd_controls, + .num_controls = ARRAY_SIZE(cq93vc_snd_controls), }; static int cq93vc_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index a20f1bb8f071..f6e953454bc0 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -25,6 +25,7 @@ #include <linux/gpio.h> #include <linux/i2c.h> #include <linux/spi/spi.h> +#include <linux/of.h> #include <linux/of_device.h> #include <linux/of_gpio.h> #include <sound/pcm.h> diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 3b20c86cdb01..549d5d6a3fef 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -17,6 +17,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/of_gpio.h> #include <linux/pm.h> #include <linux/i2c.h> #include <linux/regmap.h> @@ -28,6 +29,7 @@ #include <sound/soc-dapm.h> #include <sound/initval.h> #include <sound/tlv.h> +#include <sound/cs42l73.h> #include "cs42l73.h" struct sp_config { @@ -35,6 +37,7 @@ struct sp_config { u32 srate; }; struct cs42l73_private { + struct cs42l73_platform_data pdata; struct sp_config config[3]; struct regmap *regmap; u32 sysclk; @@ -310,15 +313,6 @@ static const struct soc_enum ng_delay_enum = SOC_ENUM_SINGLE(CS42L73_NGCAB, 0, ARRAY_SIZE(cs42l73_ng_delay_text), cs42l73_ng_delay_text); -static const char * const charge_pump_freq_text[] = { - "0", "1", "2", "3", "4", - "5", "6", "7", "8", "9", - "10", "11", "12", "13", "14", "15" }; - -static const struct soc_enum charge_pump_enum = - SOC_ENUM_SINGLE(CS42L73_CPFCHC, 4, - ARRAY_SIZE(charge_pump_freq_text), charge_pump_freq_text); - static const char * const cs42l73_mono_mix_texts[] = { "Left", "Right", "Mono Mix"}; @@ -511,8 +505,6 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = { SOC_SINGLE("NG Threshold", CS42L73_NGCAB, 2, 7, 0), SOC_ENUM("NG Delay", ng_delay_enum), - SOC_ENUM("Charge Pump Frequency", charge_pump_enum), - SOC_DOUBLE_R_TLV("XSP-IP Volume", CS42L73_XSPAIPAA, CS42L73_XSPBIPBA, 0, 0x3F, 1, attn_tlv), @@ -1055,11 +1047,11 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: - mmcc |= MS_MASTER; + mmcc |= CS42L73_MS_MASTER; break; case SND_SOC_DAIFMT_CBS_CFS: - mmcc &= ~MS_MASTER; + mmcc &= ~CS42L73_MS_MASTER; break; default: @@ -1071,11 +1063,11 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) switch (format) { case SND_SOC_DAIFMT_I2S: - spc &= ~SPDIF_PCM; + spc &= ~CS42L73_SPDIF_PCM; break; case SND_SOC_DAIFMT_DSP_A: case SND_SOC_DAIFMT_DSP_B: - if (mmcc & MS_MASTER) { + if (mmcc & CS42L73_MS_MASTER) { dev_err(codec->dev, "PCM format in slave mode only\n"); return -EINVAL; @@ -1085,25 +1077,25 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) "PCM format is not supported on ASP port\n"); return -EINVAL; } - spc |= SPDIF_PCM; + spc |= CS42L73_SPDIF_PCM; break; default: return -EINVAL; } - if (spc & SPDIF_PCM) { + if (spc & CS42L73_SPDIF_PCM) { /* Clear PCM mode, clear PCM_BIT_ORDER bit for MSB->LSB */ - spc &= ~(PCM_MODE_MASK | PCM_BIT_ORDER); + spc &= ~(CS42L73_PCM_MODE_MASK | CS42L73_PCM_BIT_ORDER); switch (format) { case SND_SOC_DAIFMT_DSP_B: if (inv == SND_SOC_DAIFMT_IB_IF) - spc |= PCM_MODE0; + spc |= CS42L73_PCM_MODE0; if (inv == SND_SOC_DAIFMT_IB_NF) - spc |= PCM_MODE1; + spc |= CS42L73_PCM_MODE1; break; case SND_SOC_DAIFMT_DSP_A: if (inv == SND_SOC_DAIFMT_IB_IF) - spc |= PCM_MODE1; + spc |= CS42L73_PCM_MODE1; break; default: return -EINVAL; @@ -1163,7 +1155,7 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream, int mclk_coeff; int srate = params_rate(params); - if (priv->config[id].mmcc & MS_MASTER) { + if (priv->config[id].mmcc & CS42L73_MS_MASTER) { /* CS42L73 Master */ /* MCLK -> srate */ mclk_coeff = @@ -1182,13 +1174,13 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream, priv->config[id].spc &= 0xFC; /* Use SCLK=64*Fs if internal MCLK >= 6.4MHz */ if (priv->mclk >= 6400000) - priv->config[id].spc |= MCK_SCLK_64FS; + priv->config[id].spc |= CS42L73_MCK_SCLK_64FS; else - priv->config[id].spc |= MCK_SCLK_MCLK; + priv->config[id].spc |= CS42L73_MCK_SCLK_MCLK; } else { /* CS42L73 Slave */ priv->config[id].spc &= 0xFC; - priv->config[id].spc |= MCK_SCLK_64FS; + priv->config[id].spc |= CS42L73_MCK_SCLK_64FS; } /* Update ASRCs */ priv->config[id].srate = srate; @@ -1208,8 +1200,8 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: - snd_soc_update_bits(codec, CS42L73_DMMCC, MCLKDIS, 0); - snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 0); + snd_soc_update_bits(codec, CS42L73_DMMCC, CS42L73_MCLKDIS, 0); + snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 0); break; case SND_SOC_BIAS_PREPARE: @@ -1220,11 +1212,11 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec, regcache_cache_only(cs42l73->regmap, false); regcache_sync(cs42l73->regmap); } - snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 1); + snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 1); break; case SND_SOC_BIAS_OFF: - snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 1); + snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 1); if (cs42l73->shutdwn_delay > 0) { mdelay(cs42l73->shutdwn_delay); cs42l73->shutdwn_delay = 0; @@ -1233,7 +1225,7 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec, * down. */ } - snd_soc_update_bits(codec, CS42L73_DMMCC, MCLKDIS, 1); + snd_soc_update_bits(codec, CS42L73_DMMCC, CS42L73_MCLKDIS, 1); break; } codec->dapm.bias_level = level; @@ -1367,11 +1359,16 @@ static int cs42l73_probe(struct snd_soc_codec *codec) return ret; } - regcache_cache_only(cs42l73->regmap, true); - cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - cs42l73->mclksel = CS42L73_CLKID_MCLK1; /* MCLK1 as master clk */ + /* Set Charge Pump Frequency */ + if (cs42l73->pdata.chgfreq) + snd_soc_update_bits(codec, CS42L73_CPFCHC, + CS42L73_CHARGEPUMP_MASK, + cs42l73->pdata.chgfreq << 4); + + /* MCLK1 as master clk */ + cs42l73->mclksel = CS42L73_CLKID_MCLK1; cs42l73->mclk = 0; return ret; @@ -1415,9 +1412,11 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) { struct cs42l73_private *cs42l73; + struct cs42l73_platform_data *pdata = dev_get_platdata(&i2c_client->dev); int ret; unsigned int devid = 0; unsigned int reg; + u32 val32; cs42l73 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l73_private), GFP_KERNEL); @@ -1426,14 +1425,49 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, return -ENOMEM; } - i2c_set_clientdata(i2c_client, cs42l73); - cs42l73->regmap = devm_regmap_init_i2c(i2c_client, &cs42l73_regmap); if (IS_ERR(cs42l73->regmap)) { ret = PTR_ERR(cs42l73->regmap); dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); return ret; } + + if (pdata) { + cs42l73->pdata = *pdata; + } else { + pdata = devm_kzalloc(&i2c_client->dev, + sizeof(struct cs42l73_platform_data), + GFP_KERNEL); + if (!pdata) { + dev_err(&i2c_client->dev, "could not allocate pdata\n"); + return -ENOMEM; + } + if (i2c_client->dev.of_node) { + if (of_property_read_u32(i2c_client->dev.of_node, + "chgfreq", &val32) >= 0) + pdata->chgfreq = val32; + } + pdata->reset_gpio = of_get_named_gpio(i2c_client->dev.of_node, + "reset-gpio", 0); + cs42l73->pdata = *pdata; + } + + i2c_set_clientdata(i2c_client, cs42l73); + + if (cs42l73->pdata.reset_gpio) { + ret = gpio_request_one(cs42l73->pdata.reset_gpio, + GPIOF_OUT_INIT_HIGH, "CS42L73 /RST"); + if (ret < 0) { + dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n", + cs42l73->pdata.reset_gpio, ret); + return ret; + } + gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 0); + gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 1); + } + + regcache_cache_bypass(cs42l73->regmap, true); + /* initialize codec */ ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, ®); devid = (reg & 0xFF) << 12; @@ -1444,7 +1478,6 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_E, ®); devid |= (reg & 0xF0) >> 4; - if (devid != CS42L73_DEVID) { ret = -ENODEV; dev_err(&i2c_client->dev, @@ -1462,7 +1495,7 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, dev_info(&i2c_client->dev, "Cirrus Logic CS42L73, Revision: %02X\n", reg & 0xFF); - regcache_cache_only(cs42l73->regmap, true); + regcache_cache_bypass(cs42l73->regmap, false); ret = snd_soc_register_codec(&i2c_client->dev, &soc_codec_dev_cs42l73, cs42l73_dai, @@ -1478,6 +1511,12 @@ static int cs42l73_i2c_remove(struct i2c_client *client) return 0; } +static const struct of_device_id cs42l73_of_match[] = { + { .compatible = "cirrus,cs42l73", }, + {}, +}; +MODULE_DEVICE_TABLE(of, cs42l73_of_match); + static const struct i2c_device_id cs42l73_id[] = { {"cs42l73", 0}, {} @@ -1489,6 +1528,7 @@ static struct i2c_driver cs42l73_i2c_driver = { .driver = { .name = "cs42l73", .owner = THIS_MODULE, + .of_match_table = cs42l73_of_match, }, .id_table = cs42l73_id, .probe = cs42l73_i2c_probe, diff --git a/sound/soc/codecs/cs42l73.h b/sound/soc/codecs/cs42l73.h index f30a4c4d62e6..45746186a678 100644 --- a/sound/soc/codecs/cs42l73.h +++ b/sound/soc/codecs/cs42l73.h @@ -128,59 +128,60 @@ /* Bitfield Definitions */ /* CS42L73_PWRCTL1 */ -#define PDN_ADCB (1 << 7) -#define PDN_DMICB (1 << 6) -#define PDN_ADCA (1 << 5) -#define PDN_DMICA (1 << 4) -#define PDN_LDO (1 << 2) -#define DISCHG_FILT (1 << 1) -#define PDN (1 << 0) +#define CS42L73_PDN_ADCB (1 << 7) +#define CS42L73_PDN_DMICB (1 << 6) +#define CS42L73_PDN_ADCA (1 << 5) +#define CS42L73_PDN_DMICA (1 << 4) +#define CS42L73_PDN_LDO (1 << 2) +#define CS42L73_DISCHG_FILT (1 << 1) +#define CS42L73_PDN (1 << 0) /* CS42L73_PWRCTL2 */ -#define PDN_MIC2_BIAS (1 << 7) -#define PDN_MIC1_BIAS (1 << 6) -#define PDN_VSP (1 << 4) -#define PDN_ASP_SDOUT (1 << 3) -#define PDN_ASP_SDIN (1 << 2) -#define PDN_XSP_SDOUT (1 << 1) -#define PDN_XSP_SDIN (1 << 0) +#define CS42L73_PDN_MIC2_BIAS (1 << 7) +#define CS42L73_PDN_MIC1_BIAS (1 << 6) +#define CS42L73_PDN_VSP (1 << 4) +#define CS42L73_PDN_ASP_SDOUT (1 << 3) +#define CS42L73_PDN_ASP_SDIN (1 << 2) +#define CS42L73_PDN_XSP_SDOUT (1 << 1) +#define CS42L73_PDN_XSP_SDIN (1 << 0) /* CS42L73_PWRCTL3 */ -#define PDN_THMS (1 << 5) -#define PDN_SPKLO (1 << 4) -#define PDN_EAR (1 << 3) -#define PDN_SPK (1 << 2) -#define PDN_LO (1 << 1) -#define PDN_HP (1 << 0) +#define CS42L73_PDN_THMS (1 << 5) +#define CS42L73_PDN_SPKLO (1 << 4) +#define CS42L73_PDN_EAR (1 << 3) +#define CS42L73_PDN_SPK (1 << 2) +#define CS42L73_PDN_LO (1 << 1) +#define CS42L73_PDN_HP (1 << 0) /* Thermal Overload Detect. Requires interrupt ... */ -#define THMOVLD_150C 0 -#define THMOVLD_132C 1 -#define THMOVLD_115C 2 -#define THMOVLD_098C 3 +#define CS42L73_THMOVLD_150C 0 +#define CS42L73_THMOVLD_132C 1 +#define CS42L73_THMOVLD_115C 2 +#define CS42L73_THMOVLD_098C 3 +#define CS42L73_CHARGEPUMP_MASK (0xF0) /* CS42L73_ASPC, CS42L73_XSPC, CS42L73_VSPC */ -#define SP_3ST (1 << 7) -#define SPDIF_I2S (0 << 6) -#define SPDIF_PCM (1 << 6) -#define PCM_MODE0 (0 << 4) -#define PCM_MODE1 (1 << 4) -#define PCM_MODE2 (2 << 4) -#define PCM_MODE_MASK (3 << 4) -#define PCM_BIT_ORDER (1 << 3) -#define MCK_SCLK_64FS (0 << 0) -#define MCK_SCLK_MCLK (2 << 0) -#define MCK_SCLK_PREMCLK (3 << 0) +#define CS42L73_SP_3ST (1 << 7) +#define CS42L73_SPDIF_I2S (0 << 6) +#define CS42L73_SPDIF_PCM (1 << 6) +#define CS42L73_PCM_MODE0 (0 << 4) +#define CS42L73_PCM_MODE1 (1 << 4) +#define CS42L73_PCM_MODE2 (2 << 4) +#define CS42L73_PCM_MODE_MASK (3 << 4) +#define CS42L73_PCM_BIT_ORDER (1 << 3) +#define CS42L73_MCK_SCLK_64FS (0 << 0) +#define CS42L73_MCK_SCLK_MCLK (2 << 0) +#define CS42L73_MCK_SCLK_PREMCLK (3 << 0) /* CS42L73_xSPMMCC */ -#define MS_MASTER (1 << 7) +#define CS42L73_MS_MASTER (1 << 7) /* CS42L73_DMMCC */ -#define MCLKDIS (1 << 0) -#define MCLKSEL_MCLK2 (1 << 4) -#define MCLKSEL_MCLK1 (0 << 4) +#define CS42L73_MCLKDIS (1 << 0) +#define CS42L73_MCLKSEL_MCLK2 (1 << 4) +#define CS42L73_MCLKSEL_MCLK1 (0 << 4) /* CS42L73 MCLK derived from MCLK1 or MCLK2 */ #define CS42L73_CLKID_MCLK1 0 @@ -194,28 +195,26 @@ #define CS42L73_VSP 2 /* IS1, IM1 */ -#define MIC2_SDET (1 << 6) -#define THMOVLD (1 << 4) -#define DIGMIXOVFL (1 << 3) -#define IPBOVFL (1 << 1) -#define IPAOVFL (1 << 0) +#define CS42L73_MIC2_SDET (1 << 6) +#define CS42L73_THMOVLD (1 << 4) +#define CS42L73_DIGMIXOVFL (1 << 3) +#define CS42L73_IPBOVFL (1 << 1) +#define CS42L73_IPAOVFL (1 << 0) /* Analog Softramp */ -#define ANLGOSFT (1 << 0) +#define CS42L73_ANLGOSFT (1 << 0) /* HP A/B Analog Mute */ -#define HPA_MUTE (1 << 7) +#define CS42L73_HPA_MUTE (1 << 7) /* LO A/B Analog Mute */ -#define LOA_MUTE (1 << 7) +#define CS42L73_LOA_MUTE (1 << 7) /* Digital Mute */ -#define HLAD_MUTE (1 << 0) -#define HLBD_MUTE (1 << 1) -#define SPKD_MUTE (1 << 2) -#define ESLD_MUTE (1 << 3) +#define CS42L73_HLAD_MUTE (1 << 0) +#define CS42L73_HLBD_MUTE (1 << 1) +#define CS42L73_SPKD_MUTE (1 << 2) +#define CS42L73_ESLD_MUTE (1 << 3) /* Misc defines for codec */ -#define CS42L73_RESET_GPIO 143 - #define CS42L73_DEVID 0x00042A73 #define CS42L73_MCLKX_MIN 5644800 #define CS42L73_MCLKX_MAX 38400000 diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 566a367c94fa..66ceee22fdad 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -15,6 +15,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> +#include <linux/regmap.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -38,294 +39,223 @@ struct max98088_cdata { }; struct max98088_priv { - enum max98088_type devtype; - struct max98088_pdata *pdata; - unsigned int sysclk; - struct max98088_cdata dai[2]; - int eq_textcnt; - const char **eq_texts; - struct soc_enum eq_enum; - u8 ina_state; - u8 inb_state; - unsigned int ex_mode; - unsigned int digmic; - unsigned int mic1pre; - unsigned int mic2pre; - unsigned int extmic_mode; + struct regmap *regmap; + enum max98088_type devtype; + struct max98088_pdata *pdata; + unsigned int sysclk; + struct max98088_cdata dai[2]; + int eq_textcnt; + const char **eq_texts; + struct soc_enum eq_enum; + u8 ina_state; + u8 inb_state; + unsigned int ex_mode; + unsigned int digmic; + unsigned int mic1pre; + unsigned int mic2pre; + unsigned int extmic_mode; }; -static const u8 max98088_reg[M98088_REG_CNT] = { - 0x00, /* 00 IRQ status */ - 0x00, /* 01 MIC status */ - 0x00, /* 02 jack status */ - 0x00, /* 03 battery voltage */ - 0x00, /* 04 */ - 0x00, /* 05 */ - 0x00, /* 06 */ - 0x00, /* 07 */ - 0x00, /* 08 */ - 0x00, /* 09 */ - 0x00, /* 0A */ - 0x00, /* 0B */ - 0x00, /* 0C */ - 0x00, /* 0D */ - 0x00, /* 0E */ - 0x00, /* 0F interrupt enable */ - - 0x00, /* 10 master clock */ - 0x00, /* 11 DAI1 clock mode */ - 0x00, /* 12 DAI1 clock control */ - 0x00, /* 13 DAI1 clock control */ - 0x00, /* 14 DAI1 format */ - 0x00, /* 15 DAI1 clock */ - 0x00, /* 16 DAI1 config */ - 0x00, /* 17 DAI1 TDM */ - 0x00, /* 18 DAI1 filters */ - 0x00, /* 19 DAI2 clock mode */ - 0x00, /* 1A DAI2 clock control */ - 0x00, /* 1B DAI2 clock control */ - 0x00, /* 1C DAI2 format */ - 0x00, /* 1D DAI2 clock */ - 0x00, /* 1E DAI2 config */ - 0x00, /* 1F DAI2 TDM */ - - 0x00, /* 20 DAI2 filters */ - 0x00, /* 21 data config */ - 0x00, /* 22 DAC mixer */ - 0x00, /* 23 left ADC mixer */ - 0x00, /* 24 right ADC mixer */ - 0x00, /* 25 left HP mixer */ - 0x00, /* 26 right HP mixer */ - 0x00, /* 27 HP control */ - 0x00, /* 28 left REC mixer */ - 0x00, /* 29 right REC mixer */ - 0x00, /* 2A REC control */ - 0x00, /* 2B left SPK mixer */ - 0x00, /* 2C right SPK mixer */ - 0x00, /* 2D SPK control */ - 0x00, /* 2E sidetone */ - 0x00, /* 2F DAI1 playback level */ - - 0x00, /* 30 DAI1 playback level */ - 0x00, /* 31 DAI2 playback level */ - 0x00, /* 32 DAI2 playbakc level */ - 0x00, /* 33 left ADC level */ - 0x00, /* 34 right ADC level */ - 0x00, /* 35 MIC1 level */ - 0x00, /* 36 MIC2 level */ - 0x00, /* 37 INA level */ - 0x00, /* 38 INB level */ - 0x00, /* 39 left HP volume */ - 0x00, /* 3A right HP volume */ - 0x00, /* 3B left REC volume */ - 0x00, /* 3C right REC volume */ - 0x00, /* 3D left SPK volume */ - 0x00, /* 3E right SPK volume */ - 0x00, /* 3F MIC config */ - - 0x00, /* 40 MIC threshold */ - 0x00, /* 41 excursion limiter filter */ - 0x00, /* 42 excursion limiter threshold */ - 0x00, /* 43 ALC */ - 0x00, /* 44 power limiter threshold */ - 0x00, /* 45 power limiter config */ - 0x00, /* 46 distortion limiter config */ - 0x00, /* 47 audio input */ - 0x00, /* 48 microphone */ - 0x00, /* 49 level control */ - 0x00, /* 4A bypass switches */ - 0x00, /* 4B jack detect */ - 0x00, /* 4C input enable */ - 0x00, /* 4D output enable */ - 0xF0, /* 4E bias control */ - 0x00, /* 4F DAC power */ - - 0x0F, /* 50 DAC power */ - 0x00, /* 51 system */ - 0x00, /* 52 DAI1 EQ1 */ - 0x00, /* 53 DAI1 EQ1 */ - 0x00, /* 54 DAI1 EQ1 */ - 0x00, /* 55 DAI1 EQ1 */ - 0x00, /* 56 DAI1 EQ1 */ - 0x00, /* 57 DAI1 EQ1 */ - 0x00, /* 58 DAI1 EQ1 */ - 0x00, /* 59 DAI1 EQ1 */ - 0x00, /* 5A DAI1 EQ1 */ - 0x00, /* 5B DAI1 EQ1 */ - 0x00, /* 5C DAI1 EQ2 */ - 0x00, /* 5D DAI1 EQ2 */ - 0x00, /* 5E DAI1 EQ2 */ - 0x00, /* 5F DAI1 EQ2 */ - - 0x00, /* 60 DAI1 EQ2 */ - 0x00, /* 61 DAI1 EQ2 */ - 0x00, /* 62 DAI1 EQ2 */ - 0x00, /* 63 DAI1 EQ2 */ - 0x00, /* 64 DAI1 EQ2 */ - 0x00, /* 65 DAI1 EQ2 */ - 0x00, /* 66 DAI1 EQ3 */ - 0x00, /* 67 DAI1 EQ3 */ - 0x00, /* 68 DAI1 EQ3 */ - 0x00, /* 69 DAI1 EQ3 */ - 0x00, /* 6A DAI1 EQ3 */ - 0x00, /* 6B DAI1 EQ3 */ - 0x00, /* 6C DAI1 EQ3 */ - 0x00, /* 6D DAI1 EQ3 */ - 0x00, /* 6E DAI1 EQ3 */ - 0x00, /* 6F DAI1 EQ3 */ - - 0x00, /* 70 DAI1 EQ4 */ - 0x00, /* 71 DAI1 EQ4 */ - 0x00, /* 72 DAI1 EQ4 */ - 0x00, /* 73 DAI1 EQ4 */ - 0x00, /* 74 DAI1 EQ4 */ - 0x00, /* 75 DAI1 EQ4 */ - 0x00, /* 76 DAI1 EQ4 */ - 0x00, /* 77 DAI1 EQ4 */ - 0x00, /* 78 DAI1 EQ4 */ - 0x00, /* 79 DAI1 EQ4 */ - 0x00, /* 7A DAI1 EQ5 */ - 0x00, /* 7B DAI1 EQ5 */ - 0x00, /* 7C DAI1 EQ5 */ - 0x00, /* 7D DAI1 EQ5 */ - 0x00, /* 7E DAI1 EQ5 */ - 0x00, /* 7F DAI1 EQ5 */ - - 0x00, /* 80 DAI1 EQ5 */ - 0x00, /* 81 DAI1 EQ5 */ - 0x00, /* 82 DAI1 EQ5 */ - 0x00, /* 83 DAI1 EQ5 */ - 0x00, /* 84 DAI2 EQ1 */ - 0x00, /* 85 DAI2 EQ1 */ - 0x00, /* 86 DAI2 EQ1 */ - 0x00, /* 87 DAI2 EQ1 */ - 0x00, /* 88 DAI2 EQ1 */ - 0x00, /* 89 DAI2 EQ1 */ - 0x00, /* 8A DAI2 EQ1 */ - 0x00, /* 8B DAI2 EQ1 */ - 0x00, /* 8C DAI2 EQ1 */ - 0x00, /* 8D DAI2 EQ1 */ - 0x00, /* 8E DAI2 EQ2 */ - 0x00, /* 8F DAI2 EQ2 */ - - 0x00, /* 90 DAI2 EQ2 */ - 0x00, /* 91 DAI2 EQ2 */ - 0x00, /* 92 DAI2 EQ2 */ - 0x00, /* 93 DAI2 EQ2 */ - 0x00, /* 94 DAI2 EQ2 */ - 0x00, /* 95 DAI2 EQ2 */ - 0x00, /* 96 DAI2 EQ2 */ - 0x00, /* 97 DAI2 EQ2 */ - 0x00, /* 98 DAI2 EQ3 */ - 0x00, /* 99 DAI2 EQ3 */ - 0x00, /* 9A DAI2 EQ3 */ - 0x00, /* 9B DAI2 EQ3 */ - 0x00, /* 9C DAI2 EQ3 */ - 0x00, /* 9D DAI2 EQ3 */ - 0x00, /* 9E DAI2 EQ3 */ - 0x00, /* 9F DAI2 EQ3 */ - - 0x00, /* A0 DAI2 EQ3 */ - 0x00, /* A1 DAI2 EQ3 */ - 0x00, /* A2 DAI2 EQ4 */ - 0x00, /* A3 DAI2 EQ4 */ - 0x00, /* A4 DAI2 EQ4 */ - 0x00, /* A5 DAI2 EQ4 */ - 0x00, /* A6 DAI2 EQ4 */ - 0x00, /* A7 DAI2 EQ4 */ - 0x00, /* A8 DAI2 EQ4 */ - 0x00, /* A9 DAI2 EQ4 */ - 0x00, /* AA DAI2 EQ4 */ - 0x00, /* AB DAI2 EQ4 */ - 0x00, /* AC DAI2 EQ5 */ - 0x00, /* AD DAI2 EQ5 */ - 0x00, /* AE DAI2 EQ5 */ - 0x00, /* AF DAI2 EQ5 */ - - 0x00, /* B0 DAI2 EQ5 */ - 0x00, /* B1 DAI2 EQ5 */ - 0x00, /* B2 DAI2 EQ5 */ - 0x00, /* B3 DAI2 EQ5 */ - 0x00, /* B4 DAI2 EQ5 */ - 0x00, /* B5 DAI2 EQ5 */ - 0x00, /* B6 DAI1 biquad */ - 0x00, /* B7 DAI1 biquad */ - 0x00, /* B8 DAI1 biquad */ - 0x00, /* B9 DAI1 biquad */ - 0x00, /* BA DAI1 biquad */ - 0x00, /* BB DAI1 biquad */ - 0x00, /* BC DAI1 biquad */ - 0x00, /* BD DAI1 biquad */ - 0x00, /* BE DAI1 biquad */ - 0x00, /* BF DAI1 biquad */ - - 0x00, /* C0 DAI2 biquad */ - 0x00, /* C1 DAI2 biquad */ - 0x00, /* C2 DAI2 biquad */ - 0x00, /* C3 DAI2 biquad */ - 0x00, /* C4 DAI2 biquad */ - 0x00, /* C5 DAI2 biquad */ - 0x00, /* C6 DAI2 biquad */ - 0x00, /* C7 DAI2 biquad */ - 0x00, /* C8 DAI2 biquad */ - 0x00, /* C9 DAI2 biquad */ - 0x00, /* CA */ - 0x00, /* CB */ - 0x00, /* CC */ - 0x00, /* CD */ - 0x00, /* CE */ - 0x00, /* CF */ - - 0x00, /* D0 */ - 0x00, /* D1 */ - 0x00, /* D2 */ - 0x00, /* D3 */ - 0x00, /* D4 */ - 0x00, /* D5 */ - 0x00, /* D6 */ - 0x00, /* D7 */ - 0x00, /* D8 */ - 0x00, /* D9 */ - 0x00, /* DA */ - 0x70, /* DB */ - 0x00, /* DC */ - 0x00, /* DD */ - 0x00, /* DE */ - 0x00, /* DF */ - - 0x00, /* E0 */ - 0x00, /* E1 */ - 0x00, /* E2 */ - 0x00, /* E3 */ - 0x00, /* E4 */ - 0x00, /* E5 */ - 0x00, /* E6 */ - 0x00, /* E7 */ - 0x00, /* E8 */ - 0x00, /* E9 */ - 0x00, /* EA */ - 0x00, /* EB */ - 0x00, /* EC */ - 0x00, /* ED */ - 0x00, /* EE */ - 0x00, /* EF */ - - 0x00, /* F0 */ - 0x00, /* F1 */ - 0x00, /* F2 */ - 0x00, /* F3 */ - 0x00, /* F4 */ - 0x00, /* F5 */ - 0x00, /* F6 */ - 0x00, /* F7 */ - 0x00, /* F8 */ - 0x00, /* F9 */ - 0x00, /* FA */ - 0x00, /* FB */ - 0x00, /* FC */ - 0x00, /* FD */ - 0x00, /* FE */ - 0x00, /* FF */ +static const struct reg_default max98088_reg[] = { + { 0xf, 0x00 }, /* 0F interrupt enable */ + + { 0x10, 0x00 }, /* 10 master clock */ + { 0x11, 0x00 }, /* 11 DAI1 clock mode */ + { 0x12, 0x00 }, /* 12 DAI1 clock control */ + { 0x13, 0x00 }, /* 13 DAI1 clock control */ + { 0x14, 0x00 }, /* 14 DAI1 format */ + { 0x15, 0x00 }, /* 15 DAI1 clock */ + { 0x16, 0x00 }, /* 16 DAI1 config */ + { 0x17, 0x00 }, /* 17 DAI1 TDM */ + { 0x18, 0x00 }, /* 18 DAI1 filters */ + { 0x19, 0x00 }, /* 19 DAI2 clock mode */ + { 0x1a, 0x00 }, /* 1A DAI2 clock control */ + { 0x1b, 0x00 }, /* 1B DAI2 clock control */ + { 0x1c, 0x00 }, /* 1C DAI2 format */ + { 0x1d, 0x00 }, /* 1D DAI2 clock */ + { 0x1e, 0x00 }, /* 1E DAI2 config */ + { 0x1f, 0x00 }, /* 1F DAI2 TDM */ + + { 0x20, 0x00 }, /* 20 DAI2 filters */ + { 0x21, 0x00 }, /* 21 data config */ + { 0x22, 0x00 }, /* 22 DAC mixer */ + { 0x23, 0x00 }, /* 23 left ADC mixer */ + { 0x24, 0x00 }, /* 24 right ADC mixer */ + { 0x25, 0x00 }, /* 25 left HP mixer */ + { 0x26, 0x00 }, /* 26 right HP mixer */ + { 0x27, 0x00 }, /* 27 HP control */ + { 0x28, 0x00 }, /* 28 left REC mixer */ + { 0x29, 0x00 }, /* 29 right REC mixer */ + { 0x2a, 0x00 }, /* 2A REC control */ + { 0x2b, 0x00 }, /* 2B left SPK mixer */ + { 0x2c, 0x00 }, /* 2C right SPK mixer */ + { 0x2d, 0x00 }, /* 2D SPK control */ + { 0x2e, 0x00 }, /* 2E sidetone */ + { 0x2f, 0x00 }, /* 2F DAI1 playback level */ + + { 0x30, 0x00 }, /* 30 DAI1 playback level */ + { 0x31, 0x00 }, /* 31 DAI2 playback level */ + { 0x32, 0x00 }, /* 32 DAI2 playbakc level */ + { 0x33, 0x00 }, /* 33 left ADC level */ + { 0x34, 0x00 }, /* 34 right ADC level */ + { 0x35, 0x00 }, /* 35 MIC1 level */ + { 0x36, 0x00 }, /* 36 MIC2 level */ + { 0x37, 0x00 }, /* 37 INA level */ + { 0x38, 0x00 }, /* 38 INB level */ + { 0x39, 0x00 }, /* 39 left HP volume */ + { 0x3a, 0x00 }, /* 3A right HP volume */ + { 0x3b, 0x00 }, /* 3B left REC volume */ + { 0x3c, 0x00 }, /* 3C right REC volume */ + { 0x3d, 0x00 }, /* 3D left SPK volume */ + { 0x3e, 0x00 }, /* 3E right SPK volume */ + { 0x3f, 0x00 }, /* 3F MIC config */ + + { 0x40, 0x00 }, /* 40 MIC threshold */ + { 0x41, 0x00 }, /* 41 excursion limiter filter */ + { 0x42, 0x00 }, /* 42 excursion limiter threshold */ + { 0x43, 0x00 }, /* 43 ALC */ + { 0x44, 0x00 }, /* 44 power limiter threshold */ + { 0x45, 0x00 }, /* 45 power limiter config */ + { 0x46, 0x00 }, /* 46 distortion limiter config */ + { 0x47, 0x00 }, /* 47 audio input */ + { 0x48, 0x00 }, /* 48 microphone */ + { 0x49, 0x00 }, /* 49 level control */ + { 0x4a, 0x00 }, /* 4A bypass switches */ + { 0x4b, 0x00 }, /* 4B jack detect */ + { 0x4c, 0x00 }, /* 4C input enable */ + { 0x4d, 0x00 }, /* 4D output enable */ + { 0x4e, 0xF0 }, /* 4E bias control */ + { 0x4f, 0x00 }, /* 4F DAC power */ + + { 0x50, 0x0F }, /* 50 DAC power */ + { 0x51, 0x00 }, /* 51 system */ + { 0x52, 0x00 }, /* 52 DAI1 EQ1 */ + { 0x53, 0x00 }, /* 53 DAI1 EQ1 */ + { 0x54, 0x00 }, /* 54 DAI1 EQ1 */ + { 0x55, 0x00 }, /* 55 DAI1 EQ1 */ + { 0x56, 0x00 }, /* 56 DAI1 EQ1 */ + { 0x57, 0x00 }, /* 57 DAI1 EQ1 */ + { 0x58, 0x00 }, /* 58 DAI1 EQ1 */ + { 0x59, 0x00 }, /* 59 DAI1 EQ1 */ + { 0x5a, 0x00 }, /* 5A DAI1 EQ1 */ + { 0x5b, 0x00 }, /* 5B DAI1 EQ1 */ + { 0x5c, 0x00 }, /* 5C DAI1 EQ2 */ + { 0x5d, 0x00 }, /* 5D DAI1 EQ2 */ + { 0x5e, 0x00 }, /* 5E DAI1 EQ2 */ + { 0x5f, 0x00 }, /* 5F DAI1 EQ2 */ + + { 0x60, 0x00 }, /* 60 DAI1 EQ2 */ + { 0x61, 0x00 }, /* 61 DAI1 EQ2 */ + { 0x62, 0x00 }, /* 62 DAI1 EQ2 */ + { 0x63, 0x00 }, /* 63 DAI1 EQ2 */ + { 0x64, 0x00 }, /* 64 DAI1 EQ2 */ + { 0x65, 0x00 }, /* 65 DAI1 EQ2 */ + { 0x66, 0x00 }, /* 66 DAI1 EQ3 */ + { 0x67, 0x00 }, /* 67 DAI1 EQ3 */ + { 0x68, 0x00 }, /* 68 DAI1 EQ3 */ + { 0x69, 0x00 }, /* 69 DAI1 EQ3 */ + { 0x6a, 0x00 }, /* 6A DAI1 EQ3 */ + { 0x6b, 0x00 }, /* 6B DAI1 EQ3 */ + { 0x6c, 0x00 }, /* 6C DAI1 EQ3 */ + { 0x6d, 0x00 }, /* 6D DAI1 EQ3 */ + { 0x6e, 0x00 }, /* 6E DAI1 EQ3 */ + { 0x6f, 0x00 }, /* 6F DAI1 EQ3 */ + + { 0x70, 0x00 }, /* 70 DAI1 EQ4 */ + { 0x71, 0x00 }, /* 71 DAI1 EQ4 */ + { 0x72, 0x00 }, /* 72 DAI1 EQ4 */ + { 0x73, 0x00 }, /* 73 DAI1 EQ4 */ + { 0x74, 0x00 }, /* 74 DAI1 EQ4 */ + { 0x75, 0x00 }, /* 75 DAI1 EQ4 */ + { 0x76, 0x00 }, /* 76 DAI1 EQ4 */ + { 0x77, 0x00 }, /* 77 DAI1 EQ4 */ + { 0x78, 0x00 }, /* 78 DAI1 EQ4 */ + { 0x79, 0x00 }, /* 79 DAI1 EQ4 */ + { 0x7a, 0x00 }, /* 7A DAI1 EQ5 */ + { 0x7b, 0x00 }, /* 7B DAI1 EQ5 */ + { 0x7c, 0x00 }, /* 7C DAI1 EQ5 */ + { 0x7d, 0x00 }, /* 7D DAI1 EQ5 */ + { 0x7e, 0x00 }, /* 7E DAI1 EQ5 */ + { 0x7f, 0x00 }, /* 7F DAI1 EQ5 */ + + { 0x80, 0x00 }, /* 80 DAI1 EQ5 */ + { 0x81, 0x00 }, /* 81 DAI1 EQ5 */ + { 0x82, 0x00 }, /* 82 DAI1 EQ5 */ + { 0x83, 0x00 }, /* 83 DAI1 EQ5 */ + { 0x84, 0x00 }, /* 84 DAI2 EQ1 */ + { 0x85, 0x00 }, /* 85 DAI2 EQ1 */ + { 0x86, 0x00 }, /* 86 DAI2 EQ1 */ + { 0x87, 0x00 }, /* 87 DAI2 EQ1 */ + { 0x88, 0x00 }, /* 88 DAI2 EQ1 */ + { 0x89, 0x00 }, /* 89 DAI2 EQ1 */ + { 0x8a, 0x00 }, /* 8A DAI2 EQ1 */ + { 0x8b, 0x00 }, /* 8B DAI2 EQ1 */ + { 0x8c, 0x00 }, /* 8C DAI2 EQ1 */ + { 0x8d, 0x00 }, /* 8D DAI2 EQ1 */ + { 0x8e, 0x00 }, /* 8E DAI2 EQ2 */ + { 0x8f, 0x00 }, /* 8F DAI2 EQ2 */ + + { 0x90, 0x00 }, /* 90 DAI2 EQ2 */ + { 0x91, 0x00 }, /* 91 DAI2 EQ2 */ + { 0x92, 0x00 }, /* 92 DAI2 EQ2 */ + { 0x93, 0x00 }, /* 93 DAI2 EQ2 */ + { 0x94, 0x00 }, /* 94 DAI2 EQ2 */ + { 0x95, 0x00 }, /* 95 DAI2 EQ2 */ + { 0x96, 0x00 }, /* 96 DAI2 EQ2 */ + { 0x97, 0x00 }, /* 97 DAI2 EQ2 */ + { 0x98, 0x00 }, /* 98 DAI2 EQ3 */ + { 0x99, 0x00 }, /* 99 DAI2 EQ3 */ + { 0x9a, 0x00 }, /* 9A DAI2 EQ3 */ + { 0x9b, 0x00 }, /* 9B DAI2 EQ3 */ + { 0x9c, 0x00 }, /* 9C DAI2 EQ3 */ + { 0x9d, 0x00 }, /* 9D DAI2 EQ3 */ + { 0x9e, 0x00 }, /* 9E DAI2 EQ3 */ + { 0x9f, 0x00 }, /* 9F DAI2 EQ3 */ + + { 0xa0, 0x00 }, /* A0 DAI2 EQ3 */ + { 0xa1, 0x00 }, /* A1 DAI2 EQ3 */ + { 0xa2, 0x00 }, /* A2 DAI2 EQ4 */ + { 0xa3, 0x00 }, /* A3 DAI2 EQ4 */ + { 0xa4, 0x00 }, /* A4 DAI2 EQ4 */ + { 0xa5, 0x00 }, /* A5 DAI2 EQ4 */ + { 0xa6, 0x00 }, /* A6 DAI2 EQ4 */ + { 0xa7, 0x00 }, /* A7 DAI2 EQ4 */ + { 0xa8, 0x00 }, /* A8 DAI2 EQ4 */ + { 0xa9, 0x00 }, /* A9 DAI2 EQ4 */ + { 0xaa, 0x00 }, /* AA DAI2 EQ4 */ + { 0xab, 0x00 }, /* AB DAI2 EQ4 */ + { 0xac, 0x00 }, /* AC DAI2 EQ5 */ + { 0xad, 0x00 }, /* AD DAI2 EQ5 */ + { 0xae, 0x00 }, /* AE DAI2 EQ5 */ + { 0xaf, 0x00 }, /* AF DAI2 EQ5 */ + + { 0xb0, 0x00 }, /* B0 DAI2 EQ5 */ + { 0xb1, 0x00 }, /* B1 DAI2 EQ5 */ + { 0xb2, 0x00 }, /* B2 DAI2 EQ5 */ + { 0xb3, 0x00 }, /* B3 DAI2 EQ5 */ + { 0xb4, 0x00 }, /* B4 DAI2 EQ5 */ + { 0xb5, 0x00 }, /* B5 DAI2 EQ5 */ + { 0xb6, 0x00 }, /* B6 DAI1 biquad */ + { 0xb7, 0x00 }, /* B7 DAI1 biquad */ + { 0xb8 ,0x00 }, /* B8 DAI1 biquad */ + { 0xb9, 0x00 }, /* B9 DAI1 biquad */ + { 0xba, 0x00 }, /* BA DAI1 biquad */ + { 0xbb, 0x00 }, /* BB DAI1 biquad */ + { 0xbc, 0x00 }, /* BC DAI1 biquad */ + { 0xbd, 0x00 }, /* BD DAI1 biquad */ + { 0xbe, 0x00 }, /* BE DAI1 biquad */ + { 0xbf, 0x00 }, /* BF DAI1 biquad */ + + { 0xc0, 0x00 }, /* C0 DAI2 biquad */ + { 0xc1, 0x00 }, /* C1 DAI2 biquad */ + { 0xc2, 0x00 }, /* C2 DAI2 biquad */ + { 0xc3, 0x00 }, /* C3 DAI2 biquad */ + { 0xc4, 0x00 }, /* C4 DAI2 biquad */ + { 0xc5, 0x00 }, /* C5 DAI2 biquad */ + { 0xc6, 0x00 }, /* C6 DAI2 biquad */ + { 0xc7, 0x00 }, /* C7 DAI2 biquad */ + { 0xc8, 0x00 }, /* C8 DAI2 biquad */ + { 0xc9, 0x00 }, /* C9 DAI2 biquad */ }; static struct { @@ -606,11 +536,28 @@ static struct { { 0xFF, 0x00, 1 }, /* FF */ }; -static int max98088_volatile_register(struct snd_soc_codec *codec, unsigned int reg) +static bool max98088_readable_register(struct device *dev, unsigned int reg) +{ + return max98088_access[reg].readable; +} + +static bool max98088_volatile_register(struct device *dev, unsigned int reg) { return max98088_access[reg].vol; } +static const struct regmap_config max98088_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .readable_reg = max98088_readable_register, + .volatile_reg = max98088_volatile_register, + .max_register = 0xff, + + .reg_defaults = max98088_reg, + .num_reg_defaults = ARRAY_SIZE(max98088_reg), + .cache_type = REGCACHE_RBTREE, +}; /* * Load equalizer DSP coefficient configurations registers @@ -1610,58 +1557,34 @@ static int max98088_dai2_digital_mute(struct snd_soc_dai *codec_dai, int mute) return 0; } -static void max98088_sync_cache(struct snd_soc_codec *codec) -{ - u8 *reg_cache = codec->reg_cache; - int i; - - if (!codec->cache_sync) - return; - - codec->cache_only = 0; - - /* write back cached values if they're writeable and - * different from the hardware default. - */ - for (i = 1; i < codec->driver->reg_cache_size; i++) { - if (!max98088_access[i].writable) - continue; - - if (reg_cache[i] == max98088_reg[i]) - continue; - - snd_soc_write(codec, i, reg_cache[i]); - } - - codec->cache_sync = 0; -} - static int max98088_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - switch (level) { - case SND_SOC_BIAS_ON: - break; - - case SND_SOC_BIAS_PREPARE: - break; - - case SND_SOC_BIAS_STANDBY: - if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) - max98088_sync_cache(codec); - - snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN, - M98088_MBEN, M98088_MBEN); - break; - - case SND_SOC_BIAS_OFF: - snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN, - M98088_MBEN, 0); - codec->cache_sync = 1; - break; - } - codec->dapm.bias_level = level; - return 0; + struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); + + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) + regcache_sync(max98088->regmap); + + snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN, + M98088_MBEN, M98088_MBEN); + break; + + case SND_SOC_BIAS_OFF: + snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN, + M98088_MBEN, 0); + regcache_mark_dirty(max98088->regmap); + break; + } + codec->dapm.bias_level = level; + return 0; } #define MAX98088_RATES SNDRV_PCM_RATE_8000_96000 @@ -1988,9 +1911,9 @@ static int max98088_probe(struct snd_soc_codec *codec) struct max98088_cdata *cdata; int ret = 0; - codec->cache_sync = 1; + regcache_mark_dirty(max98088->regmap); - ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); + 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; @@ -2048,9 +1971,6 @@ static int max98088_probe(struct snd_soc_codec *codec) max98088_handle_pdata(codec); - snd_soc_add_codec_controls(codec, max98088_snd_controls, - ARRAY_SIZE(max98088_snd_controls)); - err_access: return ret; } @@ -2066,15 +1986,13 @@ static int max98088_remove(struct snd_soc_codec *codec) } static struct snd_soc_codec_driver soc_codec_dev_max98088 = { - .probe = max98088_probe, - .remove = max98088_remove, - .suspend = max98088_suspend, - .resume = max98088_resume, - .set_bias_level = max98088_set_bias_level, - .reg_cache_size = ARRAY_SIZE(max98088_reg), - .reg_word_size = sizeof(u8), - .reg_cache_default = max98088_reg, - .volatile_register = max98088_volatile_register, + .probe = max98088_probe, + .remove = max98088_remove, + .suspend = max98088_suspend, + .resume = max98088_resume, + .set_bias_level = max98088_set_bias_level, + .controls = max98088_snd_controls, + .num_controls = ARRAY_SIZE(max98088_snd_controls), .dapm_widgets = max98088_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(max98088_dapm_widgets), .dapm_routes = max98088_audio_map, @@ -2082,7 +2000,7 @@ static struct snd_soc_codec_driver soc_codec_dev_max98088 = { }; static int max98088_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { struct max98088_priv *max98088; int ret; @@ -2092,6 +2010,10 @@ static int max98088_i2c_probe(struct i2c_client *i2c, if (max98088 == NULL) return -ENOMEM; + max98088->regmap = devm_regmap_init_i2c(i2c, &max98088_regmap); + if (IS_ERR(max98088->regmap)) + return PTR_ERR(max98088->regmap); + max98088->devtype = id->driver_data; i2c_set_clientdata(i2c, max98088); diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 8dbcacd44e6a..8fb072455802 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -39,6 +39,7 @@ struct max98095_cdata { }; struct max98095_priv { + struct regmap *regmap; enum max98095_type devtype; struct max98095_pdata *pdata; unsigned int sysclk; @@ -56,263 +57,145 @@ struct max98095_priv { struct snd_soc_jack *mic_jack; }; -static const u8 max98095_reg_def[M98095_REG_CNT] = { - 0x00, /* 00 */ - 0x00, /* 01 */ - 0x00, /* 02 */ - 0x00, /* 03 */ - 0x00, /* 04 */ - 0x00, /* 05 */ - 0x00, /* 06 */ - 0x00, /* 07 */ - 0x00, /* 08 */ - 0x00, /* 09 */ - 0x00, /* 0A */ - 0x00, /* 0B */ - 0x00, /* 0C */ - 0x00, /* 0D */ - 0x00, /* 0E */ - 0x00, /* 0F */ - 0x00, /* 10 */ - 0x00, /* 11 */ - 0x00, /* 12 */ - 0x00, /* 13 */ - 0x00, /* 14 */ - 0x00, /* 15 */ - 0x00, /* 16 */ - 0x00, /* 17 */ - 0x00, /* 18 */ - 0x00, /* 19 */ - 0x00, /* 1A */ - 0x00, /* 1B */ - 0x00, /* 1C */ - 0x00, /* 1D */ - 0x00, /* 1E */ - 0x00, /* 1F */ - 0x00, /* 20 */ - 0x00, /* 21 */ - 0x00, /* 22 */ - 0x00, /* 23 */ - 0x00, /* 24 */ - 0x00, /* 25 */ - 0x00, /* 26 */ - 0x00, /* 27 */ - 0x00, /* 28 */ - 0x00, /* 29 */ - 0x00, /* 2A */ - 0x00, /* 2B */ - 0x00, /* 2C */ - 0x00, /* 2D */ - 0x00, /* 2E */ - 0x00, /* 2F */ - 0x00, /* 30 */ - 0x00, /* 31 */ - 0x00, /* 32 */ - 0x00, /* 33 */ - 0x00, /* 34 */ - 0x00, /* 35 */ - 0x00, /* 36 */ - 0x00, /* 37 */ - 0x00, /* 38 */ - 0x00, /* 39 */ - 0x00, /* 3A */ - 0x00, /* 3B */ - 0x00, /* 3C */ - 0x00, /* 3D */ - 0x00, /* 3E */ - 0x00, /* 3F */ - 0x00, /* 40 */ - 0x00, /* 41 */ - 0x00, /* 42 */ - 0x00, /* 43 */ - 0x00, /* 44 */ - 0x00, /* 45 */ - 0x00, /* 46 */ - 0x00, /* 47 */ - 0x00, /* 48 */ - 0x00, /* 49 */ - 0x00, /* 4A */ - 0x00, /* 4B */ - 0x00, /* 4C */ - 0x00, /* 4D */ - 0x00, /* 4E */ - 0x00, /* 4F */ - 0x00, /* 50 */ - 0x00, /* 51 */ - 0x00, /* 52 */ - 0x00, /* 53 */ - 0x00, /* 54 */ - 0x00, /* 55 */ - 0x00, /* 56 */ - 0x00, /* 57 */ - 0x00, /* 58 */ - 0x00, /* 59 */ - 0x00, /* 5A */ - 0x00, /* 5B */ - 0x00, /* 5C */ - 0x00, /* 5D */ - 0x00, /* 5E */ - 0x00, /* 5F */ - 0x00, /* 60 */ - 0x00, /* 61 */ - 0x00, /* 62 */ - 0x00, /* 63 */ - 0x00, /* 64 */ - 0x00, /* 65 */ - 0x00, /* 66 */ - 0x00, /* 67 */ - 0x00, /* 68 */ - 0x00, /* 69 */ - 0x00, /* 6A */ - 0x00, /* 6B */ - 0x00, /* 6C */ - 0x00, /* 6D */ - 0x00, /* 6E */ - 0x00, /* 6F */ - 0x00, /* 70 */ - 0x00, /* 71 */ - 0x00, /* 72 */ - 0x00, /* 73 */ - 0x00, /* 74 */ - 0x00, /* 75 */ - 0x00, /* 76 */ - 0x00, /* 77 */ - 0x00, /* 78 */ - 0x00, /* 79 */ - 0x00, /* 7A */ - 0x00, /* 7B */ - 0x00, /* 7C */ - 0x00, /* 7D */ - 0x00, /* 7E */ - 0x00, /* 7F */ - 0x00, /* 80 */ - 0x00, /* 81 */ - 0x00, /* 82 */ - 0x00, /* 83 */ - 0x00, /* 84 */ - 0x00, /* 85 */ - 0x00, /* 86 */ - 0x00, /* 87 */ - 0x00, /* 88 */ - 0x00, /* 89 */ - 0x00, /* 8A */ - 0x00, /* 8B */ - 0x00, /* 8C */ - 0x00, /* 8D */ - 0x00, /* 8E */ - 0x00, /* 8F */ - 0x00, /* 90 */ - 0x00, /* 91 */ - 0x30, /* 92 */ - 0xF0, /* 93 */ - 0x00, /* 94 */ - 0x00, /* 95 */ - 0x3F, /* 96 */ - 0x00, /* 97 */ - 0x00, /* 98 */ - 0x00, /* 99 */ - 0x00, /* 9A */ - 0x00, /* 9B */ - 0x00, /* 9C */ - 0x00, /* 9D */ - 0x00, /* 9E */ - 0x00, /* 9F */ - 0x00, /* A0 */ - 0x00, /* A1 */ - 0x00, /* A2 */ - 0x00, /* A3 */ - 0x00, /* A4 */ - 0x00, /* A5 */ - 0x00, /* A6 */ - 0x00, /* A7 */ - 0x00, /* A8 */ - 0x00, /* A9 */ - 0x00, /* AA */ - 0x00, /* AB */ - 0x00, /* AC */ - 0x00, /* AD */ - 0x00, /* AE */ - 0x00, /* AF */ - 0x00, /* B0 */ - 0x00, /* B1 */ - 0x00, /* B2 */ - 0x00, /* B3 */ - 0x00, /* B4 */ - 0x00, /* B5 */ - 0x00, /* B6 */ - 0x00, /* B7 */ - 0x00, /* B8 */ - 0x00, /* B9 */ - 0x00, /* BA */ - 0x00, /* BB */ - 0x00, /* BC */ - 0x00, /* BD */ - 0x00, /* BE */ - 0x00, /* BF */ - 0x00, /* C0 */ - 0x00, /* C1 */ - 0x00, /* C2 */ - 0x00, /* C3 */ - 0x00, /* C4 */ - 0x00, /* C5 */ - 0x00, /* C6 */ - 0x00, /* C7 */ - 0x00, /* C8 */ - 0x00, /* C9 */ - 0x00, /* CA */ - 0x00, /* CB */ - 0x00, /* CC */ - 0x00, /* CD */ - 0x00, /* CE */ - 0x00, /* CF */ - 0x00, /* D0 */ - 0x00, /* D1 */ - 0x00, /* D2 */ - 0x00, /* D3 */ - 0x00, /* D4 */ - 0x00, /* D5 */ - 0x00, /* D6 */ - 0x00, /* D7 */ - 0x00, /* D8 */ - 0x00, /* D9 */ - 0x00, /* DA */ - 0x00, /* DB */ - 0x00, /* DC */ - 0x00, /* DD */ - 0x00, /* DE */ - 0x00, /* DF */ - 0x00, /* E0 */ - 0x00, /* E1 */ - 0x00, /* E2 */ - 0x00, /* E3 */ - 0x00, /* E4 */ - 0x00, /* E5 */ - 0x00, /* E6 */ - 0x00, /* E7 */ - 0x00, /* E8 */ - 0x00, /* E9 */ - 0x00, /* EA */ - 0x00, /* EB */ - 0x00, /* EC */ - 0x00, /* ED */ - 0x00, /* EE */ - 0x00, /* EF */ - 0x00, /* F0 */ - 0x00, /* F1 */ - 0x00, /* F2 */ - 0x00, /* F3 */ - 0x00, /* F4 */ - 0x00, /* F5 */ - 0x00, /* F6 */ - 0x00, /* F7 */ - 0x00, /* F8 */ - 0x00, /* F9 */ - 0x00, /* FA */ - 0x00, /* FB */ - 0x00, /* FC */ - 0x00, /* FD */ - 0x00, /* FE */ - 0x00, /* FF */ +static const struct reg_default max98095_reg_def[] = { + { 0xf, 0x00 }, /* 0F */ + { 0x10, 0x00 }, /* 10 */ + { 0x11, 0x00 }, /* 11 */ + { 0x12, 0x00 }, /* 12 */ + { 0x13, 0x00 }, /* 13 */ + { 0x14, 0x00 }, /* 14 */ + { 0x15, 0x00 }, /* 15 */ + { 0x16, 0x00 }, /* 16 */ + { 0x17, 0x00 }, /* 17 */ + { 0x18, 0x00 }, /* 18 */ + { 0x19, 0x00 }, /* 19 */ + { 0x1a, 0x00 }, /* 1A */ + { 0x1b, 0x00 }, /* 1B */ + { 0x1c, 0x00 }, /* 1C */ + { 0x1d, 0x00 }, /* 1D */ + { 0x1e, 0x00 }, /* 1E */ + { 0x1f, 0x00 }, /* 1F */ + { 0x20, 0x00 }, /* 20 */ + { 0x21, 0x00 }, /* 21 */ + { 0x22, 0x00 }, /* 22 */ + { 0x23, 0x00 }, /* 23 */ + { 0x24, 0x00 }, /* 24 */ + { 0x25, 0x00 }, /* 25 */ + { 0x26, 0x00 }, /* 26 */ + { 0x27, 0x00 }, /* 27 */ + { 0x28, 0x00 }, /* 28 */ + { 0x29, 0x00 }, /* 29 */ + { 0x2a, 0x00 }, /* 2A */ + { 0x2b, 0x00 }, /* 2B */ + { 0x2c, 0x00 }, /* 2C */ + { 0x2d, 0x00 }, /* 2D */ + { 0x2e, 0x00 }, /* 2E */ + { 0x2f, 0x00 }, /* 2F */ + { 0x30, 0x00 }, /* 30 */ + { 0x31, 0x00 }, /* 31 */ + { 0x32, 0x00 }, /* 32 */ + { 0x33, 0x00 }, /* 33 */ + { 0x34, 0x00 }, /* 34 */ + { 0x35, 0x00 }, /* 35 */ + { 0x36, 0x00 }, /* 36 */ + { 0x37, 0x00 }, /* 37 */ + { 0x38, 0x00 }, /* 38 */ + { 0x39, 0x00 }, /* 39 */ + { 0x3a, 0x00 }, /* 3A */ + { 0x3b, 0x00 }, /* 3B */ + { 0x3c, 0x00 }, /* 3C */ + { 0x3d, 0x00 }, /* 3D */ + { 0x3e, 0x00 }, /* 3E */ + { 0x3f, 0x00 }, /* 3F */ + { 0x40, 0x00 }, /* 40 */ + { 0x41, 0x00 }, /* 41 */ + { 0x42, 0x00 }, /* 42 */ + { 0x43, 0x00 }, /* 43 */ + { 0x44, 0x00 }, /* 44 */ + { 0x45, 0x00 }, /* 45 */ + { 0x46, 0x00 }, /* 46 */ + { 0x47, 0x00 }, /* 47 */ + { 0x48, 0x00 }, /* 48 */ + { 0x49, 0x00 }, /* 49 */ + { 0x4a, 0x00 }, /* 4A */ + { 0x4b, 0x00 }, /* 4B */ + { 0x4c, 0x00 }, /* 4C */ + { 0x4d, 0x00 }, /* 4D */ + { 0x4e, 0x00 }, /* 4E */ + { 0x4f, 0x00 }, /* 4F */ + { 0x50, 0x00 }, /* 50 */ + { 0x51, 0x00 }, /* 51 */ + { 0x52, 0x00 }, /* 52 */ + { 0x53, 0x00 }, /* 53 */ + { 0x54, 0x00 }, /* 54 */ + { 0x55, 0x00 }, /* 55 */ + { 0x56, 0x00 }, /* 56 */ + { 0x57, 0x00 }, /* 57 */ + { 0x58, 0x00 }, /* 58 */ + { 0x59, 0x00 }, /* 59 */ + { 0x5a, 0x00 }, /* 5A */ + { 0x5b, 0x00 }, /* 5B */ + { 0x5c, 0x00 }, /* 5C */ + { 0x5d, 0x00 }, /* 5D */ + { 0x5e, 0x00 }, /* 5E */ + { 0x5f, 0x00 }, /* 5F */ + { 0x60, 0x00 }, /* 60 */ + { 0x61, 0x00 }, /* 61 */ + { 0x62, 0x00 }, /* 62 */ + { 0x63, 0x00 }, /* 63 */ + { 0x64, 0x00 }, /* 64 */ + { 0x65, 0x00 }, /* 65 */ + { 0x66, 0x00 }, /* 66 */ + { 0x67, 0x00 }, /* 67 */ + { 0x68, 0x00 }, /* 68 */ + { 0x69, 0x00 }, /* 69 */ + { 0x6a, 0x00 }, /* 6A */ + { 0x6b, 0x00 }, /* 6B */ + { 0x6c, 0x00 }, /* 6C */ + { 0x6d, 0x00 }, /* 6D */ + { 0x6e, 0x00 }, /* 6E */ + { 0x6f, 0x00 }, /* 6F */ + { 0x70, 0x00 }, /* 70 */ + { 0x71, 0x00 }, /* 71 */ + { 0x72, 0x00 }, /* 72 */ + { 0x73, 0x00 }, /* 73 */ + { 0x74, 0x00 }, /* 74 */ + { 0x75, 0x00 }, /* 75 */ + { 0x76, 0x00 }, /* 76 */ + { 0x77, 0x00 }, /* 77 */ + { 0x78, 0x00 }, /* 78 */ + { 0x79, 0x00 }, /* 79 */ + { 0x7a, 0x00 }, /* 7A */ + { 0x7b, 0x00 }, /* 7B */ + { 0x7c, 0x00 }, /* 7C */ + { 0x7d, 0x00 }, /* 7D */ + { 0x7e, 0x00 }, /* 7E */ + { 0x7f, 0x00 }, /* 7F */ + { 0x80, 0x00 }, /* 80 */ + { 0x81, 0x00 }, /* 81 */ + { 0x82, 0x00 }, /* 82 */ + { 0x83, 0x00 }, /* 83 */ + { 0x84, 0x00 }, /* 84 */ + { 0x85, 0x00 }, /* 85 */ + { 0x86, 0x00 }, /* 86 */ + { 0x87, 0x00 }, /* 87 */ + { 0x88, 0x00 }, /* 88 */ + { 0x89, 0x00 }, /* 89 */ + { 0x8a, 0x00 }, /* 8A */ + { 0x8b, 0x00 }, /* 8B */ + { 0x8c, 0x00 }, /* 8C */ + { 0x8d, 0x00 }, /* 8D */ + { 0x8e, 0x00 }, /* 8E */ + { 0x8f, 0x00 }, /* 8F */ + { 0x90, 0x00 }, /* 90 */ + { 0x91, 0x00 }, /* 91 */ + { 0x92, 0x30 }, /* 92 */ + { 0x93, 0xF0 }, /* 93 */ + { 0x94, 0x00 }, /* 94 */ + { 0x95, 0x00 }, /* 95 */ + { 0x96, 0x3F }, /* 96 */ + { 0x97, 0x00 }, /* 97 */ + { 0xff, 0x00 }, /* FF */ }; static struct { @@ -577,14 +460,14 @@ static struct { { 0xFF, 0x00 }, /* FF */ }; -static int max98095_readable(struct snd_soc_codec *codec, unsigned int reg) +static bool max98095_readable(struct device *dev, unsigned int reg) { if (reg >= M98095_REG_CNT) return 0; return max98095_access[reg].readable != 0; } -static int max98095_volatile(struct snd_soc_codec *codec, unsigned int reg) +static bool max98095_volatile(struct device *dev, unsigned int reg) { if (reg > M98095_REG_MAX_CACHED) return 1; @@ -611,22 +494,18 @@ static int max98095_volatile(struct snd_soc_codec *codec, unsigned int reg) return 0; } -/* - * Filter coefficients are in a separate register segment - * and they share the address space of the normal registers. - * The coefficient registers do not need or share the cache. - */ -static int max98095_hw_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - int ret; +static const struct regmap_config max98095_regmap = { + .reg_bits = 8, + .val_bits = 8, - codec->cache_bypass = 1; - ret = snd_soc_write(codec, reg, value); - codec->cache_bypass = 0; + .reg_defaults = max98095_reg_def, + .num_reg_defaults = ARRAY_SIZE(max98095_reg_def), + .max_register = M98095_0FF_REV_ID, + .cache_type = REGCACHE_RBTREE, - return ret ? -EIO : 0; -} + .readable_reg = max98095_readable, + .volatile_reg = max98095_volatile, +}; /* * Load equalizer DSP coefficient configurations registers @@ -648,8 +527,8 @@ static void m98095_eq_band(struct snd_soc_codec *codec, unsigned int dai, /* Step through the registers and coefs */ for (i = 0; i < M98095_COEFS_PER_BAND; i++) { - max98095_hw_write(codec, eq_reg++, M98095_BYTE1(coefs[i])); - max98095_hw_write(codec, eq_reg++, M98095_BYTE0(coefs[i])); + snd_soc_write(codec, eq_reg++, M98095_BYTE1(coefs[i])); + snd_soc_write(codec, eq_reg++, M98095_BYTE0(coefs[i])); } } @@ -673,8 +552,8 @@ static void m98095_biquad_band(struct snd_soc_codec *codec, unsigned int dai, /* Step through the registers and coefs */ for (i = 0; i < M98095_COEFS_PER_BAND; i++) { - max98095_hw_write(codec, bq_reg++, M98095_BYTE1(coefs[i])); - max98095_hw_write(codec, bq_reg++, M98095_BYTE0(coefs[i])); + snd_soc_write(codec, bq_reg++, M98095_BYTE1(coefs[i])); + snd_soc_write(codec, bq_reg++, M98095_BYTE0(coefs[i])); } } @@ -1285,14 +1164,6 @@ static const struct snd_soc_dapm_route max98095_audio_map[] = { {"MIC2 Input", NULL, "MIC2"}, }; -static int max98095_add_widgets(struct snd_soc_codec *codec) -{ - snd_soc_add_codec_controls(codec, max98095_snd_controls, - ARRAY_SIZE(max98095_snd_controls)); - - return 0; -} - /* codec mclk clock divider coefficients */ static const struct { u32 rate; @@ -1748,6 +1619,7 @@ static int max98095_dai3_set_fmt(struct snd_soc_dai *codec_dai, static int max98095_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); int ret; switch (level) { @@ -1759,7 +1631,7 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_STANDBY: if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { - ret = snd_soc_cache_sync(codec); + ret = regcache_sync(max98095->regmap); if (ret != 0) { dev_err(codec->dev, "Failed to sync cache: %d\n", ret); @@ -1774,7 +1646,7 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_OFF: snd_soc_update_bits(codec, M98095_090_PWR_EN_IN, M98095_MBEN, 0); - codec->cache_sync = 1; + regcache_mark_dirty(max98095->regmap); break; } codec->dapm.bias_level = level; @@ -2341,7 +2213,7 @@ static int max98095_reset(struct snd_soc_codec *codec) /* Reset to hardware default for registers, as there is not * a soft reset hardware control register */ for (i = M98095_010_HOST_INT_CFG; i < M98095_REG_MAX_CACHED; i++) { - ret = snd_soc_write(codec, i, max98095_reg_def[i]); + ret = snd_soc_write(codec, i, snd_soc_read(codec, i)); if (ret < 0) { dev_err(codec->dev, "Failed to reset: %d\n", ret); return ret; @@ -2358,7 +2230,7 @@ static int max98095_probe(struct snd_soc_codec *codec) struct i2c_client *client; int ret = 0; - ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); + 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; @@ -2447,8 +2319,6 @@ static int max98095_probe(struct snd_soc_codec *codec) snd_soc_update_bits(codec, M98095_097_PWR_SYS, M98095_SHDNRUN, M98095_SHDNRUN); - max98095_add_widgets(codec); - return 0; err_irq: @@ -2480,11 +2350,8 @@ static struct snd_soc_codec_driver soc_codec_dev_max98095 = { .suspend = max98095_suspend, .resume = max98095_resume, .set_bias_level = max98095_set_bias_level, - .reg_cache_size = ARRAY_SIZE(max98095_reg_def), - .reg_word_size = sizeof(u8), - .reg_cache_default = max98095_reg_def, - .readable_register = max98095_readable, - .volatile_register = max98095_volatile, + .controls = max98095_snd_controls, + .num_controls = ARRAY_SIZE(max98095_snd_controls), .dapm_widgets = max98095_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(max98095_dapm_widgets), .dapm_routes = max98095_audio_map, @@ -2502,6 +2369,13 @@ static int max98095_i2c_probe(struct i2c_client *i2c, if (max98095 == NULL) return -ENOMEM; + max98095->regmap = devm_regmap_init_i2c(i2c, &max98095_regmap); + if (IS_ERR(max98095->regmap)) { + ret = PTR_ERR(max98095->regmap); + dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); + return ret; + } + max98095->devtype = id->driver_data; i2c_set_clientdata(i2c, max98095); max98095->pdata = i2c->dev.platform_data; diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index 58c38a5b481c..c5dd61785f8d 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c @@ -18,6 +18,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/i2c.h> +#include <linux/regmap.h> #include <linux/slab.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -27,18 +28,26 @@ #include "max9850.h" struct max9850_priv { + struct regmap *regmap; unsigned int sysclk; }; /* max9850 register cache */ -static const u8 max9850_reg[MAX9850_CACHEREGNUM] = { - 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +static const struct reg_default max9850_reg[] = { + { 2, 0x0c }, + { 3, 0x00 }, + { 4, 0x00 }, + { 5, 0x00 }, + { 6, 0x00 }, + { 7, 0x00 }, + { 8, 0x00 }, + { 9, 0x00 }, + { 10, 0x00 }, }; /* these registers are not used at the moment but provided for the sake of * completeness */ -static int max9850_volatile_register(struct snd_soc_codec *codec, - unsigned int reg) +static bool max9850_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { case MAX9850_STATUSA: @@ -49,6 +58,15 @@ static int max9850_volatile_register(struct snd_soc_codec *codec, } } +static const struct regmap_config max9850_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = MAX9850_DIGITAL_AUDIO, + .volatile_reg = max9850_volatile_register, + .cache_type = REGCACHE_RBTREE, +}; + static const unsigned int max9850_tlv[] = { TLV_DB_RANGE_HEAD(4), 0x18, 0x1f, TLV_DB_SCALE_ITEM(-7450, 400, 0), @@ -225,6 +243,7 @@ static int max9850_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) static int max9850_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct max9850_priv *max9850 = snd_soc_codec_get_drvdata(codec); int ret; switch (level) { @@ -234,7 +253,7 @@ static int max9850_set_bias_level(struct snd_soc_codec *codec, break; case SND_SOC_BIAS_STANDBY: if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { - ret = snd_soc_cache_sync(codec); + ret = regcache_sync(max9850->regmap); if (ret) { dev_err(codec->dev, "Failed to sync cache: %d\n", ret); @@ -295,7 +314,7 @@ static int max9850_probe(struct snd_soc_codec *codec) { int ret; - ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); + 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; @@ -316,10 +335,6 @@ static struct snd_soc_codec_driver soc_codec_dev_max9850 = { .suspend = max9850_suspend, .resume = max9850_resume, .set_bias_level = max9850_set_bias_level, - .reg_cache_size = ARRAY_SIZE(max9850_reg), - .reg_word_size = sizeof(u8), - .reg_cache_default = max9850_reg, - .volatile_register = max9850_volatile_register, .controls = max9850_controls, .num_controls = ARRAY_SIZE(max9850_controls), @@ -340,6 +355,10 @@ static int max9850_i2c_probe(struct i2c_client *i2c, if (max9850 == NULL) return -ENOMEM; + max9850->regmap = devm_regmap_init_i2c(i2c, &max9850_regmap); + if (IS_ERR(max9850->regmap)) + return PTR_ERR(max9850->regmap); + i2c_set_clientdata(i2c, max9850); ret = snd_soc_register_codec(&i2c->dev, diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index ea141e1d6f28..f5472adee674 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -30,16 +30,10 @@ #include <sound/soc.h> #include <sound/initval.h> #include <sound/soc-dapm.h> +#include <linux/regmap.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) @@ -95,45 +89,12 @@ struct mc13783_priv { struct mc13xxx *mc13xxx; + struct regmap *regmap; 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); - - /* include errata fix for spi audio problems */ - if (reg == MC13783_AUDIO_CODEC || reg == MC13783_AUDIO_DAC) - 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, @@ -466,6 +427,29 @@ static const struct snd_kcontrol_new right_input_mux = static const struct snd_kcontrol_new samp_ctl = SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 3, 1, 0); +static const char * const speaker_amp_source_text[] = { + "CODEC", "Right" +}; +static const SOC_ENUM_SINGLE_DECL(speaker_amp_source, MC13783_AUDIO_RX0, 4, + speaker_amp_source_text); +static const struct snd_kcontrol_new speaker_amp_source_mux = + SOC_DAPM_ENUM("Speaker Amp Source MUX", speaker_amp_source); + +static const char * const headset_amp_source_text[] = { + "CODEC", "Mixer" +}; + +static const SOC_ENUM_SINGLE_DECL(headset_amp_source, MC13783_AUDIO_RX0, 11, + headset_amp_source_text); +static const struct snd_kcontrol_new headset_amp_source_mux = + SOC_DAPM_ENUM("Headset Amp Source MUX", headset_amp_source); + +static const struct snd_kcontrol_new cdcout_ctl = + SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 18, 1, 0); + +static const struct snd_kcontrol_new adc_bypass_ctl = + SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_CODEC, 16, 1, 0); + static const struct snd_kcontrol_new lamp_ctl = SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 5, 1, 0); @@ -503,12 +487,22 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = { SND_SOC_DAPM_VIRT_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0, &right_input_mux), + SND_SOC_DAPM_MUX("Speaker Amp Source MUX", SND_SOC_NOPM, 0, 0, + &speaker_amp_source_mux), + + SND_SOC_DAPM_MUX("Headset Amp Source MUX", SND_SOC_NOPM, 0, 0, + &headset_amp_source_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", MC13783_AUDIO_CODEC, 11, 0), SND_SOC_DAPM_SUPPLY("ADC_Reset", MC13783_AUDIO_CODEC, 15, 0, NULL, 0), + SND_SOC_DAPM_PGA("Voice CODEC PGA", MC13783_AUDIO_RX1, 0, 0, NULL, 0), + SND_SOC_DAPM_SWITCH("Voice CODEC Bypass", MC13783_AUDIO_CODEC, 16, 0, + &adc_bypass_ctl), + /* Output */ SND_SOC_DAPM_SUPPLY("DAC_E", MC13783_AUDIO_DAC, 11, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("DAC_Reset", MC13783_AUDIO_DAC, 15, 0, NULL, 0), @@ -516,10 +510,15 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("RXOUTR"), SND_SOC_DAPM_OUTPUT("HSL"), SND_SOC_DAPM_OUTPUT("HSR"), + SND_SOC_DAPM_OUTPUT("LSPL"), SND_SOC_DAPM_OUTPUT("LSP"), SND_SOC_DAPM_OUTPUT("SP"), + SND_SOC_DAPM_OUTPUT("CDCOUT"), - SND_SOC_DAPM_SWITCH("Speaker Amp", MC13783_AUDIO_RX0, 3, 0, &samp_ctl), + SND_SOC_DAPM_SWITCH("CDCOUT Switch", MC13783_AUDIO_RX0, 18, 0, + &cdcout_ctl), + SND_SOC_DAPM_SWITCH("Speaker Amp Switch", MC13783_AUDIO_RX0, 3, 0, + &samp_ctl), SND_SOC_DAPM_SWITCH("Loudspeaker Amp", SND_SOC_NOPM, 0, 0, &lamp_ctl), SND_SOC_DAPM_SWITCH("Headset Amp Left", MC13783_AUDIO_RX0, 10, 0, &hlamp_ctl), @@ -554,20 +553,28 @@ static struct snd_soc_dapm_route mc13783_routes[] = { { "ADC", NULL, "PGA Right Input"}, { "ADC", NULL, "ADC_Reset"}, + { "Voice CODEC PGA", "Voice CODEC Bypass", "ADC" }, + + { "Speaker Amp Source MUX", "CODEC", "Voice CODEC PGA"}, + { "Speaker Amp Source MUX", "Right", "DAC PGA"}, + + { "Headset Amp Source MUX", "CODEC", "Voice CODEC PGA"}, + { "Headset Amp Source MUX", "Mixer", "DAC PGA"}, + /* 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"}, + { "SP", "Speaker Amp Switch", "Speaker Amp Source MUX"}, + { "LSP", "Loudspeaker Amp", "Speaker Amp Source MUX"}, + { "HSL", "Headset Amp Left", "Headset Amp Source MUX"}, + { "HSR", "Headset Amp Right", "Headset Amp Source MUX"}, { "Line out Amp Left", NULL, "DAC PGA"}, { "Line out Amp Right", NULL, "DAC PGA"}, { "DAC PGA", NULL, "DAC"}, { "DAC", NULL, "DAC_E"}, + { "CDCOUT", "CDCOUT Switch", "Voice CODEC PGA"}, }; static const char * const mc13783_3d_mixer[] = {"Stereo", "Phase Mix", @@ -580,15 +587,39 @@ static const struct soc_enum mc13783_enum_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_SINGLE("PCM Playback Switch", MC13783_AUDIO_RX1, 5, 1, 0), SOC_DOUBLE("PCM Capture Volume", MC13783_AUDIO_TX, 19, 14, 31, 0), SOC_ENUM("3D Control", mc13783_enum_3d_mixer), + + SOC_SINGLE("CDCOUT Switch", MC13783_AUDIO_RX0, 18, 1, 0), + SOC_SINGLE("Earpiece Amp Switch", MC13783_AUDIO_RX0, 3, 1, 0), + SOC_DOUBLE("Headset Amp Switch", MC13783_AUDIO_RX0, 10, 9, 1, 0), + SOC_DOUBLE("Line out Amp Switch", MC13783_AUDIO_RX0, 16, 15, 1, 0), + + SOC_SINGLE("PCM Capture Mixin Switch", MC13783_AUDIO_RX0, 22, 1, 0), + SOC_SINGLE("Line in Capture Mixin Switch", MC13783_AUDIO_RX0, 23, 1, 0), + + SOC_SINGLE("CODEC Capture Volume", MC13783_AUDIO_RX1, 1, 15, 0), + SOC_SINGLE("CODEC Capture Mixin Switch", MC13783_AUDIO_RX0, 21, 1, 0), + + SOC_SINGLE("Line in Capture Volume", MC13783_AUDIO_RX1, 12, 15, 0), + SOC_SINGLE("Line in Capture Switch", MC13783_AUDIO_RX1, 10, 1, 0), + + SOC_SINGLE("MC1 Capture Bias Switch", MC13783_AUDIO_TX, 0, 1, 0), + SOC_SINGLE("MC2 Capture Bias Switch", MC13783_AUDIO_TX, 1, 1, 0), }; static int mc13783_probe(struct snd_soc_codec *codec) { struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec); + int ret; - mc13xxx_lock(priv->mc13xxx); + codec->control_data = dev_get_regmap(codec->dev->parent, NULL); + ret = snd_soc_codec_set_cache_io(codec, 8, 24, SND_SOC_REGMAP); + if (ret != 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + return ret; + } /* these are the reset values */ mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX0, 0x25893); @@ -612,8 +643,6 @@ static int mc13783_probe(struct snd_soc_codec *codec) mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC, 0, AUDIO_SSI_SEL); - mc13xxx_unlock(priv->mc13xxx); - return 0; } @@ -621,13 +650,9 @@ 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; } @@ -717,8 +742,6 @@ static struct snd_soc_dai_driver mc13783_dai_sync[] = { 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, diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index 54ea15b87bfc..73f9c3630e2c 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -271,7 +271,7 @@ MODULE_DEVICE_TABLE(of, pcm1681_dt_ids); static const struct regmap_config pcm1681_regmap = { .reg_bits = 8, .val_bits = 8, - .max_register = ARRAY_SIZE(pcm1681_reg_defaults) + 1, + .max_register = 0x13, .reg_defaults = pcm1681_reg_defaults, .num_reg_defaults = ARRAY_SIZE(pcm1681_reg_defaults), .writeable_reg = pcm1681_writeable_reg, diff --git a/sound/soc/codecs/pcm1792a.c b/sound/soc/codecs/pcm1792a.c index 2a8eccf64c76..7613181123fe 100644 --- a/sound/soc/codecs/pcm1792a.c +++ b/sound/soc/codecs/pcm1792a.c @@ -188,7 +188,7 @@ MODULE_DEVICE_TABLE(of, pcm1792a_of_match); static const struct regmap_config pcm1792a_regmap = { .reg_bits = 8, .val_bits = 8, - .max_register = 24, + .max_register = 23, .reg_defaults = pcm1792a_reg_defaults, .num_reg_defaults = ARRAY_SIZE(pcm1792a_reg_defaults), .writeable_reg = pcm1792a_writeable_reg, diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 6e3f269243e0..64ad84d8a306 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -674,6 +674,8 @@ static const struct snd_soc_dapm_route intercon[] = { /* Left Input */ {"Left Line1L Mux", "single-ended", "LINE1L"}, {"Left Line1L Mux", "differential", "LINE1L"}, + {"Left Line1R Mux", "single-ended", "LINE1R"}, + {"Left Line1R Mux", "differential", "LINE1R"}, {"Left Line2L Mux", "single-ended", "LINE2L"}, {"Left Line2L Mux", "differential", "LINE2L"}, @@ -690,6 +692,8 @@ static const struct snd_soc_dapm_route intercon[] = { /* Right Input */ {"Right Line1R Mux", "single-ended", "LINE1R"}, {"Right Line1R Mux", "differential", "LINE1R"}, + {"Right Line1L Mux", "single-ended", "LINE1L"}, + {"Right Line1L Mux", "differential", "LINE1L"}, {"Right Line2R Mux", "single-ended", "LINE2R"}, {"Right Line2R Mux", "differential", "LINE2R"}, diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index c82f89c9475b..95970f5db3ec 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig @@ -1,9 +1,10 @@ config SND_DAVINCI_SOC - tristate "SoC Audio for the TI DAVINCI chip" - depends on ARCH_DAVINCI + tristate "SoC Audio for the TI DAVINCI or AM33XX chip" + depends on ARCH_DAVINCI || SOC_AM33XX help + Platform driver for daVinci or AM33xx Say Y or M if you want to add support for codecs attached to - the DAVINCI AC97 or I2S interface. You will also need + the DAVINCI AC97, I2S, or McASP interface. You will also need to select the audio interfaces to support below. config SND_DAVINCI_SOC_I2S @@ -15,6 +16,17 @@ config SND_DAVINCI_SOC_MCASP config SND_DAVINCI_SOC_VCIF tristate +config SND_AM33XX_SOC_EVM + tristate "SoC Audio for the AM33XX chip based boards" + depends on SND_DAVINCI_SOC && SOC_AM33XX + select SND_SOC_TLV320AIC3X + select SND_DAVINCI_SOC_MCASP + help + Say Y or M if you want to add support for SoC audio on AM33XX + boards using McASP and TLV320AIC3X codec. For example AM335X-EVM, + AM335X-EVMSK, and BeagelBone with AudioCape boards have this + setup. + config SND_DAVINCI_SOC_EVM tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM" depends on SND_DAVINCI_SOC diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile index a396ab6d6d5e..bc81e79fc301 100644 --- a/sound/soc/davinci/Makefile +++ b/sound/soc/davinci/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o snd-soc-evm-objs := davinci-evm.o obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o +obj-$(CONFIG_SND_AM33XX_SOC_EVM) += snd-soc-evm.o obj-$(CONFIG_SND_DM6467_SOC_EVM) += snd-soc-evm.o obj-$(CONFIG_SND_DA830_SOC_EVM) += snd-soc-evm.o obj-$(CONFIG_SND_DA850_SOC_EVM) += snd-soc-evm.o diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index fd7c45b9ed5a..623eb5e7c089 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -16,6 +16,7 @@ #include <linux/platform_device.h> #include <linux/platform_data/edma.h> #include <linux/i2c.h> +#include <linux/of_platform.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/soc.h> @@ -23,10 +24,16 @@ #include <asm/dma.h> #include <asm/mach-types.h> +#include <linux/edma.h> + #include "davinci-pcm.h" #include "davinci-i2s.h" #include "davinci-mcasp.h" +struct snd_soc_card_drvdata_davinci { + unsigned sysclk; +}; + #define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \ SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF) static int evm_hw_params(struct snd_pcm_substream *substream, @@ -35,27 +42,11 @@ static int evm_hw_params(struct snd_pcm_substream *substream, 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; + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_card *soc_card = codec->card; int ret = 0; - unsigned sysclk; - - /* ASP1 on DM355 EVM is clocked by an external oscillator */ - if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm() || - machine_is_davinci_dm365_evm()) - sysclk = 27000000; - - /* ASP0 in DM6446 EVM is clocked by U55, as configured by - * board-dm644x-evm.c using GPIOs from U18. There are six - * options; here we "know" we use a 48 KHz sample rate. - */ - else if (machine_is_davinci_evm()) - sysclk = 12288000; - - else if (machine_is_davinci_da830_evm() || - machine_is_davinci_da850_evm()) - sysclk = 24576000; - - else - return -EINVAL; + unsigned sysclk = ((struct snd_soc_card_drvdata_davinci *) + snd_soc_card_get_drvdata(soc_card))->sysclk; /* set codec DAI configuration */ ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT); @@ -133,13 +124,22 @@ static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; struct snd_soc_dapm_context *dapm = &codec->dapm; + struct device_node *np = codec->card->dev->of_node; + int ret; /* Add davinci-evm specific widgets */ snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets, ARRAY_SIZE(aic3x_dapm_widgets)); - /* Set up davinci-evm specific audio path audio_map */ - snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); + if (np) { + ret = snd_soc_of_parse_audio_routing(codec->card, + "ti,audio-routing"); + if (ret) + return ret; + } else { + /* Set up davinci-evm specific audio path audio_map */ + snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); + } /* not connected */ snd_soc_dapm_disable_pin(dapm, "MONO_LOUT"); @@ -243,35 +243,65 @@ static struct snd_soc_dai_link da850_evm_dai = { }; /* davinci dm6446 evm audio machine driver */ +/* + * ASP0 in DM6446 EVM is clocked by U55, as configured by + * board-dm644x-evm.c using GPIOs from U18. There are six + * options; here we "know" we use a 48 KHz sample rate. + */ +static struct snd_soc_card_drvdata_davinci dm6446_snd_soc_card_drvdata = { + .sysclk = 12288000, +}; + static struct snd_soc_card dm6446_snd_soc_card_evm = { .name = "DaVinci DM6446 EVM", .owner = THIS_MODULE, .dai_link = &dm6446_evm_dai, .num_links = 1, + .drvdata = &dm6446_snd_soc_card_drvdata, }; /* davinci dm355 evm audio machine driver */ +/* ASP1 on DM355 EVM is clocked by an external oscillator */ +static struct snd_soc_card_drvdata_davinci dm355_snd_soc_card_drvdata = { + .sysclk = 27000000, +}; + static struct snd_soc_card dm355_snd_soc_card_evm = { .name = "DaVinci DM355 EVM", .owner = THIS_MODULE, .dai_link = &dm355_evm_dai, .num_links = 1, + .drvdata = &dm355_snd_soc_card_drvdata, }; /* davinci dm365 evm audio machine driver */ +static struct snd_soc_card_drvdata_davinci dm365_snd_soc_card_drvdata = { + .sysclk = 27000000, +}; + static struct snd_soc_card dm365_snd_soc_card_evm = { .name = "DaVinci DM365 EVM", .owner = THIS_MODULE, .dai_link = &dm365_evm_dai, .num_links = 1, + .drvdata = &dm365_snd_soc_card_drvdata, }; /* davinci dm6467 evm audio machine driver */ +static struct snd_soc_card_drvdata_davinci dm6467_snd_soc_card_drvdata = { + .sysclk = 27000000, +}; + static struct snd_soc_card dm6467_snd_soc_card_evm = { .name = "DaVinci DM6467 EVM", .owner = THIS_MODULE, .dai_link = dm6467_evm_dai, .num_links = ARRAY_SIZE(dm6467_evm_dai), + .drvdata = &dm6467_snd_soc_card_drvdata, +}; + +static struct snd_soc_card_drvdata_davinci da830_snd_soc_card_drvdata = { + .sysclk = 24576000, }; static struct snd_soc_card da830_snd_soc_card = { @@ -279,6 +309,11 @@ static struct snd_soc_card da830_snd_soc_card = { .owner = THIS_MODULE, .dai_link = &da830_evm_dai, .num_links = 1, + .drvdata = &da830_snd_soc_card_drvdata, +}; + +static struct snd_soc_card_drvdata_davinci da850_snd_soc_card_drvdata = { + .sysclk = 24576000, }; static struct snd_soc_card da850_snd_soc_card = { @@ -286,8 +321,101 @@ static struct snd_soc_card da850_snd_soc_card = { .owner = THIS_MODULE, .dai_link = &da850_evm_dai, .num_links = 1, + .drvdata = &da850_snd_soc_card_drvdata, +}; + +#if defined(CONFIG_OF) + +/* + * The struct is used as place holder. It will be completely + * filled with data from dt node. + */ +static struct snd_soc_dai_link evm_dai_tlv320aic3x = { + .name = "TLV320AIC3X", + .stream_name = "AIC3X", + .codec_dai_name = "tlv320aic3x-hifi", + .ops = &evm_ops, + .init = evm_aic3x_init, +}; + +static const struct of_device_id davinci_evm_dt_ids[] = { + { + .compatible = "ti,da830-evm-audio", + .data = (void *) &evm_dai_tlv320aic3x, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, davinci_evm_dt_ids); + +/* davinci evm audio machine driver */ +static struct snd_soc_card evm_soc_card = { + .owner = THIS_MODULE, + .num_links = 1, }; +static int davinci_evm_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match = + of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev); + struct snd_soc_dai_link *dai = (struct snd_soc_dai_link *) match->data; + struct snd_soc_card_drvdata_davinci *drvdata = NULL; + int ret = 0; + + evm_soc_card.dai_link = dai; + + dai->codec_of_node = of_parse_phandle(np, "ti,audio-codec", 0); + if (!dai->codec_of_node) + return -EINVAL; + + dai->cpu_of_node = of_parse_phandle(np, "ti,mcasp-controller", 0); + if (!dai->cpu_of_node) + return -EINVAL; + + dai->platform_of_node = dai->cpu_of_node; + + evm_soc_card.dev = &pdev->dev; + ret = snd_soc_of_parse_card_name(&evm_soc_card, "ti,model"); + if (ret) + return ret; + + drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk); + if (ret < 0) + return -EINVAL; + + snd_soc_card_set_drvdata(&evm_soc_card, drvdata); + ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card); + + if (ret) + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + + return ret; +} + +static int davinci_evm_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + snd_soc_unregister_card(card); + + return 0; +} + +static struct platform_driver davinci_evm_driver = { + .probe = davinci_evm_probe, + .remove = davinci_evm_remove, + .driver = { + .name = "davinci_evm", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(davinci_evm_dt_ids), + }, +}; +#endif + static struct platform_device *evm_snd_device; static int __init evm_init(void) @@ -296,6 +424,15 @@ static int __init evm_init(void) int index; int ret; + /* + * If dtb is there, the devices will be created dynamically. + * Only register platfrom driver structure. + */ +#if defined(CONFIG_OF) + if (of_have_populated_dt()) + return platform_driver_register(&davinci_evm_driver); +#endif + if (machine_is_davinci_evm()) { evm_snd_dev_data = &dm6446_snd_soc_card_evm; index = 0; @@ -331,6 +468,13 @@ static int __init evm_init(void) static void __exit evm_exit(void) { +#if defined(CONFIG_OF) + if (of_have_populated_dt()) { + platform_driver_unregister(&davinci_evm_driver); + return; + } +#endif + platform_device_unregister(evm_snd_device); } diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 32ddb7fe5034..71e14bb3a8cd 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1001,18 +1001,40 @@ static const struct snd_soc_component_driver davinci_mcasp_component = { .name = "davinci-mcasp", }; +/* Some HW specific values and defaults. The rest is filled in from DT. */ +static struct snd_platform_data dm646x_mcasp_pdata = { + .tx_dma_offset = 0x400, + .rx_dma_offset = 0x400, + .asp_chan_q = EVENTQ_0, + .version = MCASP_VERSION_1, +}; + +static struct snd_platform_data da830_mcasp_pdata = { + .tx_dma_offset = 0x2000, + .rx_dma_offset = 0x2000, + .asp_chan_q = EVENTQ_0, + .version = MCASP_VERSION_2, +}; + +static struct snd_platform_data omap2_mcasp_pdata = { + .tx_dma_offset = 0, + .rx_dma_offset = 0, + .asp_chan_q = EVENTQ_0, + .version = MCASP_VERSION_3, +}; + static const struct of_device_id mcasp_dt_ids[] = { { .compatible = "ti,dm646x-mcasp-audio", - .data = (void *)MCASP_VERSION_1, + .data = &dm646x_mcasp_pdata, }, { .compatible = "ti,da830-mcasp-audio", - .data = (void *)MCASP_VERSION_2, + .data = &da830_mcasp_pdata, }, { - .compatible = "ti,omap2-mcasp-audio", - .data = (void *)MCASP_VERSION_3, + .compatible = "ti,am33xx-mcasp-audio", + .data = &omap2_mcasp_pdata, }, { /* sentinel */ } }; @@ -1025,9 +1047,9 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( struct snd_platform_data *pdata = NULL; const struct of_device_id *match = of_match_device(mcasp_dt_ids, &pdev->dev); + struct of_phandle_args dma_spec; const u32 *of_serial_dir32; - u8 *of_serial_dir; u32 val; int i, ret = 0; @@ -1035,20 +1057,13 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( pdata = pdev->dev.platform_data; return pdata; } else if (match) { - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - ret = -ENOMEM; - goto nodata; - } + pdata = (struct snd_platform_data *) match->data; } else { /* control shouldn't reach here. something is wrong */ ret = -EINVAL; goto nodata; } - if (match->data) - pdata->version = (u8)((int)match->data); - ret = of_property_read_u32(np, "op-mode", &val); if (ret >= 0) pdata->op_mode = val; @@ -1065,35 +1080,46 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( pdata->tdm_slots = val; } - ret = of_property_read_u32(np, "num-serializer", &val); - if (ret >= 0) - pdata->num_serializer = val; - of_serial_dir32 = of_get_property(np, "serial-dir", &val); val /= sizeof(u32); - if (val != pdata->num_serializer) { - dev_err(&pdev->dev, - "num-serializer(%d) != serial-dir size(%d)\n", - pdata->num_serializer, val); - ret = -EINVAL; - goto nodata; - } - if (of_serial_dir32) { - of_serial_dir = devm_kzalloc(&pdev->dev, - (sizeof(*of_serial_dir) * val), - GFP_KERNEL); + u8 *of_serial_dir = devm_kzalloc(&pdev->dev, + (sizeof(*of_serial_dir) * val), + GFP_KERNEL); if (!of_serial_dir) { ret = -ENOMEM; goto nodata; } - for (i = 0; i < pdata->num_serializer; i++) + for (i = 0; i < val; i++) of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]); + pdata->num_serializer = val; pdata->serial_dir = of_serial_dir; } + ret = of_property_match_string(np, "dma-names", "tx"); + if (ret < 0) + goto nodata; + + ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret, + &dma_spec); + if (ret < 0) + goto nodata; + + pdata->tx_dma_channel = dma_spec.args[0]; + + ret = of_property_match_string(np, "dma-names", "rx"); + if (ret < 0) + goto nodata; + + ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret, + &dma_spec); + if (ret < 0) + goto nodata; + + pdata->rx_dma_channel = dma_spec.args[0]; + ret = of_property_read_u32(np, "tx-num-evt", &val); if (ret >= 0) pdata->txnumevt = val; @@ -1124,7 +1150,7 @@ nodata: static int davinci_mcasp_probe(struct platform_device *pdev) { struct davinci_pcm_dma_params *dma_data; - struct resource *mem, *ioarea, *res; + struct resource *mem, *ioarea, *res, *dat; struct snd_platform_data *pdata; struct davinci_audio_dev *dev; int ret; @@ -1145,10 +1171,15 @@ static int davinci_mcasp_probe(struct platform_device *pdev) return -EINVAL; } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); if (!mem) { - dev_err(&pdev->dev, "no mem resource?\n"); - return -ENODEV; + dev_warn(dev->dev, + "\"mpu\" mem resource not found, using index 0\n"); + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "no mem resource?\n"); + return -ENODEV; + } } ioarea = devm_request_mem_region(&pdev->dev, mem->start, @@ -1182,40 +1213,36 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dev->rxnumevt = pdata->rxnumevt; dev->dev = &pdev->dev; + dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); + if (!dat) + dat = mem; + dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]; dma_data->asp_chan_q = pdata->asp_chan_q; dma_data->ram_chan_q = pdata->ram_chan_q; dma_data->sram_pool = pdata->sram_pool; dma_data->sram_size = pdata->sram_size_playback; - dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset + - mem->start); + dma_data->dma_addr = dat->start + pdata->tx_dma_offset; - /* first TX, then RX */ res = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!res) { - dev_err(&pdev->dev, "no DMA resource\n"); - ret = -ENODEV; - goto err_release_clk; - } - - dma_data->channel = res->start; + if (res) + dma_data->channel = res->start; + else + dma_data->channel = pdata->tx_dma_channel; dma_data = &dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]; dma_data->asp_chan_q = pdata->asp_chan_q; dma_data->ram_chan_q = pdata->ram_chan_q; dma_data->sram_pool = pdata->sram_pool; dma_data->sram_size = pdata->sram_size_capture; - dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset + - mem->start); + dma_data->dma_addr = dat->start + pdata->rx_dma_offset; res = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (!res) { - dev_err(&pdev->dev, "no DMA resource\n"); - ret = -ENODEV; - goto err_release_clk; - } + if (res) + dma_data->channel = res->start; + else + dma_data->channel = pdata->rx_dma_channel; - dma_data->channel = res->start; dev_set_drvdata(&pdev->dev, dev); ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, &davinci_mcasp_dai[pdata->op_mode], 1); @@ -1251,12 +1278,51 @@ static int davinci_mcasp_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int davinci_mcasp_suspend(struct device *dev) +{ + struct davinci_audio_dev *a = dev_get_drvdata(dev); + void __iomem *base = a->base; + + a->context.txfmtctl = mcasp_get_reg(base + DAVINCI_MCASP_TXFMCTL_REG); + a->context.rxfmtctl = mcasp_get_reg(base + DAVINCI_MCASP_RXFMCTL_REG); + a->context.txfmt = mcasp_get_reg(base + DAVINCI_MCASP_TXFMT_REG); + a->context.rxfmt = mcasp_get_reg(base + DAVINCI_MCASP_RXFMT_REG); + a->context.aclkxctl = mcasp_get_reg(base + DAVINCI_MCASP_ACLKXCTL_REG); + a->context.aclkrctl = mcasp_get_reg(base + DAVINCI_MCASP_ACLKRCTL_REG); + a->context.pdir = mcasp_get_reg(base + DAVINCI_MCASP_PDIR_REG); + + return 0; +} + +static int davinci_mcasp_resume(struct device *dev) +{ + struct davinci_audio_dev *a = dev_get_drvdata(dev); + void __iomem *base = a->base; + + mcasp_set_reg(base + DAVINCI_MCASP_TXFMCTL_REG, a->context.txfmtctl); + mcasp_set_reg(base + DAVINCI_MCASP_RXFMCTL_REG, a->context.rxfmtctl); + mcasp_set_reg(base + DAVINCI_MCASP_TXFMT_REG, a->context.txfmt); + mcasp_set_reg(base + DAVINCI_MCASP_RXFMT_REG, a->context.rxfmt); + mcasp_set_reg(base + DAVINCI_MCASP_ACLKXCTL_REG, a->context.aclkxctl); + mcasp_set_reg(base + DAVINCI_MCASP_ACLKRCTL_REG, a->context.aclkrctl); + mcasp_set_reg(base + DAVINCI_MCASP_PDIR_REG, a->context.pdir); + + return 0; +} +#endif + +SIMPLE_DEV_PM_OPS(davinci_mcasp_pm_ops, + davinci_mcasp_suspend, + davinci_mcasp_resume); + static struct platform_driver davinci_mcasp_driver = { .probe = davinci_mcasp_probe, .remove = davinci_mcasp_remove, .driver = { .name = "davinci-mcasp", .owner = THIS_MODULE, + .pm = &davinci_mcasp_pm_ops, .of_match_table = mcasp_dt_ids, }, }; @@ -1266,4 +1332,3 @@ module_platform_driver(davinci_mcasp_driver); MODULE_AUTHOR("Steve Chen"); MODULE_DESCRIPTION("TI DAVINCI McASP SoC Interface"); MODULE_LICENSE("GPL"); - diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index a9ac0c11da71..a2e27e1c32f3 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h @@ -43,6 +43,18 @@ struct davinci_audio_dev { /* McASP FIFO related */ u8 txnumevt; u8 rxnumevt; + +#ifdef CONFIG_PM_SLEEP + struct { + u32 txfmtctl; + u32 rxfmtctl; + u32 txfmt; + u32 rxfmt; + u32 aclkxctl; + u32 aclkrctl; + u32 pdir; + } context; +#endif }; #endif /* DAVINCI_MCASP_H */ diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 3920c3e849ce..ff1f34766ee3 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -963,7 +963,7 @@ static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg) @@ -982,7 +982,7 @@ static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static const struct regmap_config fsl_spdif_regmap_config = { @@ -1172,23 +1172,16 @@ static int fsl_spdif_probe(struct platform_device *pdev) /* Register with ASoC */ dev_set_drvdata(&pdev->dev, spdif_priv); - ret = snd_soc_register_component(&pdev->dev, &fsl_spdif_component, - &spdif_priv->cpu_dai_drv, 1); + ret = devm_snd_soc_register_component(&pdev->dev, &fsl_spdif_component, + &spdif_priv->cpu_dai_drv, 1); if (ret) { dev_err(&pdev->dev, "failed to register DAI: %d\n", ret); return ret; } ret = imx_pcm_dma_init(pdev); - if (ret) { + if (ret) dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret); - goto error_component; - } - - return ret; - -error_component: - snd_soc_unregister_component(&pdev->dev); return ret; } @@ -1196,7 +1189,6 @@ error_component: static int fsl_spdif_remove(struct platform_device *pdev) { imx_pcm_dma_exit(pdev); - snd_soc_unregister_component(&pdev->dev); return 0; } diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index c6b743978d5e..35e277379b86 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -469,19 +469,12 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, * parameters, then the second stream may be * constrained to the wrong sample rate or size. */ - if (!first_runtime->sample_bits) { - dev_err(substream->pcm->card->dev, - "set sample size in %s stream first\n", - substream->stream == - SNDRV_PCM_STREAM_PLAYBACK - ? "capture" : "playback"); - return -EAGAIN; - } - - snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + if (first_runtime->sample_bits) { + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, first_runtime->sample_bits, first_runtime->sample_bits); + } } ssi_private->second_stream = substream; @@ -748,7 +741,7 @@ static void fsl_ssi_ac97_init(void) fsl_ssi_setup(fsl_ac97_data); } -void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, +static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) { struct ccsr_ssi *ssi = fsl_ac97_data->ssi; @@ -770,7 +763,7 @@ void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, udelay(100); } -unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97, +static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97, unsigned short reg) { struct ccsr_ssi *ssi = fsl_ac97_data->ssi; @@ -936,7 +929,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) ssi_private->ssi_phys = res.start; ssi_private->irq = irq_of_parse_and_map(np, 0); - if (ssi_private->irq == NO_IRQ) { + if (!ssi_private->irq) { dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); return -ENXIO; } @@ -1135,7 +1128,6 @@ static int fsl_ssi_remove(struct platform_device *pdev) if (ssi_private->ssi_on_imx) imx_pcm_dma_exit(pdev); snd_soc_unregister_component(&pdev->dev); - dev_set_drvdata(&pdev->dev, NULL); device_remove_file(&pdev->dev, &ssi_private->dev_attr); if (ssi_private->ssi_on_imx) clk_disable_unprepare(ssi_private->clk); diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index d3bf71a0ec56..ac869931d7f1 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c @@ -66,13 +66,10 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { ssize_t ret; - char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + char *buf; int port = (int)file->private_data; u32 pdcr, ptcr; - if (!buf) - return -ENOMEM; - if (audmux_clk) { ret = clk_prepare_enable(audmux_clk); if (ret) @@ -85,6 +82,10 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf, if (audmux_clk) clk_disable_unprepare(audmux_clk); + buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + ret = snprintf(buf, PAGE_SIZE, "PDCR: %08x\nPTCR: %08x\n", pdcr, ptcr); diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c index a3d60d4bea4c..79cee782dbbf 100644 --- a/sound/soc/fsl/imx-mc13783.c +++ b/sound/soc/fsl/imx-mc13783.c @@ -112,7 +112,7 @@ static int imx_mc13783_probe(struct platform_device *pdev) return ret; } - if (machine_is_mx31_3ds()) { + if (machine_is_mx31_3ds() || machine_is_mx31moboard()) { 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) | @@ -160,6 +160,7 @@ static struct platform_driver imx_mc13783_audio_driver = { .driver = { .name = "imx_mc13783", .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, }, .probe = imx_mc13783_probe, .remove = imx_mc13783_remove diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index 4dc1296688e9..aee23077080a 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c @@ -25,12 +25,10 @@ static bool filter(struct dma_chan *chan, void *param) { - struct snd_dmaengine_dai_dma_data *dma_data = param; - if (!imx_dma_is_general_purpose(chan)) return false; - chan->private = dma_data->filter_data; + chan->private = param; return true; } diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index ca1be1d9dcf0..f2beae78969f 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -159,7 +159,7 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) 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); + ret = devm_snd_soc_register_card(&pdev->dev, &data->card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); goto fail; @@ -186,7 +186,6 @@ static int imx_sgtl5000_remove(struct platform_device *pdev) { struct imx_sgtl5000_data *data = platform_get_drvdata(pdev); - snd_soc_unregister_card(&data->card); clk_put(data->codec_clk); return 0; @@ -202,6 +201,7 @@ static struct platform_driver imx_sgtl5000_driver = { .driver = { .name = "imx-sgtl5000", .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, .of_match_table = imx_sgtl5000_dt_ids, }, .probe = imx_sgtl5000_probe, diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c index 816013b0ebba..8499d5292f08 100644 --- a/sound/soc/fsl/imx-spdif.c +++ b/sound/soc/fsl/imx-spdif.c @@ -87,7 +87,7 @@ static int imx_spdif_audio_probe(struct platform_device *pdev) if (ret) goto error_dir; - ret = snd_soc_register_card(&data->card); + ret = devm_snd_soc_register_card(&pdev->dev, &data->card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed: %d\n", ret); goto error_dir; @@ -119,8 +119,6 @@ static int imx_spdif_audio_remove(struct platform_device *pdev) if (data->txdev) platform_device_unregister(data->txdev); - snd_soc_unregister_card(&data->card); - return 0; } diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c index f58bcd85c07f..f5f248c91c16 100644 --- a/sound/soc/fsl/imx-ssi.c +++ b/sound/soc/fsl/imx-ssi.c @@ -600,22 +600,19 @@ static int imx_ssi_probe(struct platform_device *pdev) ssi->fiq_params.dma_params_rx = &ssi->dma_params_rx; ssi->fiq_params.dma_params_tx = &ssi->dma_params_tx; - ret = imx_pcm_fiq_init(pdev, &ssi->fiq_params); - if (ret) - goto failed_pcm_fiq; + ssi->fiq_init = imx_pcm_fiq_init(pdev, &ssi->fiq_params); + ssi->dma_init = imx_pcm_dma_init(pdev); - ret = imx_pcm_dma_init(pdev); - if (ret) - goto failed_pcm_dma; + if (ssi->fiq_init && ssi->dma_init) { + ret = ssi->fiq_init; + goto failed_pcm; + } return 0; -failed_pcm_dma: - imx_pcm_fiq_exit(pdev); -failed_pcm_fiq: +failed_pcm: snd_soc_unregister_component(&pdev->dev); failed_register: - release_mem_region(res->start, resource_size(res)); clk_disable_unprepare(ssi->clk); failed_clk: snd_soc_set_ac97_ops(NULL); @@ -625,18 +622,19 @@ failed_clk: static int 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); - imx_pcm_dma_exit(pdev); - imx_pcm_fiq_exit(pdev); + if (!ssi->dma_init) + imx_pcm_dma_exit(pdev); + + if (!ssi->fiq_init) + imx_pcm_fiq_exit(pdev); snd_soc_unregister_component(&pdev->dev); if (ssi->flags & IMX_SSI_USE_AC97) ac97_ssi = NULL; - release_mem_region(res->start, resource_size(res)); clk_disable_unprepare(ssi->clk); snd_soc_set_ac97_ops(NULL); diff --git a/sound/soc/fsl/imx-ssi.h b/sound/soc/fsl/imx-ssi.h index fb1616ba8c59..560c40fc9ebb 100644 --- a/sound/soc/fsl/imx-ssi.h +++ b/sound/soc/fsl/imx-ssi.h @@ -211,6 +211,8 @@ struct imx_ssi { struct imx_dma_data filter_data_rx; struct imx_pcm_fiq_params fiq_params; + int fiq_init; + int dma_init; int enabled; }; diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c index 722afe69169e..72064e995687 100644 --- a/sound/soc/fsl/imx-wm8962.c +++ b/sound/soc/fsl/imx-wm8962.c @@ -266,7 +266,7 @@ static int imx_wm8962_probe(struct platform_device *pdev) data->card.late_probe = imx_wm8962_late_probe; data->card.set_bias_level = imx_wm8962_set_bias_level; - ret = snd_soc_register_card(&data->card); + ret = devm_snd_soc_register_card(&pdev->dev, &data->card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); goto clk_fail; @@ -296,7 +296,6 @@ static int imx_wm8962_remove(struct platform_device *pdev) if (!IS_ERR(data->codec_clk)) clk_disable_unprepare(data->codec_clk); - snd_soc_unregister_card(&data->card); return 0; } @@ -311,6 +310,7 @@ static struct platform_driver imx_wm8962_driver = { .driver = { .name = "imx-wm8962", .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, .of_match_table = imx_wm8962_dt_ids, }, .probe = imx_wm8962_probe, diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c index b238434f92b0..55d0d9d3a9fd 100644 --- a/sound/soc/kirkwood/kirkwood-dma.c +++ b/sound/soc/kirkwood/kirkwood-dma.c @@ -29,9 +29,7 @@ #define KIRKWOOD_FORMATS \ (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S32_LE | \ - SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | \ - SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE) + SNDRV_PCM_FMTBIT_S32_LE) static struct kirkwood_dma_data *kirkwood_priv(struct snd_pcm_substream *subs) { @@ -161,7 +159,7 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream) * Enable Error interrupts. We're only ack'ing them but * it's useful for diagnostics */ - writel((unsigned long)-1, priv->io + KIRKWOOD_ERR_MASK); + writel((unsigned int)-1, priv->io + KIRKWOOD_ERR_MASK); } dram = mv_mbus_dram_info(); diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index 0f3d73d4ef48..9ec38d15df9e 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -103,7 +103,7 @@ static void kirkwood_set_rate(struct snd_soc_dai *dai, { uint32_t clks_ctrl; - if (rate == 44100 || rate == 48000 || rate == 96000) { + if (IS_ERR(priv->extclk)) { /* use internal dco for the supported rates * defined in kirkwood_i2s_dai */ dev_dbg(dai->dev, "%s: dco set rate = %lu\n", @@ -160,9 +160,11 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, case SNDRV_PCM_FORMAT_S16_LE: i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16; ctl_play = KIRKWOOD_PLAYCTL_SIZE_16_C | - KIRKWOOD_PLAYCTL_I2S_EN; + KIRKWOOD_PLAYCTL_I2S_EN | + KIRKWOOD_PLAYCTL_SPDIF_EN; ctl_rec = KIRKWOOD_RECCTL_SIZE_16_C | - KIRKWOOD_RECCTL_I2S_EN; + KIRKWOOD_RECCTL_I2S_EN | + KIRKWOOD_RECCTL_SPDIF_EN; break; /* * doesn't work... S20_3LE != kirkwood 20bit format ? @@ -178,9 +180,11 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, case SNDRV_PCM_FORMAT_S24_LE: i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24; ctl_play = KIRKWOOD_PLAYCTL_SIZE_24 | - KIRKWOOD_PLAYCTL_I2S_EN; + KIRKWOOD_PLAYCTL_I2S_EN | + KIRKWOOD_PLAYCTL_SPDIF_EN; ctl_rec = KIRKWOOD_RECCTL_SIZE_24 | - KIRKWOOD_RECCTL_I2S_EN; + KIRKWOOD_RECCTL_I2S_EN | + KIRKWOOD_RECCTL_SPDIF_EN; break; case SNDRV_PCM_FORMAT_S32_LE: i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32; @@ -240,6 +244,11 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, ctl); } + if (dai->id == 0) + ctl &= ~KIRKWOOD_PLAYCTL_SPDIF_EN; /* i2s */ + else + ctl &= ~KIRKWOOD_PLAYCTL_I2S_EN; /* spdif */ + switch (cmd) { case SNDRV_PCM_TRIGGER_START: /* configure */ @@ -258,7 +267,8 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_STOP: /* stop audio, disable interrupts */ - ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; + ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE | + KIRKWOOD_PLAYCTL_SPDIF_MUTE; writel(ctl, priv->io + KIRKWOOD_PLAYCTL); value = readl(priv->io + KIRKWOOD_INT_MASK); @@ -272,13 +282,15 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: - ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; + ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE | + KIRKWOOD_PLAYCTL_SPDIF_MUTE; writel(ctl, priv->io + KIRKWOOD_PLAYCTL); break; case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE); + ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE | + KIRKWOOD_PLAYCTL_SPDIF_MUTE); writel(ctl, priv->io + KIRKWOOD_PLAYCTL); break; @@ -301,7 +313,13 @@ static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_START: /* configure */ ctl = priv->ctl_rec; - value = ctl & ~KIRKWOOD_RECCTL_I2S_EN; + if (dai->id == 0) + ctl &= ~KIRKWOOD_RECCTL_SPDIF_EN; /* i2s */ + else + ctl &= ~KIRKWOOD_RECCTL_I2S_EN; /* spdif */ + + value = ctl & ~(KIRKWOOD_RECCTL_I2S_EN | + KIRKWOOD_RECCTL_SPDIF_EN); writel(value, priv->io + KIRKWOOD_RECCTL); /* enable interrupts */ @@ -361,9 +379,8 @@ static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static int kirkwood_i2s_probe(struct snd_soc_dai *dai) +static int kirkwood_i2s_init(struct kirkwood_dma_data *priv) { - struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); unsigned long value; unsigned int reg_data; @@ -404,9 +421,10 @@ static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = { .set_fmt = kirkwood_i2s_set_fmt, }; - -static struct snd_soc_dai_driver kirkwood_i2s_dai = { - .probe = kirkwood_i2s_probe, +static struct snd_soc_dai_driver kirkwood_i2s_dai[2] = { + { + .name = "i2s", + .id = 0, .playback = { .channels_min = 1, .channels_max = 2, @@ -422,10 +440,53 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai = { .formats = KIRKWOOD_I2S_FORMATS, }, .ops = &kirkwood_i2s_dai_ops, + }, + { + .name = "spdif", + .id = 1, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000, + .formats = KIRKWOOD_I2S_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000, + .formats = KIRKWOOD_I2S_FORMATS, + }, + .ops = &kirkwood_i2s_dai_ops, + }, }; -static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = { - .probe = kirkwood_i2s_probe, +static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk[2] = { + { + .name = "i2s", + .id = 0, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000 | + SNDRV_PCM_RATE_CONTINUOUS | + SNDRV_PCM_RATE_KNOT, + .formats = KIRKWOOD_I2S_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000 | + SNDRV_PCM_RATE_CONTINUOUS | + SNDRV_PCM_RATE_KNOT, + .formats = KIRKWOOD_I2S_FORMATS, + }, + .ops = &kirkwood_i2s_dai_ops, + }, + { + .name = "spdif", + .id = 1, .playback = { .channels_min = 1, .channels_max = 2, @@ -443,6 +504,7 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = { .formats = KIRKWOOD_I2S_FORMATS, }, .ops = &kirkwood_i2s_dai_ops, + }, }; static const struct snd_soc_component_driver kirkwood_i2s_component = { @@ -452,7 +514,7 @@ static const struct snd_soc_component_driver kirkwood_i2s_component = { static int kirkwood_i2s_dev_probe(struct platform_device *pdev) { struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data; - struct snd_soc_dai_driver *soc_dai = &kirkwood_i2s_dai; + struct snd_soc_dai_driver *soc_dai = kirkwood_i2s_dai; struct kirkwood_dma_data *priv; struct resource *mem; struct device_node *np = pdev->dev.of_node; @@ -496,7 +558,10 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) return err; priv->extclk = devm_clk_get(&pdev->dev, "extclk"); - if (!IS_ERR(priv->extclk)) { + if (IS_ERR(priv->extclk)) { + if (PTR_ERR(priv->extclk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + } else { if (priv->extclk == priv->clk) { devm_clk_put(&pdev->dev, priv->extclk); priv->extclk = ERR_PTR(-EINVAL); @@ -521,7 +586,7 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) } err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component, - soc_dai, 1); + soc_dai, 2); if (err) { dev_err(&pdev->dev, "snd_soc_register_component failed\n"); goto err_component; @@ -532,6 +597,9 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) dev_err(&pdev->dev, "snd_soc_register_platform failed\n"); goto err_platform; } + + kirkwood_i2s_init(priv); + return 0; err_platform: snd_soc_unregister_component(&pdev->dev); diff --git a/sound/soc/kirkwood/kirkwood-openrd.c b/sound/soc/kirkwood/kirkwood-openrd.c index 025be0e97164..65f2a5b9ec3b 100644 --- a/sound/soc/kirkwood/kirkwood-openrd.c +++ b/sound/soc/kirkwood/kirkwood-openrd.c @@ -52,7 +52,7 @@ static struct snd_soc_dai_link openrd_client_dai[] = { { .name = "CS42L51", .stream_name = "CS42L51 HiFi", - .cpu_dai_name = "mvebu-audio", + .cpu_dai_name = "i2s", .platform_name = "mvebu-audio", .codec_dai_name = "cs42l51-hifi", .codec_name = "cs42l51-codec.0-004a", diff --git a/sound/soc/kirkwood/kirkwood-t5325.c b/sound/soc/kirkwood/kirkwood-t5325.c index 27545b0c4856..d213832b0c72 100644 --- a/sound/soc/kirkwood/kirkwood-t5325.c +++ b/sound/soc/kirkwood/kirkwood-t5325.c @@ -68,7 +68,7 @@ static struct snd_soc_dai_link t5325_dai[] = { { .name = "ALC5621", .stream_name = "ALC5621 HiFi", - .cpu_dai_name = "mvebu-audio", + .cpu_dai_name = "i2s", .platform_name = "mvebu-audio", .codec_dai_name = "alc5621-hifi", .codec_name = "alc562x-codec.0-001a", diff --git a/sound/soc/kirkwood/kirkwood.h b/sound/soc/kirkwood/kirkwood.h index f8e1ccc1c58c..bf23afbba1d7 100644 --- a/sound/soc/kirkwood/kirkwood.h +++ b/sound/soc/kirkwood/kirkwood.h @@ -123,8 +123,8 @@ /* need to find where they come from */ #define KIRKWOOD_SND_MIN_PERIODS 8 #define KIRKWOOD_SND_MAX_PERIODS 16 -#define KIRKWOOD_SND_MIN_PERIOD_BYTES 0x4000 -#define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x4000 +#define KIRKWOOD_SND_MIN_PERIOD_BYTES 0x800 +#define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x8000 #define KIRKWOOD_SND_MAX_BUFFER_BYTES (KIRKWOOD_SND_MAX_PERIOD_BYTES \ * KIRKWOOD_SND_MAX_PERIODS) diff --git a/sound/soc/mid-x86/mfld_machine.c b/sound/soc/mid-x86/mfld_machine.c index ee363845759e..d3d4c32434f7 100644 --- a/sound/soc/mid-x86/mfld_machine.c +++ b/sound/soc/mid-x86/mfld_machine.c @@ -400,7 +400,7 @@ static int snd_mfld_mc_probe(struct platform_device *pdev) } /* register the soc card */ snd_soc_card_mfld.dev = &pdev->dev; - ret_val = snd_soc_register_card(&snd_soc_card_mfld); + ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_mfld); if (ret_val) { pr_debug("snd_soc_register_card failed %d\n", ret_val); return ret_val; @@ -410,20 +410,12 @@ static int snd_mfld_mc_probe(struct platform_device *pdev) return 0; } -static int snd_mfld_mc_remove(struct platform_device *pdev) -{ - pr_debug("snd_mfld_mc_remove called\n"); - snd_soc_unregister_card(&snd_soc_card_mfld); - return 0; -} - static struct platform_driver snd_mfld_mc_driver = { .driver = { .owner = THIS_MODULE, .name = "msic_audio", }, .probe = snd_mfld_mc_probe, - .remove = snd_mfld_mc_remove, }; module_platform_driver(snd_mfld_mc_driver); diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index b56b8a0e8deb..54e622acac33 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -494,6 +494,7 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd, struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai); struct mxs_saif *master_saif; u32 delay; + int ret; master_saif = mxs_saif_get_master(saif); if (!master_saif) @@ -503,23 +504,37 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (saif->state == MXS_SAIF_STATE_RUNNING) + return 0; + dev_dbg(cpu_dai->dev, "start\n"); - clk_enable(master_saif->clk); - if (!master_saif->mclk_in_use) - __raw_writel(BM_SAIF_CTRL_RUN, - master_saif->base + SAIF_CTRL + MXS_SET_ADDR); + ret = clk_enable(master_saif->clk); + if (ret) { + dev_err(saif->dev, "Failed to enable master clock\n"); + return ret; + } /* * If the saif's master is not himself, we also need to enable * itself clk for its internal basic logic to work. */ if (saif != master_saif) { - clk_enable(saif->clk); + ret = clk_enable(saif->clk); + if (ret) { + dev_err(saif->dev, "Failed to enable master clock\n"); + clk_disable(master_saif->clk); + return ret; + } + __raw_writel(BM_SAIF_CTRL_RUN, saif->base + SAIF_CTRL + MXS_SET_ADDR); } + if (!master_saif->mclk_in_use) + __raw_writel(BM_SAIF_CTRL_RUN, + master_saif->base + SAIF_CTRL + MXS_SET_ADDR); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* * write data to saif data register to trigger @@ -543,6 +558,7 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd, } master_saif->ongoing = 1; + saif->state = MXS_SAIF_STATE_RUNNING; dev_dbg(saif->dev, "CTRL 0x%x STAT 0x%x\n", __raw_readl(saif->base + SAIF_CTRL), @@ -555,6 +571,9 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (saif->state == MXS_SAIF_STATE_STOPPED) + return 0; + dev_dbg(cpu_dai->dev, "stop\n"); /* wait a while for the current sample to complete */ @@ -575,6 +594,7 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd, } master_saif->ongoing = 0; + saif->state = MXS_SAIF_STATE_STOPPED; break; default: @@ -768,8 +788,8 @@ static int mxs_saif_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "failed to init clocks\n"); } - ret = snd_soc_register_component(&pdev->dev, &mxs_saif_component, - &mxs_saif_dai, 1); + ret = devm_snd_soc_register_component(&pdev->dev, &mxs_saif_component, + &mxs_saif_dai, 1); if (ret) { dev_err(&pdev->dev, "register DAI failed\n"); return ret; @@ -778,21 +798,15 @@ static int mxs_saif_probe(struct platform_device *pdev) ret = mxs_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "register PCM failed: %d\n", ret); - goto failed_pdev_alloc; + return ret; } return 0; - -failed_pdev_alloc: - snd_soc_unregister_component(&pdev->dev); - - return ret; } static int mxs_saif_remove(struct platform_device *pdev) { mxs_pcm_platform_unregister(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); return 0; } diff --git a/sound/soc/mxs/mxs-saif.h b/sound/soc/mxs/mxs-saif.h index 53eaa4bf0e27..fbaf7badfdfb 100644 --- a/sound/soc/mxs/mxs-saif.h +++ b/sound/soc/mxs/mxs-saif.h @@ -124,6 +124,11 @@ struct mxs_saif { u32 fifo_underrun; u32 fifo_overrun; + + enum { + MXS_SAIF_STATE_STOPPED, + MXS_SAIF_STATE_RUNNING, + } state; }; extern int mxs_saif_put_mclk(unsigned int saif_id); diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c index 4bb273786ff3..61822cc53bd3 100644 --- a/sound/soc/mxs/mxs-sgtl5000.c +++ b/sound/soc/mxs/mxs-sgtl5000.c @@ -122,14 +122,12 @@ static struct snd_soc_card mxs_sgtl5000 = { .num_links = ARRAY_SIZE(mxs_sgtl5000_dai), }; -static int mxs_sgtl5000_probe_dt(struct platform_device *pdev) +static int mxs_sgtl5000_probe(struct platform_device *pdev) { + struct snd_soc_card *card = &mxs_sgtl5000; + int ret, i; struct device_node *np = pdev->dev.of_node; struct device_node *saif_np[2], *codec_np; - int i; - - 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); @@ -152,18 +150,6 @@ static int mxs_sgtl5000_probe_dt(struct platform_device *pdev) of_node_put(saif_np[0]); of_node_put(saif_np[1]); - return 0; -} - -static int 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 diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index daa78a0095fa..4a07f7179690 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -1,6 +1,6 @@ config SND_OMAP_SOC tristate "SoC Audio for the Texas Instruments OMAP chips" - depends on (ARCH_OMAP && DMA_OMAP) || (ARCH_ARM && COMPILE_TEST) + depends on (ARCH_OMAP && DMA_OMAP) || (ARM && COMPILE_TEST) select SND_DMAENGINE_PCM config SND_OMAP_SOC_DMIC @@ -26,7 +26,7 @@ config SND_OMAP_SOC_N810 config SND_OMAP_SOC_RX51 tristate "SoC Audio support for Nokia RX-51" - depends on SND_OMAP_SOC && ARCH_ARM && (MACH_NOKIA_RX51 || COMPILE_TEST) + depends on SND_OMAP_SOC && ARM && (MACH_NOKIA_RX51 || COMPILE_TEST) select SND_OMAP_SOC_MCBSP select SND_SOC_TLV320AIC3X select SND_SOC_TPA6130A2 diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index 90d2a7cd2563..cd9ee167959d 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -490,14 +490,9 @@ static int asoc_mcpdm_probe(struct platform_device *pdev) mcpdm->dev = &pdev->dev; - return snd_soc_register_component(&pdev->dev, &omap_mcpdm_component, - &omap_mcpdm_dai, 1); -} - -static int asoc_mcpdm_remove(struct platform_device *pdev) -{ - snd_soc_unregister_component(&pdev->dev); - return 0; + return devm_snd_soc_register_component(&pdev->dev, + &omap_mcpdm_component, + &omap_mcpdm_dai, 1); } static const struct of_device_id omap_mcpdm_of_match[] = { @@ -514,7 +509,6 @@ static struct platform_driver asoc_mcpdm_driver = { }, .probe = asoc_mcpdm_probe, - .remove = asoc_mcpdm_remove, }; module_platform_driver(asoc_mcpdm_driver); diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c index 2a9324f794d8..6a8d6b5f160d 100644 --- a/sound/soc/omap/omap-twl4030.c +++ b/sound/soc/omap/omap-twl4030.c @@ -338,9 +338,9 @@ static int omap_twl4030_probe(struct platform_device *pdev) } snd_soc_card_set_drvdata(card, priv); - ret = snd_soc_register_card(card); + ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", + dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n", ret); return ret; } @@ -357,7 +357,6 @@ static int omap_twl4030_remove(struct platform_device *pdev) snd_soc_jack_free_gpios(&priv->hs_jack, ARRAY_SIZE(hs_jack_gpios), hs_jack_gpios); - snd_soc_unregister_card(card); return 0; } diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index 41752a5fe3b0..5bf5f1f7cac5 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c @@ -455,8 +455,8 @@ static int asoc_mmp_sspa_probe(struct platform_device *pdev) priv->dai_fmt = (unsigned int) -1; platform_set_drvdata(pdev, priv); - return snd_soc_register_component(&pdev->dev, &mmp_sspa_component, - &mmp_sspa_dai, 1); + return devm_snd_soc_register_component(&pdev->dev, &mmp_sspa_component, + &mmp_sspa_dai, 1); } static int asoc_mmp_sspa_remove(struct platform_device *pdev) @@ -466,7 +466,6 @@ static int asoc_mmp_sspa_remove(struct platform_device *pdev) clk_disable(priv->audio_clk); clk_put(priv->audio_clk); clk_put(priv->sysclk); - snd_soc_unregister_component(&pdev->dev); return 0; } diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index b302f3b7a587..3e08b6c0f7ba 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -702,13 +702,6 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, } writel(mod, i2s->addr + I2SMOD); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_dai_set_dma_data(dai, substream, - (void *)&i2s->dma_playback); - else - snd_soc_dai_set_dma_data(dai, substream, - (void *)&i2s->dma_capture); - i2s->frmclk = params_rate(params); return 0; @@ -970,6 +963,8 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) } clk_prepare_enable(i2s->clk); + snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); + if (other) { other->addr = i2s->addr; other->clk = i2s->clk; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 9cc6986a8cfb..5dd87f4c919e 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -220,8 +220,8 @@ int rsnd_gen_path_exit(struct rsnd_priv *priv, void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg); -#define rsnd_is_gen1(s) ((s)->info->flags & RSND_GEN1) -#define rsnd_is_gen2(s) ((s)->info->flags & RSND_GEN2) +#define rsnd_is_gen1(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1) +#define rsnd_is_gen2(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN2) /* * R-Car ADG diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index e72f55428f0b..1b6663f45b34 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -11,12 +11,9 @@ * option) any later version. */ -#include <linux/i2c.h> -#include <linux/spi/spi.h> #include <sound/soc.h> -#include <linux/bitmap.h> -#include <linux/rbtree.h> #include <linux/export.h> +#include <linux/slab.h> #include <trace/events/asoc.h> @@ -66,126 +63,42 @@ static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx, return -1; } -static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) +int snd_soc_cache_init(struct snd_soc_codec *codec) { - int i; - int ret; - const struct snd_soc_codec_driver *codec_drv; - unsigned int val; + const struct snd_soc_codec_driver *codec_drv = codec->driver; + size_t reg_size; - codec_drv = codec->driver; - for (i = 0; i < codec_drv->reg_cache_size; ++i) { - ret = snd_soc_cache_read(codec, i, &val); - if (ret) - return ret; - if (codec->reg_def_copy) - if (snd_soc_get_cache_val(codec->reg_def_copy, - i, codec_drv->reg_word_size) == val) - continue; + reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; - WARN_ON(!snd_soc_codec_writable_register(codec, i)); - - ret = snd_soc_write(codec, i, val); - if (ret) - return ret; - dev_dbg(codec->dev, "ASoC: Synced register %#x, value = %#x\n", - i, val); - } - return 0; -} - -static int snd_soc_flat_cache_write(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) -{ - snd_soc_set_cache_val(codec->reg_cache, reg, value, - codec->driver->reg_word_size); - return 0; -} - -static int snd_soc_flat_cache_read(struct snd_soc_codec *codec, - unsigned int reg, unsigned int *value) -{ - *value = snd_soc_get_cache_val(codec->reg_cache, reg, - codec->driver->reg_word_size); - return 0; -} + mutex_init(&codec->cache_rw_mutex); -static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec) -{ - if (!codec->reg_cache) - return 0; - kfree(codec->reg_cache); - codec->reg_cache = NULL; - return 0; -} + dev_dbg(codec->dev, "ASoC: Initializing cache for %s codec\n", + codec->name); -static int snd_soc_flat_cache_init(struct snd_soc_codec *codec) -{ - if (codec->reg_def_copy) - codec->reg_cache = kmemdup(codec->reg_def_copy, - codec->reg_size, GFP_KERNEL); + if (codec_drv->reg_cache_default) + codec->reg_cache = kmemdup(codec_drv->reg_cache_default, + reg_size, GFP_KERNEL); else - codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL); + codec->reg_cache = kzalloc(reg_size, GFP_KERNEL); if (!codec->reg_cache) return -ENOMEM; return 0; } -/* an array of all supported compression types */ -static const struct snd_soc_cache_ops cache_types[] = { - /* Flat *must* be the first entry for fallback */ - { - .id = SND_SOC_FLAT_COMPRESSION, - .name = "flat", - .init = snd_soc_flat_cache_init, - .exit = snd_soc_flat_cache_exit, - .read = snd_soc_flat_cache_read, - .write = snd_soc_flat_cache_write, - .sync = snd_soc_flat_cache_sync - }, -}; - -int snd_soc_cache_init(struct snd_soc_codec *codec) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(cache_types); ++i) - if (cache_types[i].id == codec->compress_type) - break; - - /* Fall back to flat compression */ - if (i == ARRAY_SIZE(cache_types)) { - dev_warn(codec->dev, "ASoC: Could not match compress type: %d\n", - codec->compress_type); - i = 0; - } - - mutex_init(&codec->cache_rw_mutex); - codec->cache_ops = &cache_types[i]; - - if (codec->cache_ops->init) { - if (codec->cache_ops->name) - dev_dbg(codec->dev, "ASoC: Initializing %s cache for %s codec\n", - codec->cache_ops->name, codec->name); - return codec->cache_ops->init(codec); - } - return -ENOSYS; -} - /* * NOTE: keep in mind that this function might be called * multiple times. */ int snd_soc_cache_exit(struct snd_soc_codec *codec) { - if (codec->cache_ops && codec->cache_ops->exit) { - if (codec->cache_ops->name) - dev_dbg(codec->dev, "ASoC: Destroying %s cache for %s codec\n", - codec->cache_ops->name, codec->name); - return codec->cache_ops->exit(codec); - } - return -ENOSYS; + dev_dbg(codec->dev, "ASoC: Destroying cache for %s codec\n", + codec->name); + if (!codec->reg_cache) + return 0; + kfree(codec->reg_cache); + codec->reg_cache = NULL; + return 0; } /** @@ -198,18 +111,15 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec) int snd_soc_cache_read(struct snd_soc_codec *codec, unsigned int reg, unsigned int *value) { - int ret; + if (!value) + return -EINVAL; mutex_lock(&codec->cache_rw_mutex); - - if (value && codec->cache_ops && codec->cache_ops->read) { - ret = codec->cache_ops->read(codec, reg, value); - mutex_unlock(&codec->cache_rw_mutex); - return ret; - } - + *value = snd_soc_get_cache_val(codec->reg_cache, reg, + codec->driver->reg_word_size); mutex_unlock(&codec->cache_rw_mutex); - return -ENOSYS; + + return 0; } EXPORT_SYMBOL_GPL(snd_soc_cache_read); @@ -223,20 +133,42 @@ EXPORT_SYMBOL_GPL(snd_soc_cache_read); int snd_soc_cache_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { + mutex_lock(&codec->cache_rw_mutex); + snd_soc_set_cache_val(codec->reg_cache, reg, value, + codec->driver->reg_word_size); + mutex_unlock(&codec->cache_rw_mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_cache_write); + +static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) +{ + int i; int ret; + const struct snd_soc_codec_driver *codec_drv; + unsigned int val; - mutex_lock(&codec->cache_rw_mutex); + codec_drv = codec->driver; + for (i = 0; i < codec_drv->reg_cache_size; ++i) { + ret = snd_soc_cache_read(codec, i, &val); + if (ret) + return ret; + if (codec_drv->reg_cache_default) + if (snd_soc_get_cache_val(codec_drv->reg_cache_default, + i, codec_drv->reg_word_size) == val) + continue; - if (codec->cache_ops && codec->cache_ops->write) { - ret = codec->cache_ops->write(codec, reg, value); - mutex_unlock(&codec->cache_rw_mutex); - return ret; - } + WARN_ON(!snd_soc_codec_writable_register(codec, i)); - mutex_unlock(&codec->cache_rw_mutex); - return -ENOSYS; + ret = snd_soc_write(codec, i, val); + if (ret) + return ret; + dev_dbg(codec->dev, "ASoC: Synced register %#x, value = %#x\n", + i, val); + } + return 0; } -EXPORT_SYMBOL_GPL(snd_soc_cache_write); /** * snd_soc_cache_sync: Sync the register cache with the hardware. @@ -249,92 +181,19 @@ EXPORT_SYMBOL_GPL(snd_soc_cache_write); */ int snd_soc_cache_sync(struct snd_soc_codec *codec) { + const char *name = "flat"; int ret; - const char *name; - if (!codec->cache_sync) { + if (!codec->cache_sync) return 0; - } - - if (!codec->cache_ops || !codec->cache_ops->sync) - return -ENOSYS; - if (codec->cache_ops->name) - name = codec->cache_ops->name; - else - name = "unknown"; - - if (codec->cache_ops->name) - dev_dbg(codec->dev, "ASoC: Syncing %s cache for %s codec\n", - codec->cache_ops->name, codec->name); + dev_dbg(codec->dev, "ASoC: Syncing cache for %s codec\n", + codec->name); trace_snd_soc_cache_sync(codec, name, "start"); - ret = codec->cache_ops->sync(codec); + ret = snd_soc_flat_cache_sync(codec); if (!ret) codec->cache_sync = 0; trace_snd_soc_cache_sync(codec, name, "end"); return ret; } EXPORT_SYMBOL_GPL(snd_soc_cache_sync); - -static int snd_soc_get_reg_access_index(struct snd_soc_codec *codec, - unsigned int reg) -{ - const struct snd_soc_codec_driver *codec_drv; - unsigned int min, max, index; - - codec_drv = codec->driver; - min = 0; - max = codec_drv->reg_access_size - 1; - do { - index = (min + max) / 2; - if (codec_drv->reg_access_default[index].reg == reg) - return index; - if (codec_drv->reg_access_default[index].reg < reg) - min = index + 1; - else - max = index; - } while (min <= max); - return -1; -} - -int snd_soc_default_volatile_register(struct snd_soc_codec *codec, - unsigned int reg) -{ - int index; - - if (reg >= codec->driver->reg_cache_size) - return 1; - index = snd_soc_get_reg_access_index(codec, reg); - if (index < 0) - return 0; - return codec->driver->reg_access_default[index].vol; -} -EXPORT_SYMBOL_GPL(snd_soc_default_volatile_register); - -int snd_soc_default_readable_register(struct snd_soc_codec *codec, - unsigned int reg) -{ - int index; - - if (reg >= codec->driver->reg_cache_size) - return 1; - index = snd_soc_get_reg_access_index(codec, reg); - if (index < 0) - return 0; - return codec->driver->reg_access_default[index].read; -} -EXPORT_SYMBOL_GPL(snd_soc_default_readable_register); - -int snd_soc_default_writable_register(struct snd_soc_codec *codec, - unsigned int reg) -{ - int index; - - if (reg >= codec->driver->reg_cache_size) - return 1; - index = snd_soc_get_reg_access_index(codec, reg); - if (index < 0) - return 0; - return codec->driver->reg_access_default[index].write; -} -EXPORT_SYMBOL_GPL(snd_soc_default_writable_register); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1a38be0d0ca8..afc3fa8b7470 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1589,17 +1589,13 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num) soc_remove_codec(codec); } -static int snd_soc_init_codec_cache(struct snd_soc_codec *codec, - enum snd_soc_compress_type compress_type) +static int snd_soc_init_codec_cache(struct snd_soc_codec *codec) { int ret; if (codec->cache_init) return 0; - /* override the compress_type if necessary */ - if (compress_type && codec->compress_type != compress_type) - codec->compress_type = compress_type; ret = snd_soc_cache_init(codec); if (ret < 0) { dev_err(codec->dev, @@ -1614,8 +1610,6 @@ static int snd_soc_init_codec_cache(struct snd_soc_codec *codec, 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, dai_fmt; @@ -1639,19 +1633,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) list_for_each_entry(codec, &codec_list, list) { if (codec->cache_init) continue; - /* by default we don't override the compress_type */ - compress_type = 0; - /* check to see if we need to override the compress_type */ - for (i = 0; i < card->num_configs; ++i) { - codec_conf = &card->codec_conf[i]; - if (!strcmp(codec->name, codec_conf->dev_name)) { - compress_type = codec_conf->compress_type; - if (compress_type && compress_type - != codec->compress_type) - break; - } - } - ret = snd_soc_init_codec_cache(codec, compress_type); + ret = snd_soc_init_codec_cache(codec); if (ret < 0) goto base_error; } @@ -2297,13 +2279,6 @@ unsigned int snd_soc_write(struct snd_soc_codec *codec, } EXPORT_SYMBOL_GPL(snd_soc_write); -unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec, - unsigned int reg, const void *data, size_t len) -{ - return codec->bulk_write_raw(codec, reg, data, len); -} -EXPORT_SYMBOL_GPL(snd_soc_bulk_write_raw); - /** * snd_soc_update_bits - update codec register bits * @codec: audio codec @@ -3576,6 +3551,22 @@ int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source, EXPORT_SYMBOL_GPL(snd_soc_codec_set_pll); /** + * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio. + * @dai: DAI + * @ratio Ratio of BCLK to Sample rate. + * + * Configures the DAI for a preset BCLK to sample rate ratio. + */ +int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + if (dai->driver && dai->driver->ops->set_bclk_ratio) + return dai->driver->ops->set_bclk_ratio(dai, ratio); + else + return -EINVAL; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio); + +/** * snd_soc_dai_set_fmt - configure DAI hardware audio format. * @dai: DAI * @fmt: SND_SOC_DAIFMT_ format value. @@ -4020,6 +4011,113 @@ static void snd_soc_unregister_dais(struct device *dev, size_t count) } /** + * snd_soc_register_component - Register a component with the ASoC core + * + */ +static int +__snd_soc_register_component(struct device *dev, + struct snd_soc_component *cmpnt, + const struct snd_soc_component_driver *cmpnt_drv, + struct snd_soc_dai_driver *dai_drv, + int num_dai, bool allow_single_dai) +{ + int ret; + + dev_dbg(dev, "component register %s\n", dev_name(dev)); + + if (!cmpnt) { + dev_err(dev, "ASoC: Failed to connecting component\n"); + return -ENOMEM; + } + + cmpnt->name = fmt_single_name(dev, &cmpnt->id); + if (!cmpnt->name) { + dev_err(dev, "ASoC: Failed to simplifying name\n"); + return -ENOMEM; + } + + cmpnt->dev = dev; + cmpnt->driver = cmpnt_drv; + cmpnt->dai_drv = dai_drv; + cmpnt->num_dai = num_dai; + + /* + * snd_soc_register_dai() uses fmt_single_name(), and + * snd_soc_register_dais() uses fmt_multiple_name() + * for dai->name which is used for name based matching + * + * this function is used from cpu/codec. + * allow_single_dai flag can ignore "codec" driver reworking + * since it had been used snd_soc_register_dais(), + */ + if ((1 == num_dai) && allow_single_dai) + ret = snd_soc_register_dai(dev, dai_drv); + else + ret = snd_soc_register_dais(dev, dai_drv, num_dai); + if (ret < 0) { + dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); + goto error_component_name; + } + + mutex_lock(&client_mutex); + list_add(&cmpnt->list, &component_list); + mutex_unlock(&client_mutex); + + dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name); + + return ret; + +error_component_name: + kfree(cmpnt->name); + + return ret; +} + +int snd_soc_register_component(struct device *dev, + const struct snd_soc_component_driver *cmpnt_drv, + struct snd_soc_dai_driver *dai_drv, + int num_dai) +{ + struct snd_soc_component *cmpnt; + + cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL); + if (!cmpnt) { + dev_err(dev, "ASoC: Failed to allocate memory\n"); + return -ENOMEM; + } + + return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, + dai_drv, num_dai, true); +} +EXPORT_SYMBOL_GPL(snd_soc_register_component); + +/** + * snd_soc_unregister_component - Unregister a component from the ASoC core + * + */ +void snd_soc_unregister_component(struct device *dev) +{ + struct snd_soc_component *cmpnt; + + list_for_each_entry(cmpnt, &component_list, list) { + if (dev == cmpnt->dev) + goto found; + } + return; + +found: + snd_soc_unregister_dais(dev, cmpnt->num_dai); + + mutex_lock(&client_mutex); + list_del(&cmpnt->list); + mutex_unlock(&client_mutex); + + dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name); + kfree(cmpnt->name); +} +EXPORT_SYMBOL_GPL(snd_soc_unregister_component); + +/** * snd_soc_add_platform - Add a platform to the ASoC core * @dev: The parent device for the platform * @platform: The platform to add @@ -4165,7 +4263,6 @@ int snd_soc_register_codec(struct device *dev, struct snd_soc_dai_driver *dai_drv, int num_dai) { - size_t reg_size; struct snd_soc_codec *codec; int ret, i; @@ -4182,11 +4279,6 @@ int snd_soc_register_codec(struct device *dev, goto fail_codec; } - if (codec_drv->compress_type) - codec->compress_type = codec_drv->compress_type; - else - codec->compress_type = SND_SOC_FLAT_COMPRESSION; - codec->write = codec_drv->write; codec->read = codec_drv->read; codec->volatile_register = codec_drv->volatile_register; @@ -4203,35 +4295,6 @@ int snd_soc_register_codec(struct device *dev, codec->num_dai = num_dai; mutex_init(&codec->mutex); - /* allocate CODEC register cache */ - if (codec_drv->reg_cache_size && codec_drv->reg_word_size) { - reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; - codec->reg_size = reg_size; - /* it is necessary to make a copy of the default register cache - * because in the case of using a compression type that requires - * the default register cache to be marked as the - * kernel might have freed the array by the time we initialize - * the cache. - */ - if (codec_drv->reg_cache_default) { - codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default, - reg_size, GFP_KERNEL); - if (!codec->reg_def_copy) { - ret = -ENOMEM; - goto fail_codec_name; - } - } - } - - if (codec_drv->reg_access_size && codec_drv->reg_access_default) { - if (!codec->volatile_register) - codec->volatile_register = snd_soc_default_volatile_register; - if (!codec->readable_register) - codec->readable_register = snd_soc_default_readable_register; - if (!codec->writable_register) - codec->writable_register = snd_soc_default_writable_register; - } - for (i = 0; i < num_dai; i++) { fixup_codec_formats(&dai_drv[i].playback); fixup_codec_formats(&dai_drv[i].capture); @@ -4241,10 +4304,12 @@ int snd_soc_register_codec(struct device *dev, list_add(&codec->list, &codec_list); mutex_unlock(&client_mutex); - /* register any DAIs */ - ret = snd_soc_register_dais(dev, dai_drv, num_dai); + /* register component */ + ret = __snd_soc_register_component(dev, &codec->component, + &codec_drv->component_driver, + dai_drv, num_dai, false); if (ret < 0) { - dev_err(codec->dev, "ASoC: Failed to regster DAIs: %d\n", ret); + dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret); goto fail_codec_name; } @@ -4279,7 +4344,7 @@ void snd_soc_unregister_codec(struct device *dev) return; found: - snd_soc_unregister_dais(dev, codec->num_dai); + snd_soc_unregister_component(dev); mutex_lock(&client_mutex); list_del(&codec->list); @@ -4288,98 +4353,11 @@ found: dev_dbg(codec->dev, "ASoC: Unregistered codec '%s'\n", codec->name); snd_soc_cache_exit(codec); - kfree(codec->reg_def_copy); kfree(codec->name); kfree(codec); } EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); - -/** - * snd_soc_register_component - Register a component with the ASoC core - * - */ -int snd_soc_register_component(struct device *dev, - const struct snd_soc_component_driver *cmpnt_drv, - struct snd_soc_dai_driver *dai_drv, - int num_dai) -{ - struct snd_soc_component *cmpnt; - int ret; - - dev_dbg(dev, "component register %s\n", dev_name(dev)); - - cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL); - if (!cmpnt) { - dev_err(dev, "ASoC: Failed to allocate memory\n"); - return -ENOMEM; - } - - cmpnt->name = fmt_single_name(dev, &cmpnt->id); - if (!cmpnt->name) { - dev_err(dev, "ASoC: Failed to simplifying name\n"); - return -ENOMEM; - } - - cmpnt->dev = dev; - cmpnt->driver = cmpnt_drv; - cmpnt->num_dai = num_dai; - - /* - * snd_soc_register_dai() uses fmt_single_name(), and - * snd_soc_register_dais() uses fmt_multiple_name() - * for dai->name which is used for name based matching - */ - if (1 == num_dai) - ret = snd_soc_register_dai(dev, dai_drv); - else - ret = snd_soc_register_dais(dev, dai_drv, num_dai); - if (ret < 0) { - dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); - goto error_component_name; - } - - mutex_lock(&client_mutex); - list_add(&cmpnt->list, &component_list); - mutex_unlock(&client_mutex); - - dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name); - - return ret; - -error_component_name: - kfree(cmpnt->name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_register_component); - -/** - * snd_soc_unregister_component - Unregister a component from the ASoC core - * - */ -void snd_soc_unregister_component(struct device *dev) -{ - struct snd_soc_component *cmpnt; - - list_for_each_entry(cmpnt, &component_list, list) { - if (dev == cmpnt->dev) - goto found; - } - return; - -found: - snd_soc_unregister_dais(dev, cmpnt->num_dai); - - mutex_lock(&client_mutex); - list_del(&cmpnt->list); - mutex_unlock(&client_mutex); - - dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name); - kfree(cmpnt->name); -} -EXPORT_SYMBOL_GPL(snd_soc_unregister_component); - /* Retrieve a card's name from device tree */ int snd_soc_of_parse_card_name(struct snd_soc_card *card, const char *propname) @@ -4567,6 +4545,60 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); +int snd_soc_of_get_dai_name(struct device_node *of_node, + const char **dai_name) +{ + struct snd_soc_component *pos; + struct of_phandle_args args; + int ret; + + ret = of_parse_phandle_with_args(of_node, "sound-dai", + "#sound-dai-cells", 0, &args); + if (ret) + return ret; + + ret = -EPROBE_DEFER; + + mutex_lock(&client_mutex); + list_for_each_entry(pos, &component_list, list) { + if (pos->dev->of_node != args.np) + continue; + + if (pos->driver->of_xlate_dai_name) { + ret = pos->driver->of_xlate_dai_name(pos, &args, dai_name); + } else { + int id = -1; + + switch (args.args_count) { + case 0: + id = 0; /* same as dai_drv[0] */ + break; + case 1: + id = args.args[0]; + break; + default: + /* not supported */ + break; + } + + if (id < 0 || id >= pos->num_dai) { + ret = -EINVAL; + } else { + *dai_name = pos->dai_drv[id].name; + ret = 0; + } + } + + break; + } + mutex_unlock(&client_mutex); + + of_node_put(args.np); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name); + static int __init snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index c17c14c394df..2fb0b72d8a3c 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -59,31 +59,31 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, /* dapm power sequences - make this per codec in the future */ static int dapm_up_seq[] = { [snd_soc_dapm_pre] = 0, - [snd_soc_dapm_supply] = 1, [snd_soc_dapm_regulator_supply] = 1, [snd_soc_dapm_clock_supply] = 1, - [snd_soc_dapm_micbias] = 2, + [snd_soc_dapm_supply] = 2, + [snd_soc_dapm_micbias] = 3, [snd_soc_dapm_dai_link] = 2, - [snd_soc_dapm_dai_in] = 3, - [snd_soc_dapm_dai_out] = 3, - [snd_soc_dapm_aif_in] = 3, - [snd_soc_dapm_aif_out] = 3, - [snd_soc_dapm_mic] = 4, - [snd_soc_dapm_mux] = 5, - [snd_soc_dapm_virt_mux] = 5, - [snd_soc_dapm_value_mux] = 5, - [snd_soc_dapm_dac] = 6, - [snd_soc_dapm_switch] = 7, - [snd_soc_dapm_mixer] = 7, - [snd_soc_dapm_mixer_named_ctl] = 7, - [snd_soc_dapm_pga] = 8, - [snd_soc_dapm_adc] = 9, - [snd_soc_dapm_out_drv] = 10, - [snd_soc_dapm_hp] = 10, - [snd_soc_dapm_spk] = 10, - [snd_soc_dapm_line] = 10, - [snd_soc_dapm_kcontrol] = 11, - [snd_soc_dapm_post] = 12, + [snd_soc_dapm_dai_in] = 4, + [snd_soc_dapm_dai_out] = 4, + [snd_soc_dapm_aif_in] = 4, + [snd_soc_dapm_aif_out] = 4, + [snd_soc_dapm_mic] = 5, + [snd_soc_dapm_mux] = 6, + [snd_soc_dapm_virt_mux] = 6, + [snd_soc_dapm_value_mux] = 6, + [snd_soc_dapm_dac] = 7, + [snd_soc_dapm_switch] = 8, + [snd_soc_dapm_mixer] = 8, + [snd_soc_dapm_mixer_named_ctl] = 8, + [snd_soc_dapm_pga] = 9, + [snd_soc_dapm_adc] = 10, + [snd_soc_dapm_out_drv] = 11, + [snd_soc_dapm_hp] = 11, + [snd_soc_dapm_spk] = 11, + [snd_soc_dapm_line] = 11, + [snd_soc_dapm_kcontrol] = 12, + [snd_soc_dapm_post] = 13, }; static int dapm_down_seq[] = { @@ -109,10 +109,10 @@ static int dapm_down_seq[] = { [snd_soc_dapm_dai_in] = 10, [snd_soc_dapm_dai_out] = 10, [snd_soc_dapm_dai_link] = 11, - [snd_soc_dapm_clock_supply] = 12, - [snd_soc_dapm_regulator_supply] = 12, [snd_soc_dapm_supply] = 12, - [snd_soc_dapm_post] = 13, + [snd_soc_dapm_clock_supply] = 13, + [snd_soc_dapm_regulator_supply] = 13, + [snd_soc_dapm_post] = 14, }; static void pop_wait(u32 pop_time) @@ -409,6 +409,12 @@ static inline void soc_widget_unlock(struct snd_soc_dapm_widget *w) mutex_unlock(&w->platform->mutex); } +static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm) +{ + if (dapm->codec && dapm->codec->using_regmap) + regmap_async_complete(dapm->codec->control_data); +} + static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w, unsigned short reg, unsigned int mask, unsigned int value) { @@ -417,8 +423,9 @@ static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w, int ret; if (w->codec && w->codec->using_regmap) { - ret = regmap_update_bits_check(w->codec->control_data, - reg, mask, value, &change); + ret = regmap_update_bits_check_async(w->codec->control_data, + reg, mask, value, + &change); if (ret != 0) return ret; } else { @@ -499,18 +506,22 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, int val; struct soc_mixer_control *mc = (struct soc_mixer_control *) w->kcontrol_news[i].private_value; - unsigned int reg = mc->reg; + int reg = mc->reg; unsigned int shift = mc->shift; int max = mc->max; unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert; - val = soc_widget_read(w, reg); - val = (val >> shift) & mask; - if (invert) - val = max - val; + if (reg != SND_SOC_NOPM) { + val = soc_widget_read(w, reg); + val = (val >> shift) & mask; + if (invert) + val = max - val; + p->connect = !!val; + } else { + p->connect = 0; + } - p->connect = !!val; } break; case snd_soc_dapm_mux: { @@ -1197,6 +1208,8 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, { int ret; + soc_dapm_async_complete(w->dapm); + if (SND_SOC_DAPM_EVENT_ON(event)) { if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) { ret = regulator_allow_bypass(w->regulator, false); @@ -1230,6 +1243,8 @@ int dapm_clock_event(struct snd_soc_dapm_widget *w, if (!w->clk) return -EIO; + soc_dapm_async_complete(w->dapm); + #ifdef CONFIG_HAVE_CLK if (SND_SOC_DAPM_EVENT_ON(event)) { return clk_prepare_enable(w->clk); @@ -1422,6 +1437,7 @@ static void dapm_seq_check_event(struct snd_soc_card *card, if (w->event && (w->event_flags & event)) { pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n", w->name, ev_name); + soc_dapm_async_complete(w->dapm); trace_snd_soc_dapm_widget_event_start(w, event); ret = w->event(w, NULL, event); trace_snd_soc_dapm_widget_event_done(w, event); @@ -1494,6 +1510,7 @@ static void dapm_seq_run(struct snd_soc_card *card, struct list_head *list, int event, bool power_up) { struct snd_soc_dapm_widget *w, *n; + struct snd_soc_dapm_context *d; LIST_HEAD(pending); int cur_sort = -1; int cur_subseq = -1; @@ -1524,6 +1541,9 @@ static void dapm_seq_run(struct snd_soc_card *card, cur_subseq); } + if (cur_dapm && w->dapm != cur_dapm) + soc_dapm_async_complete(cur_dapm); + INIT_LIST_HEAD(&pending); cur_sort = -1; cur_subseq = INT_MIN; @@ -1582,6 +1602,10 @@ static void dapm_seq_run(struct snd_soc_card *card, cur_dapm->seq_notifier(cur_dapm, i, cur_subseq); } + + list_for_each_entry(d, &card->dapm_list, list) { + soc_dapm_async_complete(d); + } } static void dapm_widget_update(struct snd_soc_card *card) @@ -1840,6 +1864,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) */ switch (w->id) { case snd_soc_dapm_siggen: + case snd_soc_dapm_vmid: break; case snd_soc_dapm_supply: case snd_soc_dapm_regulator_supply: @@ -2791,7 +2816,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, struct snd_soc_card *card = codec->card; struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg = mc->reg; + int reg = mc->reg; unsigned int shift = mc->shift; int max = mc->max; unsigned int mask = (1 << fls(max)) - 1; @@ -2804,7 +2829,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, kcontrol->id.name); mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - if (dapm_kcontrol_is_powered(kcontrol)) + if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) val = (snd_soc_read(codec, reg) >> shift) & mask; else val = dapm_kcontrol_get_value(kcontrol); @@ -2835,7 +2860,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, struct snd_soc_card *card = codec->card; struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg = mc->reg; + int reg = mc->reg; unsigned int shift = mc->shift; int max = mc->max; unsigned int mask = (1 << fls(max)) - 1; @@ -2857,19 +2882,24 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - dapm_kcontrol_set_value(kcontrol, val); + change = dapm_kcontrol_set_value(kcontrol, val); + + if (reg != SND_SOC_NOPM) { + mask = mask << shift; + val = val << shift; - mask = mask << shift; - val = val << shift; + change = snd_soc_test_bits(codec, reg, mask, val); + } - change = snd_soc_test_bits(codec, reg, mask, val); if (change) { - update.kcontrol = kcontrol; - update.reg = reg; - update.mask = mask; - update.val = val; + if (reg != SND_SOC_NOPM) { + update.kcontrol = kcontrol; + update.reg = reg; + update.mask = mask; + update.val = val; - card->update = &update; + card->update = &update; + } soc_dapm_mixer_update_power(card, kcontrol, connect); diff --git a/sound/soc/soc-devres.c b/sound/soc/soc-devres.c new file mode 100644 index 000000000000..b1d732255c02 --- /dev/null +++ b/sound/soc/soc-devres.c @@ -0,0 +1,86 @@ +/* + * soc-devres.c -- ALSA SoC Audio Layer devres functions + * + * Copyright (C) 2013 Linaro Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <sound/soc.h> + +static void devm_component_release(struct device *dev, void *res) +{ + snd_soc_unregister_component(*(struct device **)res); +} + +/** + * devm_snd_soc_register_component - resource managed component registration + * @dev: Device used to manage component + * @cmpnt_drv: Component driver + * @dai_drv: DAI driver + * @num_dai: Number of DAIs to register + * + * Register a component with automatic unregistration when the device is + * unregistered. + */ +int devm_snd_soc_register_component(struct device *dev, + const struct snd_soc_component_driver *cmpnt_drv, + struct snd_soc_dai_driver *dai_drv, int num_dai) +{ + struct device **ptr; + int ret; + + ptr = devres_alloc(devm_component_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = snd_soc_register_component(dev, cmpnt_drv, dai_drv, num_dai); + if (ret == 0) { + *ptr = dev; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return ret; +} +EXPORT_SYMBOL_GPL(devm_snd_soc_register_component); + +static void devm_card_release(struct device *dev, void *res) +{ + snd_soc_unregister_card(*(struct snd_soc_card **)res); +} + +/** + * devm_snd_soc_register_card - resource managed card registration + * @dev: Device used to manage card + * @card: Card to register + * + * Register a card with automatic unregistration when the device is + * unregistered. + */ +int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card) +{ + struct device **ptr; + int ret; + + ptr = devres_alloc(devm_card_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = snd_soc_register_card(card); + if (ret == 0) { + *ptr = dev; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return ret; +} +EXPORT_SYMBOL_GPL(devm_snd_soc_register_card); diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index e29ec3cd84b1..0c469cbbe881 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -36,6 +36,15 @@ static struct dmaengine_pcm *soc_platform_to_pcm(struct snd_soc_platform *p) return container_of(p, struct dmaengine_pcm, platform); } +static struct device *dmaengine_dma_dev(struct dmaengine_pcm *pcm, + struct snd_pcm_substream *substream) +{ + if (!pcm->chan[substream->stream]) + return NULL; + + return pcm->chan[substream->stream]->device->dev; +} + /** * snd_dmaengine_pcm_prepare_slave_config() - Generic prepare_slave_config callback * @substream: PCM substream @@ -75,12 +84,19 @@ static int dmaengine_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream); + int (*prepare_slave_config)(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct dma_slave_config *slave_config); struct dma_slave_config slave_config; int ret; - if (pcm->config->prepare_slave_config) { - ret = pcm->config->prepare_slave_config(substream, params, - &slave_config); + if (!pcm->config) + prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config; + else + prepare_slave_config = pcm->config->prepare_slave_config; + + if (prepare_slave_config) { + ret = prepare_slave_config(substream, params, &slave_config); if (ret) return ret; @@ -92,28 +108,54 @@ static int dmaengine_pcm_hw_params(struct snd_pcm_substream *substream, return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); } -static int dmaengine_pcm_open(struct snd_pcm_substream *substream) +static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); + struct device *dma_dev = dmaengine_dma_dev(pcm, substream); struct dma_chan *chan = pcm->chan[substream->stream]; + struct snd_dmaengine_dai_dma_data *dma_data; + struct dma_slave_caps dma_caps; + struct snd_pcm_hardware hw; int ret; - ret = snd_soc_set_runtime_hwparams(substream, + if (pcm->config && pcm->config->pcm_hardware) + return snd_soc_set_runtime_hwparams(substream, pcm->config->pcm_hardware); - if (ret) - return ret; - return snd_dmaengine_pcm_open(substream, chan); + dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + + memset(&hw, 0, sizeof(hw)); + hw.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED; + hw.periods_min = 2; + hw.periods_max = UINT_MAX; + hw.period_bytes_min = 256; + hw.period_bytes_max = dma_get_max_seg_size(dma_dev); + hw.buffer_bytes_max = SIZE_MAX; + hw.fifo_size = dma_data->fifo_size; + + ret = dma_get_slave_caps(chan, &dma_caps); + if (ret == 0) { + if (dma_caps.cmd_pause) + hw.info |= SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME; + } + + return snd_soc_set_runtime_hwparams(substream, &hw); } -static struct device *dmaengine_dma_dev(struct dmaengine_pcm *pcm, - struct snd_pcm_substream *substream) +static int dmaengine_pcm_open(struct snd_pcm_substream *substream) { - if (!pcm->chan[substream->stream]) - return NULL; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); + struct dma_chan *chan = pcm->chan[substream->stream]; + int ret; - return pcm->chan[substream->stream]->device->dev; + ret = dmaengine_pcm_set_runtime_hwparams(substream); + if (ret) + return ret; + + return snd_dmaengine_pcm_open(substream, chan); } static void dmaengine_pcm_free(struct snd_pcm *pcm) @@ -126,6 +168,9 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel( struct snd_pcm_substream *substream) { struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); + struct snd_dmaengine_dai_dma_data *dma_data; + + dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) && pcm->chan[0]) return pcm->chan[0]; @@ -134,22 +179,42 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel( return pcm->config->compat_request_channel(rtd, substream); return snd_dmaengine_pcm_request_channel(pcm->config->compat_filter_fn, - snd_soc_dai_get_dma_data(rtd->cpu_dai, substream)); + dma_data->filter_data); } static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); const struct snd_dmaengine_pcm_config *config = pcm->config; + struct device *dev = rtd->platform->dev; + struct snd_dmaengine_dai_dma_data *dma_data; struct snd_pcm_substream *substream; + size_t prealloc_buffer_size; + size_t max_buffer_size; unsigned int i; int ret; + if (config && config->prealloc_buffer_size) { + prealloc_buffer_size = config->prealloc_buffer_size; + max_buffer_size = config->pcm_hardware->buffer_bytes_max; + } else { + prealloc_buffer_size = 512 * 1024; + max_buffer_size = SIZE_MAX; + } + + for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { substream = rtd->pcm->streams[i].substream; if (!substream) continue; + dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + + if (!pcm->chan[i] && + (pcm->flags & SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) + pcm->chan[i] = dma_request_slave_channel(dev, + dma_data->chan_name); + if (!pcm->chan[i] && (pcm->flags & SND_DMAENGINE_PCM_FLAG_COMPAT)) { pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd, substream); @@ -165,8 +230,8 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) ret = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, dmaengine_dma_dev(pcm, substream), - config->prealloc_buffer_size, - config->pcm_hardware->buffer_bytes_max); + prealloc_buffer_size, + max_buffer_size); if (ret) goto err_free; } @@ -222,7 +287,9 @@ static void dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, { unsigned int i; - if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_DT) || !dev->of_node) + if ((pcm->flags & (SND_DMAENGINE_PCM_FLAG_NO_DT | + SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) || + !dev->of_node) return; if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) { diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c index 122c0c18b9dd..4f11d23f2062 100644 --- a/sound/soc/soc-io.c +++ b/sound/soc/soc-io.c @@ -65,31 +65,6 @@ static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg) return val; } -/* Primitive bulk write support for soc-cache. The data pointed to by - * `data' needs to already be in the form the hardware expects. Any - * data written through this function will not go through the cache as - * it only handles writing to volatile or out of bounds registers. - * - * This is currently only supported for devices using the regmap API - * wrappers. - */ -static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, - unsigned int reg, - const void *data, size_t len) -{ - /* To ensure that we don't get out of sync with the cache, check - * whether the base register is volatile or if we've directly asked - * to bypass the cache. Out of bounds registers are considered - * volatile. - */ - if (!codec->cache_bypass - && !snd_soc_codec_volatile_register(codec, reg) - && reg < codec->driver->reg_cache_size) - return -EINVAL; - - return regmap_raw_write(codec->control_data, reg, data, len); -} - /** * snd_soc_codec_set_cache_io: Set up standard I/O functions. * @@ -119,7 +94,6 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, memset(&config, 0, sizeof(config)); codec->write = hw_write; codec->read = hw_read; - codec->bulk_write_raw = snd_soc_hw_bulk_write_raw; config.reg_bits = addr_bits; config.val_bits = data_bits; diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index 71358e3b54d9..23d43dac91da 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -65,6 +65,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) struct snd_soc_codec *codec; struct snd_soc_dapm_context *dapm; struct snd_soc_jack_pin *pin; + unsigned int sync = 0; int enable; trace_snd_soc_jack_report(jack, mask, status); @@ -92,12 +93,16 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) snd_soc_dapm_enable_pin(dapm, pin->pin); else snd_soc_dapm_disable_pin(dapm, pin->pin); + + /* we need to sync for this case only */ + sync = 1; } /* Report before the DAPM sync to help users updating micbias status */ blocking_notifier_call_chain(&jack->notifier, jack->status, jack); - snd_soc_dapm_sync(dapm); + if (sync) + snd_soc_dapm_sync(dapm); snd_jack_report(jack->jack, jack->status); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 330c9a6b5cb5..d4498723b375 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -721,7 +721,7 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, 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", + 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); @@ -749,7 +749,7 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe, if (dpcm->fe == fe) continue; - dev_dbg(fe->dev, " reparent %s path %s %s %s\n", + 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); @@ -773,7 +773,7 @@ static void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE) continue; - dev_dbg(fe->dev, " freed DSP %s path %s %s %s\n", + 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); @@ -2116,7 +2116,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) pcm->private_free = platform->driver->pcm_free; out: - dev_info(rtd->card->dev, " %s <-> %s mapping ok\n", codec_dai->name, + dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", codec_dai->name, cpu_dai->name); return ret; } diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index 29b211e9c060..5e633659c1b3 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -75,7 +75,11 @@ static const struct snd_pcm_hardware dummy_dma_hardware = { static int dummy_dma_open(struct snd_pcm_substream *substream) { - snd_soc_set_runtime_hwparams(substream, &dummy_dma_hardware); + struct snd_soc_pcm_runtime *rtd = substream->private_data; + + /* BE's dont need dummy params */ + if (!rtd->dai_link->no_pcm) + snd_soc_set_runtime_hwparams(substream, &dummy_dma_hardware); return 0; } diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index f056f632557c..7b2d23ba69b3 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -56,7 +56,6 @@ static const struct snd_pcm_hardware tegra_pcm_hardware = { static const struct snd_dmaengine_pcm_config tegra_dmaengine_pcm_config = { .pcm_hardware = &tegra_pcm_hardware, .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, - .compat_filter_fn = NULL, .prealloc_buffer_size = PAGE_SIZE * 8, }; diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index d0323a693ba2..999550bbad40 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -262,7 +262,9 @@ static int usb_stream_hwdep_mmap(struct snd_hwdep *hw, } area->vm_ops = &usb_stream_hwdep_vm_ops; - area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; + area->vm_flags |= VM_DONTDUMP; + if (!read) + area->vm_flags |= VM_DONTEXPAND; area->vm_private_data = us122l; atomic_inc(&us122l->mmap_count); out: diff --git a/tools/testing/selftests/timers/posix_timers.c b/tools/testing/selftests/timers/posix_timers.c index 4fa655d68a81..41bd85559d4b 100644 --- a/tools/testing/selftests/timers/posix_timers.c +++ b/tools/testing/selftests/timers/posix_timers.c @@ -151,7 +151,7 @@ static int check_timer_create(int which) fflush(stdout); done = 0; - timer_create(which, NULL, &id); + err = timer_create(which, NULL, &id); if (err < 0) { perror("Can't create timer\n"); return -1; |