mirror of
https://github.com/torvalds/linux.git
synced 2026-06-05 13:06:59 +02:00
Merge branch 'asoc-5.5' into asoc-next
This commit is contained in:
commit
94fae3e24c
90
Documentation/devicetree/bindings/sound/adi,adau7118.yaml
Normal file
90
Documentation/devicetree/bindings/sound/adi,adau7118.yaml
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/adi,adau7118.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
|
||||
title: Analog Devices ADAU7118 8 Channel PDM to I2S/TDM Converter
|
||||
|
||||
maintainers:
|
||||
- Nuno Sá <nuno.sa@analog.com>
|
||||
|
||||
description: |
|
||||
Analog Devices ADAU7118 8 Channel PDM to I2S/TDM Converter over I2C or HW
|
||||
standalone mode.
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ADAU7118.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,adau7118
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
IOVDD-supply:
|
||||
description: Digital Input/Output Power Supply.
|
||||
$ref: "/schemas/types.yaml#/definitions/phandle"
|
||||
|
||||
DVDD-supply:
|
||||
description: Internal Core Digital Power Supply.
|
||||
$ref: "/schemas/types.yaml#/definitions/phandle"
|
||||
|
||||
adi,decimation-ratio:
|
||||
description: |
|
||||
This property set's the decimation ratio of PDM to PCM audio data.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
- enum: [64, 32, 16]
|
||||
default: 64
|
||||
|
||||
adi,pdm-clk-map:
|
||||
description: |
|
||||
The ADAU7118 has two PDM clocks for the four Inputs. Each input must be
|
||||
assigned to one of these two clocks. This property set's the mapping
|
||||
between the clocks and the inputs.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
- minItems: 4
|
||||
maxItems: 4
|
||||
items:
|
||||
maximum: 1
|
||||
default: [0, 0, 1, 1]
|
||||
|
||||
required:
|
||||
- "#sound-dai-cells"
|
||||
- compatible
|
||||
- IOVDD-supply
|
||||
- DVDD-supply
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c0 {
|
||||
/* example with i2c support */
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "okay";
|
||||
adau7118_codec: adau7118-codec@14 {
|
||||
compatible = "adi,adau7118";
|
||||
reg = <14>;
|
||||
#sound-dai-cells = <0>;
|
||||
status = "okay";
|
||||
IOVDD-supply = <&supply>;
|
||||
DVDD-supply = <&supply>;
|
||||
adi,pdm-clk-map = <1 1 0 0>;
|
||||
adi,decimation-ratio = <16>;
|
||||
};
|
||||
};
|
||||
|
||||
/* example with hw standalone mode */
|
||||
adau7118_codec_hw: adau7118-codec-hw {
|
||||
compatible = "adi,adau7118";
|
||||
#sound-dai-cells = <0>;
|
||||
status = "okay";
|
||||
IOVDD-supply = <&supply>;
|
||||
DVDD-supply = <&supply>;
|
||||
};
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/allwinner,sun8i-a23-codec-analog.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Allwinner A23 Analog Codec Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
- Maxime Ripard <maxime.ripard@bootlin.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
# FIXME: This is documented in the PRCM binding, but needs to be
|
||||
# migrated here at some point
|
||||
# - allwinner,sun8i-a23-codec-analog
|
||||
- allwinner,sun8i-h3-codec-analog
|
||||
- allwinner,sun8i-v3s-codec-analog
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
codec_analog: codec-analog@1f015c0 {
|
||||
compatible = "allwinner,sun8i-h3-codec-analog";
|
||||
reg = <0x01f015c0 0x4>;
|
||||
};
|
||||
|
||||
...
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
Audio Binding for Arndale boards
|
||||
|
||||
Required properties:
|
||||
- compatible : Can be the following,
|
||||
"samsung,arndale-rt5631"
|
||||
- compatible : Can be one of the following:
|
||||
"samsung,arndale-rt5631",
|
||||
"samsung,arndale-wm1811"
|
||||
|
||||
- samsung,audio-cpu: The phandle of the Samsung I2S controller
|
||||
- samsung,audio-codec: The phandle of the audio codec
|
||||
|
|
|
|||
36
Documentation/devicetree/bindings/sound/fsl,mqs.txt
Normal file
36
Documentation/devicetree/bindings/sound/fsl,mqs.txt
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
fsl,mqs audio CODEC
|
||||
|
||||
Required properties:
|
||||
- compatible : Must contain one of "fsl,imx6sx-mqs", "fsl,codec-mqs"
|
||||
"fsl,imx8qm-mqs", "fsl,imx8qxp-mqs".
|
||||
- clocks : A list of phandles + clock-specifiers, one for each entry in
|
||||
clock-names
|
||||
- clock-names : "mclk" - must required.
|
||||
"core" - required if compatible is "fsl,imx8qm-mqs", it
|
||||
is for register access.
|
||||
- gpr : A phandle of General Purpose Registers in IOMUX Controller.
|
||||
Required if compatible is "fsl,imx6sx-mqs".
|
||||
|
||||
Required if compatible is "fsl,imx8qm-mqs":
|
||||
- power-domains: A phandle of PM domain provider node.
|
||||
- reg: Offset and length of the register set for the device.
|
||||
|
||||
Example:
|
||||
|
||||
mqs: mqs {
|
||||
compatible = "fsl,imx6sx-mqs";
|
||||
gpr = <&gpr>;
|
||||
clocks = <&clks IMX6SX_CLK_SAI1>;
|
||||
clock-names = "mclk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
mqs: mqs@59850000 {
|
||||
compatible = "fsl,imx8qm-mqs";
|
||||
reg = <0x59850000 0x10000>;
|
||||
clocks = <&clk IMX8QM_AUD_MQS_IPG>,
|
||||
<&clk IMX8QM_AUD_MQS_HMCLK>;
|
||||
clock-names = "core", "mclk";
|
||||
power-domains = <&pd_mqs0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
|
@ -4,6 +4,10 @@ Required properties:
|
|||
- compatible = "mediatek,mt68183-audio";
|
||||
- reg: register location and size
|
||||
- interrupts: should contain AFE interrupt
|
||||
- resets: Must contain an entry for each entry in reset-names
|
||||
See ../reset/reset.txt for details.
|
||||
- reset-names: should have these reset names:
|
||||
"audiosys";
|
||||
- power-domains: should define the power domain
|
||||
- clocks: Must contain an entry for each entry in clock-names
|
||||
- clock-names: should have these clock names:
|
||||
|
|
@ -20,6 +24,8 @@ Example:
|
|||
compatible = "mediatek,mt8183-audio";
|
||||
reg = <0 0x11220000 0 0x1000>;
|
||||
interrupts = <GIC_SPI 161 IRQ_TYPE_LEVEL_LOW>;
|
||||
resets = <&watchdog MT8183_TOPRGU_AUDIO_SW_RST>;
|
||||
reset-names = "audiosys";
|
||||
power-domains = <&scpsys MT8183_POWER_DOMAIN_AUDIO>;
|
||||
clocks = <&infrasys CLK_INFRA_AUDIO>,
|
||||
<&infrasys CLK_INFRA_AUDIO_26M_BCLK>,
|
||||
|
|
|
|||
|
|
@ -2,9 +2,11 @@ MT8183 with MT6358, TS3A227 and MAX98357 CODECS
|
|||
|
||||
Required properties:
|
||||
- compatible : "mediatek,mt8183_mt6358_ts3a227_max98357"
|
||||
- mediatek,headset-codec: the phandles of ts3a227 codecs
|
||||
- mediatek,platform: the phandle of MT8183 ASoC platform
|
||||
|
||||
Optional properties:
|
||||
- mediatek,headset-codec: the phandles of ts3a227 codecs
|
||||
|
||||
Example:
|
||||
|
||||
sound {
|
||||
|
|
|
|||
|
|
@ -268,6 +268,7 @@ Required properties:
|
|||
- "renesas,rcar_sound-r8a7745" (RZ/G1E)
|
||||
- "renesas,rcar_sound-r8a77470" (RZ/G1C)
|
||||
- "renesas,rcar_sound-r8a774a1" (RZ/G2M)
|
||||
- "renesas,rcar_sound-r8a774b1" (RZ/G2N)
|
||||
- "renesas,rcar_sound-r8a774c0" (RZ/G2E)
|
||||
- "renesas,rcar_sound-r8a7778" (R-Car M1A)
|
||||
- "renesas,rcar_sound-r8a7779" (R-Car H1)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,14 @@ Required properties:
|
|||
| 1 | 1 | 0x3b |
|
||||
-------------------------------------
|
||||
|
||||
Optional properties:
|
||||
|
||||
- realtek,temperature_calib
|
||||
u32. The temperature was measured while doing the calibration. Units: Celsius degree
|
||||
|
||||
- realtek,r0_calib
|
||||
u32. This is r0 calibration data which was measured in factory mode.
|
||||
|
||||
Pins on the device (for linking into audio routes) for RT1011:
|
||||
|
||||
* SPO
|
||||
|
|
@ -29,4 +37,6 @@ Example:
|
|||
rt1011: codec@38 {
|
||||
compatible = "realtek,rt1011";
|
||||
reg = <0x38>;
|
||||
realtek,temperature_calib = <25>;
|
||||
realtek,r0_calib = <0x224050>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
* Allwinner Codec Analog Controls
|
||||
|
||||
Required properties:
|
||||
- compatible: must be one of the following compatibles:
|
||||
- "allwinner,sun8i-a23-codec-analog"
|
||||
- "allwinner,sun8i-h3-codec-analog"
|
||||
- "allwinner,sun8i-v3s-codec-analog"
|
||||
|
||||
Required properties if not a sub-node of the PRCM node:
|
||||
- reg: must contain the registers location and length
|
||||
|
||||
Example:
|
||||
prcm: prcm@1f01400 {
|
||||
codec_analog: codec-analog {
|
||||
compatible = "allwinner,sun8i-a23-codec-analog";
|
||||
};
|
||||
};
|
||||
34
Documentation/devicetree/bindings/sound/tas2562.txt
Normal file
34
Documentation/devicetree/bindings/sound/tas2562.txt
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
Texas Instruments TAS2562 Smart PA
|
||||
|
||||
The TAS2562 is a mono, digital input Class-D audio amplifier optimized for
|
||||
efficiently driving high peak power into small loudspeakers.
|
||||
Integrated speaker voltage and current sense provides for
|
||||
real time monitoring of loudspeaker behavior.
|
||||
|
||||
Required properties:
|
||||
- #address-cells - Should be <1>.
|
||||
- #size-cells - Should be <0>.
|
||||
- compatible: - Should contain "ti,tas2562".
|
||||
- reg: - The i2c address. Should be 0x4c, 0x4d, 0x4e or 0x4f.
|
||||
- ti,imon-slot-no:- TDM TX current sense time slot.
|
||||
|
||||
Optional properties:
|
||||
- interrupt-parent: phandle to the interrupt controller which provides
|
||||
the interrupt.
|
||||
- interrupts: (GPIO) interrupt to which the chip is connected.
|
||||
- shut-down: GPIO used to control the state of the device.
|
||||
|
||||
Examples:
|
||||
tas2562@4c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "ti,tas2562";
|
||||
reg = <0x4c>;
|
||||
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <14>;
|
||||
|
||||
shut-down = <&gpio1 15 0>;
|
||||
ti,imon-slot-no = <0>;
|
||||
};
|
||||
|
||||
37
Documentation/devicetree/bindings/sound/tas2770.txt
Normal file
37
Documentation/devicetree/bindings/sound/tas2770.txt
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
Texas Instruments TAS2770 Smart PA
|
||||
|
||||
The TAS2770 is a mono, digital input Class-D audio amplifier optimized for
|
||||
efficiently driving high peak power into small loudspeakers.
|
||||
Integrated speaker voltage and current sense provides for
|
||||
real time monitoring of loudspeaker behavior.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: - Should contain "ti,tas2770".
|
||||
- reg: - The i2c address. Should contain <0x4c>, <0x4d>,<0x4e>, or <0x4f>.
|
||||
- #address-cells - Should be <1>.
|
||||
- #size-cells - Should be <0>.
|
||||
- ti,asi-format: - Sets TDM RX capture edge. 0->Rising; 1->Falling.
|
||||
- ti,imon-slot-no:- TDM TX current sense time slot.
|
||||
- ti,vmon-slot-no:- TDM TX voltage sense time slot.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- interrupt-parent: the phandle to the interrupt controller which provides
|
||||
the interrupt.
|
||||
- interrupts: interrupt specification for data-ready.
|
||||
|
||||
Examples:
|
||||
|
||||
tas2770@4c {
|
||||
compatible = "ti,tas2770";
|
||||
reg = <0x4c>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupt-parent = <&msm_gpio>;
|
||||
interrupts = <97 0>;
|
||||
ti,asi-format = <0>;
|
||||
ti,imon-slot-no = <0>;
|
||||
ti,vmon-slot-no = <2>;
|
||||
};
|
||||
|
||||
|
|
@ -1002,6 +1002,7 @@ F: drivers/media/i2c/adv7842*
|
|||
|
||||
ANALOG DEVICES INC ASOC CODEC DRIVERS
|
||||
M: Lars-Peter Clausen <lars@metafoo.de>
|
||||
M: Nuno Sá <nuno.sa@analog.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
W: http://wiki.analog.com/
|
||||
W: http://ez.analog.com/community/linux-device-drivers
|
||||
|
|
|
|||
|
|
@ -83,6 +83,11 @@ void snd_dmaengine_pcm_set_config_from_dai_data(
|
|||
const struct snd_dmaengine_dai_dma_data *dma_data,
|
||||
struct dma_slave_config *config);
|
||||
|
||||
int snd_dmaengine_pcm_refine_runtime_hwparams(
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_dmaengine_dai_dma_data *dma_data,
|
||||
struct snd_pcm_hardware *hw,
|
||||
struct dma_chan *chan);
|
||||
|
||||
/*
|
||||
* Try to request the DMA channel using compat_request_channel or
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ struct snd_pcm_substream;
|
|||
struct snd_pcm_hw_params;
|
||||
struct snd_soc_pcm_runtime;
|
||||
struct snd_pcm;
|
||||
struct snd_soc_component;
|
||||
|
||||
extern int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params);
|
||||
|
|
@ -23,8 +24,29 @@ extern int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
|
|||
struct vm_area_struct *vma);
|
||||
extern int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream);
|
||||
extern void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm);
|
||||
extern int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd);
|
||||
extern const struct snd_pcm_ops pxa2xx_pcm_ops;
|
||||
extern void pxa2xx_soc_pcm_free(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm);
|
||||
extern int pxa2xx_soc_pcm_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd);
|
||||
extern int pxa2xx_soc_pcm_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream);
|
||||
extern int pxa2xx_soc_pcm_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream);
|
||||
extern int pxa2xx_soc_pcm_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params);
|
||||
extern int pxa2xx_soc_pcm_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream);
|
||||
extern int pxa2xx_soc_pcm_prepare(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream);
|
||||
extern int pxa2xx_soc_pcm_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd);
|
||||
extern snd_pcm_uframes_t
|
||||
pxa2xx_soc_pcm_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream);
|
||||
extern int pxa2xx_soc_pcm_mmap(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma);
|
||||
|
||||
/* AC97 */
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#ifndef __SIMPLE_CARD_UTILS_H
|
||||
#define __SIMPLE_CARD_UTILS_H
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#define asoc_simple_init_hp(card, sjack, prefix) \
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ struct snd_soc_acpi_mach_params {
|
|||
* all firmware/topology related fields.
|
||||
*
|
||||
* @id: ACPI ID (usually the codec's) used to find a matching machine driver.
|
||||
* @link_mask: describes required board layout, e.g. for SoundWire.
|
||||
* @drv_name: machine driver name
|
||||
* @fw_filename: firmware file name. Used when SOF is not enabled.
|
||||
* @board: board name
|
||||
|
|
@ -90,6 +91,7 @@ struct snd_soc_acpi_mach_params {
|
|||
/* Descriptor for SST ASoC machine driver */
|
||||
struct snd_soc_acpi_mach {
|
||||
const u8 id[ACPI_ID_LEN];
|
||||
const u32 link_mask;
|
||||
const char *drv_name;
|
||||
const char *fw_filename;
|
||||
const char *board;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,6 @@
|
|||
* soc-component.h
|
||||
*
|
||||
* Copyright (c) 2019 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#ifndef __SOC_COMPONENT_H
|
||||
#define __SOC_COMPONENT_H
|
||||
|
|
@ -51,8 +47,10 @@ struct snd_soc_component_driver {
|
|||
unsigned int reg, unsigned int val);
|
||||
|
||||
/* pcm creation and destruction */
|
||||
int (*pcm_new)(struct snd_soc_pcm_runtime *rtd);
|
||||
void (*pcm_free)(struct snd_pcm *pcm);
|
||||
int (*pcm_construct)(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd);
|
||||
void (*pcm_destruct)(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm);
|
||||
|
||||
/* component wide operations */
|
||||
int (*set_sysclk)(struct snd_soc_component *component,
|
||||
|
|
@ -74,7 +72,40 @@ struct snd_soc_component_driver {
|
|||
int (*set_bias_level)(struct snd_soc_component *component,
|
||||
enum snd_soc_bias_level level);
|
||||
|
||||
const struct snd_pcm_ops *ops;
|
||||
int (*open)(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream);
|
||||
int (*close)(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream);
|
||||
int (*ioctl)(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
unsigned int cmd, void *arg);
|
||||
int (*hw_params)(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params);
|
||||
int (*hw_free)(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream);
|
||||
int (*prepare)(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream);
|
||||
int (*trigger)(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd);
|
||||
snd_pcm_uframes_t (*pointer)(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream);
|
||||
int (*get_time_info)(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, struct timespec *system_ts,
|
||||
struct timespec *audio_ts,
|
||||
struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
|
||||
struct snd_pcm_audio_tstamp_report *audio_tstamp_report);
|
||||
int (*copy_user)(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int channel,
|
||||
unsigned long pos, void __user *buf,
|
||||
unsigned long bytes);
|
||||
struct page *(*page)(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
unsigned long offset);
|
||||
int (*mmap)(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma);
|
||||
|
||||
const struct snd_compr_ops *compr_ops;
|
||||
|
||||
/* probe ordering - for components with runtime dependencies */
|
||||
|
|
|
|||
|
|
@ -1148,7 +1148,6 @@ struct snd_soc_pcm_runtime {
|
|||
struct list_head component_list; /* list of connected components */
|
||||
|
||||
/* bit field */
|
||||
unsigned int dev_registered:1;
|
||||
unsigned int pop_wait:1;
|
||||
unsigned int fe_compr:1; /* for Dynamic PCM */
|
||||
};
|
||||
|
|
@ -1391,6 +1390,11 @@ static inline void snd_soc_dapm_mutex_unlock(struct snd_soc_dapm_context *dapm)
|
|||
mutex_unlock(&dapm->card->dapm_mutex);
|
||||
}
|
||||
|
||||
/* bypass */
|
||||
int snd_soc_pcm_lib_ioctl(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
unsigned int cmd, void *arg);
|
||||
|
||||
#include <sound/soc-component.h>
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -61,6 +61,9 @@ struct sof_dev_desc {
|
|||
/* list of machines using this configuration */
|
||||
struct snd_soc_acpi_mach *machines;
|
||||
|
||||
/* alternate list of machines using this configuration */
|
||||
struct snd_soc_acpi_mach *alt_machines;
|
||||
|
||||
/* Platform resource indexes in BAR / ACPI resources. */
|
||||
/* Must set to -1 if not used - add new items to end */
|
||||
int resindex_lpe_base;
|
||||
|
|
|
|||
34
include/sound/sof/dai-imx.h
Normal file
34
include/sound/sof/dai-imx.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
|
||||
/*
|
||||
* Copyright 2019 NXP
|
||||
*
|
||||
* Author: Daniel Baluta <daniel.baluta@nxp.com>
|
||||
*/
|
||||
|
||||
#ifndef __INCLUDE_SOUND_SOF_DAI_IMX_H__
|
||||
#define __INCLUDE_SOUND_SOF_DAI_IMX_H__
|
||||
|
||||
#include <sound/sof/header.h>
|
||||
|
||||
/* ESAI Configuration Request - SOF_IPC_DAI_ESAI_CONFIG */
|
||||
struct sof_ipc_dai_esai_params {
|
||||
struct sof_ipc_hdr hdr;
|
||||
|
||||
/* MCLK */
|
||||
uint16_t reserved1;
|
||||
uint16_t mclk_id;
|
||||
uint32_t mclk_direction;
|
||||
|
||||
uint32_t mclk_rate; /* MCLK frequency in Hz */
|
||||
uint32_t fsync_rate; /* FSYNC frequency in Hz */
|
||||
uint32_t bclk_rate; /* BCLK frequency in Hz */
|
||||
|
||||
/* TDM */
|
||||
uint32_t tdm_slots;
|
||||
uint32_t rx_slots;
|
||||
uint32_t tx_slots;
|
||||
uint16_t tdm_slot_width;
|
||||
uint16_t reserved2; /* alignment */
|
||||
} __packed;
|
||||
|
||||
#endif
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <sound/sof/header.h>
|
||||
#include <sound/sof/dai-intel.h>
|
||||
#include <sound/sof/dai-imx.h>
|
||||
|
||||
/*
|
||||
* DAI Configuration.
|
||||
|
|
@ -73,6 +74,7 @@ struct sof_ipc_dai_config {
|
|||
struct sof_ipc_dai_dmic_params dmic;
|
||||
struct sof_ipc_dai_hda_params hda;
|
||||
struct sof_ipc_dai_alh_params alh;
|
||||
struct sof_ipc_dai_esai_params esai;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#ifndef __INCLUDE_SOUND_SOF_HEADER_H__
|
||||
#define __INCLUDE_SOUND_SOF_HEADER_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <uapi/sound/sof/abi.h>
|
||||
|
||||
/** \addtogroup sof_uapi uAPI
|
||||
|
|
|
|||
|
|
@ -83,10 +83,10 @@ struct sof_ipc_stream_params {
|
|||
uint16_t sample_valid_bytes;
|
||||
uint16_t sample_container_bytes;
|
||||
|
||||
/* for notifying host period has completed - 0 means no period IRQ */
|
||||
uint32_t host_period_bytes;
|
||||
uint16_t no_stream_position; /**< 1 means don't send stream position */
|
||||
|
||||
uint32_t reserved[2];
|
||||
uint16_t reserved[3];
|
||||
uint16_t chmap[SOF_IPC_MAX_CHANNELS]; /**< channel map - SOF_CHMAP_ */
|
||||
} __packed;
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
/* SOF ABI version major, minor and patch numbers */
|
||||
#define SOF_ABI_MAJOR 3
|
||||
#define SOF_ABI_MINOR 10
|
||||
#define SOF_ABI_MINOR 11
|
||||
#define SOF_ABI_PATCH 0
|
||||
|
||||
/* SOF ABI version number. Format within 32bit word is MMmmmppp */
|
||||
|
|
|
|||
|
|
@ -111,7 +111,10 @@
|
|||
/* TODO: Add SAI tokens */
|
||||
|
||||
/* ESAI */
|
||||
#define SOF_TKN_IMX_ESAI_FIRST_TOKEN 1100
|
||||
/* TODO: Add ESAI tokens */
|
||||
#define SOF_TKN_IMX_ESAI_MCLK_ID 1100
|
||||
|
||||
/* Led control for mute switches */
|
||||
#define SOF_TKN_MUTE_LED_USE 1300
|
||||
#define SOF_TKN_MUTE_LED_DIRECTION 1301
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -175,7 +175,15 @@ void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
|
|||
}
|
||||
EXPORT_SYMBOL(pxa2xx_pcm_free_dma_buffers);
|
||||
|
||||
int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
void pxa2xx_soc_pcm_free(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm)
|
||||
{
|
||||
pxa2xx_pcm_free_dma_buffers(pcm);
|
||||
}
|
||||
EXPORT_SYMBOL(pxa2xx_soc_pcm_free);
|
||||
|
||||
int pxa2xx_soc_pcm_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_card *card = rtd->card->snd_card;
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
|
|
@ -203,18 +211,64 @@ int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
|||
}
|
||||
EXPORT_SYMBOL(pxa2xx_soc_pcm_new);
|
||||
|
||||
const struct snd_pcm_ops pxa2xx_pcm_ops = {
|
||||
.open = pxa2xx_pcm_open,
|
||||
.close = pxa2xx_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = pxa2xx_pcm_hw_params,
|
||||
.hw_free = pxa2xx_pcm_hw_free,
|
||||
.prepare = pxa2xx_pcm_prepare,
|
||||
.trigger = pxa2xx_pcm_trigger,
|
||||
.pointer = pxa2xx_pcm_pointer,
|
||||
.mmap = pxa2xx_pcm_mmap,
|
||||
};
|
||||
EXPORT_SYMBOL(pxa2xx_pcm_ops);
|
||||
int pxa2xx_soc_pcm_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
return pxa2xx_pcm_open(substream);
|
||||
}
|
||||
EXPORT_SYMBOL(pxa2xx_soc_pcm_open);
|
||||
|
||||
int pxa2xx_soc_pcm_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
return pxa2xx_pcm_close(substream);
|
||||
}
|
||||
EXPORT_SYMBOL(pxa2xx_soc_pcm_close);
|
||||
|
||||
int pxa2xx_soc_pcm_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
return pxa2xx_pcm_hw_params(substream, params);
|
||||
}
|
||||
EXPORT_SYMBOL(pxa2xx_soc_pcm_hw_params);
|
||||
|
||||
int pxa2xx_soc_pcm_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
return pxa2xx_pcm_hw_free(substream);
|
||||
}
|
||||
EXPORT_SYMBOL(pxa2xx_soc_pcm_hw_free);
|
||||
|
||||
int pxa2xx_soc_pcm_prepare(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
return pxa2xx_pcm_prepare(substream);
|
||||
}
|
||||
EXPORT_SYMBOL(pxa2xx_soc_pcm_prepare);
|
||||
|
||||
int pxa2xx_soc_pcm_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
return pxa2xx_pcm_trigger(substream, cmd);
|
||||
}
|
||||
EXPORT_SYMBOL(pxa2xx_soc_pcm_trigger);
|
||||
|
||||
snd_pcm_uframes_t
|
||||
pxa2xx_soc_pcm_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
return pxa2xx_pcm_pointer(substream);
|
||||
}
|
||||
EXPORT_SYMBOL(pxa2xx_soc_pcm_pointer);
|
||||
|
||||
int pxa2xx_soc_pcm_mmap(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
return pxa2xx_pcm_mmap(substream, vma);
|
||||
}
|
||||
EXPORT_SYMBOL(pxa2xx_soc_pcm_mmap);
|
||||
|
||||
MODULE_AUTHOR("Nicolas Pitre");
|
||||
MODULE_DESCRIPTION("Intel PXA2xx sound library");
|
||||
|
|
|
|||
|
|
@ -369,4 +369,87 @@ int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan);
|
||||
|
||||
/**
|
||||
* snd_dmaengine_pcm_refine_runtime_hwparams - Refine runtime hw params
|
||||
* @substream: PCM substream
|
||||
* @dma_data: DAI DMA data
|
||||
* @hw: PCM hw params
|
||||
* @chan: DMA channel to use for data transfers
|
||||
*
|
||||
* Returns 0 on success, a negative error code otherwise.
|
||||
*
|
||||
* This function will query DMA capability, then refine the pcm hardware
|
||||
* parameters.
|
||||
*/
|
||||
int snd_dmaengine_pcm_refine_runtime_hwparams(
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_dmaengine_dai_dma_data *dma_data,
|
||||
struct snd_pcm_hardware *hw,
|
||||
struct dma_chan *chan)
|
||||
{
|
||||
struct dma_slave_caps dma_caps;
|
||||
u32 addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
|
||||
snd_pcm_format_t i;
|
||||
int ret = 0;
|
||||
|
||||
if (!hw || !chan || !dma_data)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dma_get_slave_caps(chan, &dma_caps);
|
||||
if (ret == 0) {
|
||||
if (dma_caps.cmd_pause && dma_caps.cmd_resume)
|
||||
hw->info |= SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME;
|
||||
if (dma_caps.residue_granularity <= DMA_RESIDUE_GRANULARITY_SEGMENT)
|
||||
hw->info |= SNDRV_PCM_INFO_BATCH;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
addr_widths = dma_caps.dst_addr_widths;
|
||||
else
|
||||
addr_widths = dma_caps.src_addr_widths;
|
||||
}
|
||||
|
||||
/*
|
||||
* If SND_DMAENGINE_PCM_DAI_FLAG_PACK is set keep
|
||||
* hw.formats set to 0, meaning no restrictions are in place.
|
||||
* In this case it's the responsibility of the DAI driver to
|
||||
* provide the supported format information.
|
||||
*/
|
||||
if (!(dma_data->flags & SND_DMAENGINE_PCM_DAI_FLAG_PACK))
|
||||
/*
|
||||
* Prepare formats mask for valid/allowed sample types. If the
|
||||
* dma does not have support for the given physical word size,
|
||||
* it needs to be masked out so user space can not use the
|
||||
* format which produces corrupted audio.
|
||||
* In case the dma driver does not implement the slave_caps the
|
||||
* default assumption is that it supports 1, 2 and 4 bytes
|
||||
* widths.
|
||||
*/
|
||||
for (i = SNDRV_PCM_FORMAT_FIRST; i <= SNDRV_PCM_FORMAT_LAST; i++) {
|
||||
int bits = snd_pcm_format_physical_width(i);
|
||||
|
||||
/*
|
||||
* Enable only samples with DMA supported physical
|
||||
* widths
|
||||
*/
|
||||
switch (bits) {
|
||||
case 8:
|
||||
case 16:
|
||||
case 24:
|
||||
case 32:
|
||||
case 64:
|
||||
if (addr_widths & (1 << (bits / 8)))
|
||||
hw->formats |= pcm_format_to_bits(i);
|
||||
break;
|
||||
default:
|
||||
/* Unsupported types */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_refine_runtime_hwparams);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -759,14 +759,12 @@ static irqreturn_t dma_irq_handler(int irq, void *arg)
|
|||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static int acp_dma_open(struct snd_pcm_substream *substream)
|
||||
static int acp_dma_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
u16 bank;
|
||||
int ret = 0;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *prtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd,
|
||||
DRV_NAME);
|
||||
struct audio_drv_data *intr_data = dev_get_drvdata(component->dev);
|
||||
struct audio_substream_data *adata =
|
||||
kzalloc(sizeof(struct audio_substream_data), GFP_KERNEL);
|
||||
|
|
@ -834,7 +832,8 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int acp_dma_hw_params(struct snd_pcm_substream *substream,
|
||||
static int acp_dma_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
int status;
|
||||
|
|
@ -843,8 +842,6 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_pcm_runtime *runtime;
|
||||
struct audio_substream_data *rtd;
|
||||
struct snd_soc_pcm_runtime *prtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd,
|
||||
DRV_NAME);
|
||||
struct audio_drv_data *adata = dev_get_drvdata(component->dev);
|
||||
struct snd_soc_card *card = prtd->card;
|
||||
struct acp_platform_info *pinfo = snd_soc_card_get_drvdata(card);
|
||||
|
|
@ -995,7 +992,8 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
|
|||
return status;
|
||||
}
|
||||
|
||||
static int acp_dma_hw_free(struct snd_pcm_substream *substream)
|
||||
static int acp_dma_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_pcm_lib_free_pages(substream);
|
||||
}
|
||||
|
|
@ -1011,7 +1009,8 @@ static u64 acp_get_byte_count(struct audio_substream_data *rtd)
|
|||
return byte_count.bytescount;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
|
||||
static snd_pcm_uframes_t acp_dma_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
u32 buffersize;
|
||||
u32 pos = 0;
|
||||
|
|
@ -1053,13 +1052,15 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
|
|||
return bytes_to_frames(runtime, pos);
|
||||
}
|
||||
|
||||
static int acp_dma_mmap(struct snd_pcm_substream *substream,
|
||||
static int acp_dma_mmap(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
return snd_pcm_lib_default_mmap(substream, vma);
|
||||
}
|
||||
|
||||
static int acp_dma_prepare(struct snd_pcm_substream *substream)
|
||||
static int acp_dma_prepare(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct audio_substream_data *rtd = runtime->private_data;
|
||||
|
|
@ -1086,7 +1087,8 @@ static int acp_dma_prepare(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
static int acp_dma_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
|
@ -1132,10 +1134,9 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int acp_dma_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int acp_dma_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd,
|
||||
DRV_NAME);
|
||||
struct audio_drv_data *adata = dev_get_drvdata(component->dev);
|
||||
struct device *parent = component->dev->parent;
|
||||
|
||||
|
|
@ -1158,14 +1159,12 @@ static int acp_dma_new(struct snd_soc_pcm_runtime *rtd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int acp_dma_close(struct snd_pcm_substream *substream)
|
||||
static int acp_dma_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
u16 bank;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct audio_substream_data *rtd = runtime->private_data;
|
||||
struct snd_soc_pcm_runtime *prtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd,
|
||||
DRV_NAME);
|
||||
struct audio_drv_data *adata = dev_get_drvdata(component->dev);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
|
|
@ -1216,22 +1215,18 @@ static int acp_dma_close(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops acp_dma_ops = {
|
||||
.open = acp_dma_open,
|
||||
.close = acp_dma_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = acp_dma_hw_params,
|
||||
.hw_free = acp_dma_hw_free,
|
||||
.trigger = acp_dma_trigger,
|
||||
.pointer = acp_dma_pointer,
|
||||
.mmap = acp_dma_mmap,
|
||||
.prepare = acp_dma_prepare,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver acp_asoc_platform = {
|
||||
.name = DRV_NAME,
|
||||
.ops = &acp_dma_ops,
|
||||
.pcm_new = acp_dma_new,
|
||||
.name = DRV_NAME,
|
||||
.open = acp_dma_open,
|
||||
.close = acp_dma_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = acp_dma_hw_params,
|
||||
.hw_free = acp_dma_hw_free,
|
||||
.trigger = acp_dma_trigger,
|
||||
.pointer = acp_dma_pointer,
|
||||
.mmap = acp_dma_mmap,
|
||||
.prepare = acp_dma_prepare,
|
||||
.pcm_construct = acp_dma_new,
|
||||
};
|
||||
|
||||
static int acp_audio_probe(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -275,16 +275,12 @@ static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction)
|
|||
rtd->acp3x_base + mmACP_EXTERNAL_INTR_CNTL);
|
||||
}
|
||||
|
||||
static int acp3x_dma_open(struct snd_pcm_substream *substream)
|
||||
static int acp3x_dma_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *prtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd,
|
||||
DRV_NAME);
|
||||
struct i2s_dev_data *adata = dev_get_drvdata(component->dev);
|
||||
|
||||
struct i2s_stream_instance *i2s_data = kzalloc(sizeof(struct i2s_stream_instance),
|
||||
GFP_KERNEL);
|
||||
if (!i2s_data)
|
||||
|
|
@ -334,7 +330,8 @@ static u64 acp_get_byte_count(struct i2s_stream_instance *rtd, int direction)
|
|||
return byte_count;
|
||||
}
|
||||
|
||||
static int acp3x_dma_hw_params(struct snd_pcm_substream *substream,
|
||||
static int acp3x_dma_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
int status;
|
||||
|
|
@ -362,7 +359,8 @@ static int acp3x_dma_hw_params(struct snd_pcm_substream *substream,
|
|||
return status;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_pcm_substream *substream)
|
||||
static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
u32 pos = 0;
|
||||
u32 buffersize = 0;
|
||||
|
|
@ -379,33 +377,32 @@ static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_pcm_substream *substream)
|
|||
return bytes_to_frames(substream->runtime, pos);
|
||||
}
|
||||
|
||||
static int acp3x_dma_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int acp3x_dma_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd,
|
||||
DRV_NAME);
|
||||
struct device *parent = component->dev->parent;
|
||||
snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
|
||||
parent, MIN_BUFFER, MAX_BUFFER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acp3x_dma_hw_free(struct snd_pcm_substream *substream)
|
||||
static int acp3x_dma_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_pcm_lib_free_pages(substream);
|
||||
}
|
||||
|
||||
static int acp3x_dma_mmap(struct snd_pcm_substream *substream,
|
||||
static int acp3x_dma_mmap(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
return snd_pcm_lib_default_mmap(substream, vma);
|
||||
}
|
||||
|
||||
static int acp3x_dma_close(struct snd_pcm_substream *substream)
|
||||
static int acp3x_dma_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *prtd = substream->private_data;
|
||||
struct i2s_stream_instance *rtd = substream->runtime->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd,
|
||||
DRV_NAME);
|
||||
struct i2s_dev_data *adata = dev_get_drvdata(component->dev);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
|
|
@ -422,17 +419,6 @@ static int acp3x_dma_close(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_pcm_ops acp3x_dma_ops = {
|
||||
.open = acp3x_dma_open,
|
||||
.close = acp3x_dma_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = acp3x_dma_hw_params,
|
||||
.hw_free = acp3x_dma_hw_free,
|
||||
.pointer = acp3x_dma_pointer,
|
||||
.mmap = acp3x_dma_mmap,
|
||||
};
|
||||
|
||||
|
||||
static int acp3x_dai_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
|
||||
{
|
||||
|
||||
|
|
@ -610,9 +596,15 @@ static struct snd_soc_dai_driver acp3x_i2s_dai_driver = {
|
|||
};
|
||||
|
||||
static const struct snd_soc_component_driver acp3x_i2s_component = {
|
||||
.name = DRV_NAME,
|
||||
.ops = &acp3x_dma_ops,
|
||||
.pcm_new = acp3x_dma_new,
|
||||
.name = DRV_NAME,
|
||||
.open = acp3x_dma_open,
|
||||
.close = acp3x_dma_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = acp3x_dma_hw_params,
|
||||
.hw_free = acp3x_dma_hw_free,
|
||||
.pointer = acp3x_dma_pointer,
|
||||
.mmap = acp3x_dma_mmap,
|
||||
.pcm_construct = acp3x_dma_new,
|
||||
};
|
||||
|
||||
static int acp3x_audio_probe(struct platform_device *pdev)
|
||||
|
|
@ -631,7 +623,7 @@ static int acp3x_audio_probe(struct platform_device *pdev)
|
|||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
|
||||
return -ENODEV;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
adata = devm_kzalloc(&pdev->dev, sizeof(*adata), GFP_KERNEL);
|
||||
|
|
|
|||
|
|
@ -56,15 +56,17 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_pcm_mmap(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
static int atmel_pcm_mmap(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
return remap_pfn_range(vma, vma->vm_start,
|
||||
substream->dma_buffer.addr >> PAGE_SHIFT,
|
||||
vma->vm_end - vma->vm_start, vma->vm_page_prot);
|
||||
}
|
||||
|
||||
static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int atmel_pcm_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_card *card = rtd->card->snd_card;
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
|
|
@ -93,7 +95,8 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void atmel_pcm_free(struct snd_pcm *pcm)
|
||||
static void atmel_pcm_free(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm)
|
||||
{
|
||||
struct snd_pcm_substream *substream;
|
||||
struct snd_dma_buffer *buf;
|
||||
|
|
@ -196,8 +199,9 @@ static void atmel_pcm_dma_irq(u32 ssc_sr,
|
|||
/*--------------------------------------------------------------------------*\
|
||||
* PCM operations
|
||||
\*--------------------------------------------------------------------------*/
|
||||
static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
static int atmel_pcm_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct atmel_runtime_data *prtd = runtime->private_data;
|
||||
|
|
@ -225,7 +229,8 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
static int atmel_pcm_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct atmel_runtime_data *prtd = substream->runtime->private_data;
|
||||
struct atmel_pcm_dma_params *params = prtd->params;
|
||||
|
|
@ -239,7 +244,8 @@ static int atmel_pcm_hw_free(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
static int atmel_pcm_prepare(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct atmel_runtime_data *prtd = substream->runtime->private_data;
|
||||
struct atmel_pcm_dma_params *params = prtd->params;
|
||||
|
|
@ -251,8 +257,8 @@ static int atmel_pcm_prepare(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_pcm_trigger(struct snd_pcm_substream *substream,
|
||||
int cmd)
|
||||
static int atmel_pcm_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_pcm_runtime *rtd = substream->runtime;
|
||||
struct atmel_runtime_data *prtd = rtd->private_data;
|
||||
|
|
@ -317,8 +323,8 @@ static int atmel_pcm_trigger(struct snd_pcm_substream *substream,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t atmel_pcm_pointer(
|
||||
struct snd_pcm_substream *substream)
|
||||
static snd_pcm_uframes_t atmel_pcm_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct atmel_runtime_data *prtd = runtime->private_data;
|
||||
|
|
@ -335,7 +341,8 @@ static snd_pcm_uframes_t atmel_pcm_pointer(
|
|||
return x;
|
||||
}
|
||||
|
||||
static int atmel_pcm_open(struct snd_pcm_substream *substream)
|
||||
static int atmel_pcm_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct atmel_runtime_data *prtd;
|
||||
|
|
@ -360,7 +367,8 @@ static int atmel_pcm_open(struct snd_pcm_substream *substream)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int atmel_pcm_close(struct snd_pcm_substream *substream)
|
||||
static int atmel_pcm_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct atmel_runtime_data *prtd = substream->runtime->private_data;
|
||||
|
||||
|
|
@ -368,22 +376,18 @@ static int atmel_pcm_close(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops atmel_pcm_ops = {
|
||||
static const struct snd_soc_component_driver atmel_soc_platform = {
|
||||
.open = atmel_pcm_open,
|
||||
.close = atmel_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = atmel_pcm_hw_params,
|
||||
.hw_free = atmel_pcm_hw_free,
|
||||
.prepare = atmel_pcm_prepare,
|
||||
.trigger = atmel_pcm_trigger,
|
||||
.pointer = atmel_pcm_pointer,
|
||||
.mmap = atmel_pcm_mmap,
|
||||
};
|
||||
|
||||
static struct snd_soc_component_driver atmel_soc_platform = {
|
||||
.ops = &atmel_pcm_ops,
|
||||
.pcm_new = atmel_pcm_new,
|
||||
.pcm_free = atmel_pcm_free,
|
||||
.pcm_construct = atmel_pcm_new,
|
||||
.pcm_destruct = atmel_pcm_free,
|
||||
};
|
||||
|
||||
int atmel_pcm_pdc_platform_register(struct device *dev)
|
||||
|
|
|
|||
|
|
@ -182,15 +182,15 @@ static int au1x_pcm_dbdma_realloc(struct au1xpsc_audio_dmadata *pcd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream *ss)
|
||||
static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream *ss,
|
||||
struct snd_soc_component *component)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = ss->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct au1xpsc_audio_dmadata *pcd = snd_soc_component_get_drvdata(component);
|
||||
return &pcd[ss->stream];
|
||||
}
|
||||
|
||||
static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
static int au1xpsc_pcm_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
|
@ -202,7 +202,7 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
goto out;
|
||||
|
||||
stype = substream->stream;
|
||||
pcd = to_dmadata(substream);
|
||||
pcd = to_dmadata(substream, component);
|
||||
|
||||
DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %zu "
|
||||
"runtime->min_align %lu\n",
|
||||
|
|
@ -232,15 +232,17 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int au1xpsc_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
static int au1xpsc_pcm_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
snd_pcm_lib_free_pages(substream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
static int au1xpsc_pcm_prepare(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream);
|
||||
struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream, component);
|
||||
|
||||
au1xxx_dbdma_reset(pcd->ddma_chan);
|
||||
|
||||
|
|
@ -255,9 +257,10 @@ static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
static int au1xpsc_pcm_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
u32 c = to_dmadata(substream)->ddma_chan;
|
||||
u32 c = to_dmadata(substream, component)->ddma_chan;
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
|
|
@ -275,14 +278,17 @@ static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
}
|
||||
|
||||
static snd_pcm_uframes_t
|
||||
au1xpsc_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
au1xpsc_pcm_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
return bytes_to_frames(substream->runtime, to_dmadata(substream)->pos);
|
||||
return bytes_to_frames(substream->runtime,
|
||||
to_dmadata(substream, component)->pos);
|
||||
}
|
||||
|
||||
static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
|
||||
static int au1xpsc_pcm_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream);
|
||||
struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream, component);
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
int stype = substream->stream, *dmaids;
|
||||
|
||||
|
|
@ -296,24 +302,15 @@ static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int au1xpsc_pcm_close(struct snd_pcm_substream *substream)
|
||||
static int au1xpsc_pcm_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
au1x_pcm_dbdma_free(to_dmadata(substream));
|
||||
au1x_pcm_dbdma_free(to_dmadata(substream, component));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops au1xpsc_pcm_ops = {
|
||||
.open = au1xpsc_pcm_open,
|
||||
.close = au1xpsc_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = au1xpsc_pcm_hw_params,
|
||||
.hw_free = au1xpsc_pcm_hw_free,
|
||||
.prepare = au1xpsc_pcm_prepare,
|
||||
.trigger = au1xpsc_pcm_trigger,
|
||||
.pointer = au1xpsc_pcm_pointer,
|
||||
};
|
||||
|
||||
static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int au1xpsc_pcm_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_card *card = rtd->card->snd_card;
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
|
|
@ -327,8 +324,15 @@ static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
|||
/* au1xpsc audio platform */
|
||||
static struct snd_soc_component_driver au1xpsc_soc_component = {
|
||||
.name = DRV_NAME,
|
||||
.ops = &au1xpsc_pcm_ops,
|
||||
.pcm_new = au1xpsc_pcm_new,
|
||||
.open = au1xpsc_pcm_open,
|
||||
.close = au1xpsc_pcm_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = au1xpsc_pcm_hw_params,
|
||||
.hw_free = au1xpsc_pcm_hw_free,
|
||||
.prepare = au1xpsc_pcm_prepare,
|
||||
.trigger = au1xpsc_pcm_trigger,
|
||||
.pointer = au1xpsc_pcm_pointer,
|
||||
.pcm_construct = au1xpsc_pcm_new,
|
||||
};
|
||||
|
||||
static int au1xpsc_pcm_drvprobe(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -174,22 +174,23 @@ static const struct snd_pcm_hardware alchemy_pcm_hardware = {
|
|||
.fifo_size = 16,
|
||||
};
|
||||
|
||||
static inline struct alchemy_pcm_ctx *ss_to_ctx(struct snd_pcm_substream *ss)
|
||||
static inline struct alchemy_pcm_ctx *ss_to_ctx(struct snd_pcm_substream *ss,
|
||||
struct snd_soc_component *component)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = ss->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
return snd_soc_component_get_drvdata(component);
|
||||
}
|
||||
|
||||
static inline struct audio_stream *ss_to_as(struct snd_pcm_substream *ss)
|
||||
static inline struct audio_stream *ss_to_as(struct snd_pcm_substream *ss,
|
||||
struct snd_soc_component *component)
|
||||
{
|
||||
struct alchemy_pcm_ctx *ctx = ss_to_ctx(ss);
|
||||
struct alchemy_pcm_ctx *ctx = ss_to_ctx(ss, component);
|
||||
return &(ctx->stream[ss->stream]);
|
||||
}
|
||||
|
||||
static int alchemy_pcm_open(struct snd_pcm_substream *substream)
|
||||
static int alchemy_pcm_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream);
|
||||
struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream, component);
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
int *dmaids, s = substream->stream;
|
||||
char *name;
|
||||
|
|
@ -213,9 +214,10 @@ static int alchemy_pcm_open(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int alchemy_pcm_close(struct snd_pcm_substream *substream)
|
||||
static int alchemy_pcm_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream);
|
||||
struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream, component);
|
||||
int stype = substream->stream;
|
||||
|
||||
ctx->stream[stype].substream = NULL;
|
||||
|
|
@ -224,10 +226,11 @@ static int alchemy_pcm_close(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int alchemy_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
static int alchemy_pcm_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
{
|
||||
struct audio_stream *stream = ss_to_as(substream);
|
||||
struct audio_stream *stream = ss_to_as(substream, component);
|
||||
int err;
|
||||
|
||||
err = snd_pcm_lib_malloc_pages(substream,
|
||||
|
|
@ -243,16 +246,18 @@ static int alchemy_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int alchemy_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
static int alchemy_pcm_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct audio_stream *stream = ss_to_as(substream);
|
||||
struct audio_stream *stream = ss_to_as(substream, component);
|
||||
au1000_release_dma_link(stream);
|
||||
return snd_pcm_lib_free_pages(substream);
|
||||
}
|
||||
|
||||
static int alchemy_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
static int alchemy_pcm_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct audio_stream *stream = ss_to_as(substream);
|
||||
struct audio_stream *stream = ss_to_as(substream, component);
|
||||
int err = 0;
|
||||
|
||||
switch (cmd) {
|
||||
|
|
@ -269,9 +274,10 @@ static int alchemy_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
return err;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t alchemy_pcm_pointer(struct snd_pcm_substream *ss)
|
||||
static snd_pcm_uframes_t alchemy_pcm_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *ss)
|
||||
{
|
||||
struct audio_stream *stream = ss_to_as(ss);
|
||||
struct audio_stream *stream = ss_to_as(ss, component);
|
||||
long location;
|
||||
|
||||
location = get_dma_residue(stream->dma);
|
||||
|
|
@ -281,17 +287,8 @@ static snd_pcm_uframes_t alchemy_pcm_pointer(struct snd_pcm_substream *ss)
|
|||
return bytes_to_frames(ss->runtime, location);
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops alchemy_pcm_ops = {
|
||||
.open = alchemy_pcm_open,
|
||||
.close = alchemy_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = alchemy_pcm_hw_params,
|
||||
.hw_free = alchemy_pcm_hw_free,
|
||||
.trigger = alchemy_pcm_trigger,
|
||||
.pointer = alchemy_pcm_pointer,
|
||||
};
|
||||
|
||||
static int alchemy_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int alchemy_pcm_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
|
||||
|
|
@ -303,8 +300,14 @@ static int alchemy_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
|||
|
||||
static struct snd_soc_component_driver alchemy_pcm_soc_component = {
|
||||
.name = DRV_NAME,
|
||||
.ops = &alchemy_pcm_ops,
|
||||
.pcm_new = alchemy_pcm_new,
|
||||
.open = alchemy_pcm_open,
|
||||
.close = alchemy_pcm_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = alchemy_pcm_hw_params,
|
||||
.hw_free = alchemy_pcm_hw_free,
|
||||
.trigger = alchemy_pcm_trigger,
|
||||
.pointer = alchemy_pcm_pointer,
|
||||
.pcm_construct = alchemy_pcm_new,
|
||||
};
|
||||
|
||||
static int alchemy_pcm_drvprobe(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -376,7 +376,8 @@ static void disable_intr(struct snd_pcm_substream *substream)
|
|||
|
||||
}
|
||||
|
||||
static int cygnus_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
static int cygnus_pcm_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
|
|
@ -577,7 +578,8 @@ static irqreturn_t cygnus_dma_irq(int irq, void *data)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int cygnus_pcm_open(struct snd_pcm_substream *substream)
|
||||
static int cygnus_pcm_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
|
@ -613,7 +615,8 @@ static int cygnus_pcm_open(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cygnus_pcm_close(struct snd_pcm_substream *substream)
|
||||
static int cygnus_pcm_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct cygnus_aio_port *aio;
|
||||
|
|
@ -633,8 +636,9 @@ static int cygnus_pcm_close(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cygnus_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
static int cygnus_pcm_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
|
@ -649,7 +653,8 @@ static int cygnus_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cygnus_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
static int cygnus_pcm_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct cygnus_aio_port *aio;
|
||||
|
|
@ -661,7 +666,8 @@ static int cygnus_pcm_hw_free(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cygnus_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
static int cygnus_pcm_prepare(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
|
@ -694,7 +700,8 @@ static int cygnus_pcm_prepare(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t cygnus_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
static snd_pcm_uframes_t cygnus_pcm_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct cygnus_aio_port *aio;
|
||||
unsigned int res = 0, cur = 0, base = 0;
|
||||
|
|
@ -750,19 +757,8 @@ static int cygnus_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct snd_pcm_ops cygnus_pcm_ops = {
|
||||
.open = cygnus_pcm_open,
|
||||
.close = cygnus_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = cygnus_pcm_hw_params,
|
||||
.hw_free = cygnus_pcm_hw_free,
|
||||
.prepare = cygnus_pcm_prepare,
|
||||
.trigger = cygnus_pcm_trigger,
|
||||
.pointer = cygnus_pcm_pointer,
|
||||
};
|
||||
|
||||
static void cygnus_dma_free_dma_buffers(struct snd_pcm *pcm)
|
||||
static void cygnus_dma_free_dma_buffers(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm)
|
||||
{
|
||||
struct snd_pcm_substream *substream;
|
||||
struct snd_dma_buffer *buf;
|
||||
|
|
@ -788,7 +784,8 @@ static void cygnus_dma_free_dma_buffers(struct snd_pcm *pcm)
|
|||
}
|
||||
}
|
||||
|
||||
static int cygnus_dma_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int cygnus_dma_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_card *card = rtd->card->snd_card;
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
|
|
@ -810,7 +807,7 @@ static int cygnus_dma_new(struct snd_soc_pcm_runtime *rtd)
|
|||
ret = cygnus_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_CAPTURE);
|
||||
if (ret) {
|
||||
cygnus_dma_free_dma_buffers(pcm);
|
||||
cygnus_dma_free_dma_buffers(component, pcm);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
@ -819,9 +816,16 @@ static int cygnus_dma_new(struct snd_soc_pcm_runtime *rtd)
|
|||
}
|
||||
|
||||
static struct snd_soc_component_driver cygnus_soc_platform = {
|
||||
.ops = &cygnus_pcm_ops,
|
||||
.pcm_new = cygnus_dma_new,
|
||||
.pcm_free = cygnus_dma_free_dma_buffers,
|
||||
.open = cygnus_pcm_open,
|
||||
.close = cygnus_pcm_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = cygnus_pcm_hw_params,
|
||||
.hw_free = cygnus_pcm_hw_free,
|
||||
.prepare = cygnus_pcm_prepare,
|
||||
.trigger = cygnus_pcm_trigger,
|
||||
.pointer = cygnus_pcm_pointer,
|
||||
.pcm_construct = cygnus_dma_new,
|
||||
.pcm_destruct = cygnus_dma_free_dma_buffers,
|
||||
};
|
||||
|
||||
int cygnus_soc_platform_register(struct device *dev,
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_ADAU1977_I2C if I2C
|
||||
select SND_SOC_ADAU1701 if I2C
|
||||
select SND_SOC_ADAU7002
|
||||
select SND_SOC_ADAU7118_I2C if I2C
|
||||
select SND_SOC_ADAU7118_HW
|
||||
select SND_SOC_ADS117X
|
||||
select SND_SOC_AK4104 if SPI_MASTER
|
||||
select SND_SOC_AK4118 if I2C
|
||||
|
|
@ -179,6 +181,8 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
|
||||
select SND_SOC_STI_SAS
|
||||
select SND_SOC_TAS2552 if I2C
|
||||
select SND_SOC_TAS2562 if I2C
|
||||
select SND_SOC_TAS2770 if I2C
|
||||
select SND_SOC_TAS5086 if I2C
|
||||
select SND_SOC_TAS571X if I2C
|
||||
select SND_SOC_TAS5720 if I2C
|
||||
|
|
@ -395,6 +399,33 @@ config SND_SOC_ADAU1977_I2C
|
|||
config SND_SOC_ADAU7002
|
||||
tristate "Analog Devices ADAU7002 Stereo PDM-to-I2S/TDM Converter"
|
||||
|
||||
config SND_SOC_ADAU7118
|
||||
tristate
|
||||
|
||||
config SND_SOC_ADAU7118_HW
|
||||
tristate "Analog Devices ADAU7118 8 Channel PDM-to-I2S/TDM Converter - HW Mode"
|
||||
select SND_SOC_ADAU7118
|
||||
help
|
||||
Enable support for the Analog Devices ADAU7118 8 Channel PDM-to-I2S/TDM
|
||||
Converter. In this mode, the device works in standalone mode which
|
||||
means that there is no bus to comunicate with it. Stereo mode is not
|
||||
supported in this mode.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-soc-adau7118-hw.
|
||||
|
||||
config SND_SOC_ADAU7118_I2C
|
||||
tristate "Analog Devices ADAU7118 8 Channel PDM-to-I2S/TDM Converter - I2C"
|
||||
depends on I2C
|
||||
select SND_SOC_ADAU7118
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Enable support for the Analog Devices ADAU7118 8 Channel PDM-to-I2S/TDM
|
||||
Converter over I2C. This gives full support over the device.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-soc-adau7118-i2c.
|
||||
|
||||
config SND_SOC_ADAV80X
|
||||
tristate
|
||||
|
||||
|
|
@ -1104,6 +1135,14 @@ config SND_SOC_TAS2552
|
|||
tristate "Texas Instruments TAS2552 Mono Audio amplifier"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_TAS2562
|
||||
tristate "Texas Instruments TAS2562 Mono Audio amplifier"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_TAS2770
|
||||
tristate "Texas Instruments TAS2770 speaker amplifier"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_TAS5086
|
||||
tristate "Texas Instruments TAS5086 speaker amplifier"
|
||||
depends on I2C
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ snd-soc-adau1977-objs := adau1977.o
|
|||
snd-soc-adau1977-spi-objs := adau1977-spi.o
|
||||
snd-soc-adau1977-i2c-objs := adau1977-i2c.o
|
||||
snd-soc-adau7002-objs := adau7002.o
|
||||
snd-soc-adau7118-objs := adau7118.o
|
||||
snd-soc-adau7118-i2c-objs := adau7118-i2c.o
|
||||
snd-soc-adau7118-hw-objs := adau7118-hw.o
|
||||
snd-soc-adav80x-objs := adav80x.o
|
||||
snd-soc-adav801-objs := adav801.o
|
||||
snd-soc-adav803-objs := adav803.o
|
||||
|
|
@ -196,6 +199,7 @@ snd-soc-tas571x-objs := tas571x.o
|
|||
snd-soc-tas5720-objs := tas5720.o
|
||||
snd-soc-tas6424-objs := tas6424.o
|
||||
snd-soc-tda7419-objs := tda7419.o
|
||||
snd-soc-tas2770-objs := tas2770.o
|
||||
snd-soc-tfa9879-objs := tfa9879.o
|
||||
snd-soc-tlv320aic23-objs := tlv320aic23.o
|
||||
snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
|
||||
|
|
@ -280,6 +284,7 @@ snd-soc-max98504-objs := max98504.o
|
|||
snd-soc-simple-amplifier-objs := simple-amplifier.o
|
||||
snd-soc-tpa6130a2-objs := tpa6130a2.o
|
||||
snd-soc-tas2552-objs := tas2552.o
|
||||
snd-soc-tas2562-objs := tas2562.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o
|
||||
obj-$(CONFIG_SND_SOC_AB8500_CODEC) += snd-soc-ab8500-codec.o
|
||||
|
|
@ -304,6 +309,9 @@ obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o
|
|||
obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU7002) += snd-soc-adau7002.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU7118) += snd-soc-adau7118.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU7118_I2C) += snd-soc-adau7118-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU7118_HW) += snd-soc-adau7118-hw.o
|
||||
obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o
|
||||
obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o
|
||||
obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o
|
||||
|
|
@ -474,11 +482,13 @@ obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o
|
|||
obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
|
||||
obj-$(CONFIG_SND_SOC_STI_SAS) += snd-soc-sti-sas.o
|
||||
obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o
|
||||
obj-$(CONFIG_SND_SOC_TAS2562) += snd-soc-tas2562.o
|
||||
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
|
||||
obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o
|
||||
obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o
|
||||
obj-$(CONFIG_SND_SOC_TAS6424) += snd-soc-tas6424.o
|
||||
obj-$(CONFIG_SND_SOC_TDA7419) += snd-soc-tda7419.o
|
||||
obj-$(CONFIG_SND_SOC_TAS2770) += snd-soc-tas2770.o
|
||||
obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@
|
|||
#define ADAU1761_REC_MIXER_RIGHT1 0x400d
|
||||
#define ADAU1761_LEFT_DIFF_INPUT_VOL 0x400e
|
||||
#define ADAU1761_RIGHT_DIFF_INPUT_VOL 0x400f
|
||||
#define ADAU1761_ALC_CTRL0 0x4011
|
||||
#define ADAU1761_ALC_CTRL1 0x4012
|
||||
#define ADAU1761_ALC_CTRL2 0x4013
|
||||
#define ADAU1761_ALC_CTRL3 0x4014
|
||||
#define ADAU1761_PLAY_LR_MIXER_LEFT 0x4020
|
||||
#define ADAU1761_PLAY_MIXER_LEFT0 0x401c
|
||||
#define ADAU1761_PLAY_MIXER_LEFT1 0x401d
|
||||
|
|
@ -71,6 +75,10 @@ static const struct reg_default adau1761_reg_defaults[] = {
|
|||
{ ADAU1761_REC_MIXER_RIGHT0, 0x00 },
|
||||
{ ADAU1761_REC_MIXER_RIGHT1, 0x00 },
|
||||
{ ADAU1761_LEFT_DIFF_INPUT_VOL, 0x00 },
|
||||
{ ADAU1761_ALC_CTRL0, 0x00 },
|
||||
{ ADAU1761_ALC_CTRL1, 0x00 },
|
||||
{ ADAU1761_ALC_CTRL2, 0x00 },
|
||||
{ ADAU1761_ALC_CTRL3, 0x00 },
|
||||
{ ADAU1761_RIGHT_DIFF_INPUT_VOL, 0x00 },
|
||||
{ ADAU1761_PLAY_LR_MIXER_LEFT, 0x00 },
|
||||
{ ADAU1761_PLAY_MIXER_LEFT0, 0x00 },
|
||||
|
|
@ -121,6 +129,10 @@ static const DECLARE_TLV_DB_SCALE(adau1761_sidetone_tlv, -1800, 300, 1);
|
|||
static const DECLARE_TLV_DB_SCALE(adau1761_boost_tlv, -600, 600, 1);
|
||||
static const DECLARE_TLV_DB_SCALE(adau1761_pga_boost_tlv, -2000, 2000, 1);
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(adau1761_alc_max_gain_tlv, -1200, 600, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(adau1761_alc_target_tlv, -2850, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(adau1761_alc_ng_threshold_tlv, -7650, 150, 0);
|
||||
|
||||
static const unsigned int adau1761_bias_select_values[] = {
|
||||
0, 2, 3,
|
||||
};
|
||||
|
|
@ -147,6 +159,103 @@ static SOC_VALUE_ENUM_SINGLE_DECL(adau1761_capture_bias_enum,
|
|||
ADAU17X1_REC_POWER_MGMT, 1, 0x3, adau1761_bias_select_text,
|
||||
adau1761_bias_select_values);
|
||||
|
||||
static const unsigned int adau1761_pga_slew_time_values[] = {
|
||||
3, 0, 1, 2,
|
||||
};
|
||||
|
||||
static const char * const adau1761_pga_slew_time_text[] = {
|
||||
"Off",
|
||||
"24 ms",
|
||||
"48 ms",
|
||||
"96 ms",
|
||||
};
|
||||
|
||||
static const char * const adau1761_alc_function_text[] = {
|
||||
"Off",
|
||||
"Right",
|
||||
"Left",
|
||||
"Stereo",
|
||||
"DSP control",
|
||||
};
|
||||
|
||||
static const char * const adau1761_alc_hold_time_text[] = {
|
||||
"2.67 ms",
|
||||
"5.34 ms",
|
||||
"10.68 ms",
|
||||
"21.36 ms",
|
||||
"42.72 ms",
|
||||
"85.44 ms",
|
||||
"170.88 ms",
|
||||
"341.76 ms",
|
||||
"683.52 ms",
|
||||
"1367 ms",
|
||||
"2734.1 ms",
|
||||
"5468.2 ms",
|
||||
"10936 ms",
|
||||
"21873 ms",
|
||||
"43745 ms",
|
||||
"87491 ms",
|
||||
};
|
||||
|
||||
static const char * const adau1761_alc_attack_time_text[] = {
|
||||
"6 ms",
|
||||
"12 ms",
|
||||
"24 ms",
|
||||
"48 ms",
|
||||
"96 ms",
|
||||
"192 ms",
|
||||
"384 ms",
|
||||
"768 ms",
|
||||
"1540 ms",
|
||||
"3070 ms",
|
||||
"6140 ms",
|
||||
"12290 ms",
|
||||
"24580 ms",
|
||||
"49150 ms",
|
||||
"98300 ms",
|
||||
"196610 ms",
|
||||
};
|
||||
|
||||
static const char * const adau1761_alc_decay_time_text[] = {
|
||||
"24 ms",
|
||||
"48 ms",
|
||||
"96 ms",
|
||||
"192 ms",
|
||||
"384 ms",
|
||||
"768 ms",
|
||||
"15400 ms",
|
||||
"30700 ms",
|
||||
"61400 ms",
|
||||
"12290 ms",
|
||||
"24580 ms",
|
||||
"49150 ms",
|
||||
"98300 ms",
|
||||
"196610 ms",
|
||||
"393220 ms",
|
||||
"786430 ms",
|
||||
};
|
||||
|
||||
static const char * const adau1761_alc_ng_type_text[] = {
|
||||
"Hold",
|
||||
"Mute",
|
||||
"Fade",
|
||||
"Fade + Mute",
|
||||
};
|
||||
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(adau1761_pga_slew_time_enum,
|
||||
ADAU1761_ALC_CTRL0, 6, 0x3, adau1761_pga_slew_time_text,
|
||||
adau1761_pga_slew_time_values);
|
||||
static SOC_ENUM_SINGLE_DECL(adau1761_alc_function_enum,
|
||||
ADAU1761_ALC_CTRL0, 0, adau1761_alc_function_text);
|
||||
static SOC_ENUM_SINGLE_DECL(adau1761_alc_hold_time_enum,
|
||||
ADAU1761_ALC_CTRL1, 4, adau1761_alc_hold_time_text);
|
||||
static SOC_ENUM_SINGLE_DECL(adau1761_alc_attack_time_enum,
|
||||
ADAU1761_ALC_CTRL2, 4, adau1761_alc_attack_time_text);
|
||||
static SOC_ENUM_SINGLE_DECL(adau1761_alc_decay_time_enum,
|
||||
ADAU1761_ALC_CTRL2, 0, adau1761_alc_decay_time_text);
|
||||
static SOC_ENUM_SINGLE_DECL(adau1761_alc_ng_type_enum,
|
||||
ADAU1761_ALC_CTRL3, 6, adau1761_alc_ng_type_text);
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_jack_detect_controls[] = {
|
||||
SOC_SINGLE("Speaker Auto-mute Switch", ADAU1761_DIGMIC_JACKDETECT,
|
||||
4, 1, 0),
|
||||
|
|
@ -161,6 +270,22 @@ static const struct snd_kcontrol_new adau1761_differential_mode_controls[] = {
|
|||
|
||||
SOC_DOUBLE_R_TLV("PGA Boost Capture Volume", ADAU1761_REC_MIXER_LEFT1,
|
||||
ADAU1761_REC_MIXER_RIGHT1, 3, 2, 0, adau1761_pga_boost_tlv),
|
||||
|
||||
SOC_ENUM("PGA Capture Slew Time", adau1761_pga_slew_time_enum),
|
||||
|
||||
SOC_SINGLE_TLV("ALC Capture Max Gain Volume", ADAU1761_ALC_CTRL0,
|
||||
3, 7, 0, adau1761_alc_max_gain_tlv),
|
||||
SOC_ENUM("ALC Capture Function", adau1761_alc_function_enum),
|
||||
SOC_ENUM("ALC Capture Hold Time", adau1761_alc_hold_time_enum),
|
||||
SOC_SINGLE_TLV("ALC Capture Target Volume", ADAU1761_ALC_CTRL1,
|
||||
0, 15, 0, adau1761_alc_target_tlv),
|
||||
SOC_ENUM("ALC Capture Attack Time", adau1761_alc_decay_time_enum),
|
||||
SOC_ENUM("ALC Capture Decay Time", adau1761_alc_attack_time_enum),
|
||||
SOC_ENUM("ALC Capture Noise Gate Type", adau1761_alc_ng_type_enum),
|
||||
SOC_SINGLE("ALC Capture Noise Gate Switch",
|
||||
ADAU1761_ALC_CTRL3, 5, 1, 0),
|
||||
SOC_SINGLE_TLV("ALC Capture Noise Gate Threshold Volume",
|
||||
ADAU1761_ALC_CTRL3, 0, 31, 0, adau1761_alc_ng_threshold_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_single_mode_controls[] = {
|
||||
|
|
@ -632,6 +757,10 @@ static bool adau1761_readable_register(struct device *dev, unsigned int reg)
|
|||
case ADAU1761_DEJITTER:
|
||||
case ADAU1761_CLK_ENABLE0:
|
||||
case ADAU1761_CLK_ENABLE1:
|
||||
case ADAU1761_ALC_CTRL0:
|
||||
case ADAU1761_ALC_CTRL1:
|
||||
case ADAU1761_ALC_CTRL2:
|
||||
case ADAU1761_ALC_CTRL3:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
|
|
|
|||
43
sound/soc/codecs/adau7118-hw.c
Normal file
43
sound/soc/codecs/adau7118-hw.c
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Analog Devices ADAU7118 8 channel PDM-to-I2S/TDM Converter Standalone Hw
|
||||
// driver
|
||||
//
|
||||
// Copyright 2019 Analog Devices Inc.
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "adau7118.h"
|
||||
|
||||
static int adau7118_probe_hw(struct platform_device *pdev)
|
||||
{
|
||||
return adau7118_probe(&pdev->dev, NULL, true);
|
||||
}
|
||||
|
||||
static const struct of_device_id adau7118_of_match[] = {
|
||||
{ .compatible = "adi,adau7118" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adau7118_of_match);
|
||||
|
||||
static const struct platform_device_id adau7118_id[] = {
|
||||
{ .name = "adau7118" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, adau7118_id);
|
||||
|
||||
static struct platform_driver adau7118_driver_hw = {
|
||||
.driver = {
|
||||
.name = "adau7118",
|
||||
.of_match_table = adau7118_of_match,
|
||||
},
|
||||
.probe = adau7118_probe_hw,
|
||||
.id_table = adau7118_id,
|
||||
};
|
||||
module_platform_driver(adau7118_driver_hw);
|
||||
|
||||
MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
|
||||
MODULE_DESCRIPTION("ADAU7118 8 channel PDM-to-I2S/TDM Converter driver for standalone hw mode");
|
||||
MODULE_LICENSE("GPL");
|
||||
82
sound/soc/codecs/adau7118-i2c.c
Normal file
82
sound/soc/codecs/adau7118-i2c.c
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Analog Devices ADAU7118 8 channel PDM-to-I2S/TDM Converter driver over I2C
|
||||
//
|
||||
// Copyright 2019 Analog Devices Inc.
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "adau7118.h"
|
||||
|
||||
static const struct reg_default adau7118_reg_defaults[] = {
|
||||
{ ADAU7118_REG_VENDOR_ID, 0x41 },
|
||||
{ ADAU7118_REG_DEVICE_ID1, 0x71 },
|
||||
{ ADAU7118_REG_DEVICE_ID2, 0x18 },
|
||||
{ ADAU7118_REG_REVISION_ID, 0x00 },
|
||||
{ ADAU7118_REG_ENABLES, 0x3F },
|
||||
{ ADAU7118_REG_DEC_RATIO_CLK_MAP, 0xC0 },
|
||||
{ ADAU7118_REG_HPF_CONTROL, 0xD0 },
|
||||
{ ADAU7118_REG_SPT_CTRL1, 0x41 },
|
||||
{ ADAU7118_REG_SPT_CTRL2, 0x00 },
|
||||
{ ADAU7118_REG_SPT_CX(0), 0x01 },
|
||||
{ ADAU7118_REG_SPT_CX(1), 0x11 },
|
||||
{ ADAU7118_REG_SPT_CX(2), 0x21 },
|
||||
{ ADAU7118_REG_SPT_CX(3), 0x31 },
|
||||
{ ADAU7118_REG_SPT_CX(4), 0x41 },
|
||||
{ ADAU7118_REG_SPT_CX(5), 0x51 },
|
||||
{ ADAU7118_REG_SPT_CX(6), 0x61 },
|
||||
{ ADAU7118_REG_SPT_CX(7), 0x71 },
|
||||
{ ADAU7118_REG_DRIVE_STRENGTH, 0x2a },
|
||||
{ ADAU7118_REG_RESET, 0x00 },
|
||||
};
|
||||
|
||||
static const struct regmap_config adau7118_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.reg_defaults = adau7118_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(adau7118_reg_defaults),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.max_register = ADAU7118_REG_RESET,
|
||||
};
|
||||
|
||||
static int adau7118_probe_i2c(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct regmap *map;
|
||||
|
||||
map = devm_regmap_init_i2c(i2c, &adau7118_regmap_config);
|
||||
if (IS_ERR(map)) {
|
||||
dev_err(&i2c->dev, "Failed to init regmap %ld\n", PTR_ERR(map));
|
||||
return PTR_ERR(map);
|
||||
}
|
||||
|
||||
return adau7118_probe(&i2c->dev, map, false);
|
||||
}
|
||||
|
||||
static const struct of_device_id adau7118_of_match[] = {
|
||||
{ .compatible = "adi,adau7118" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adau7118_of_match);
|
||||
|
||||
static const struct i2c_device_id adau7118_id[] = {
|
||||
{"adau7118", 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adau7118_id);
|
||||
|
||||
static struct i2c_driver adau7118_driver = {
|
||||
.driver = {
|
||||
.name = "adau7118",
|
||||
.of_match_table = adau7118_of_match,
|
||||
},
|
||||
.probe = adau7118_probe_i2c,
|
||||
.id_table = adau7118_id,
|
||||
};
|
||||
module_i2c_driver(adau7118_driver);
|
||||
|
||||
MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
|
||||
MODULE_DESCRIPTION("ADAU7118 8 channel PDM-to-I2S/TDM Converter driver over I2C");
|
||||
MODULE_LICENSE("GPL");
|
||||
586
sound/soc/codecs/adau7118.c
Normal file
586
sound/soc/codecs/adau7118.c
Normal file
|
|
@ -0,0 +1,586 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Analog Devices ADAU7118 8 channel PDM-to-I2S/TDM Converter driver
|
||||
//
|
||||
// Copyright 2019 Analog Devices Inc.
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "adau7118.h"
|
||||
|
||||
#define ADAU7118_DEC_RATIO_MASK GENMASK(1, 0)
|
||||
#define ADAU7118_DEC_RATIO(x) FIELD_PREP(ADAU7118_DEC_RATIO_MASK, x)
|
||||
#define ADAU7118_CLK_MAP_MASK GENMASK(7, 4)
|
||||
#define ADAU7118_SLOT_WIDTH_MASK GENMASK(5, 4)
|
||||
#define ADAU7118_SLOT_WIDTH(x) FIELD_PREP(ADAU7118_SLOT_WIDTH_MASK, x)
|
||||
#define ADAU7118_TRISTATE_MASK BIT(6)
|
||||
#define ADAU7118_TRISTATE(x) FIELD_PREP(ADAU7118_TRISTATE_MASK, x)
|
||||
#define ADAU7118_DATA_FMT_MASK GENMASK(3, 1)
|
||||
#define ADAU7118_DATA_FMT(x) FIELD_PREP(ADAU7118_DATA_FMT_MASK, x)
|
||||
#define ADAU7118_SAI_MODE_MASK BIT(0)
|
||||
#define ADAU7118_SAI_MODE(x) FIELD_PREP(ADAU7118_SAI_MODE_MASK, x)
|
||||
#define ADAU7118_LRCLK_BCLK_POL_MASK GENMASK(1, 0)
|
||||
#define ADAU7118_LRCLK_BCLK_POL(x) \
|
||||
FIELD_PREP(ADAU7118_LRCLK_BCLK_POL_MASK, x)
|
||||
#define ADAU7118_SPT_SLOT_MASK GENMASK(7, 4)
|
||||
#define ADAU7118_SPT_SLOT(x) FIELD_PREP(ADAU7118_SPT_SLOT_MASK, x)
|
||||
#define ADAU7118_FULL_SOFT_R_MASK BIT(1)
|
||||
#define ADAU7118_FULL_SOFT_R(x) FIELD_PREP(ADAU7118_FULL_SOFT_R_MASK, x)
|
||||
|
||||
struct adau7118_data {
|
||||
struct regmap *map;
|
||||
struct device *dev;
|
||||
struct regulator *iovdd;
|
||||
struct regulator *dvdd;
|
||||
u32 slot_width;
|
||||
u32 slots;
|
||||
bool hw_mode;
|
||||
bool right_j;
|
||||
};
|
||||
|
||||
/* Input Enable */
|
||||
static const struct snd_kcontrol_new adau7118_dapm_pdm_control[4] = {
|
||||
SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 0, 1, 0),
|
||||
SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 1, 1, 0),
|
||||
SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 2, 1, 0),
|
||||
SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 3, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget adau7118_widgets_sw[] = {
|
||||
/* Input Enable Switches */
|
||||
SND_SOC_DAPM_SWITCH("PDM0", SND_SOC_NOPM, 0, 0,
|
||||
&adau7118_dapm_pdm_control[0]),
|
||||
SND_SOC_DAPM_SWITCH("PDM1", SND_SOC_NOPM, 0, 0,
|
||||
&adau7118_dapm_pdm_control[1]),
|
||||
SND_SOC_DAPM_SWITCH("PDM2", SND_SOC_NOPM, 0, 0,
|
||||
&adau7118_dapm_pdm_control[2]),
|
||||
SND_SOC_DAPM_SWITCH("PDM3", SND_SOC_NOPM, 0, 0,
|
||||
&adau7118_dapm_pdm_control[3]),
|
||||
|
||||
/* PDM Clocks */
|
||||
SND_SOC_DAPM_SUPPLY("PDM_CLK0", ADAU7118_REG_ENABLES, 4, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("PDM_CLK1", ADAU7118_REG_ENABLES, 5, 0, NULL, 0),
|
||||
|
||||
/* Output channels */
|
||||
SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0, ADAU7118_REG_SPT_CX(0),
|
||||
0, 0),
|
||||
SND_SOC_DAPM_AIF_OUT("AIF1TX2", "Capture", 0, ADAU7118_REG_SPT_CX(1),
|
||||
0, 0),
|
||||
SND_SOC_DAPM_AIF_OUT("AIF1TX3", "Capture", 0, ADAU7118_REG_SPT_CX(2),
|
||||
0, 0),
|
||||
SND_SOC_DAPM_AIF_OUT("AIF1TX4", "Capture", 0, ADAU7118_REG_SPT_CX(3),
|
||||
0, 0),
|
||||
SND_SOC_DAPM_AIF_OUT("AIF1TX5", "Capture", 0, ADAU7118_REG_SPT_CX(4),
|
||||
0, 0),
|
||||
SND_SOC_DAPM_AIF_OUT("AIF1TX6", "Capture", 0, ADAU7118_REG_SPT_CX(5),
|
||||
0, 0),
|
||||
SND_SOC_DAPM_AIF_OUT("AIF1TX7", "Capture", 0, ADAU7118_REG_SPT_CX(6),
|
||||
0, 0),
|
||||
SND_SOC_DAPM_AIF_OUT("AIF1TX8", "Capture", 0, ADAU7118_REG_SPT_CX(7),
|
||||
0, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau7118_routes_sw[] = {
|
||||
{ "PDM0", "Capture Switch", "PDM_DAT0" },
|
||||
{ "PDM1", "Capture Switch", "PDM_DAT1" },
|
||||
{ "PDM2", "Capture Switch", "PDM_DAT2" },
|
||||
{ "PDM3", "Capture Switch", "PDM_DAT3" },
|
||||
{ "AIF1TX1", NULL, "PDM0" },
|
||||
{ "AIF1TX2", NULL, "PDM0" },
|
||||
{ "AIF1TX3", NULL, "PDM1" },
|
||||
{ "AIF1TX4", NULL, "PDM1" },
|
||||
{ "AIF1TX5", NULL, "PDM2" },
|
||||
{ "AIF1TX6", NULL, "PDM2" },
|
||||
{ "AIF1TX7", NULL, "PDM3" },
|
||||
{ "AIF1TX8", NULL, "PDM3" },
|
||||
{ "Capture", NULL, "PDM_CLK0" },
|
||||
{ "Capture", NULL, "PDM_CLK1" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget adau7118_widgets_hw[] = {
|
||||
SND_SOC_DAPM_AIF_OUT("AIF1TX", "Capture", 0, SND_SOC_NOPM, 0, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau7118_routes_hw[] = {
|
||||
{ "AIF1TX", NULL, "PDM_DAT0" },
|
||||
{ "AIF1TX", NULL, "PDM_DAT1" },
|
||||
{ "AIF1TX", NULL, "PDM_DAT2" },
|
||||
{ "AIF1TX", NULL, "PDM_DAT3" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget adau7118_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("PDM_DAT0"),
|
||||
SND_SOC_DAPM_INPUT("PDM_DAT1"),
|
||||
SND_SOC_DAPM_INPUT("PDM_DAT2"),
|
||||
SND_SOC_DAPM_INPUT("PDM_DAT3"),
|
||||
};
|
||||
|
||||
static int adau7118_set_channel_map(struct snd_soc_dai *dai,
|
||||
unsigned int tx_num, unsigned int *tx_slot,
|
||||
unsigned int rx_num, unsigned int *rx_slot)
|
||||
{
|
||||
struct adau7118_data *st =
|
||||
snd_soc_component_get_drvdata(dai->component);
|
||||
int chan, ret;
|
||||
|
||||
dev_dbg(st->dev, "Set channel map, %d", tx_num);
|
||||
|
||||
for (chan = 0; chan < tx_num; chan++) {
|
||||
ret = snd_soc_component_update_bits(dai->component,
|
||||
ADAU7118_REG_SPT_CX(chan),
|
||||
ADAU7118_SPT_SLOT_MASK,
|
||||
ADAU7118_SPT_SLOT(tx_slot[chan]));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau7118_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
{
|
||||
struct adau7118_data *st =
|
||||
snd_soc_component_get_drvdata(dai->component);
|
||||
int ret = 0;
|
||||
u32 regval;
|
||||
|
||||
dev_dbg(st->dev, "Set format, fmt:%d\n", fmt);
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
ret = snd_soc_component_update_bits(dai->component,
|
||||
ADAU7118_REG_SPT_CTRL1,
|
||||
ADAU7118_DATA_FMT_MASK,
|
||||
ADAU7118_DATA_FMT(0));
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
ret = snd_soc_component_update_bits(dai->component,
|
||||
ADAU7118_REG_SPT_CTRL1,
|
||||
ADAU7118_DATA_FMT_MASK,
|
||||
ADAU7118_DATA_FMT(1));
|
||||
break;
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
st->right_j = true;
|
||||
break;
|
||||
default:
|
||||
dev_err(st->dev, "Invalid format %d",
|
||||
fmt & SND_SOC_DAIFMT_FORMAT_MASK);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
regval = ADAU7118_LRCLK_BCLK_POL(0);
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
regval = ADAU7118_LRCLK_BCLK_POL(2);
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
regval = ADAU7118_LRCLK_BCLK_POL(1);
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
regval = ADAU7118_LRCLK_BCLK_POL(3);
|
||||
break;
|
||||
default:
|
||||
dev_err(st->dev, "Invalid Inv mask %d",
|
||||
fmt & SND_SOC_DAIFMT_INV_MASK);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snd_soc_component_update_bits(dai->component,
|
||||
ADAU7118_REG_SPT_CTRL2,
|
||||
ADAU7118_LRCLK_BCLK_POL_MASK,
|
||||
regval);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau7118_set_tristate(struct snd_soc_dai *dai, int tristate)
|
||||
{
|
||||
struct adau7118_data *st =
|
||||
snd_soc_component_get_drvdata(dai->component);
|
||||
int ret;
|
||||
|
||||
dev_dbg(st->dev, "Set tristate, %d\n", tristate);
|
||||
|
||||
ret = snd_soc_component_update_bits(dai->component,
|
||||
ADAU7118_REG_SPT_CTRL1,
|
||||
ADAU7118_TRISTATE_MASK,
|
||||
ADAU7118_TRISTATE(tristate));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau7118_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
|
||||
unsigned int rx_mask, int slots,
|
||||
int slot_width)
|
||||
{
|
||||
struct adau7118_data *st =
|
||||
snd_soc_component_get_drvdata(dai->component);
|
||||
int ret = 0;
|
||||
u32 regval;
|
||||
|
||||
dev_dbg(st->dev, "Set tdm, slots:%d width:%d\n", slots, slot_width);
|
||||
|
||||
switch (slot_width) {
|
||||
case 32:
|
||||
regval = ADAU7118_SLOT_WIDTH(0);
|
||||
break;
|
||||
case 24:
|
||||
regval = ADAU7118_SLOT_WIDTH(2);
|
||||
break;
|
||||
case 16:
|
||||
regval = ADAU7118_SLOT_WIDTH(1);
|
||||
break;
|
||||
default:
|
||||
dev_err(st->dev, "Invalid slot width:%d\n", slot_width);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snd_soc_component_update_bits(dai->component,
|
||||
ADAU7118_REG_SPT_CTRL1,
|
||||
ADAU7118_SLOT_WIDTH_MASK, regval);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
st->slot_width = slot_width;
|
||||
st->slots = slots;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau7118_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct adau7118_data *st =
|
||||
snd_soc_component_get_drvdata(dai->component);
|
||||
u32 data_width = params_width(params), slots_width;
|
||||
int ret;
|
||||
u32 regval;
|
||||
|
||||
if (!st->slots) {
|
||||
/* set stereo mode */
|
||||
ret = snd_soc_component_update_bits(dai->component,
|
||||
ADAU7118_REG_SPT_CTRL1,
|
||||
ADAU7118_SAI_MODE_MASK,
|
||||
ADAU7118_SAI_MODE(0));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
slots_width = 32;
|
||||
} else {
|
||||
slots_width = st->slot_width;
|
||||
}
|
||||
|
||||
if (data_width > slots_width) {
|
||||
dev_err(st->dev, "Invalid data_width:%d, slots_width:%d",
|
||||
data_width, slots_width);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (st->right_j) {
|
||||
switch (slots_width - data_width) {
|
||||
case 8:
|
||||
/* delay bclck by 8 */
|
||||
regval = ADAU7118_DATA_FMT(2);
|
||||
break;
|
||||
case 12:
|
||||
/* delay bclck by 12 */
|
||||
regval = ADAU7118_DATA_FMT(3);
|
||||
break;
|
||||
case 16:
|
||||
/* delay bclck by 16 */
|
||||
regval = ADAU7118_DATA_FMT(4);
|
||||
break;
|
||||
default:
|
||||
dev_err(st->dev,
|
||||
"Cannot set right_j setting, slot_w:%d, data_w:%d\n",
|
||||
slots_width, data_width);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snd_soc_component_update_bits(dai->component,
|
||||
ADAU7118_REG_SPT_CTRL1,
|
||||
ADAU7118_DATA_FMT_MASK,
|
||||
regval);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau7118_set_bias_level(struct snd_soc_component *component,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct adau7118_data *st = snd_soc_component_get_drvdata(component);
|
||||
int ret = 0;
|
||||
|
||||
dev_dbg(st->dev, "Set bias level %d\n", level);
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
if (snd_soc_component_get_bias_level(component) ==
|
||||
SND_SOC_BIAS_OFF) {
|
||||
/* power on */
|
||||
ret = regulator_enable(st->iovdd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* there's no timing constraints before enabling dvdd */
|
||||
ret = regulator_enable(st->dvdd);
|
||||
if (ret) {
|
||||
regulator_disable(st->iovdd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (st->hw_mode)
|
||||
return 0;
|
||||
|
||||
regcache_cache_only(st->map, false);
|
||||
/* sync cache */
|
||||
ret = snd_soc_component_cache_sync(component);
|
||||
}
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
/* power off */
|
||||
ret = regulator_disable(st->dvdd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regulator_disable(st->iovdd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (st->hw_mode)
|
||||
return 0;
|
||||
|
||||
/* cache only */
|
||||
regcache_mark_dirty(st->map);
|
||||
regcache_cache_only(st->map, true);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adau7118_component_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct adau7118_data *st = snd_soc_component_get_drvdata(component);
|
||||
struct snd_soc_dapm_context *dapm =
|
||||
snd_soc_component_get_dapm(component);
|
||||
int ret = 0;
|
||||
|
||||
if (st->hw_mode) {
|
||||
ret = snd_soc_dapm_new_controls(dapm, adau7118_widgets_hw,
|
||||
ARRAY_SIZE(adau7118_widgets_hw));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dapm_add_routes(dapm, adau7118_routes_hw,
|
||||
ARRAY_SIZE(adau7118_routes_hw));
|
||||
} else {
|
||||
snd_soc_component_init_regmap(component, st->map);
|
||||
ret = snd_soc_dapm_new_controls(dapm, adau7118_widgets_sw,
|
||||
ARRAY_SIZE(adau7118_widgets_sw));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dapm_add_routes(dapm, adau7118_routes_sw,
|
||||
ARRAY_SIZE(adau7118_routes_sw));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops adau7118_ops = {
|
||||
.hw_params = adau7118_hw_params,
|
||||
.set_channel_map = adau7118_set_channel_map,
|
||||
.set_fmt = adau7118_set_fmt,
|
||||
.set_tdm_slot = adau7118_set_tdm_slot,
|
||||
.set_tristate = adau7118_set_tristate,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver adau7118_dai = {
|
||||
.name = "adau7118-hifi-capture",
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |
|
||||
SNDRV_PCM_FMTBIT_S20_LE | SNDRV_PCM_FMTBIT_S24_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_3LE,
|
||||
.rates = SNDRV_PCM_RATE_CONTINUOUS,
|
||||
.rate_min = 4000,
|
||||
.rate_max = 192000,
|
||||
.sig_bits = 24,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver adau7118_component_driver = {
|
||||
.probe = adau7118_component_probe,
|
||||
.set_bias_level = adau7118_set_bias_level,
|
||||
.dapm_widgets = adau7118_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(adau7118_widgets),
|
||||
.use_pmdown_time = 1,
|
||||
.endianness = 1,
|
||||
.non_legacy_dai_naming = 1,
|
||||
};
|
||||
|
||||
static void adau7118_regulator_disable(void *data)
|
||||
{
|
||||
struct adau7118_data *st = data;
|
||||
int ret;
|
||||
/*
|
||||
* If we fail to disable DVDD, don't bother in trying IOVDD. We
|
||||
* actually don't want to be left in the situation where DVDD
|
||||
* is enabled and IOVDD is disabled.
|
||||
*/
|
||||
ret = regulator_disable(st->dvdd);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
regulator_disable(st->iovdd);
|
||||
}
|
||||
|
||||
static int adau7118_regulator_setup(struct adau7118_data *st)
|
||||
{
|
||||
st->iovdd = devm_regulator_get(st->dev, "IOVDD");
|
||||
if (IS_ERR(st->iovdd)) {
|
||||
dev_err(st->dev, "Could not get iovdd: %ld\n",
|
||||
PTR_ERR(st->iovdd));
|
||||
return PTR_ERR(st->iovdd);
|
||||
}
|
||||
|
||||
st->dvdd = devm_regulator_get(st->dev, "DVDD");
|
||||
if (IS_ERR(st->dvdd)) {
|
||||
dev_err(st->dev, "Could not get dvdd: %ld\n",
|
||||
PTR_ERR(st->dvdd));
|
||||
return PTR_ERR(st->dvdd);
|
||||
}
|
||||
/* just assume the device is in reset */
|
||||
if (!st->hw_mode) {
|
||||
regcache_mark_dirty(st->map);
|
||||
regcache_cache_only(st->map, true);
|
||||
}
|
||||
|
||||
return devm_add_action_or_reset(st->dev, adau7118_regulator_disable,
|
||||
st);
|
||||
}
|
||||
|
||||
static int adau7118_parset_dt(const struct adau7118_data *st)
|
||||
{
|
||||
int ret;
|
||||
u32 dec_ratio = 0;
|
||||
/* 4 inputs */
|
||||
u32 clk_map[4], regval;
|
||||
|
||||
if (st->hw_mode)
|
||||
return 0;
|
||||
|
||||
ret = device_property_read_u32(st->dev, "adi,decimation-ratio",
|
||||
&dec_ratio);
|
||||
if (!ret) {
|
||||
switch (dec_ratio) {
|
||||
case 64:
|
||||
regval = ADAU7118_DEC_RATIO(0);
|
||||
break;
|
||||
case 32:
|
||||
regval = ADAU7118_DEC_RATIO(1);
|
||||
break;
|
||||
case 16:
|
||||
regval = ADAU7118_DEC_RATIO(2);
|
||||
break;
|
||||
default:
|
||||
dev_err(st->dev, "Invalid dec ratio: %u", dec_ratio);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(st->map,
|
||||
ADAU7118_REG_DEC_RATIO_CLK_MAP,
|
||||
ADAU7118_DEC_RATIO_MASK, regval);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = device_property_read_u32_array(st->dev, "adi,pdm-clk-map",
|
||||
clk_map, ARRAY_SIZE(clk_map));
|
||||
if (!ret) {
|
||||
int pdm;
|
||||
u32 _clk_map = 0;
|
||||
|
||||
for (pdm = 0; pdm < ARRAY_SIZE(clk_map); pdm++)
|
||||
_clk_map |= (clk_map[pdm] << (pdm + 4));
|
||||
|
||||
ret = regmap_update_bits(st->map,
|
||||
ADAU7118_REG_DEC_RATIO_CLK_MAP,
|
||||
ADAU7118_CLK_MAP_MASK, _clk_map);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int adau7118_probe(struct device *dev, struct regmap *map, bool hw_mode)
|
||||
{
|
||||
struct adau7118_data *st;
|
||||
int ret;
|
||||
|
||||
st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
|
||||
if (!st)
|
||||
return -ENOMEM;
|
||||
|
||||
st->dev = dev;
|
||||
st->hw_mode = hw_mode;
|
||||
dev_set_drvdata(dev, st);
|
||||
|
||||
if (!hw_mode) {
|
||||
st->map = map;
|
||||
adau7118_dai.ops = &adau7118_ops;
|
||||
/*
|
||||
* Perform a full soft reset. This will set all register's
|
||||
* with their reset values.
|
||||
*/
|
||||
ret = regmap_update_bits(map, ADAU7118_REG_RESET,
|
||||
ADAU7118_FULL_SOFT_R_MASK,
|
||||
ADAU7118_FULL_SOFT_R(1));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = adau7118_parset_dt(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = adau7118_regulator_setup(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_snd_soc_register_component(dev,
|
||||
&adau7118_component_driver,
|
||||
&adau7118_dai, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau7118_probe);
|
||||
|
||||
MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
|
||||
MODULE_DESCRIPTION("ADAU7118 8 channel PDM-to-I2S/TDM Converter driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
24
sound/soc/codecs/adau7118.h
Normal file
24
sound/soc/codecs/adau7118.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _LINUX_ADAU7118_H
|
||||
#define _LINUX_ADAU7118_H
|
||||
|
||||
struct regmap;
|
||||
struct device;
|
||||
|
||||
/* register map */
|
||||
#define ADAU7118_REG_VENDOR_ID 0x00
|
||||
#define ADAU7118_REG_DEVICE_ID1 0x01
|
||||
#define ADAU7118_REG_DEVICE_ID2 0x02
|
||||
#define ADAU7118_REG_REVISION_ID 0x03
|
||||
#define ADAU7118_REG_ENABLES 0x04
|
||||
#define ADAU7118_REG_DEC_RATIO_CLK_MAP 0x05
|
||||
#define ADAU7118_REG_HPF_CONTROL 0x06
|
||||
#define ADAU7118_REG_SPT_CTRL1 0x07
|
||||
#define ADAU7118_REG_SPT_CTRL2 0x08
|
||||
#define ADAU7118_REG_SPT_CX(num) (0x09 + (num))
|
||||
#define ADAU7118_REG_DRIVE_STRENGTH 0x11
|
||||
#define ADAU7118_REG_RESET 0x12
|
||||
|
||||
int adau7118_probe(struct device *dev, struct regmap *map, bool hw_mode);
|
||||
|
||||
#endif
|
||||
|
|
@ -27,6 +27,7 @@
|
|||
#define MADERA_FLL_SRC_NONE -1
|
||||
#define MADERA_FLL_SRC_MCLK1 0
|
||||
#define MADERA_FLL_SRC_MCLK2 1
|
||||
#define MADERA_FLL_SRC_MCLK3 2
|
||||
#define MADERA_FLL_SRC_SLIMCLK 3
|
||||
#define MADERA_FLL_SRC_FLL1 4
|
||||
#define MADERA_FLL_SRC_FLL2 5
|
||||
|
|
@ -51,6 +52,7 @@
|
|||
|
||||
#define MADERA_CLK_SRC_MCLK1 0x0
|
||||
#define MADERA_CLK_SRC_MCLK2 0x1
|
||||
#define MADERA_CLK_SRC_MCLK3 0x2
|
||||
#define MADERA_CLK_SRC_FLL1 0x4
|
||||
#define MADERA_CLK_SRC_FLL2 0x5
|
||||
#define MADERA_CLK_SRC_FLL3 0x6
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ struct pcm3168a_priv {
|
|||
unsigned long sysclk;
|
||||
|
||||
struct pcm3168a_io_params io_params[2];
|
||||
struct snd_soc_dai_driver dai_drv[2];
|
||||
};
|
||||
|
||||
static const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" };
|
||||
|
|
@ -314,6 +315,34 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void pcm3168a_update_fixup_pcm_stream(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
|
||||
u64 formats = SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE;
|
||||
unsigned int channel_max = dai->id == PCM3168A_DAI_DAC ? 8 : 6;
|
||||
|
||||
if (pcm3168a->io_params[dai->id].fmt == PCM3168A_FMT_RIGHT_J) {
|
||||
/* S16_LE is only supported in RIGHT_J mode */
|
||||
formats |= SNDRV_PCM_FMTBIT_S16_LE;
|
||||
|
||||
/*
|
||||
* If multi DIN/DOUT is not selected, RIGHT_J can only support
|
||||
* two channels (no TDM support)
|
||||
*/
|
||||
if (pcm3168a->io_params[dai->id].tdm_slots != 2)
|
||||
channel_max = 2;
|
||||
}
|
||||
|
||||
if (dai->id == PCM3168A_DAI_DAC) {
|
||||
dai->driver->playback.channels_max = channel_max;
|
||||
dai->driver->playback.formats = formats;
|
||||
} else {
|
||||
dai->driver->capture.channels_max = channel_max;
|
||||
dai->driver->capture.formats = formats;
|
||||
}
|
||||
}
|
||||
|
||||
static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
|
|
@ -376,6 +405,8 @@ static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)
|
|||
|
||||
regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);
|
||||
|
||||
pcm3168a_update_fixup_pcm_stream(dai);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -409,6 +440,8 @@ static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
|
|||
else
|
||||
io_params->tdm_mask = rx_mask;
|
||||
|
||||
pcm3168a_update_fixup_pcm_stream(dai);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -530,63 +563,7 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int pcm3168a_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
|
||||
unsigned int sample_min;
|
||||
unsigned int channel_max;
|
||||
unsigned int channel_maxs[] = {
|
||||
8, /* DAC */
|
||||
6 /* ADC */
|
||||
};
|
||||
|
||||
/*
|
||||
* Available Data Bits
|
||||
*
|
||||
* RIGHT_J : 24 / 16
|
||||
* LEFT_J : 24
|
||||
* I2S : 24
|
||||
*
|
||||
* TDM available
|
||||
*
|
||||
* I2S
|
||||
* LEFT_J
|
||||
*/
|
||||
switch (pcm3168a->io_params[dai->id].fmt) {
|
||||
case PCM3168A_FMT_RIGHT_J:
|
||||
sample_min = 16;
|
||||
channel_max = 2;
|
||||
break;
|
||||
case PCM3168A_FMT_LEFT_J:
|
||||
case PCM3168A_FMT_I2S:
|
||||
case PCM3168A_FMT_DSP_A:
|
||||
case PCM3168A_FMT_DSP_B:
|
||||
sample_min = 24;
|
||||
channel_max = channel_maxs[dai->id];
|
||||
break;
|
||||
default:
|
||||
sample_min = 24;
|
||||
channel_max = 2;
|
||||
}
|
||||
|
||||
snd_pcm_hw_constraint_minmax(substream->runtime,
|
||||
SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
|
||||
sample_min, 32);
|
||||
|
||||
/* Allow all channels in multi DIN/DOUT mode */
|
||||
if (pcm3168a->io_params[dai->id].tdm_slots == 2)
|
||||
channel_max = channel_maxs[dai->id];
|
||||
|
||||
snd_pcm_hw_constraint_minmax(substream->runtime,
|
||||
SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||
2, channel_max);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static const struct snd_soc_dai_ops pcm3168a_dai_ops = {
|
||||
.startup = pcm3168a_startup,
|
||||
.set_fmt = pcm3168a_set_dai_fmt,
|
||||
.set_sysclk = pcm3168a_set_dai_sysclk,
|
||||
.hw_params = pcm3168a_hw_params,
|
||||
|
|
@ -776,8 +753,10 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap)
|
|||
pm_runtime_enable(dev);
|
||||
pm_runtime_idle(dev);
|
||||
|
||||
ret = devm_snd_soc_register_component(dev, &pcm3168a_driver, pcm3168a_dais,
|
||||
ARRAY_SIZE(pcm3168a_dais));
|
||||
memcpy(pcm3168a->dai_drv, pcm3168a_dais, sizeof(pcm3168a->dai_drv));
|
||||
ret = devm_snd_soc_register_component(dev, &pcm3168a_driver,
|
||||
pcm3168a->dai_drv,
|
||||
ARRAY_SIZE(pcm3168a->dai_drv));
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register component: %d\n", ret);
|
||||
goto err_regulator;
|
||||
|
|
|
|||
|
|
@ -1805,8 +1805,8 @@ static int rt1011_set_tdm_slot(struct snd_soc_dai *dai,
|
|||
struct snd_soc_component *component = dai->component;
|
||||
struct snd_soc_dapm_context *dapm =
|
||||
snd_soc_component_get_dapm(component);
|
||||
unsigned int val = 0, tdm_en = 0;
|
||||
int ret = 0;
|
||||
unsigned int val = 0, tdm_en = 0, rx_slotnum, tx_slotnum;
|
||||
int ret = 0, first_bit, last_bit;
|
||||
|
||||
snd_soc_dapm_mutex_lock(dapm);
|
||||
if (rx_mask || tx_mask)
|
||||
|
|
@ -1829,6 +1829,7 @@ static int rt1011_set_tdm_slot(struct snd_soc_dai *dai,
|
|||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto _set_tdm_err_;
|
||||
}
|
||||
|
||||
switch (slot_width) {
|
||||
|
|
@ -1848,6 +1849,135 @@ static int rt1011_set_tdm_slot(struct snd_soc_dai *dai,
|
|||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto _set_tdm_err_;
|
||||
}
|
||||
|
||||
/* Rx slot configuration */
|
||||
rx_slotnum = hweight_long(rx_mask);
|
||||
first_bit = find_next_bit((unsigned long *)&rx_mask, 32, 0);
|
||||
if (rx_slotnum > 1 || rx_slotnum == 0) {
|
||||
ret = -EINVAL;
|
||||
dev_dbg(component->dev, "too many rx slots or zero slot\n");
|
||||
goto _set_tdm_err_;
|
||||
}
|
||||
|
||||
switch (first_bit) {
|
||||
case 0:
|
||||
case 2:
|
||||
case 4:
|
||||
case 6:
|
||||
snd_soc_component_update_bits(component,
|
||||
RT1011_CROSS_BQ_SET_1, RT1011_MONO_LR_SEL_MASK,
|
||||
RT1011_MONO_L_CHANNEL);
|
||||
snd_soc_component_update_bits(component,
|
||||
RT1011_TDM1_SET_4,
|
||||
RT1011_TDM_I2S_TX_L_DAC1_1_MASK |
|
||||
RT1011_TDM_I2S_TX_R_DAC1_1_MASK,
|
||||
(first_bit << RT1011_TDM_I2S_TX_L_DAC1_1_SFT) |
|
||||
((first_bit+1) << RT1011_TDM_I2S_TX_R_DAC1_1_SFT));
|
||||
break;
|
||||
case 1:
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
snd_soc_component_update_bits(component,
|
||||
RT1011_CROSS_BQ_SET_1, RT1011_MONO_LR_SEL_MASK,
|
||||
RT1011_MONO_R_CHANNEL);
|
||||
snd_soc_component_update_bits(component,
|
||||
RT1011_TDM1_SET_4,
|
||||
RT1011_TDM_I2S_TX_L_DAC1_1_MASK |
|
||||
RT1011_TDM_I2S_TX_R_DAC1_1_MASK,
|
||||
((first_bit-1) << RT1011_TDM_I2S_TX_L_DAC1_1_SFT) |
|
||||
(first_bit << RT1011_TDM_I2S_TX_R_DAC1_1_SFT));
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto _set_tdm_err_;
|
||||
}
|
||||
|
||||
/* Tx slot configuration */
|
||||
tx_slotnum = hweight_long(tx_mask);
|
||||
first_bit = find_next_bit((unsigned long *)&tx_mask, 32, 0);
|
||||
last_bit = find_last_bit((unsigned long *)&tx_mask, 32);
|
||||
if (tx_slotnum > 2 || (last_bit-first_bit) > 1) {
|
||||
ret = -EINVAL;
|
||||
dev_dbg(component->dev, "too many tx slots or tx slot location error\n");
|
||||
goto _set_tdm_err_;
|
||||
}
|
||||
|
||||
if (tx_slotnum == 1) {
|
||||
snd_soc_component_update_bits(component, RT1011_TDM1_SET_2,
|
||||
RT1011_TDM_I2S_DOCK_ADCDAT_LEN_1_MASK |
|
||||
RT1011_TDM_ADCDAT1_DATA_LOCATION, first_bit);
|
||||
switch (first_bit) {
|
||||
case 1:
|
||||
snd_soc_component_update_bits(component,
|
||||
RT1011_TDM1_SET_3,
|
||||
RT1011_TDM_I2S_RX_ADC1_1_MASK,
|
||||
RT1011_TDM_I2S_RX_ADC1_1_LL);
|
||||
break;
|
||||
case 3:
|
||||
snd_soc_component_update_bits(component,
|
||||
RT1011_TDM1_SET_3,
|
||||
RT1011_TDM_I2S_RX_ADC2_1_MASK,
|
||||
RT1011_TDM_I2S_RX_ADC2_1_LL);
|
||||
break;
|
||||
case 5:
|
||||
snd_soc_component_update_bits(component,
|
||||
RT1011_TDM1_SET_3,
|
||||
RT1011_TDM_I2S_RX_ADC3_1_MASK,
|
||||
RT1011_TDM_I2S_RX_ADC3_1_LL);
|
||||
break;
|
||||
case 7:
|
||||
snd_soc_component_update_bits(component,
|
||||
RT1011_TDM1_SET_3,
|
||||
RT1011_TDM_I2S_RX_ADC4_1_MASK,
|
||||
RT1011_TDM_I2S_RX_ADC4_1_LL);
|
||||
break;
|
||||
case 0:
|
||||
snd_soc_component_update_bits(component,
|
||||
RT1011_TDM1_SET_3,
|
||||
RT1011_TDM_I2S_RX_ADC1_1_MASK, 0);
|
||||
break;
|
||||
case 2:
|
||||
snd_soc_component_update_bits(component,
|
||||
RT1011_TDM1_SET_3,
|
||||
RT1011_TDM_I2S_RX_ADC2_1_MASK, 0);
|
||||
break;
|
||||
case 4:
|
||||
snd_soc_component_update_bits(component,
|
||||
RT1011_TDM1_SET_3,
|
||||
RT1011_TDM_I2S_RX_ADC3_1_MASK, 0);
|
||||
break;
|
||||
case 6:
|
||||
snd_soc_component_update_bits(component,
|
||||
RT1011_TDM1_SET_3,
|
||||
RT1011_TDM_I2S_RX_ADC4_1_MASK, 0);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
dev_dbg(component->dev,
|
||||
"tx slot location error\n");
|
||||
goto _set_tdm_err_;
|
||||
}
|
||||
} else if (tx_slotnum == 2) {
|
||||
switch (first_bit) {
|
||||
case 0:
|
||||
case 2:
|
||||
case 4:
|
||||
case 6:
|
||||
snd_soc_component_update_bits(component,
|
||||
RT1011_TDM1_SET_2,
|
||||
RT1011_TDM_I2S_DOCK_ADCDAT_LEN_1_MASK |
|
||||
RT1011_TDM_ADCDAT1_DATA_LOCATION,
|
||||
RT1011_TDM_I2S_DOCK_ADCDAT_2CH | first_bit);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
dev_dbg(component->dev,
|
||||
"tx slot location should be paired and start from slot0/2/4/6\n");
|
||||
goto _set_tdm_err_;
|
||||
}
|
||||
}
|
||||
|
||||
snd_soc_component_update_bits(component, RT1011_TDM1_SET_1,
|
||||
|
|
@ -1860,10 +1990,12 @@ static int rt1011_set_tdm_slot(struct snd_soc_dai *dai,
|
|||
RT1011_TDM_I2S_DOCK_EN_1_MASK, tdm_en);
|
||||
snd_soc_component_update_bits(component, RT1011_TDM2_SET_2,
|
||||
RT1011_TDM_I2S_DOCK_EN_2_MASK, tdm_en);
|
||||
snd_soc_component_update_bits(component, RT1011_TDM_TOTAL_SET,
|
||||
RT1011_ADCDAT1_PIN_CONFIG | RT1011_ADCDAT2_PIN_CONFIG,
|
||||
RT1011_ADCDAT1_OUTPUT | RT1011_ADCDAT2_OUTPUT);
|
||||
if (tx_slotnum)
|
||||
snd_soc_component_update_bits(component, RT1011_TDM_TOTAL_SET,
|
||||
RT1011_ADCDAT1_PIN_CONFIG | RT1011_ADCDAT2_PIN_CONFIG,
|
||||
RT1011_ADCDAT1_OUTPUT | RT1011_ADCDAT2_OUTPUT);
|
||||
|
||||
_set_tdm_err_:
|
||||
snd_soc_dapm_mutex_unlock(dapm);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -2196,8 +2328,12 @@ static void rt1011_calibration_work(struct work_struct *work)
|
|||
struct rt1011_priv *rt1011 =
|
||||
container_of(work, struct rt1011_priv, cali_work);
|
||||
struct snd_soc_component *component = rt1011->component;
|
||||
unsigned int r0_integer, r0_factor, format;
|
||||
|
||||
rt1011_calibrate(rt1011, 1);
|
||||
if (rt1011->r0_calib)
|
||||
rt1011_calibrate(rt1011, 0);
|
||||
else
|
||||
rt1011_calibrate(rt1011, 1);
|
||||
|
||||
/*
|
||||
* This flag should reset after booting.
|
||||
|
|
@ -2208,6 +2344,39 @@ static void rt1011_calibration_work(struct work_struct *work)
|
|||
|
||||
/* initial */
|
||||
rt1011_reg_init(component);
|
||||
|
||||
/* Apply temperature and calibration data from device property */
|
||||
if (rt1011->temperature_calib) {
|
||||
snd_soc_component_update_bits(component,
|
||||
RT1011_STP_INITIAL_RESISTANCE_TEMP, 0x3ff,
|
||||
(rt1011->temperature_calib << 2));
|
||||
}
|
||||
|
||||
if (rt1011->r0_calib) {
|
||||
rt1011->r0_reg = rt1011->r0_calib;
|
||||
|
||||
format = 2147483648U; /* 2^24 * 128 */
|
||||
r0_integer = format / rt1011->r0_reg / 128;
|
||||
r0_factor = ((format / rt1011->r0_reg * 100) / 128)
|
||||
- (r0_integer * 100);
|
||||
dev_info(component->dev, "DP r0 resistance about %d.%02d ohm, reg=0x%X\n",
|
||||
r0_integer, r0_factor, rt1011->r0_reg);
|
||||
|
||||
rt1011_r0_load(rt1011);
|
||||
}
|
||||
}
|
||||
|
||||
static int rt1011_parse_dp(struct rt1011_priv *rt1011, struct device *dev)
|
||||
{
|
||||
device_property_read_u32(dev, "realtek,temperature_calib",
|
||||
&rt1011->temperature_calib);
|
||||
device_property_read_u32(dev, "realtek,r0_calib",
|
||||
&rt1011->r0_calib);
|
||||
|
||||
dev_dbg(dev, "%s: r0_calib: 0x%x, temperture_calib: 0x%x",
|
||||
__func__, rt1011->r0_calib, rt1011->temperature_calib);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt1011_i2c_probe(struct i2c_client *i2c,
|
||||
|
|
@ -2224,6 +2393,8 @@ static int rt1011_i2c_probe(struct i2c_client *i2c,
|
|||
|
||||
i2c_set_clientdata(i2c, rt1011);
|
||||
|
||||
rt1011_parse_dp(rt1011, &i2c->dev);
|
||||
|
||||
rt1011->regmap = devm_regmap_init_i2c(i2c, &rt1011_regmap);
|
||||
if (IS_ERR(rt1011->regmap)) {
|
||||
ret = PTR_ERR(rt1011->regmap);
|
||||
|
|
|
|||
|
|
@ -460,6 +460,23 @@
|
|||
#define RT1011_TDM_I2S_DOCK_EN_1_MASK (0x1 << 3)
|
||||
#define RT1011_TDM_I2S_DOCK_EN_1_SFT 3
|
||||
#define RT1011_TDM_I2S_DOCK_EN_1 (0x1 << 3)
|
||||
#define RT1011_TDM_ADCDAT1_DATA_LOCATION (0x7 << 0)
|
||||
|
||||
/* TDM1 Setting-3 (0x0118) */
|
||||
#define RT1011_TDM_I2S_RX_ADC1_1_MASK (0x3 << 6)
|
||||
#define RT1011_TDM_I2S_RX_ADC2_1_MASK (0x3 << 4)
|
||||
#define RT1011_TDM_I2S_RX_ADC3_1_MASK (0x3 << 2)
|
||||
#define RT1011_TDM_I2S_RX_ADC4_1_MASK (0x3 << 0)
|
||||
#define RT1011_TDM_I2S_RX_ADC1_1_LL (0x2 << 6)
|
||||
#define RT1011_TDM_I2S_RX_ADC2_1_LL (0x2 << 4)
|
||||
#define RT1011_TDM_I2S_RX_ADC3_1_LL (0x2 << 2)
|
||||
#define RT1011_TDM_I2S_RX_ADC4_1_LL (0x2 << 0)
|
||||
|
||||
/* TDM1 Setting-4 (0x011a) */
|
||||
#define RT1011_TDM_I2S_TX_L_DAC1_1_MASK (0x7 << 12)
|
||||
#define RT1011_TDM_I2S_TX_R_DAC1_1_MASK (0x7 << 8)
|
||||
#define RT1011_TDM_I2S_TX_L_DAC1_1_SFT 12
|
||||
#define RT1011_TDM_I2S_TX_R_DAC1_1_SFT 8
|
||||
|
||||
/* TDM2 Setting-2 (0x0120) */
|
||||
#define RT1011_TDM_I2S_DOCK_ADCDAT_LEN_2_MASK (0x7 << 13)
|
||||
|
|
@ -585,6 +602,12 @@
|
|||
#define RT1011_STP_T0_EN_BIT 6
|
||||
#define RT1011_STP_T0_EN (0x1 << 6)
|
||||
|
||||
/* Cross Biquad Setting-1 (0x0702) */
|
||||
#define RT1011_MONO_LR_SEL_MASK (0x3 << 5)
|
||||
#define RT1011_MONO_L_CHANNEL (0x0 << 5)
|
||||
#define RT1011_MONO_R_CHANNEL (0x1 << 5)
|
||||
#define RT1011_MONO_LR_MIX_CHANNEL (0x2 << 5)
|
||||
|
||||
/* ClassD Internal Setting-1 (0x1300) */
|
||||
#define RT1011_DRIVER_READY_SPK (0x1 << 12)
|
||||
#define RT1011_DRIVER_READY_SPK_BIT 12
|
||||
|
|
@ -667,6 +690,7 @@ struct rt1011_priv {
|
|||
|
||||
int bq_drc_set;
|
||||
unsigned int r0_reg, cali_done;
|
||||
unsigned int r0_calib, temperature_calib;
|
||||
int recv_spk_mode;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -201,18 +201,18 @@ static irqreturn_t rt5514_spi_irq(int irq, void *data)
|
|||
}
|
||||
|
||||
/* PCM for streaming audio from the DSP buffer */
|
||||
static int rt5514_spi_pcm_open(struct snd_pcm_substream *substream)
|
||||
static int rt5514_spi_pcm_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
snd_soc_set_runtime_hwparams(substream, &rt5514_spi_pcm_hardware);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt5514_spi_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
static int rt5514_spi_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct rt5514_dsp *rt5514_dsp =
|
||||
snd_soc_component_get_drvdata(component);
|
||||
int ret;
|
||||
|
|
@ -234,10 +234,9 @@ static int rt5514_spi_hw_params(struct snd_pcm_substream *substream,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int rt5514_spi_hw_free(struct snd_pcm_substream *substream)
|
||||
static int rt5514_spi_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct rt5514_dsp *rt5514_dsp =
|
||||
snd_soc_component_get_drvdata(component);
|
||||
|
||||
|
|
@ -251,24 +250,22 @@ static int rt5514_spi_hw_free(struct snd_pcm_substream *substream)
|
|||
}
|
||||
|
||||
static snd_pcm_uframes_t rt5514_spi_pcm_pointer(
|
||||
struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct rt5514_dsp *rt5514_dsp =
|
||||
snd_soc_component_get_drvdata(component);
|
||||
|
||||
return bytes_to_frames(runtime, rt5514_dsp->dma_offset);
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops rt5514_spi_pcm_ops = {
|
||||
.open = rt5514_spi_pcm_open,
|
||||
.hw_params = rt5514_spi_hw_params,
|
||||
.hw_free = rt5514_spi_hw_free,
|
||||
.pointer = rt5514_spi_pcm_pointer,
|
||||
.page = snd_pcm_lib_get_vmalloc_page,
|
||||
};
|
||||
static struct page *rt5514_spi_pcm_page(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
unsigned long offset)
|
||||
{
|
||||
return snd_pcm_lib_get_vmalloc_page(substream, offset);
|
||||
}
|
||||
|
||||
static int rt5514_spi_pcm_probe(struct snd_soc_component *component)
|
||||
{
|
||||
|
|
@ -302,9 +299,13 @@ static int rt5514_spi_pcm_probe(struct snd_soc_component *component)
|
|||
}
|
||||
|
||||
static const struct snd_soc_component_driver rt5514_spi_component = {
|
||||
.name = DRV_NAME,
|
||||
.probe = rt5514_spi_pcm_probe,
|
||||
.ops = &rt5514_spi_pcm_ops,
|
||||
.name = DRV_NAME,
|
||||
.probe = rt5514_spi_pcm_probe,
|
||||
.open = rt5514_spi_pcm_open,
|
||||
.hw_params = rt5514_spi_hw_params,
|
||||
.hw_free = rt5514_spi_hw_free,
|
||||
.pointer = rt5514_spi_pcm_pointer,
|
||||
.page = rt5514_spi_pcm_page,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -3644,7 +3644,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
|
|||
regmap_update_bits(rt5663->regmap, RT5663_PWR_ANLG_1,
|
||||
RT5663_LDO1_DVO_MASK | RT5663_AMP_HP_MASK,
|
||||
RT5663_LDO1_DVO_0_9V | RT5663_AMP_HP_3X);
|
||||
break;
|
||||
break;
|
||||
case CODEC_VER_0:
|
||||
regmap_update_bits(rt5663->regmap, RT5663_DIG_MISC,
|
||||
RT5663_DIG_GATE_CTRL_MASK, RT5663_DIG_GATE_CTRL_EN);
|
||||
|
|
@ -3663,7 +3663,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
|
|||
regmap_update_bits(rt5663->regmap, RT5663_TDM_2,
|
||||
RT5663_DATA_SWAP_ADCDAT1_MASK,
|
||||
RT5663_DATA_SWAP_ADCDAT1_LL);
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
dev_err(&i2c->dev, "%s:Unknown codec type\n", __func__);
|
||||
}
|
||||
|
|
|
|||
590
sound/soc/codecs/tas2562.c
Normal file
590
sound/soc/codecs/tas2562.c
Normal file
|
|
@ -0,0 +1,590 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Driver for the Texas Instruments TAS2562 CODEC
|
||||
// Copyright (C) 2019 Texas Instruments Inc.
|
||||
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "tas2562.h"
|
||||
|
||||
#define TAS2562_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\
|
||||
SNDRV_PCM_FORMAT_S32_LE)
|
||||
|
||||
struct tas2562_data {
|
||||
struct snd_soc_component *component;
|
||||
struct gpio_desc *sdz_gpio;
|
||||
struct regmap *regmap;
|
||||
struct device *dev;
|
||||
struct i2c_client *client;
|
||||
int v_sense_slot;
|
||||
int i_sense_slot;
|
||||
};
|
||||
|
||||
static int tas2562_set_bias_level(struct snd_soc_component *component,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct tas2562_data *tas2562 =
|
||||
snd_soc_component_get_drvdata(component);
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
snd_soc_component_update_bits(component,
|
||||
TAS2562_PWR_CTRL,
|
||||
TAS2562_MODE_MASK, TAS2562_ACTIVE);
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
snd_soc_component_update_bits(component,
|
||||
TAS2562_PWR_CTRL,
|
||||
TAS2562_MODE_MASK, TAS2562_MUTE);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
snd_soc_component_update_bits(component,
|
||||
TAS2562_PWR_CTRL,
|
||||
TAS2562_MODE_MASK, TAS2562_SHUTDOWN);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(tas2562->dev,
|
||||
"wrong power level setting %d\n", level);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2562_set_samplerate(struct tas2562_data *tas2562, int samplerate)
|
||||
{
|
||||
int samp_rate;
|
||||
int ramp_rate;
|
||||
|
||||
switch (samplerate) {
|
||||
case 7350:
|
||||
ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1;
|
||||
samp_rate = TAS2562_TDM_CFG0_SAMPRATE_7305_8KHZ;
|
||||
break;
|
||||
case 8000:
|
||||
ramp_rate = 0;
|
||||
samp_rate = TAS2562_TDM_CFG0_SAMPRATE_7305_8KHZ;
|
||||
break;
|
||||
case 14700:
|
||||
ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1;
|
||||
samp_rate = TAS2562_TDM_CFG0_SAMPRATE_14_7_16KHZ;
|
||||
break;
|
||||
case 16000:
|
||||
ramp_rate = 0;
|
||||
samp_rate = TAS2562_TDM_CFG0_SAMPRATE_14_7_16KHZ;
|
||||
break;
|
||||
case 22050:
|
||||
ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1;
|
||||
samp_rate = TAS2562_TDM_CFG0_SAMPRATE_22_05_24KHZ;
|
||||
break;
|
||||
case 24000:
|
||||
ramp_rate = 0;
|
||||
samp_rate = TAS2562_TDM_CFG0_SAMPRATE_22_05_24KHZ;
|
||||
break;
|
||||
case 29400:
|
||||
ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1;
|
||||
samp_rate = TAS2562_TDM_CFG0_SAMPRATE_29_4_32KHZ;
|
||||
break;
|
||||
case 32000:
|
||||
ramp_rate = 0;
|
||||
samp_rate = TAS2562_TDM_CFG0_SAMPRATE_29_4_32KHZ;
|
||||
break;
|
||||
case 44100:
|
||||
ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1;
|
||||
samp_rate = TAS2562_TDM_CFG0_SAMPRATE_44_1_48KHZ;
|
||||
break;
|
||||
case 48000:
|
||||
ramp_rate = 0;
|
||||
samp_rate = TAS2562_TDM_CFG0_SAMPRATE_44_1_48KHZ;
|
||||
break;
|
||||
case 88200:
|
||||
ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1;
|
||||
samp_rate = TAS2562_TDM_CFG0_SAMPRATE_88_2_96KHZ;
|
||||
break;
|
||||
case 96000:
|
||||
ramp_rate = 0;
|
||||
samp_rate = TAS2562_TDM_CFG0_SAMPRATE_88_2_96KHZ;
|
||||
break;
|
||||
case 176400:
|
||||
ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1;
|
||||
samp_rate = TAS2562_TDM_CFG0_SAMPRATE_176_4_192KHZ;
|
||||
break;
|
||||
case 192000:
|
||||
ramp_rate = 0;
|
||||
samp_rate = TAS2562_TDM_CFG0_SAMPRATE_176_4_192KHZ;
|
||||
break;
|
||||
default:
|
||||
dev_info(tas2562->dev, "%s, unsupported sample rate, %d\n",
|
||||
__func__, samplerate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_component_update_bits(tas2562->component, TAS2562_TDM_CFG0,
|
||||
TAS2562_TDM_CFG0_RAMPRATE_MASK, ramp_rate);
|
||||
snd_soc_component_update_bits(tas2562->component, TAS2562_TDM_CFG0,
|
||||
TAS2562_TDM_CFG0_SAMPRATE_MASK, samp_rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2562_set_dai_tdm_slot(struct snd_soc_dai *dai,
|
||||
unsigned int tx_mask, unsigned int rx_mask,
|
||||
int slots, int slot_width)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
|
||||
int ret = 0;
|
||||
|
||||
switch (slot_width) {
|
||||
case 16:
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2562_TDM_CFG2,
|
||||
TAS2562_TDM_CFG2_RXLEN_MASK,
|
||||
TAS2562_TDM_CFG2_RXLEN_16B);
|
||||
break;
|
||||
case 24:
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2562_TDM_CFG2,
|
||||
TAS2562_TDM_CFG2_RXLEN_MASK,
|
||||
TAS2562_TDM_CFG2_RXLEN_24B);
|
||||
break;
|
||||
case 32:
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2562_TDM_CFG2,
|
||||
TAS2562_TDM_CFG2_RXLEN_MASK,
|
||||
TAS2562_TDM_CFG2_RXLEN_32B);
|
||||
break;
|
||||
|
||||
case 0:
|
||||
/* Do not change slot width */
|
||||
break;
|
||||
default:
|
||||
dev_err(tas2562->dev, "slot width not supported");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2562_set_bitwidth(struct tas2562_data *tas2562, int bitwidth)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (bitwidth) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
snd_soc_component_update_bits(tas2562->component,
|
||||
TAS2562_TDM_CFG2,
|
||||
TAS2562_TDM_CFG2_RXWLEN_MASK,
|
||||
TAS2562_TDM_CFG2_RXWLEN_16B);
|
||||
tas2562->v_sense_slot = tas2562->i_sense_slot + 2;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
snd_soc_component_update_bits(tas2562->component,
|
||||
TAS2562_TDM_CFG2,
|
||||
TAS2562_TDM_CFG2_RXWLEN_MASK,
|
||||
TAS2562_TDM_CFG2_RXWLEN_24B);
|
||||
tas2562->v_sense_slot = tas2562->i_sense_slot + 4;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
snd_soc_component_update_bits(tas2562->component,
|
||||
TAS2562_TDM_CFG2,
|
||||
TAS2562_TDM_CFG2_RXWLEN_MASK,
|
||||
TAS2562_TDM_CFG2_RXWLEN_32B);
|
||||
tas2562->v_sense_slot = tas2562->i_sense_slot + 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_info(tas2562->dev, "Not supported params format\n");
|
||||
}
|
||||
|
||||
ret = snd_soc_component_update_bits(tas2562->component,
|
||||
TAS2562_TDM_CFG5,
|
||||
TAS2562_TDM_CFG5_VSNS_EN | TAS2562_TDM_CFG5_VSNS_SLOT_MASK,
|
||||
TAS2562_TDM_CFG5_VSNS_EN | tas2562->v_sense_slot);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_component_update_bits(tas2562->component,
|
||||
TAS2562_TDM_CFG6,
|
||||
TAS2562_TDM_CFG6_ISNS_EN | TAS2562_TDM_CFG6_ISNS_SLOT_MASK,
|
||||
TAS2562_TDM_CFG6_ISNS_EN | tas2562->i_sense_slot);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2562_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
|
||||
int ret;
|
||||
|
||||
ret = tas2562_set_bitwidth(tas2562, params_format(params));
|
||||
if (ret) {
|
||||
dev_err(tas2562->dev, "set bitwidth failed, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tas2562_set_samplerate(tas2562, params_rate(params));
|
||||
if (ret)
|
||||
dev_err(tas2562->dev, "set bitwidth failed, %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tas2562_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
|
||||
u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0;
|
||||
int ret;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
asi_cfg_1 = 0;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
asi_cfg_1 |= TAS2562_TDM_CFG1_RX_FALLING;
|
||||
break;
|
||||
default:
|
||||
dev_err(tas2562->dev, "ASI format Inverse is not found\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snd_soc_component_update_bits(component, TAS2562_TDM_CFG1,
|
||||
TAS2562_TDM_CFG1_RX_EDGE_MASK,
|
||||
asi_cfg_1);
|
||||
if (ret < 0) {
|
||||
dev_err(tas2562->dev, "Failed to set RX edge\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case (SND_SOC_DAIFMT_I2S):
|
||||
case (SND_SOC_DAIFMT_DSP_A):
|
||||
case (SND_SOC_DAIFMT_DSP_B):
|
||||
tdm_rx_start_slot = BIT(1);
|
||||
break;
|
||||
case (SND_SOC_DAIFMT_LEFT_J):
|
||||
tdm_rx_start_slot = 0;
|
||||
break;
|
||||
default:
|
||||
dev_err(tas2562->dev, "DAI Format is not found, fmt=0x%x\n",
|
||||
fmt);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = snd_soc_component_update_bits(component, TAS2562_TDM_CFG1,
|
||||
TAS2562_TDM_CFG1_RX_OFFSET_MASK,
|
||||
tdm_rx_start_slot);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2562_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
|
||||
return snd_soc_component_update_bits(component, TAS2562_PWR_CTRL,
|
||||
TAS2562_MODE_MASK,
|
||||
mute ? TAS2562_MUTE : 0);
|
||||
}
|
||||
|
||||
static int tas2562_codec_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
|
||||
int ret;
|
||||
|
||||
tas2562->component = component;
|
||||
|
||||
if (tas2562->sdz_gpio)
|
||||
gpiod_set_value_cansleep(tas2562->sdz_gpio, 1);
|
||||
|
||||
ret = snd_soc_component_update_bits(component, TAS2562_PWR_CTRL,
|
||||
TAS2562_MODE_MASK, TAS2562_MUTE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int tas2562_suspend(struct snd_soc_component *component)
|
||||
{
|
||||
struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
regcache_cache_only(tas2562->regmap, true);
|
||||
regcache_mark_dirty(tas2562->regmap);
|
||||
|
||||
if (tas2562->sdz_gpio)
|
||||
gpiod_set_value_cansleep(tas2562->sdz_gpio, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2562_resume(struct snd_soc_component *component)
|
||||
{
|
||||
struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
if (tas2562->sdz_gpio)
|
||||
gpiod_set_value_cansleep(tas2562->sdz_gpio, 1);
|
||||
|
||||
regcache_cache_only(tas2562->regmap, false);
|
||||
|
||||
return regcache_sync(tas2562->regmap);
|
||||
}
|
||||
#else
|
||||
#define tas2562_suspend NULL
|
||||
#define tas2562_resume NULL
|
||||
#endif
|
||||
|
||||
static const char * const tas2562_ASI1_src[] = {
|
||||
"I2C offset", "Left", "Right", "LeftRightDiv2",
|
||||
};
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(tas2562_ASI1_src_enum, TAS2562_TDM_CFG2, 4,
|
||||
tas2562_ASI1_src);
|
||||
|
||||
static const struct snd_kcontrol_new tas2562_asi1_mux =
|
||||
SOC_DAPM_ENUM("ASI1 Source", tas2562_ASI1_src_enum);
|
||||
|
||||
static int tas2562_dac_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_component *component =
|
||||
snd_soc_dapm_to_component(w->dapm);
|
||||
struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
dev_info(tas2562->dev, "SND_SOC_DAPM_POST_PMU\n");
|
||||
break;
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
dev_info(tas2562->dev, "SND_SOC_DAPM_PRE_PMD\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DECLARE_TLV_DB_SCALE(tas2562_dac_tlv, 850, 50, 0);
|
||||
|
||||
static const struct snd_kcontrol_new isense_switch =
|
||||
SOC_DAPM_SINGLE("Switch", TAS2562_PWR_CTRL, TAS2562_ISENSE_POWER_EN,
|
||||
1, 1);
|
||||
|
||||
static const struct snd_kcontrol_new vsense_switch =
|
||||
SOC_DAPM_SINGLE("Switch", TAS2562_PWR_CTRL, TAS2562_VSENSE_POWER_EN,
|
||||
1, 1);
|
||||
|
||||
static const struct snd_kcontrol_new tas2562_snd_controls[] = {
|
||||
SOC_SINGLE_TLV("Amp Gain Volume", TAS2562_PB_CFG1, 0, 0x1c, 0,
|
||||
tas2562_dac_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget tas2562_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, &tas2562_asi1_mux),
|
||||
SND_SOC_DAPM_AIF_IN("DAC IN", "Playback", 0, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2562_dac_event,
|
||||
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
|
||||
SND_SOC_DAPM_SWITCH("ISENSE", TAS2562_PWR_CTRL, 3, 1, &isense_switch),
|
||||
SND_SOC_DAPM_SWITCH("VSENSE", TAS2562_PWR_CTRL, 2, 1, &vsense_switch),
|
||||
SND_SOC_DAPM_SIGGEN("VMON"),
|
||||
SND_SOC_DAPM_SIGGEN("IMON"),
|
||||
SND_SOC_DAPM_OUTPUT("OUT"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route tas2562_audio_map[] = {
|
||||
{"ASI1 Sel", "I2C offset", "ASI1"},
|
||||
{"ASI1 Sel", "Left", "ASI1"},
|
||||
{"ASI1 Sel", "Right", "ASI1"},
|
||||
{"ASI1 Sel", "LeftRightDiv2", "ASI1"},
|
||||
{ "DAC", NULL, "DAC IN" },
|
||||
{ "OUT", NULL, "DAC" },
|
||||
{"ISENSE", "Switch", "IMON"},
|
||||
{"VSENSE", "Switch", "VMON"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver soc_component_dev_tas2562 = {
|
||||
.probe = tas2562_codec_probe,
|
||||
.suspend = tas2562_suspend,
|
||||
.resume = tas2562_resume,
|
||||
.set_bias_level = tas2562_set_bias_level,
|
||||
.controls = tas2562_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(tas2562_snd_controls),
|
||||
.dapm_widgets = tas2562_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(tas2562_dapm_widgets),
|
||||
.dapm_routes = tas2562_audio_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(tas2562_audio_map),
|
||||
.idle_bias_on = 1,
|
||||
.use_pmdown_time = 1,
|
||||
.endianness = 1,
|
||||
.non_legacy_dai_naming = 1,
|
||||
};
|
||||
|
||||
static const struct snd_soc_dai_ops tas2562_speaker_dai_ops = {
|
||||
.hw_params = tas2562_hw_params,
|
||||
.set_fmt = tas2562_set_dai_fmt,
|
||||
.set_tdm_slot = tas2562_set_dai_tdm_slot,
|
||||
.digital_mute = tas2562_mute,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver tas2562_dai[] = {
|
||||
{
|
||||
.name = "tas2562-amplifier",
|
||||
.id = 0,
|
||||
.playback = {
|
||||
.stream_name = "ASI1 Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = TAS2562_FORMATS,
|
||||
},
|
||||
.ops = &tas2562_speaker_dai_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_range_cfg tas2562_ranges[] = {
|
||||
{
|
||||
.range_min = 0,
|
||||
.range_max = 5 * 128,
|
||||
.selector_reg = TAS2562_PAGE_CTRL,
|
||||
.selector_mask = 0xff,
|
||||
.selector_shift = 0,
|
||||
.window_start = 0,
|
||||
.window_len = 128,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct reg_default tas2562_reg_defaults[] = {
|
||||
{ TAS2562_PAGE_CTRL, 0x00 },
|
||||
{ TAS2562_SW_RESET, 0x00 },
|
||||
{ TAS2562_PWR_CTRL, 0x0e },
|
||||
{ TAS2562_PB_CFG1, 0x20 },
|
||||
{ TAS2562_TDM_CFG0, 0x09 },
|
||||
{ TAS2562_TDM_CFG1, 0x02 },
|
||||
};
|
||||
|
||||
static const struct regmap_config tas2562_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = 5 * 128,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.reg_defaults = tas2562_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(tas2562_reg_defaults),
|
||||
.ranges = tas2562_ranges,
|
||||
.num_ranges = ARRAY_SIZE(tas2562_ranges),
|
||||
};
|
||||
|
||||
static int tas2562_parse_dt(struct tas2562_data *tas2562)
|
||||
{
|
||||
struct device *dev = tas2562->dev;
|
||||
int ret = 0;
|
||||
|
||||
tas2562->sdz_gpio = devm_gpiod_get_optional(dev, "shut-down-gpio",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(tas2562->sdz_gpio)) {
|
||||
if (PTR_ERR(tas2562->sdz_gpio) == -EPROBE_DEFER) {
|
||||
tas2562->sdz_gpio = NULL;
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
}
|
||||
|
||||
ret = fwnode_property_read_u32(dev->fwnode, "ti,imon-slot-no",
|
||||
&tas2562->i_sense_slot);
|
||||
if (ret)
|
||||
dev_err(dev, "Looking up %s property failed %d\n",
|
||||
"ti,imon-slot-no", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tas2562_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct tas2562_data *data;
|
||||
int ret;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->client = client;
|
||||
data->dev = &client->dev;
|
||||
|
||||
tas2562_parse_dt(data);
|
||||
|
||||
data->regmap = devm_regmap_init_i2c(client, &tas2562_regmap_config);
|
||||
if (IS_ERR(data->regmap)) {
|
||||
ret = PTR_ERR(data->regmap);
|
||||
dev_err(dev, "failed to allocate register map: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&client->dev, data);
|
||||
|
||||
return devm_snd_soc_register_component(dev, &soc_component_dev_tas2562,
|
||||
tas2562_dai,
|
||||
ARRAY_SIZE(tas2562_dai));
|
||||
|
||||
}
|
||||
|
||||
static const struct i2c_device_id tas2562_id[] = {
|
||||
{ "tas2562", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tas2562_id);
|
||||
|
||||
static const struct of_device_id tas2562_of_match[] = {
|
||||
{ .compatible = "ti,tas2562", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tas2562_of_match);
|
||||
|
||||
static struct i2c_driver tas2562_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "tas2562",
|
||||
.of_match_table = of_match_ptr(tas2562_of_match),
|
||||
},
|
||||
.probe = tas2562_probe,
|
||||
.id_table = tas2562_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(tas2562_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
|
||||
MODULE_DESCRIPTION("TAS2562 Audio amplifier driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
85
sound/soc/codecs/tas2562.h
Normal file
85
sound/soc/codecs/tas2562.h
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* tas2562.h - ALSA SoC Texas Instruments TAS2562 Mono Audio Amplifier
|
||||
*
|
||||
* Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
|
||||
*
|
||||
* Author: Dan Murphy <dmurphy@ti.com>
|
||||
*/
|
||||
|
||||
#ifndef __TAS2562_H__
|
||||
#define __TAS2562_H__
|
||||
|
||||
#define TAS2562_PAGE_CTRL 0x00
|
||||
|
||||
#define TAS2562_REG(page, reg) ((page * 128) + reg)
|
||||
|
||||
#define TAS2562_SW_RESET TAS2562_REG(0, 0x01)
|
||||
#define TAS2562_PWR_CTRL TAS2562_REG(0, 0x02)
|
||||
#define TAS2562_PB_CFG1 TAS2562_REG(0, 0x03)
|
||||
#define TAS2562_MISC_CFG1 TAS2562_REG(0, 0x04)
|
||||
#define TAS2562_MISC_CFG2 TAS2562_REG(0, 0x05)
|
||||
|
||||
#define TAS2562_TDM_CFG0 TAS2562_REG(0, 0x06)
|
||||
#define TAS2562_TDM_CFG1 TAS2562_REG(0, 0x07)
|
||||
#define TAS2562_TDM_CFG2 TAS2562_REG(0, 0x08)
|
||||
#define TAS2562_TDM_CFG3 TAS2562_REG(0, 0x09)
|
||||
#define TAS2562_TDM_CFG4 TAS2562_REG(0, 0x0a)
|
||||
#define TAS2562_TDM_CFG5 TAS2562_REG(0, 0x0b)
|
||||
#define TAS2562_TDM_CFG6 TAS2562_REG(0, 0x0c)
|
||||
#define TAS2562_TDM_CFG7 TAS2562_REG(0, 0x0d)
|
||||
#define TAS2562_TDM_CFG8 TAS2562_REG(0, 0x0e)
|
||||
#define TAS2562_TDM_CFG9 TAS2562_REG(0, 0x0f)
|
||||
#define TAS2562_TDM_CFG10 TAS2562_REG(0, 0x10)
|
||||
#define TAS2562_TDM_DET TAS2562_REG(0, 0x11)
|
||||
#define TAS2562_REV_ID TAS2562_REG(0, 0x7d)
|
||||
|
||||
/* Page 2 */
|
||||
#define TAS2562_DVC_CFG1 TAS2562_REG(2, 0x01)
|
||||
#define TAS2562_DVC_CFG2 TAS2562_REG(2, 0x02)
|
||||
|
||||
#define TAS2562_RESET BIT(0)
|
||||
|
||||
#define TAS2562_MODE_MASK 0x3
|
||||
#define TAS2562_ACTIVE 0x0
|
||||
#define TAS2562_MUTE 0x1
|
||||
#define TAS2562_SHUTDOWN 0x2
|
||||
|
||||
#define TAS2562_TDM_CFG1_RX_EDGE_MASK BIT(0)
|
||||
#define TAS2562_TDM_CFG1_RX_FALLING 1
|
||||
#define TAS2562_TDM_CFG1_RX_OFFSET_MASK GENMASK(4, 0)
|
||||
|
||||
#define TAS2562_TDM_CFG0_RAMPRATE_MASK BIT(5)
|
||||
#define TAS2562_TDM_CFG0_RAMPRATE_44_1 BIT(5)
|
||||
#define TAS2562_TDM_CFG0_SAMPRATE_MASK GENMASK(3, 1)
|
||||
#define TAS2562_TDM_CFG0_SAMPRATE_7305_8KHZ 0x0
|
||||
#define TAS2562_TDM_CFG0_SAMPRATE_14_7_16KHZ 0x1
|
||||
#define TAS2562_TDM_CFG0_SAMPRATE_22_05_24KHZ 0x2
|
||||
#define TAS2562_TDM_CFG0_SAMPRATE_29_4_32KHZ 0x3
|
||||
#define TAS2562_TDM_CFG0_SAMPRATE_44_1_48KHZ 0x4
|
||||
#define TAS2562_TDM_CFG0_SAMPRATE_88_2_96KHZ 0x5
|
||||
#define TAS2562_TDM_CFG0_SAMPRATE_176_4_192KHZ 0x6
|
||||
|
||||
#define TAS2562_TDM_CFG2_RIGHT_JUSTIFY BIT(6)
|
||||
|
||||
#define TAS2562_TDM_CFG2_RXLEN_MASK GENMASK(0, 1)
|
||||
#define TAS2562_TDM_CFG2_RXLEN_16B 0x0
|
||||
#define TAS2562_TDM_CFG2_RXLEN_24B BIT(0)
|
||||
#define TAS2562_TDM_CFG2_RXLEN_32B BIT(1)
|
||||
|
||||
#define TAS2562_TDM_CFG2_RXWLEN_MASK GENMASK(3, 2)
|
||||
#define TAS2562_TDM_CFG2_RXWLEN_16B 0x0
|
||||
#define TAS2562_TDM_CFG2_RXWLEN_20B BIT(2)
|
||||
#define TAS2562_TDM_CFG2_RXWLEN_24B BIT(3)
|
||||
#define TAS2562_TDM_CFG2_RXWLEN_32B (BIT(2) | BIT(3))
|
||||
|
||||
#define TAS2562_VSENSE_POWER_EN BIT(2)
|
||||
#define TAS2562_ISENSE_POWER_EN BIT(3)
|
||||
|
||||
#define TAS2562_TDM_CFG5_VSNS_EN BIT(6)
|
||||
#define TAS2562_TDM_CFG5_VSNS_SLOT_MASK GENMASK(5, 0)
|
||||
|
||||
#define TAS2562_TDM_CFG6_ISNS_EN BIT(6)
|
||||
#define TAS2562_TDM_CFG6_ISNS_SLOT_MASK GENMASK(5, 0)
|
||||
|
||||
#endif /* __TAS2562_H__ */
|
||||
819
sound/soc/codecs/tas2770.c
Normal file
819
sound/soc/codecs/tas2770.c
Normal file
|
|
@ -0,0 +1,819 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// ALSA SoC Texas Instruments TAS2770 20-W Digital Input Mono Class-D
|
||||
// Audio Amplifier with Speaker I/V Sense
|
||||
//
|
||||
// Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/
|
||||
// Author: Tracy Yi <tracy-yi@ti.com>
|
||||
// Frank Shi <shifu0704@thundersoft.com>
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "tas2770.h"
|
||||
|
||||
#define TAS2770_MDELAY 0xFFFFFFFE
|
||||
|
||||
static void tas2770_reset(struct tas2770_priv *tas2770)
|
||||
{
|
||||
if (tas2770->reset_gpio) {
|
||||
gpiod_set_value_cansleep(tas2770->reset_gpio, 0);
|
||||
msleep(20);
|
||||
gpiod_set_value_cansleep(tas2770->reset_gpio, 1);
|
||||
}
|
||||
snd_soc_component_write(tas2770->component, TAS2770_SW_RST,
|
||||
TAS2770_RST);
|
||||
}
|
||||
|
||||
static int tas2770_set_bias_level(struct snd_soc_component *component,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct tas2770_priv *tas2770 =
|
||||
snd_soc_component_get_drvdata(component);
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
snd_soc_component_update_bits(component,
|
||||
TAS2770_PWR_CTRL,
|
||||
TAS2770_PWR_CTRL_MASK,
|
||||
TAS2770_PWR_CTRL_ACTIVE);
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_OFF:
|
||||
snd_soc_component_update_bits(component,
|
||||
TAS2770_PWR_CTRL,
|
||||
TAS2770_PWR_CTRL_MASK,
|
||||
TAS2770_PWR_CTRL_SHUTDOWN);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(tas2770->dev,
|
||||
"wrong power level setting %d\n", level);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int tas2770_codec_suspend(struct snd_soc_component *component)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_PWR_CTRL,
|
||||
TAS2770_PWR_CTRL_MASK,
|
||||
TAS2770_PWR_CTRL_SHUTDOWN);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2770_codec_resume(struct snd_soc_component *component)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_PWR_CTRL,
|
||||
TAS2770_PWR_CTRL_MASK,
|
||||
TAS2770_PWR_CTRL_ACTIVE);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define tas2770_codec_suspend NULL
|
||||
#define tas2770_codec_resume NULL
|
||||
#endif
|
||||
|
||||
static const char * const tas2770_ASI1_src[] = {
|
||||
"I2C offset", "Left", "Right", "LeftRightDiv2",
|
||||
};
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
tas2770_ASI1_src_enum, TAS2770_TDM_CFG_REG2,
|
||||
4, tas2770_ASI1_src);
|
||||
|
||||
static const struct snd_kcontrol_new tas2770_asi1_mux =
|
||||
SOC_DAPM_ENUM("ASI1 Source", tas2770_ASI1_src_enum);
|
||||
|
||||
static int tas2770_dac_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_component *component =
|
||||
snd_soc_dapm_to_component(w->dapm);
|
||||
struct tas2770_priv *tas2770 =
|
||||
snd_soc_component_get_drvdata(component);
|
||||
int ret;
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_PWR_CTRL,
|
||||
TAS2770_PWR_CTRL_MASK,
|
||||
TAS2770_PWR_CTRL_MUTE);
|
||||
if (ret)
|
||||
goto end;
|
||||
break;
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_PWR_CTRL,
|
||||
TAS2770_PWR_CTRL_MASK,
|
||||
TAS2770_PWR_CTRL_SHUTDOWN);
|
||||
if (ret)
|
||||
goto end;
|
||||
break;
|
||||
default:
|
||||
dev_err(tas2770->dev, "Not supported evevt\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
end:
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new isense_switch =
|
||||
SOC_DAPM_SINGLE("Switch", TAS2770_PWR_CTRL, 3, 1, 1);
|
||||
static const struct snd_kcontrol_new vsense_switch =
|
||||
SOC_DAPM_SINGLE("Switch", TAS2770_PWR_CTRL, 2, 1, 1);
|
||||
|
||||
static const struct snd_soc_dapm_widget tas2770_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0,
|
||||
&tas2770_asi1_mux),
|
||||
SND_SOC_DAPM_SWITCH("ISENSE", TAS2770_PWR_CTRL, 3, 1,
|
||||
&isense_switch),
|
||||
SND_SOC_DAPM_SWITCH("VSENSE", TAS2770_PWR_CTRL, 2, 1,
|
||||
&vsense_switch),
|
||||
SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2770_dac_event,
|
||||
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
|
||||
SND_SOC_DAPM_OUTPUT("OUT"),
|
||||
SND_SOC_DAPM_SIGGEN("VMON"),
|
||||
SND_SOC_DAPM_SIGGEN("IMON")
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route tas2770_audio_map[] = {
|
||||
{"ASI1 Sel", "I2C offset", "ASI1"},
|
||||
{"ASI1 Sel", "Left", "ASI1"},
|
||||
{"ASI1 Sel", "Right", "ASI1"},
|
||||
{"ASI1 Sel", "LeftRightDiv2", "ASI1"},
|
||||
{"DAC", NULL, "ASI1 Sel"},
|
||||
{"OUT", NULL, "DAC"},
|
||||
{"ISENSE", "Switch", "IMON"},
|
||||
{"VSENSE", "Switch", "VMON"},
|
||||
};
|
||||
|
||||
static int tas2770_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
int ret;
|
||||
|
||||
if (mute)
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_PWR_CTRL,
|
||||
TAS2770_PWR_CTRL_MASK,
|
||||
TAS2770_PWR_CTRL_MUTE);
|
||||
else
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_PWR_CTRL,
|
||||
TAS2770_PWR_CTRL_MASK,
|
||||
TAS2770_PWR_CTRL_ACTIVE);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2770_set_bitwidth(struct tas2770_priv *tas2770, int bitwidth)
|
||||
{
|
||||
int ret;
|
||||
struct snd_soc_component *component = tas2770->component;
|
||||
|
||||
switch (bitwidth) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_TDM_CFG_REG2,
|
||||
TAS2770_TDM_CFG_REG2_RXW_MASK,
|
||||
TAS2770_TDM_CFG_REG2_RXW_16BITS);
|
||||
tas2770->v_sense_slot = tas2770->i_sense_slot + 2;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_TDM_CFG_REG2,
|
||||
TAS2770_TDM_CFG_REG2_RXW_MASK,
|
||||
TAS2770_TDM_CFG_REG2_RXW_24BITS);
|
||||
tas2770->v_sense_slot = tas2770->i_sense_slot + 4;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_TDM_CFG_REG2,
|
||||
TAS2770_TDM_CFG_REG2_RXW_MASK,
|
||||
TAS2770_TDM_CFG_REG2_RXW_32BITS);
|
||||
tas2770->v_sense_slot = tas2770->i_sense_slot + 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tas2770->channel_size = bitwidth;
|
||||
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_TDM_CFG_REG5,
|
||||
TAS2770_TDM_CFG_REG5_VSNS_MASK |
|
||||
TAS2770_TDM_CFG_REG5_50_MASK,
|
||||
TAS2770_TDM_CFG_REG5_VSNS_ENABLE |
|
||||
tas2770->v_sense_slot);
|
||||
if (ret)
|
||||
goto end;
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_TDM_CFG_REG6,
|
||||
TAS2770_TDM_CFG_REG6_ISNS_MASK |
|
||||
TAS2770_TDM_CFG_REG6_50_MASK,
|
||||
TAS2770_TDM_CFG_REG6_ISNS_ENABLE |
|
||||
tas2770->i_sense_slot);
|
||||
|
||||
end:
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2770_set_samplerate(struct tas2770_priv *tas2770, int samplerate)
|
||||
{
|
||||
int ret;
|
||||
struct snd_soc_component *component = tas2770->component;
|
||||
|
||||
switch (samplerate) {
|
||||
case 48000:
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_TDM_CFG_REG0,
|
||||
TAS2770_TDM_CFG_REG0_SMP_MASK,
|
||||
TAS2770_TDM_CFG_REG0_SMP_48KHZ);
|
||||
if (ret)
|
||||
goto end;
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_TDM_CFG_REG0,
|
||||
TAS2770_TDM_CFG_REG0_31_MASK,
|
||||
TAS2770_TDM_CFG_REG0_31_44_1_48KHZ);
|
||||
if (ret)
|
||||
goto end;
|
||||
break;
|
||||
case 44100:
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_TDM_CFG_REG0,
|
||||
TAS2770_TDM_CFG_REG0_SMP_MASK,
|
||||
TAS2770_TDM_CFG_REG0_SMP_44_1KHZ);
|
||||
if (ret)
|
||||
goto end;
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_TDM_CFG_REG0,
|
||||
TAS2770_TDM_CFG_REG0_31_MASK,
|
||||
TAS2770_TDM_CFG_REG0_31_44_1_48KHZ);
|
||||
if (ret)
|
||||
goto end;
|
||||
break;
|
||||
case 96000:
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_TDM_CFG_REG0,
|
||||
TAS2770_TDM_CFG_REG0_SMP_MASK,
|
||||
TAS2770_TDM_CFG_REG0_SMP_48KHZ);
|
||||
if (ret)
|
||||
goto end;
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_TDM_CFG_REG0,
|
||||
TAS2770_TDM_CFG_REG0_31_MASK,
|
||||
TAS2770_TDM_CFG_REG0_31_88_2_96KHZ);
|
||||
break;
|
||||
case 88200:
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_TDM_CFG_REG0,
|
||||
TAS2770_TDM_CFG_REG0_SMP_MASK,
|
||||
TAS2770_TDM_CFG_REG0_SMP_44_1KHZ);
|
||||
if (ret)
|
||||
goto end;
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_TDM_CFG_REG0,
|
||||
TAS2770_TDM_CFG_REG0_31_MASK,
|
||||
TAS2770_TDM_CFG_REG0_31_88_2_96KHZ);
|
||||
break;
|
||||
case 19200:
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_TDM_CFG_REG0,
|
||||
TAS2770_TDM_CFG_REG0_SMP_MASK,
|
||||
TAS2770_TDM_CFG_REG0_SMP_48KHZ);
|
||||
if (ret)
|
||||
goto end;
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_TDM_CFG_REG0,
|
||||
TAS2770_TDM_CFG_REG0_31_MASK,
|
||||
TAS2770_TDM_CFG_REG0_31_176_4_192KHZ);
|
||||
if (ret)
|
||||
goto end;
|
||||
break;
|
||||
case 17640:
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_TDM_CFG_REG0,
|
||||
TAS2770_TDM_CFG_REG0_SMP_MASK,
|
||||
TAS2770_TDM_CFG_REG0_SMP_44_1KHZ);
|
||||
if (ret)
|
||||
goto end;
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_TDM_CFG_REG0,
|
||||
TAS2770_TDM_CFG_REG0_31_MASK,
|
||||
TAS2770_TDM_CFG_REG0_31_176_4_192KHZ);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
end:
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
tas2770->sampling_rate = samplerate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2770_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct tas2770_priv *tas2770 =
|
||||
snd_soc_component_get_drvdata(component);
|
||||
int ret;
|
||||
|
||||
ret = tas2770_set_bitwidth(tas2770, params_format(params));
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
|
||||
|
||||
ret = tas2770_set_samplerate(tas2770, params_rate(params));
|
||||
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
{
|
||||
u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0;
|
||||
int ret;
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct tas2770_priv *tas2770 =
|
||||
snd_soc_component_get_drvdata(component);
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
break;
|
||||
default:
|
||||
dev_err(tas2770->dev, "ASI format master is not found\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
asi_cfg_1 |= TAS2770_TDM_CFG_REG1_RX_RSING;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
asi_cfg_1 |= TAS2770_TDM_CFG_REG1_RX_FALING;
|
||||
break;
|
||||
default:
|
||||
dev_err(tas2770->dev, "ASI format Inverse is not found\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG1,
|
||||
TAS2770_TDM_CFG_REG1_RX_MASK,
|
||||
asi_cfg_1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
tdm_rx_start_slot = 1;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
tdm_rx_start_slot = 0;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
tdm_rx_start_slot = 1;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
tdm_rx_start_slot = 0;
|
||||
break;
|
||||
default:
|
||||
dev_err(tas2770->dev,
|
||||
"DAI Format is not found, fmt=0x%x\n", fmt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG1,
|
||||
TAS2770_TDM_CFG_REG1_MASK,
|
||||
(tdm_rx_start_slot << TAS2770_TDM_CFG_REG1_51_SHIFT));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
tas2770->asi_format = fmt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2770_set_dai_tdm_slot(struct snd_soc_dai *dai,
|
||||
unsigned int tx_mask,
|
||||
unsigned int rx_mask,
|
||||
int slots, int slot_width)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct tas2770_priv *tas2770 =
|
||||
snd_soc_component_get_drvdata(component);
|
||||
int left_slot, right_slot;
|
||||
int ret;
|
||||
|
||||
if (tx_mask == 0 || rx_mask != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (slots == 1) {
|
||||
if (tx_mask != 1)
|
||||
return -EINVAL;
|
||||
left_slot = 0;
|
||||
right_slot = 0;
|
||||
} else {
|
||||
left_slot = __ffs(tx_mask);
|
||||
tx_mask &= ~(1 << left_slot);
|
||||
if (tx_mask == 0) {
|
||||
right_slot = left_slot;
|
||||
} else {
|
||||
right_slot = __ffs(tx_mask);
|
||||
tx_mask &= ~(1 << right_slot);
|
||||
}
|
||||
}
|
||||
|
||||
if (tx_mask != 0 || left_slot >= slots || right_slot >= slots)
|
||||
return -EINVAL;
|
||||
|
||||
ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG3,
|
||||
TAS2770_TDM_CFG_REG3_30_MASK,
|
||||
(left_slot << TAS2770_TDM_CFG_REG3_30_SHIFT));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG3,
|
||||
TAS2770_TDM_CFG_REG3_RXS_MASK,
|
||||
(right_slot << TAS2770_TDM_CFG_REG3_RXS_SHIFT));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (slot_width) {
|
||||
case 16:
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_TDM_CFG_REG2,
|
||||
TAS2770_TDM_CFG_REG2_RXS_MASK,
|
||||
TAS2770_TDM_CFG_REG2_RXS_16BITS);
|
||||
break;
|
||||
|
||||
case 24:
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_TDM_CFG_REG2,
|
||||
TAS2770_TDM_CFG_REG2_RXS_MASK,
|
||||
TAS2770_TDM_CFG_REG2_RXS_24BITS);
|
||||
break;
|
||||
|
||||
case 32:
|
||||
ret = snd_soc_component_update_bits(component,
|
||||
TAS2770_TDM_CFG_REG2,
|
||||
TAS2770_TDM_CFG_REG2_RXS_MASK,
|
||||
TAS2770_TDM_CFG_REG2_RXS_32BITS);
|
||||
break;
|
||||
|
||||
case 0:
|
||||
/* Do not change slot width */
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
tas2770->slot_width = slot_width;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_ops tas2770_dai_ops = {
|
||||
.digital_mute = tas2770_mute,
|
||||
.hw_params = tas2770_hw_params,
|
||||
.set_fmt = tas2770_set_fmt,
|
||||
.set_tdm_slot = tas2770_set_dai_tdm_slot,
|
||||
};
|
||||
|
||||
#define TAS2770_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
|
||||
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
#define TAS2770_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
|
||||
SNDRV_PCM_RATE_96000 |\
|
||||
SNDRV_PCM_RATE_192000\
|
||||
)
|
||||
|
||||
static struct snd_soc_dai_driver tas2770_dai_driver[] = {
|
||||
{
|
||||
.name = "tas2770 ASI1",
|
||||
.id = 0,
|
||||
.playback = {
|
||||
.stream_name = "ASI1 Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = TAS2770_RATES,
|
||||
.formats = TAS2770_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "ASI1 Capture",
|
||||
.channels_min = 0,
|
||||
.channels_max = 2,
|
||||
.rates = TAS2770_RATES,
|
||||
.formats = TAS2770_FORMATS,
|
||||
},
|
||||
.ops = &tas2770_dai_ops,
|
||||
.symmetric_rates = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static int tas2770_codec_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct tas2770_priv *tas2770 =
|
||||
snd_soc_component_get_drvdata(component);
|
||||
|
||||
tas2770->component = component;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DECLARE_TLV_DB_SCALE(tas2770_digital_tlv, 1100, 50, 0);
|
||||
static DECLARE_TLV_DB_SCALE(tas2770_playback_volume, -12750, 50, 0);
|
||||
|
||||
static const struct snd_kcontrol_new tas2770_snd_controls[] = {
|
||||
SOC_SINGLE_TLV("Speaker Playback Volume", TAS2770_PLAY_CFG_REG2,
|
||||
0, TAS2770_PLAY_CFG_REG2_VMAX, 1,
|
||||
tas2770_playback_volume),
|
||||
SOC_SINGLE_TLV("Amp Gain Volume", TAS2770_PLAY_CFG_REG0,
|
||||
0, 0x14, 0,
|
||||
tas2770_digital_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver soc_component_driver_tas2770 = {
|
||||
.probe = tas2770_codec_probe,
|
||||
.suspend = tas2770_codec_suspend,
|
||||
.resume = tas2770_codec_resume,
|
||||
.set_bias_level = tas2770_set_bias_level,
|
||||
.controls = tas2770_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(tas2770_snd_controls),
|
||||
.dapm_widgets = tas2770_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(tas2770_dapm_widgets),
|
||||
.dapm_routes = tas2770_audio_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(tas2770_audio_map),
|
||||
.idle_bias_on = 1,
|
||||
.endianness = 1,
|
||||
.non_legacy_dai_naming = 1,
|
||||
};
|
||||
|
||||
static int tas2770_register_codec(struct tas2770_priv *tas2770)
|
||||
{
|
||||
return devm_snd_soc_register_component(tas2770->dev,
|
||||
&soc_component_driver_tas2770,
|
||||
tas2770_dai_driver, ARRAY_SIZE(tas2770_dai_driver));
|
||||
}
|
||||
|
||||
static const struct reg_default tas2770_reg_defaults[] = {
|
||||
{ TAS2770_PAGE, 0x00 },
|
||||
{ TAS2770_SW_RST, 0x00 },
|
||||
{ TAS2770_PWR_CTRL, 0x0e },
|
||||
{ TAS2770_PLAY_CFG_REG0, 0x10 },
|
||||
{ TAS2770_PLAY_CFG_REG1, 0x01 },
|
||||
{ TAS2770_PLAY_CFG_REG2, 0x00 },
|
||||
{ TAS2770_MSC_CFG_REG0, 0x07 },
|
||||
{ TAS2770_TDM_CFG_REG1, 0x02 },
|
||||
{ TAS2770_TDM_CFG_REG2, 0x0a },
|
||||
{ TAS2770_TDM_CFG_REG3, 0x10 },
|
||||
{ TAS2770_INT_MASK_REG0, 0xfc },
|
||||
{ TAS2770_INT_MASK_REG1, 0xb1 },
|
||||
{ TAS2770_INT_CFG, 0x05 },
|
||||
{ TAS2770_MISC_IRQ, 0x81 },
|
||||
{ TAS2770_CLK_CGF, 0x0c },
|
||||
|
||||
};
|
||||
|
||||
static bool tas2770_volatile(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case TAS2770_PAGE: /* regmap implementation requires this */
|
||||
case TAS2770_SW_RST: /* always clears after write */
|
||||
case TAS2770_BO_PRV_REG0:/* has a self clearing bit */
|
||||
case TAS2770_LVE_INT_REG0:
|
||||
case TAS2770_LVE_INT_REG1:
|
||||
case TAS2770_LAT_INT_REG0:/* Sticky interrupt flags */
|
||||
case TAS2770_LAT_INT_REG1:/* Sticky interrupt flags */
|
||||
case TAS2770_VBAT_MSB:
|
||||
case TAS2770_VBAT_LSB:
|
||||
case TAS2770_TEMP_MSB:
|
||||
case TAS2770_TEMP_LSB:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool tas2770_writeable(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case TAS2770_LVE_INT_REG0:
|
||||
case TAS2770_LVE_INT_REG1:
|
||||
case TAS2770_LAT_INT_REG0:
|
||||
case TAS2770_LAT_INT_REG1:
|
||||
case TAS2770_VBAT_MSB:
|
||||
case TAS2770_VBAT_LSB:
|
||||
case TAS2770_TEMP_MSB:
|
||||
case TAS2770_TEMP_LSB:
|
||||
case TAS2770_TDM_CLK_DETC:
|
||||
case TAS2770_REV_AND_GPID:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static const struct regmap_range_cfg tas2770_regmap_ranges[] = {
|
||||
{
|
||||
.range_min = 0,
|
||||
.range_max = 1 * 128,
|
||||
.selector_reg = TAS2770_PAGE,
|
||||
.selector_mask = 0xff,
|
||||
.selector_shift = 0,
|
||||
.window_start = 0,
|
||||
.window_len = 128,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_config tas2770_i2c_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.writeable_reg = tas2770_writeable,
|
||||
.volatile_reg = tas2770_volatile,
|
||||
.reg_defaults = tas2770_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(tas2770_reg_defaults),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.ranges = tas2770_regmap_ranges,
|
||||
.num_ranges = ARRAY_SIZE(tas2770_regmap_ranges),
|
||||
.max_register = 1 * 128,
|
||||
};
|
||||
|
||||
static int tas2770_parse_dt(struct device *dev, struct tas2770_priv *tas2770)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
rc = fwnode_property_read_u32(dev->fwnode, "ti,asi-format",
|
||||
&tas2770->asi_format);
|
||||
if (rc) {
|
||||
dev_err(tas2770->dev, "Looking up %s property failed %d\n",
|
||||
"ti,asi-format", rc);
|
||||
goto end;
|
||||
}
|
||||
|
||||
rc = fwnode_property_read_u32(dev->fwnode, "ti,imon-slot-no",
|
||||
&tas2770->i_sense_slot);
|
||||
if (rc) {
|
||||
dev_err(tas2770->dev, "Looking up %s property failed %d\n",
|
||||
"ti,imon-slot-no", rc);
|
||||
goto end;
|
||||
}
|
||||
|
||||
rc = fwnode_property_read_u32(dev->fwnode, "ti,vmon-slot-no",
|
||||
&tas2770->v_sense_slot);
|
||||
if (rc) {
|
||||
dev_err(tas2770->dev, "Looking up %s property failed %d\n",
|
||||
"ti,vmon-slot-no", rc);
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int tas2770_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct tas2770_priv *tas2770;
|
||||
int result;
|
||||
|
||||
tas2770 = devm_kzalloc(&client->dev,
|
||||
sizeof(struct tas2770_priv), GFP_KERNEL);
|
||||
if (!tas2770)
|
||||
return -ENOMEM;
|
||||
tas2770->dev = &client->dev;
|
||||
|
||||
i2c_set_clientdata(client, tas2770);
|
||||
dev_set_drvdata(&client->dev, tas2770);
|
||||
tas2770->power_state = TAS2770_POWER_SHUTDOWN;
|
||||
|
||||
tas2770->regmap = devm_regmap_init_i2c(client, &tas2770_i2c_regmap);
|
||||
if (IS_ERR(tas2770->regmap)) {
|
||||
result = PTR_ERR(tas2770->regmap);
|
||||
dev_err(&client->dev, "Failed to allocate register map: %d\n",
|
||||
result);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (client->dev.of_node) {
|
||||
result = tas2770_parse_dt(&client->dev, tas2770);
|
||||
if (result) {
|
||||
dev_err(tas2770->dev, "%s: Failed to parse devicetree\n",
|
||||
__func__);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
tas2770->reset_gpio = devm_gpiod_get_optional(tas2770->dev,
|
||||
"reset-gpio",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(tas2770->reset_gpio)) {
|
||||
if (PTR_ERR(tas2770->reset_gpio) == -EPROBE_DEFER) {
|
||||
tas2770->reset_gpio = NULL;
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
}
|
||||
|
||||
tas2770->channel_size = 0;
|
||||
tas2770->slot_width = 0;
|
||||
|
||||
tas2770_reset(tas2770);
|
||||
|
||||
result = tas2770_register_codec(tas2770);
|
||||
if (result)
|
||||
dev_err(tas2770->dev, "Register codec failed.\n");
|
||||
|
||||
end:
|
||||
return result;
|
||||
}
|
||||
|
||||
static int tas2770_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
pm_runtime_disable(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct i2c_device_id tas2770_i2c_id[] = {
|
||||
{ "tas2770", 0},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tas2770_i2c_id);
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct of_device_id tas2770_of_match[] = {
|
||||
{ .compatible = "ti,tas2770" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tas2770_of_match);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver tas2770_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "tas2770",
|
||||
.of_match_table = of_match_ptr(tas2770_of_match),
|
||||
},
|
||||
.probe = tas2770_i2c_probe,
|
||||
.remove = tas2770_i2c_remove,
|
||||
.id_table = tas2770_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(tas2770_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Shi Fu <shifu0704@thundersoft.com>");
|
||||
MODULE_DESCRIPTION("TAS2770 I2C Smart Amplifier driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
143
sound/soc/codecs/tas2770.h
Normal file
143
sound/soc/codecs/tas2770.h
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* ALSA SoC TAS2770 codec driver
|
||||
*
|
||||
* Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/
|
||||
*/
|
||||
#ifndef __TAS2770__
|
||||
#define __TAS2770__
|
||||
|
||||
/* Book Control Register (available in page0 of each book) */
|
||||
#define TAS2770_BOOKCTL_PAGE 0
|
||||
#define TAS2770_BOOKCTL_REG 127
|
||||
#define TAS2770_REG(page, reg) ((page * 128) + reg)
|
||||
/* Page */
|
||||
#define TAS2770_PAGE TAS2770_REG(0X0, 0x00)
|
||||
#define TAS2770_PAGE_PAGE_MASK 255
|
||||
/* Software Reset */
|
||||
#define TAS2770_SW_RST TAS2770_REG(0X0, 0x01)
|
||||
#define TAS2770_RST BIT(0)
|
||||
/* Power Control */
|
||||
#define TAS2770_PWR_CTRL TAS2770_REG(0X0, 0x02)
|
||||
#define TAS2770_PWR_CTRL_MASK 0x3
|
||||
#define TAS2770_PWR_CTRL_ACTIVE 0x0
|
||||
#define TAS2770_PWR_CTRL_MUTE BIT(0)
|
||||
#define TAS2770_PWR_CTRL_SHUTDOWN 0x2
|
||||
/* Playback Configuration Reg0 */
|
||||
#define TAS2770_PLAY_CFG_REG0 TAS2770_REG(0X0, 0x03)
|
||||
/* Playback Configuration Reg1 */
|
||||
#define TAS2770_PLAY_CFG_REG1 TAS2770_REG(0X0, 0x04)
|
||||
/* Playback Configuration Reg2 */
|
||||
#define TAS2770_PLAY_CFG_REG2 TAS2770_REG(0X0, 0x05)
|
||||
#define TAS2770_PLAY_CFG_REG2_VMAX 0xc9
|
||||
/* Misc Configuration Reg0 */
|
||||
#define TAS2770_MSC_CFG_REG0 TAS2770_REG(0X0, 0x07)
|
||||
/* TDM Configuration Reg0 */
|
||||
#define TAS2770_TDM_CFG_REG0 TAS2770_REG(0X0, 0x0A)
|
||||
#define TAS2770_TDM_CFG_REG0_SMP_MASK BIT(5)
|
||||
#define TAS2770_TDM_CFG_REG0_SMP_48KHZ 0x0
|
||||
#define TAS2770_TDM_CFG_REG0_SMP_44_1KHZ BIT(5)
|
||||
#define TAS2770_TDM_CFG_REG0_31_MASK 0xe
|
||||
#define TAS2770_TDM_CFG_REG0_31_44_1_48KHZ 0x6
|
||||
#define TAS2770_TDM_CFG_REG0_31_88_2_96KHZ 0x8
|
||||
#define TAS2770_TDM_CFG_REG0_31_176_4_192KHZ 0xa
|
||||
/* TDM Configuration Reg1 */
|
||||
#define TAS2770_TDM_CFG_REG1 TAS2770_REG(0X0, 0x0B)
|
||||
#define TAS2770_TDM_CFG_REG1_MASK 0x3e
|
||||
#define TAS2770_TDM_CFG_REG1_51_SHIFT 1
|
||||
#define TAS2770_TDM_CFG_REG1_RX_MASK BIT(0)
|
||||
#define TAS2770_TDM_CFG_REG1_RX_RSING 0x0
|
||||
#define TAS2770_TDM_CFG_REG1_RX_FALING BIT(0)
|
||||
/* TDM Configuration Reg2 */
|
||||
#define TAS2770_TDM_CFG_REG2 TAS2770_REG(0X0, 0x0C)
|
||||
#define TAS2770_TDM_CFG_REG2_RXW_MASK 0xc
|
||||
#define TAS2770_TDM_CFG_REG2_RXW_16BITS 0x0
|
||||
#define TAS2770_TDM_CFG_REG2_RXW_24BITS 0x8
|
||||
#define TAS2770_TDM_CFG_REG2_RXW_32BITS 0xc
|
||||
#define TAS2770_TDM_CFG_REG2_RXS_MASK 0x3
|
||||
#define TAS2770_TDM_CFG_REG2_RXS_16BITS 0x0
|
||||
#define TAS2770_TDM_CFG_REG2_RXS_24BITS BIT(0)
|
||||
#define TAS2770_TDM_CFG_REG2_RXS_32BITS 0x2
|
||||
/* TDM Configuration Reg3 */
|
||||
#define TAS2770_TDM_CFG_REG3 TAS2770_REG(0X0, 0x0D)
|
||||
#define TAS2770_TDM_CFG_REG3_RXS_MASK 0xf0
|
||||
#define TAS2770_TDM_CFG_REG3_RXS_SHIFT 0x4
|
||||
#define TAS2770_TDM_CFG_REG3_30_MASK 0xf
|
||||
#define TAS2770_TDM_CFG_REG3_30_SHIFT 0
|
||||
/* TDM Configuration Reg5 */
|
||||
#define TAS2770_TDM_CFG_REG5 TAS2770_REG(0X0, 0x0F)
|
||||
#define TAS2770_TDM_CFG_REG5_VSNS_MASK BIT(6)
|
||||
#define TAS2770_TDM_CFG_REG5_VSNS_ENABLE BIT(6)
|
||||
#define TAS2770_TDM_CFG_REG5_50_MASK 0x3f
|
||||
/* TDM Configuration Reg6 */
|
||||
#define TAS2770_TDM_CFG_REG6 TAS2770_REG(0X0, 0x10)
|
||||
#define TAS2770_TDM_CFG_REG6_ISNS_MASK BIT(6)
|
||||
#define TAS2770_TDM_CFG_REG6_ISNS_ENABLE BIT(6)
|
||||
#define TAS2770_TDM_CFG_REG6_50_MASK 0x3f
|
||||
/* Brown Out Prevention Reg0 */
|
||||
#define TAS2770_BO_PRV_REG0 TAS2770_REG(0X0, 0x1B)
|
||||
/* Interrupt MASK Reg0 */
|
||||
#define TAS2770_INT_MASK_REG0 TAS2770_REG(0X0, 0x20)
|
||||
#define TAS2770_INT_REG0_DEFAULT 0xfc
|
||||
#define TAS2770_INT_MASK_REG0_DISABLE 0xff
|
||||
/* Interrupt MASK Reg1 */
|
||||
#define TAS2770_INT_MASK_REG1 TAS2770_REG(0X0, 0x21)
|
||||
#define TAS2770_INT_REG1_DEFAULT 0xb1
|
||||
#define TAS2770_INT_MASK_REG1_DISABLE 0xff
|
||||
/* Live-Interrupt Reg0 */
|
||||
#define TAS2770_LVE_INT_REG0 TAS2770_REG(0X0, 0x22)
|
||||
/* Live-Interrupt Reg1 */
|
||||
#define TAS2770_LVE_INT_REG1 TAS2770_REG(0X0, 0x23)
|
||||
/* Latched-Interrupt Reg0 */
|
||||
#define TAS2770_LAT_INT_REG0 TAS2770_REG(0X0, 0x24)
|
||||
#define TAS2770_LAT_INT_REG0_OCE_FLG BIT(1)
|
||||
#define TAS2770_LAT_INT_REG0_OTE_FLG BIT(0)
|
||||
/* Latched-Interrupt Reg1 */
|
||||
#define TAS2770_LAT_INT_REG1 TAS2770_REG(0X0, 0x25)
|
||||
#define TAS2770_LAT_INT_REG1_VBA_TOV BIT(3)
|
||||
#define TAS2770_LAT_INT_REG1_VBA_TUV BIT(2)
|
||||
#define TAS2770_LAT_INT_REG1_BOUT_FLG BIT(1)
|
||||
/* VBAT MSB */
|
||||
#define TAS2770_VBAT_MSB TAS2770_REG(0X0, 0x27)
|
||||
/* VBAT LSB */
|
||||
#define TAS2770_VBAT_LSB TAS2770_REG(0X0, 0x28)
|
||||
/* TEMP MSB */
|
||||
#define TAS2770_TEMP_MSB TAS2770_REG(0X0, 0x29)
|
||||
/* TEMP LSB */
|
||||
#define TAS2770_TEMP_LSB TAS2770_REG(0X0, 0x2A)
|
||||
/* Interrupt Configuration */
|
||||
#define TAS2770_INT_CFG TAS2770_REG(0X0, 0x30)
|
||||
/* Misc IRQ */
|
||||
#define TAS2770_MISC_IRQ TAS2770_REG(0X0, 0x32)
|
||||
/* Clock Configuration */
|
||||
#define TAS2770_CLK_CGF TAS2770_REG(0X0, 0x3C)
|
||||
/* TDM Clock detection monitor */
|
||||
#define TAS2770_TDM_CLK_DETC TAS2770_REG(0X0, 0x77)
|
||||
/* Revision and PG ID */
|
||||
#define TAS2770_REV_AND_GPID TAS2770_REG(0X0, 0x7D)
|
||||
|
||||
#define TAS2770_POWER_ACTIVE 0
|
||||
#define TAS2770_POWER_MUTE 1
|
||||
#define TAS2770_POWER_SHUTDOWN 2
|
||||
#define ERROR_OVER_CURRENT 0x0000001
|
||||
#define ERROR_DIE_OVERTEMP 0x0000002
|
||||
#define ERROR_OVER_VOLTAGE 0x0000004
|
||||
#define ERROR_UNDER_VOLTAGE 0x0000008
|
||||
#define ERROR_BROWNOUT 0x0000010
|
||||
#define ERROR_CLASSD_PWR 0x0000020
|
||||
|
||||
struct tas2770_priv {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct snd_soc_component *component;
|
||||
int power_state;
|
||||
int asi_format;
|
||||
struct gpio_desc *reset_gpio;
|
||||
int sampling_rate;
|
||||
int channel_size;
|
||||
int slot_width;
|
||||
int v_sense_slot;
|
||||
int i_sense_slot;
|
||||
};
|
||||
|
||||
#endif /* __TAS2770__ */
|
||||
|
|
@ -2837,11 +2837,11 @@ static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w,
|
|||
TX_HPF_CUT_OFF_FREQ_MASK) >> 5;
|
||||
snd_soc_component_update_bits(comp, tx_vol_ctl_reg, 0x10, 0x10);
|
||||
snd_soc_component_update_bits(comp, dec_cfg_reg, 0x08, 0x00);
|
||||
if (hpf_coff_freq != CF_MIN_3DB_150HZ) {
|
||||
snd_soc_component_update_bits(comp, dec_cfg_reg,
|
||||
TX_HPF_CUT_OFF_FREQ_MASK,
|
||||
hpf_coff_freq << 5);
|
||||
}
|
||||
if (hpf_coff_freq != CF_MIN_3DB_150HZ) {
|
||||
snd_soc_component_update_bits(comp, dec_cfg_reg,
|
||||
TX_HPF_CUT_OFF_FREQ_MASK,
|
||||
hpf_coff_freq << 5);
|
||||
}
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
snd_soc_component_update_bits(comp, tx_vol_ctl_reg, 0x10, 0x00);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
#include <linux/mfd/wm8994/pdata.h>
|
||||
#include <linux/mfd/wm8994/gpio.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "wm8994.h"
|
||||
|
||||
#define WM_FW_BLOCK_INFO 0xff
|
||||
|
|
@ -58,18 +60,15 @@ static int wm8958_dsp2_fw(struct snd_soc_component *component, const char *name,
|
|||
}
|
||||
|
||||
if (memcmp(fw->data, "WMFW", 4) != 0) {
|
||||
memcpy(&data32, fw->data, sizeof(data32));
|
||||
data32 = be32_to_cpu(data32);
|
||||
data32 = get_unaligned_be32(fw->data);
|
||||
dev_err(component->dev, "%s: firmware has bad file magic %08x\n",
|
||||
name, data32);
|
||||
goto err;
|
||||
}
|
||||
|
||||
memcpy(&data32, fw->data + 4, sizeof(data32));
|
||||
len = be32_to_cpu(data32);
|
||||
len = get_unaligned_be32(fw->data + 4);
|
||||
data32 = get_unaligned_be32(fw->data + 8);
|
||||
|
||||
memcpy(&data32, fw->data + 8, sizeof(data32));
|
||||
data32 = be32_to_cpu(data32);
|
||||
if ((data32 >> 24) & 0xff) {
|
||||
dev_err(component->dev, "%s: unsupported firmware version %d\n",
|
||||
name, (data32 >> 24) & 0xff);
|
||||
|
|
@ -87,9 +86,8 @@ static int wm8958_dsp2_fw(struct snd_soc_component *component, const char *name,
|
|||
}
|
||||
|
||||
if (check) {
|
||||
memcpy(&data64, fw->data + 24, sizeof(u64));
|
||||
dev_info(component->dev, "%s timestamp %llx\n",
|
||||
name, be64_to_cpu(data64));
|
||||
data64 = get_unaligned_be64(fw->data + 24);
|
||||
dev_info(component->dev, "%s timestamp %llx\n", name, data64);
|
||||
} else {
|
||||
snd_soc_component_write(component, 0x102, 0x2);
|
||||
snd_soc_component_write(component, 0x900, 0x2);
|
||||
|
|
@ -104,8 +102,7 @@ static int wm8958_dsp2_fw(struct snd_soc_component *component, const char *name,
|
|||
goto err;
|
||||
}
|
||||
|
||||
memcpy(&data32, data + 4, sizeof(data32));
|
||||
block_len = be32_to_cpu(data32);
|
||||
block_len = get_unaligned_be32(data + 4);
|
||||
if (block_len + 8 > len) {
|
||||
dev_err(component->dev, "%zd byte block longer than file\n",
|
||||
block_len);
|
||||
|
|
@ -116,8 +113,7 @@ static int wm8958_dsp2_fw(struct snd_soc_component *component, const char *name,
|
|||
goto err;
|
||||
}
|
||||
|
||||
memcpy(&data32, data, sizeof(data32));
|
||||
data32 = be32_to_cpu(data32);
|
||||
data32 = get_unaligned_be32(data);
|
||||
|
||||
switch ((data32 >> 24) & 0xff) {
|
||||
case WM_FW_BLOCK_INFO:
|
||||
|
|
|
|||
|
|
@ -167,12 +167,12 @@ static int configure_aif_clock(struct snd_soc_component *component, int aif)
|
|||
|
||||
switch (wm8994->sysclk[aif]) {
|
||||
case WM8994_SYSCLK_MCLK1:
|
||||
rate = wm8994->mclk[0];
|
||||
rate = wm8994->mclk_rate[0];
|
||||
break;
|
||||
|
||||
case WM8994_SYSCLK_MCLK2:
|
||||
reg1 |= 0x8;
|
||||
rate = wm8994->mclk[1];
|
||||
rate = wm8994->mclk_rate[1];
|
||||
break;
|
||||
|
||||
case WM8994_SYSCLK_FLL1:
|
||||
|
|
@ -1038,6 +1038,45 @@ static bool wm8994_check_class_w_digital(struct snd_soc_component *component)
|
|||
return true;
|
||||
}
|
||||
|
||||
static int aif_mclk_set(struct snd_soc_component *component, int aif, bool enable)
|
||||
{
|
||||
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
|
||||
unsigned int offset, val, clk_idx;
|
||||
int ret;
|
||||
|
||||
if (aif)
|
||||
offset = 4;
|
||||
else
|
||||
offset = 0;
|
||||
|
||||
val = snd_soc_component_read32(component, WM8994_AIF1_CLOCKING_1 + offset);
|
||||
val &= WM8994_AIF1CLK_SRC_MASK;
|
||||
|
||||
switch (val) {
|
||||
case 0:
|
||||
clk_idx = WM8994_MCLK1;
|
||||
break;
|
||||
case 1:
|
||||
clk_idx = WM8994_MCLK2;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
ret = clk_prepare_enable(wm8994->mclk[clk_idx].clk);
|
||||
if (ret < 0) {
|
||||
dev_err(component->dev, "Failed to enable MCLK%d\n",
|
||||
clk_idx);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
clk_disable_unprepare(wm8994->mclk[clk_idx].clk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aif1clk_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
|
|
@ -1045,7 +1084,7 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w,
|
|||
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
|
||||
struct wm8994 *control = wm8994->wm8994;
|
||||
int mask = WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA;
|
||||
int i;
|
||||
int ret, i;
|
||||
int dac;
|
||||
int adc;
|
||||
int val;
|
||||
|
|
@ -1061,6 +1100,10 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w,
|
|||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
ret = aif_mclk_set(component, 0, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Don't enable timeslot 2 if not in use */
|
||||
if (wm8994->channels[0] <= 2)
|
||||
mask &= ~(WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA);
|
||||
|
|
@ -1133,6 +1176,12 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w,
|
|||
break;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
aif_mclk_set(component, 0, false);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1140,13 +1189,17 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w,
|
|||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
|
||||
int i;
|
||||
int ret, i;
|
||||
int dac;
|
||||
int adc;
|
||||
int val;
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
ret = aif_mclk_set(component, 1, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val = snd_soc_component_read32(component, WM8994_AIF2_CONTROL_1);
|
||||
if ((val & WM8994_AIF2ADCL_SRC) &&
|
||||
(val & WM8994_AIF2ADCR_SRC))
|
||||
|
|
@ -1218,6 +1271,12 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w,
|
|||
break;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
aif_mclk_set(component, 1, false);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1623,10 +1682,10 @@ SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev)
|
|||
static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, aif1clk_ev,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
|
||||
SND_SOC_DAPM_PRE_PMD),
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, aif2clk_ev,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
|
||||
SND_SOC_DAPM_PRE_PMD),
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
|
||||
left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
|
||||
|
|
@ -2141,6 +2200,7 @@ static int _wm8994_set_fll(struct snd_soc_component *component, int id, int src,
|
|||
u16 reg, clk1, aif_reg, aif_src;
|
||||
unsigned long timeout;
|
||||
bool was_enabled;
|
||||
struct clk *mclk;
|
||||
|
||||
switch (id) {
|
||||
case WM8994_FLL1:
|
||||
|
|
@ -2216,6 +2276,27 @@ static int _wm8994_set_fll(struct snd_soc_component *component, int id, int src,
|
|||
snd_soc_component_update_bits(component, WM8994_FLL1_CONTROL_1 + reg_offset,
|
||||
WM8994_FLL1_ENA, 0);
|
||||
|
||||
/* Disable MCLK if needed before we possibly change to new clock parent */
|
||||
if (was_enabled) {
|
||||
reg = snd_soc_component_read32(component, WM8994_FLL1_CONTROL_5
|
||||
+ reg_offset);
|
||||
reg = ((reg & WM8994_FLL1_REFCLK_SRC_MASK)
|
||||
>> WM8994_FLL1_REFCLK_SRC_SHIFT) + 1;
|
||||
|
||||
switch (reg) {
|
||||
case WM8994_FLL_SRC_MCLK1:
|
||||
mclk = wm8994->mclk[WM8994_MCLK1].clk;
|
||||
break;
|
||||
case WM8994_FLL_SRC_MCLK2:
|
||||
mclk = wm8994->mclk[WM8994_MCLK2].clk;
|
||||
break;
|
||||
default:
|
||||
mclk = NULL;
|
||||
}
|
||||
|
||||
clk_disable_unprepare(mclk);
|
||||
}
|
||||
|
||||
if (wm8994->fll_byp && src == WM8994_FLL_SRC_BCLK &&
|
||||
freq_in == freq_out && freq_out) {
|
||||
dev_dbg(component->dev, "Bypassing FLL%d\n", id + 1);
|
||||
|
|
@ -2260,10 +2341,29 @@ static int _wm8994_set_fll(struct snd_soc_component *component, int id, int src,
|
|||
/* Clear any pending completion from a previous failure */
|
||||
try_wait_for_completion(&wm8994->fll_locked[id]);
|
||||
|
||||
switch (src) {
|
||||
case WM8994_FLL_SRC_MCLK1:
|
||||
mclk = wm8994->mclk[WM8994_MCLK1].clk;
|
||||
break;
|
||||
case WM8994_FLL_SRC_MCLK2:
|
||||
mclk = wm8994->mclk[WM8994_MCLK2].clk;
|
||||
break;
|
||||
default:
|
||||
mclk = NULL;
|
||||
}
|
||||
|
||||
/* Enable (with fractional mode if required) */
|
||||
if (freq_out) {
|
||||
ret = clk_prepare_enable(mclk);
|
||||
if (ret < 0) {
|
||||
dev_err(component->dev, "Failed to enable MCLK for FLL%d\n",
|
||||
id + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enable VMID if we need it */
|
||||
if (!was_enabled) {
|
||||
|
||||
active_reference(component);
|
||||
|
||||
switch (control->type) {
|
||||
|
|
@ -2372,12 +2472,29 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
|
|||
return _wm8994_set_fll(dai->component, id, src, freq_in, freq_out);
|
||||
}
|
||||
|
||||
static int wm8994_set_mclk_rate(struct wm8994_priv *wm8994, unsigned int id,
|
||||
unsigned int *freq)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!wm8994->mclk[id].clk || *freq == wm8994->mclk_rate[id])
|
||||
return 0;
|
||||
|
||||
ret = clk_set_rate(wm8994->mclk[id].clk, *freq);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*freq = clk_get_rate(wm8994->mclk[id].clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
|
||||
int i;
|
||||
int ret, i;
|
||||
|
||||
switch (dai->id) {
|
||||
case 1:
|
||||
|
|
@ -2392,7 +2509,12 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
|
|||
switch (clk_id) {
|
||||
case WM8994_SYSCLK_MCLK1:
|
||||
wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK1;
|
||||
wm8994->mclk[0] = freq;
|
||||
|
||||
ret = wm8994_set_mclk_rate(wm8994, dai->id - 1, &freq);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
wm8994->mclk_rate[0] = freq;
|
||||
dev_dbg(dai->dev, "AIF%d using MCLK1 at %uHz\n",
|
||||
dai->id, freq);
|
||||
break;
|
||||
|
|
@ -2400,7 +2522,12 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
|
|||
case WM8994_SYSCLK_MCLK2:
|
||||
/* TODO: Set GPIO AF */
|
||||
wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK2;
|
||||
wm8994->mclk[1] = freq;
|
||||
|
||||
ret = wm8994_set_mclk_rate(wm8994, dai->id - 1, &freq);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
wm8994->mclk_rate[1] = freq;
|
||||
dev_dbg(dai->dev, "AIF%d using MCLK2 at %uHz\n",
|
||||
dai->id, freq);
|
||||
break;
|
||||
|
|
@ -4456,6 +4583,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm8994 = {
|
|||
static int wm8994_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct wm8994_priv *wm8994;
|
||||
int ret;
|
||||
|
||||
wm8994 = devm_kzalloc(&pdev->dev, sizeof(struct wm8994_priv),
|
||||
GFP_KERNEL);
|
||||
|
|
@ -4467,6 +4595,16 @@ static int wm8994_probe(struct platform_device *pdev)
|
|||
|
||||
wm8994->wm8994 = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
wm8994->mclk[WM8994_MCLK1].id = "MCLK1";
|
||||
wm8994->mclk[WM8994_MCLK2].id = "MCLK2";
|
||||
|
||||
ret = devm_clk_bulk_get_optional(pdev->dev.parent, ARRAY_SIZE(wm8994->mclk),
|
||||
wm8994->mclk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get clocks: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_idle(&pdev->dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#ifndef _WM8994_H
|
||||
#define _WM8994_H
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <sound/soc.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/completion.h>
|
||||
|
|
@ -14,6 +15,12 @@
|
|||
|
||||
#include "wm_hubs.h"
|
||||
|
||||
enum {
|
||||
WM8994_MCLK1,
|
||||
WM8994_MCLK2,
|
||||
WM8994_NUM_MCLK
|
||||
};
|
||||
|
||||
/* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */
|
||||
#define WM8994_SYSCLK_MCLK1 1
|
||||
#define WM8994_SYSCLK_MCLK2 2
|
||||
|
|
@ -73,9 +80,10 @@ struct wm8994;
|
|||
struct wm8994_priv {
|
||||
struct wm_hubs_data hubs;
|
||||
struct wm8994 *wm8994;
|
||||
struct clk_bulk_data mclk[WM8994_NUM_MCLK];
|
||||
int sysclk[2];
|
||||
int sysclk_rate[2];
|
||||
int mclk[2];
|
||||
int mclk_rate[2];
|
||||
int aifclk[2];
|
||||
int aifdiv[2];
|
||||
int channels[2];
|
||||
|
|
|
|||
|
|
@ -135,7 +135,8 @@ void dw_pcm_pop_rx(struct dw_i2s_dev *dev)
|
|||
dw_pcm_transfer(dev, false);
|
||||
}
|
||||
|
||||
static int dw_pcm_open(struct snd_pcm_substream *substream)
|
||||
static int dw_pcm_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
|
|
@ -148,14 +149,16 @@ static int dw_pcm_open(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dw_pcm_close(struct snd_pcm_substream *substream)
|
||||
static int dw_pcm_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
synchronize_rcu();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
static int dw_pcm_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct dw_i2s_dev *dev = runtime->private_data;
|
||||
|
|
@ -192,12 +195,14 @@ static int dw_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dw_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
static int dw_pcm_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_pcm_lib_free_pages(substream);
|
||||
}
|
||||
|
||||
static int dw_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
static int dw_pcm_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct dw_i2s_dev *dev = runtime->private_data;
|
||||
|
|
@ -231,7 +236,8 @@ static int dw_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t dw_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
static snd_pcm_uframes_t dw_pcm_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct dw_i2s_dev *dev = runtime->private_data;
|
||||
|
|
@ -245,7 +251,8 @@ static snd_pcm_uframes_t dw_pcm_pointer(struct snd_pcm_substream *substream)
|
|||
return pos < runtime->buffer_size ? pos : 0;
|
||||
}
|
||||
|
||||
static int dw_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int dw_pcm_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
size_t size = dw_pcm_hardware.buffer_bytes_max;
|
||||
|
||||
|
|
@ -255,25 +262,22 @@ static int dw_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void dw_pcm_free(struct snd_pcm *pcm)
|
||||
static void dw_pcm_free(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm)
|
||||
{
|
||||
snd_pcm_lib_preallocate_free_for_all(pcm);
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops dw_pcm_ops = {
|
||||
.open = dw_pcm_open,
|
||||
.close = dw_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = dw_pcm_hw_params,
|
||||
.hw_free = dw_pcm_hw_free,
|
||||
.trigger = dw_pcm_trigger,
|
||||
.pointer = dw_pcm_pointer,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver dw_pcm_component = {
|
||||
.pcm_new = dw_pcm_new,
|
||||
.pcm_free = dw_pcm_free,
|
||||
.ops = &dw_pcm_ops,
|
||||
.open = dw_pcm_open,
|
||||
.close = dw_pcm_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = dw_pcm_hw_params,
|
||||
.hw_free = dw_pcm_hw_free,
|
||||
.trigger = dw_pcm_trigger,
|
||||
.pointer = dw_pcm_pointer,
|
||||
.pcm_construct = dw_pcm_new,
|
||||
.pcm_destruct = dw_pcm_free,
|
||||
};
|
||||
|
||||
int dw_pcm_register(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,16 @@ config SND_SOC_FSL_SAI
|
|||
This option is only useful for out-of-tree drivers since
|
||||
in-tree drivers select it automatically.
|
||||
|
||||
config SND_SOC_FSL_MQS
|
||||
tristate "Medium Quality Sound (MQS) module support"
|
||||
depends on SND_SOC_FSL_SAI
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
Say Y if you want to add Medium Quality Sound (MQS)
|
||||
support for the Freescale CPUs.
|
||||
This option is only useful for out-of-tree drivers since
|
||||
in-tree drivers select it automatically.
|
||||
|
||||
config SND_SOC_FSL_AUDMIX
|
||||
tristate "Audio Mixer (AUDMIX) module support"
|
||||
select REGMAP_MMIO
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ snd-soc-fsl-esai-objs := fsl_esai.o
|
|||
snd-soc-fsl-micfil-objs := fsl_micfil.o
|
||||
snd-soc-fsl-utils-objs := fsl_utils.o
|
||||
snd-soc-fsl-dma-objs := fsl_dma.o
|
||||
snd-soc-fsl-mqs-objs := fsl_mqs.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o
|
||||
obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o
|
||||
|
|
@ -33,6 +34,7 @@ obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o
|
|||
obj-$(CONFIG_SND_SOC_FSL_ESAI) += snd-soc-fsl-esai.o
|
||||
obj-$(CONFIG_SND_SOC_FSL_MICFIL) += snd-soc-fsl-micfil.o
|
||||
obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
|
||||
obj-$(CONFIG_SND_SOC_FSL_MQS) += snd-soc-fsl-mqs.o
|
||||
obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
|
||||
|
||||
# MPC5200 Platform Support
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ static void fsl_asrc_sel_proc(int inrate, int outrate,
|
|||
* within range [ANCA, ANCA+ANCB-1], depends on the channels of pair A
|
||||
* while pair A and pair C are comparatively independent.
|
||||
*/
|
||||
static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair)
|
||||
int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair)
|
||||
{
|
||||
enum asrc_pair_index index = ASRC_INVALID_PAIR;
|
||||
struct fsl_asrc *asrc_priv = pair->asrc_priv;
|
||||
|
|
@ -158,7 +158,7 @@ static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair)
|
|||
*
|
||||
* It clears the resource from asrc_priv and releases the occupied channels.
|
||||
*/
|
||||
static void fsl_asrc_release_pair(struct fsl_asrc_pair *pair)
|
||||
void fsl_asrc_release_pair(struct fsl_asrc_pair *pair)
|
||||
{
|
||||
struct fsl_asrc *asrc_priv = pair->asrc_priv;
|
||||
enum asrc_pair_index index = pair->index;
|
||||
|
|
@ -265,6 +265,8 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair)
|
|||
struct asrc_config *config = pair->config;
|
||||
struct fsl_asrc *asrc_priv = pair->asrc_priv;
|
||||
enum asrc_pair_index index = pair->index;
|
||||
enum asrc_word_width input_word_width;
|
||||
enum asrc_word_width output_word_width;
|
||||
u32 inrate, outrate, indiv, outdiv;
|
||||
u32 clk_index[2], div[2];
|
||||
int in, out, channels;
|
||||
|
|
@ -283,9 +285,32 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Validate output width */
|
||||
if (config->output_word_width == ASRC_WIDTH_8_BIT) {
|
||||
pair_err("does not support 8bit width output\n");
|
||||
switch (snd_pcm_format_width(config->input_format)) {
|
||||
case 8:
|
||||
input_word_width = ASRC_WIDTH_8_BIT;
|
||||
break;
|
||||
case 16:
|
||||
input_word_width = ASRC_WIDTH_16_BIT;
|
||||
break;
|
||||
case 24:
|
||||
input_word_width = ASRC_WIDTH_24_BIT;
|
||||
break;
|
||||
default:
|
||||
pair_err("does not support this input format, %d\n",
|
||||
config->input_format);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (snd_pcm_format_width(config->output_format)) {
|
||||
case 16:
|
||||
output_word_width = ASRC_WIDTH_16_BIT;
|
||||
break;
|
||||
case 24:
|
||||
output_word_width = ASRC_WIDTH_24_BIT;
|
||||
break;
|
||||
default:
|
||||
pair_err("does not support this output format, %d\n",
|
||||
config->output_format);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -383,8 +408,8 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair)
|
|||
/* Implement word_width configurations */
|
||||
regmap_update_bits(asrc_priv->regmap, REG_ASRMCR1(index),
|
||||
ASRMCR1i_OW16_MASK | ASRMCR1i_IWD_MASK,
|
||||
ASRMCR1i_OW16(config->output_word_width) |
|
||||
ASRMCR1i_IWD(config->input_word_width));
|
||||
ASRMCR1i_OW16(output_word_width) |
|
||||
ASRMCR1i_IWD(input_word_width));
|
||||
|
||||
/* Enable BUFFER STALL */
|
||||
regmap_update_bits(asrc_priv->regmap, REG_ASRMCR(index),
|
||||
|
|
@ -497,13 +522,13 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai);
|
||||
int width = params_width(params);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct fsl_asrc_pair *pair = runtime->private_data;
|
||||
unsigned int channels = params_channels(params);
|
||||
unsigned int rate = params_rate(params);
|
||||
struct asrc_config config;
|
||||
int word_width, ret;
|
||||
snd_pcm_format_t format;
|
||||
int ret;
|
||||
|
||||
ret = fsl_asrc_request_pair(channels, pair);
|
||||
if (ret) {
|
||||
|
|
@ -513,15 +538,10 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
|
|||
|
||||
pair->config = &config;
|
||||
|
||||
if (width == 16)
|
||||
width = ASRC_WIDTH_16_BIT;
|
||||
else
|
||||
width = ASRC_WIDTH_24_BIT;
|
||||
|
||||
if (asrc_priv->asrc_width == 16)
|
||||
word_width = ASRC_WIDTH_16_BIT;
|
||||
format = SNDRV_PCM_FORMAT_S16_LE;
|
||||
else
|
||||
word_width = ASRC_WIDTH_24_BIT;
|
||||
format = SNDRV_PCM_FORMAT_S24_LE;
|
||||
|
||||
config.pair = pair->index;
|
||||
config.channel_num = channels;
|
||||
|
|
@ -529,13 +549,13 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
|
|||
config.outclk = OUTCLK_ASRCK1_CLK;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
config.input_word_width = width;
|
||||
config.output_word_width = word_width;
|
||||
config.input_format = params_format(params);
|
||||
config.output_format = format;
|
||||
config.input_sample_rate = rate;
|
||||
config.output_sample_rate = asrc_priv->asrc_rate;
|
||||
} else {
|
||||
config.input_word_width = word_width;
|
||||
config.output_word_width = width;
|
||||
config.input_format = format;
|
||||
config.output_format = params_format(params);
|
||||
config.input_sample_rate = asrc_priv->asrc_rate;
|
||||
config.output_sample_rate = rate;
|
||||
}
|
||||
|
|
@ -604,7 +624,7 @@ static int fsl_asrc_dai_probe(struct snd_soc_dai *dai)
|
|||
|
||||
#define FSL_ASRC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \
|
||||
SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S20_3LE)
|
||||
SNDRV_PCM_FMTBIT_S24_3LE)
|
||||
|
||||
static struct snd_soc_dai_driver fsl_asrc_dai = {
|
||||
.probe = fsl_asrc_dai_probe,
|
||||
|
|
@ -615,7 +635,8 @@ static struct snd_soc_dai_driver fsl_asrc_dai = {
|
|||
.rate_min = 5512,
|
||||
.rate_max = 192000,
|
||||
.rates = SNDRV_PCM_RATE_KNOT,
|
||||
.formats = FSL_ASRC_FORMATS,
|
||||
.formats = FSL_ASRC_FORMATS |
|
||||
SNDRV_PCM_FMTBIT_S8,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "ASRC-Capture",
|
||||
|
|
|
|||
|
|
@ -342,8 +342,8 @@ struct asrc_config {
|
|||
unsigned int dma_buffer_size;
|
||||
unsigned int input_sample_rate;
|
||||
unsigned int output_sample_rate;
|
||||
enum asrc_word_width input_word_width;
|
||||
enum asrc_word_width output_word_width;
|
||||
snd_pcm_format_t input_format;
|
||||
snd_pcm_format_t output_format;
|
||||
enum asrc_inclk inclk;
|
||||
enum asrc_outclk outclk;
|
||||
};
|
||||
|
|
@ -462,4 +462,7 @@ struct fsl_asrc {
|
|||
#define DRV_NAME "fsl-asrc-dai"
|
||||
extern struct snd_soc_component_driver fsl_asrc_component;
|
||||
struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, bool dir);
|
||||
int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair);
|
||||
void fsl_asrc_release_pair(struct fsl_asrc_pair *pair);
|
||||
|
||||
#endif /* _FSL_ASRC_H */
|
||||
|
|
|
|||
|
|
@ -16,13 +16,11 @@
|
|||
|
||||
#define FSL_ASRC_DMABUF_SIZE (256 * 1024)
|
||||
|
||||
static const struct snd_pcm_hardware snd_imx_hardware = {
|
||||
static struct snd_pcm_hardware snd_imx_hardware = {
|
||||
.info = SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_RESUME,
|
||||
SNDRV_PCM_INFO_MMAP_VALID,
|
||||
.buffer_bytes_max = FSL_ASRC_DMABUF_SIZE,
|
||||
.period_bytes_min = 128,
|
||||
.period_bytes_max = 65535, /* Limited by SDMA engine */
|
||||
|
|
@ -54,13 +52,12 @@ static void fsl_asrc_dma_complete(void *arg)
|
|||
snd_pcm_period_elapsed(substream);
|
||||
}
|
||||
|
||||
static int fsl_asrc_dma_prepare_and_submit(struct snd_pcm_substream *substream)
|
||||
static int fsl_asrc_dma_prepare_and_submit(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_component *component)
|
||||
{
|
||||
u8 dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? OUT : IN;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct fsl_asrc_pair *pair = runtime->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct device *dev = component->dev;
|
||||
unsigned long flags = DMA_CTRL_ACK;
|
||||
|
||||
|
|
@ -97,7 +94,8 @@ static int fsl_asrc_dma_prepare_and_submit(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_asrc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
static int fsl_asrc_dma_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct fsl_asrc_pair *pair = runtime->private_data;
|
||||
|
|
@ -107,7 +105,7 @@ static int fsl_asrc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
ret = fsl_asrc_dma_prepare_and_submit(substream);
|
||||
ret = fsl_asrc_dma_prepare_and_submit(substream, component);
|
||||
if (ret)
|
||||
return ret;
|
||||
dma_async_issue_pending(pair->dma_chan[IN]);
|
||||
|
|
@ -126,7 +124,8 @@ static int fsl_asrc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_asrc_dma_hw_params(struct snd_pcm_substream *substream,
|
||||
static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
|
||||
|
|
@ -134,7 +133,6 @@ static int fsl_asrc_dma_hw_params(struct snd_pcm_substream *substream,
|
|||
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||
struct snd_dmaengine_dai_dma_data *dma_params_fe = NULL;
|
||||
struct snd_dmaengine_dai_dma_data *dma_params_be = NULL;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct fsl_asrc_pair *pair = runtime->private_data;
|
||||
struct fsl_asrc *asrc_priv = pair->asrc_priv;
|
||||
|
|
@ -249,7 +247,8 @@ static int fsl_asrc_dma_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_asrc_dma_hw_free(struct snd_pcm_substream *substream)
|
||||
static int fsl_asrc_dma_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct fsl_asrc_pair *pair = runtime->private_data;
|
||||
|
|
@ -268,14 +267,27 @@ static int fsl_asrc_dma_hw_free(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_asrc_dma_startup(struct snd_pcm_substream *substream)
|
||||
static int fsl_asrc_dma_startup(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct snd_dmaengine_dai_dma_data *dma_data;
|
||||
struct device *dev = component->dev;
|
||||
struct fsl_asrc *asrc_priv = dev_get_drvdata(dev);
|
||||
struct fsl_asrc_pair *pair;
|
||||
struct dma_chan *tmp_chan = NULL;
|
||||
u8 dir = tx ? OUT : IN;
|
||||
bool release_pair = true;
|
||||
int ret = 0;
|
||||
|
||||
ret = snd_pcm_hw_constraint_integer(substream->runtime,
|
||||
SNDRV_PCM_HW_PARAM_PERIODS);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to set pcm hw params periods\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pair = kzalloc(sizeof(struct fsl_asrc_pair), GFP_KERNEL);
|
||||
if (!pair)
|
||||
|
|
@ -285,14 +297,54 @@ static int fsl_asrc_dma_startup(struct snd_pcm_substream *substream)
|
|||
|
||||
runtime->private_data = pair;
|
||||
|
||||
snd_pcm_hw_constraint_integer(substream->runtime,
|
||||
SNDRV_PCM_HW_PARAM_PERIODS);
|
||||
/* Request a dummy pair, which will be released later.
|
||||
* Request pair function needs channel num as input, for this
|
||||
* dummy pair, we just request "1" channel temporarily.
|
||||
*/
|
||||
ret = fsl_asrc_request_pair(1, pair);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to request asrc pair\n");
|
||||
goto req_pair_err;
|
||||
}
|
||||
|
||||
/* Request a dummy dma channel, which will be released later. */
|
||||
tmp_chan = fsl_asrc_get_dma_channel(pair, dir);
|
||||
if (!tmp_chan) {
|
||||
dev_err(dev, "failed to get dma channel\n");
|
||||
ret = -EINVAL;
|
||||
goto dma_chan_err;
|
||||
}
|
||||
|
||||
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
/* Refine the snd_imx_hardware according to caps of DMA. */
|
||||
ret = snd_dmaengine_pcm_refine_runtime_hwparams(substream,
|
||||
dma_data,
|
||||
&snd_imx_hardware,
|
||||
tmp_chan);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to refine runtime hwparams\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
release_pair = false;
|
||||
snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
|
||||
|
||||
return 0;
|
||||
out:
|
||||
dma_release_channel(tmp_chan);
|
||||
|
||||
dma_chan_err:
|
||||
fsl_asrc_release_pair(pair);
|
||||
|
||||
req_pair_err:
|
||||
if (release_pair)
|
||||
kfree(pair);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fsl_asrc_dma_shutdown(struct snd_pcm_substream *substream)
|
||||
static int fsl_asrc_dma_shutdown(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct fsl_asrc_pair *pair = runtime->private_data;
|
||||
|
|
@ -311,7 +363,9 @@ static int fsl_asrc_dma_shutdown(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t fsl_asrc_dma_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
static snd_pcm_uframes_t
|
||||
fsl_asrc_dma_pcm_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct fsl_asrc_pair *pair = runtime->private_data;
|
||||
|
|
@ -319,17 +373,8 @@ static snd_pcm_uframes_t fsl_asrc_dma_pcm_pointer(struct snd_pcm_substream *subs
|
|||
return bytes_to_frames(substream->runtime, pair->pos);
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops fsl_asrc_dma_pcm_ops = {
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = fsl_asrc_dma_hw_params,
|
||||
.hw_free = fsl_asrc_dma_hw_free,
|
||||
.trigger = fsl_asrc_dma_trigger,
|
||||
.open = fsl_asrc_dma_startup,
|
||||
.close = fsl_asrc_dma_shutdown,
|
||||
.pointer = fsl_asrc_dma_pcm_pointer,
|
||||
};
|
||||
|
||||
static int fsl_asrc_dma_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int fsl_asrc_dma_pcm_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_card *card = rtd->card->snd_card;
|
||||
struct snd_pcm_substream *substream;
|
||||
|
|
@ -364,7 +409,8 @@ static int fsl_asrc_dma_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void fsl_asrc_dma_pcm_free(struct snd_pcm *pcm)
|
||||
static void fsl_asrc_dma_pcm_free(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm)
|
||||
{
|
||||
struct snd_pcm_substream *substream;
|
||||
int i;
|
||||
|
|
@ -382,8 +428,14 @@ static void fsl_asrc_dma_pcm_free(struct snd_pcm *pcm)
|
|||
|
||||
struct snd_soc_component_driver fsl_asrc_component = {
|
||||
.name = DRV_NAME,
|
||||
.ops = &fsl_asrc_dma_pcm_ops,
|
||||
.pcm_new = fsl_asrc_dma_pcm_new,
|
||||
.pcm_free = fsl_asrc_dma_pcm_free,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = fsl_asrc_dma_hw_params,
|
||||
.hw_free = fsl_asrc_dma_hw_free,
|
||||
.trigger = fsl_asrc_dma_trigger,
|
||||
.open = fsl_asrc_dma_startup,
|
||||
.close = fsl_asrc_dma_shutdown,
|
||||
.pointer = fsl_asrc_dma_pcm_pointer,
|
||||
.pcm_construct = fsl_asrc_dma_pcm_new,
|
||||
.pcm_destruct = fsl_asrc_dma_pcm_free,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(fsl_asrc_component);
|
||||
|
|
|
|||
|
|
@ -201,8 +201,7 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
|
|||
struct fsl_dma_private *dma_private = dev_id;
|
||||
struct snd_pcm_substream *substream = dma_private->substream;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct device *dev = component->dev;
|
||||
struct device *dev = rtd->dev;
|
||||
struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
u32 sr, sr2 = 0;
|
||||
|
|
@ -280,7 +279,8 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
|
|||
* Regardless of where the memory is actually allocated, since the device can
|
||||
* technically DMA to any 36-bit address, we do need to set the DMA mask to 36.
|
||||
*/
|
||||
static int fsl_dma_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int fsl_dma_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_card *card = rtd->card->snd_card;
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
|
|
@ -380,11 +380,10 @@ static int fsl_dma_new(struct snd_soc_pcm_runtime *rtd)
|
|||
* buffer, which is what ALSA expects. We're just dividing it into
|
||||
* contiguous parts, and creating a link descriptor for each one.
|
||||
*/
|
||||
static int fsl_dma_open(struct snd_pcm_substream *substream)
|
||||
static int fsl_dma_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct device *dev = component->dev;
|
||||
struct dma_object *dma =
|
||||
container_of(component->driver, struct dma_object, dai);
|
||||
|
|
@ -533,13 +532,12 @@ static int fsl_dma_open(struct snd_pcm_substream *substream)
|
|||
* and 8 bytes at a time). So we do not support packed 24-bit samples.
|
||||
* 24-bit data must be padded to 32 bits.
|
||||
*/
|
||||
static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
static int fsl_dma_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct fsl_dma_private *dma_private = runtime->private_data;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct device *dev = component->dev;
|
||||
|
||||
/* Number of bits per sample */
|
||||
|
|
@ -698,12 +696,11 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
|
|||
* The base address of the buffer is stored in the source_addr field of the
|
||||
* first link descriptor.
|
||||
*/
|
||||
static snd_pcm_uframes_t fsl_dma_pointer(struct snd_pcm_substream *substream)
|
||||
static snd_pcm_uframes_t fsl_dma_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct fsl_dma_private *dma_private = runtime->private_data;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct device *dev = component->dev;
|
||||
struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
|
||||
dma_addr_t position;
|
||||
|
|
@ -763,7 +760,8 @@ static snd_pcm_uframes_t fsl_dma_pointer(struct snd_pcm_substream *substream)
|
|||
*
|
||||
* This function can be called multiple times.
|
||||
*/
|
||||
static int fsl_dma_hw_free(struct snd_pcm_substream *substream)
|
||||
static int fsl_dma_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct fsl_dma_private *dma_private = runtime->private_data;
|
||||
|
|
@ -796,12 +794,11 @@ static int fsl_dma_hw_free(struct snd_pcm_substream *substream)
|
|||
/**
|
||||
* fsl_dma_close: close the stream.
|
||||
*/
|
||||
static int fsl_dma_close(struct snd_pcm_substream *substream)
|
||||
static int fsl_dma_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct fsl_dma_private *dma_private = runtime->private_data;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct device *dev = component->dev;
|
||||
struct dma_object *dma =
|
||||
container_of(component->driver, struct dma_object, dai);
|
||||
|
|
@ -824,7 +821,8 @@ static int fsl_dma_close(struct snd_pcm_substream *substream)
|
|||
/*
|
||||
* Remove this PCM driver.
|
||||
*/
|
||||
static void fsl_dma_free_dma_buffers(struct snd_pcm *pcm)
|
||||
static void fsl_dma_free_dma_buffers(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm)
|
||||
{
|
||||
struct snd_pcm_substream *substream;
|
||||
unsigned int i;
|
||||
|
|
@ -872,15 +870,6 @@ static struct device_node *find_ssi_node(struct device_node *dma_channel_np)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops fsl_dma_ops = {
|
||||
.open = fsl_dma_open,
|
||||
.close = fsl_dma_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = fsl_dma_hw_params,
|
||||
.hw_free = fsl_dma_hw_free,
|
||||
.pointer = fsl_dma_pointer,
|
||||
};
|
||||
|
||||
static int fsl_soc_dma_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct dma_object *dma;
|
||||
|
|
@ -913,8 +902,14 @@ static int fsl_soc_dma_probe(struct platform_device *pdev)
|
|||
|
||||
dma->dai.name = DRV_NAME;
|
||||
dma->dai.ops = &fsl_dma_ops;
|
||||
dma->dai.pcm_new = fsl_dma_new;
|
||||
dma->dai.pcm_free = fsl_dma_free_dma_buffers;
|
||||
dma->dai.open = fsl_dma_open;
|
||||
dma->dai.close = fsl_dma_close;
|
||||
dma->dai.ioctl = snd_soc_pcm_lib_ioctl;
|
||||
dma->dai.hw_params = fsl_dma_hw_params;
|
||||
dma->dai.hw_free = fsl_dma_hw_free;
|
||||
dma->dai.pointer = fsl_dma_pointer;
|
||||
dma->dai.pcm_construct = fsl_dma_new;
|
||||
dma->dai.pcm_destruct = fsl_dma_free_dma_buffers;
|
||||
|
||||
/* Store the SSI-specific information that we need */
|
||||
dma->ssi_stx_phys = res.start + REG_SSI_STX0;
|
||||
|
|
|
|||
335
sound/soc/fsl/fsl_mqs.c
Normal file
335
sound/soc/fsl/fsl_mqs.c
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// ALSA SoC IMX MQS driver
|
||||
//
|
||||
// Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
|
||||
// Copyright 2019 NXP
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/initval.h>
|
||||
|
||||
#define REG_MQS_CTRL 0x00
|
||||
|
||||
#define MQS_EN_MASK (0x1 << 28)
|
||||
#define MQS_EN_SHIFT (28)
|
||||
#define MQS_SW_RST_MASK (0x1 << 24)
|
||||
#define MQS_SW_RST_SHIFT (24)
|
||||
#define MQS_OVERSAMPLE_MASK (0x1 << 20)
|
||||
#define MQS_OVERSAMPLE_SHIFT (20)
|
||||
#define MQS_CLK_DIV_MASK (0xFF << 0)
|
||||
#define MQS_CLK_DIV_SHIFT (0)
|
||||
|
||||
/* codec private data */
|
||||
struct fsl_mqs {
|
||||
struct regmap *regmap;
|
||||
struct clk *mclk;
|
||||
struct clk *ipg;
|
||||
|
||||
unsigned int reg_iomuxc_gpr2;
|
||||
unsigned int reg_mqs_ctrl;
|
||||
bool use_gpr;
|
||||
};
|
||||
|
||||
#define FSL_MQS_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
|
||||
#define FSL_MQS_FORMATS SNDRV_PCM_FMTBIT_S16_LE
|
||||
|
||||
static int fsl_mqs_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component);
|
||||
unsigned long mclk_rate;
|
||||
int div, res;
|
||||
int lrclk;
|
||||
|
||||
mclk_rate = clk_get_rate(mqs_priv->mclk);
|
||||
lrclk = params_rate(params);
|
||||
|
||||
/*
|
||||
* mclk_rate / (oversample(32,64) * FS * 2 * divider ) = repeat_rate;
|
||||
* if repeat_rate is 8, mqs can achieve better quality.
|
||||
* oversample rate is fix to 32 currently.
|
||||
*/
|
||||
div = mclk_rate / (32 * lrclk * 2 * 8);
|
||||
res = mclk_rate % (32 * lrclk * 2 * 8);
|
||||
|
||||
if (res == 0 && div > 0 && div <= 256) {
|
||||
if (mqs_priv->use_gpr) {
|
||||
regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2,
|
||||
IMX6SX_GPR2_MQS_CLK_DIV_MASK,
|
||||
(div - 1) << IMX6SX_GPR2_MQS_CLK_DIV_SHIFT);
|
||||
regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2,
|
||||
IMX6SX_GPR2_MQS_OVERSAMPLE_MASK, 0);
|
||||
} else {
|
||||
regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL,
|
||||
MQS_CLK_DIV_MASK,
|
||||
(div - 1) << MQS_CLK_DIV_SHIFT);
|
||||
regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL,
|
||||
MQS_OVERSAMPLE_MASK, 0);
|
||||
}
|
||||
} else {
|
||||
dev_err(component->dev, "can't get proper divider\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_mqs_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
{
|
||||
/* Only LEFT_J & SLAVE mode is supported. */
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_mqs_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component);
|
||||
|
||||
if (mqs_priv->use_gpr)
|
||||
regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2,
|
||||
IMX6SX_GPR2_MQS_EN_MASK,
|
||||
1 << IMX6SX_GPR2_MQS_EN_SHIFT);
|
||||
else
|
||||
regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL,
|
||||
MQS_EN_MASK,
|
||||
1 << MQS_EN_SHIFT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fsl_mqs_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component);
|
||||
|
||||
if (mqs_priv->use_gpr)
|
||||
regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2,
|
||||
IMX6SX_GPR2_MQS_EN_MASK, 0);
|
||||
else
|
||||
regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL,
|
||||
MQS_EN_MASK, 0);
|
||||
}
|
||||
|
||||
static const struct snd_soc_component_driver soc_codec_fsl_mqs = {
|
||||
.idle_bias_on = 1,
|
||||
.non_legacy_dai_naming = 1,
|
||||
};
|
||||
|
||||
static const struct snd_soc_dai_ops fsl_mqs_dai_ops = {
|
||||
.startup = fsl_mqs_startup,
|
||||
.shutdown = fsl_mqs_shutdown,
|
||||
.hw_params = fsl_mqs_hw_params,
|
||||
.set_fmt = fsl_mqs_set_dai_fmt,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver fsl_mqs_dai = {
|
||||
.name = "fsl-mqs-dai",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = FSL_MQS_RATES,
|
||||
.formats = FSL_MQS_FORMATS,
|
||||
},
|
||||
.ops = &fsl_mqs_dai_ops,
|
||||
};
|
||||
|
||||
static const struct regmap_config fsl_mqs_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.max_register = REG_MQS_CTRL,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
};
|
||||
|
||||
static int fsl_mqs_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device_node *gpr_np = NULL;
|
||||
struct fsl_mqs *mqs_priv;
|
||||
void __iomem *regs;
|
||||
int ret;
|
||||
|
||||
mqs_priv = devm_kzalloc(&pdev->dev, sizeof(*mqs_priv), GFP_KERNEL);
|
||||
if (!mqs_priv)
|
||||
return -ENOMEM;
|
||||
|
||||
/* On i.MX6sx the MQS control register is in GPR domain
|
||||
* But in i.MX8QM/i.MX8QXP the control register is moved
|
||||
* to its own domain.
|
||||
*/
|
||||
if (of_device_is_compatible(np, "fsl,imx8qm-mqs"))
|
||||
mqs_priv->use_gpr = false;
|
||||
else
|
||||
mqs_priv->use_gpr = true;
|
||||
|
||||
if (mqs_priv->use_gpr) {
|
||||
gpr_np = of_parse_phandle(np, "gpr", 0);
|
||||
if (!gpr_np) {
|
||||
dev_err(&pdev->dev, "failed to get gpr node by phandle\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mqs_priv->regmap = syscon_node_to_regmap(gpr_np);
|
||||
if (IS_ERR(mqs_priv->regmap)) {
|
||||
dev_err(&pdev->dev, "failed to get gpr regmap\n");
|
||||
ret = PTR_ERR(mqs_priv->regmap);
|
||||
goto err_free_gpr_np;
|
||||
}
|
||||
} else {
|
||||
regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(regs))
|
||||
return PTR_ERR(regs);
|
||||
|
||||
mqs_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
|
||||
"core",
|
||||
regs,
|
||||
&fsl_mqs_regmap_config);
|
||||
if (IS_ERR(mqs_priv->regmap)) {
|
||||
dev_err(&pdev->dev, "failed to init regmap: %ld\n",
|
||||
PTR_ERR(mqs_priv->regmap));
|
||||
return PTR_ERR(mqs_priv->regmap);
|
||||
}
|
||||
|
||||
mqs_priv->ipg = devm_clk_get(&pdev->dev, "core");
|
||||
if (IS_ERR(mqs_priv->ipg)) {
|
||||
dev_err(&pdev->dev, "failed to get the clock: %ld\n",
|
||||
PTR_ERR(mqs_priv->ipg));
|
||||
return PTR_ERR(mqs_priv->ipg);
|
||||
}
|
||||
}
|
||||
|
||||
mqs_priv->mclk = devm_clk_get(&pdev->dev, "mclk");
|
||||
if (IS_ERR(mqs_priv->mclk)) {
|
||||
dev_err(&pdev->dev, "failed to get the clock: %ld\n",
|
||||
PTR_ERR(mqs_priv->mclk));
|
||||
ret = PTR_ERR(mqs_priv->mclk);
|
||||
goto err_free_gpr_np;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&pdev->dev, mqs_priv);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_fsl_mqs,
|
||||
&fsl_mqs_dai, 1);
|
||||
if (ret)
|
||||
goto err_free_gpr_np;
|
||||
return 0;
|
||||
|
||||
err_free_gpr_np:
|
||||
of_node_put(gpr_np);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fsl_mqs_remove(struct platform_device *pdev)
|
||||
{
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int fsl_mqs_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct fsl_mqs *mqs_priv = dev_get_drvdata(dev);
|
||||
|
||||
if (mqs_priv->ipg)
|
||||
clk_prepare_enable(mqs_priv->ipg);
|
||||
|
||||
if (mqs_priv->mclk)
|
||||
clk_prepare_enable(mqs_priv->mclk);
|
||||
|
||||
if (mqs_priv->use_gpr)
|
||||
regmap_write(mqs_priv->regmap, IOMUXC_GPR2,
|
||||
mqs_priv->reg_iomuxc_gpr2);
|
||||
else
|
||||
regmap_write(mqs_priv->regmap, REG_MQS_CTRL,
|
||||
mqs_priv->reg_mqs_ctrl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_mqs_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct fsl_mqs *mqs_priv = dev_get_drvdata(dev);
|
||||
|
||||
if (mqs_priv->use_gpr)
|
||||
regmap_read(mqs_priv->regmap, IOMUXC_GPR2,
|
||||
&mqs_priv->reg_iomuxc_gpr2);
|
||||
else
|
||||
regmap_read(mqs_priv->regmap, REG_MQS_CTRL,
|
||||
&mqs_priv->reg_mqs_ctrl);
|
||||
|
||||
if (mqs_priv->mclk)
|
||||
clk_disable_unprepare(mqs_priv->mclk);
|
||||
|
||||
if (mqs_priv->ipg)
|
||||
clk_disable_unprepare(mqs_priv->ipg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops fsl_mqs_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(fsl_mqs_runtime_suspend,
|
||||
fsl_mqs_runtime_resume,
|
||||
NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id fsl_mqs_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx8qm-mqs", },
|
||||
{ .compatible = "fsl,imx6sx-mqs", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, fsl_mqs_dt_ids);
|
||||
|
||||
static struct platform_driver fsl_mqs_driver = {
|
||||
.probe = fsl_mqs_probe,
|
||||
.remove = fsl_mqs_remove,
|
||||
.driver = {
|
||||
.name = "fsl-mqs",
|
||||
.of_match_table = fsl_mqs_dt_ids,
|
||||
.pm = &fsl_mqs_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(fsl_mqs_driver);
|
||||
|
||||
MODULE_AUTHOR("Shengjiu Wang <Shengjiu.Wang@nxp.com>");
|
||||
MODULE_DESCRIPTION("MQS codec driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform: fsl-mqs");
|
||||
|
|
@ -69,8 +69,9 @@ static struct fiq_handler fh = {
|
|||
.name = DRV_NAME,
|
||||
};
|
||||
|
||||
static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
static int snd_imx_pcm_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
|
||||
|
|
@ -85,7 +86,8 @@ static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
static int snd_imx_pcm_prepare(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
|
||||
|
|
@ -104,7 +106,8 @@ static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream)
|
|||
|
||||
static int imx_pcm_fiq;
|
||||
|
||||
static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
static int snd_imx_pcm_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
|
||||
|
|
@ -141,7 +144,9 @@ static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
static snd_pcm_uframes_t
|
||||
snd_imx_pcm_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
|
||||
|
|
@ -165,7 +170,8 @@ static const struct snd_pcm_hardware snd_imx_hardware = {
|
|||
.fifo_size = 0,
|
||||
};
|
||||
|
||||
static int snd_imx_open(struct snd_pcm_substream *substream)
|
||||
static int snd_imx_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct imx_pcm_runtime_data *iprtd;
|
||||
|
|
@ -194,7 +200,8 @@ static int snd_imx_open(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int snd_imx_close(struct snd_pcm_substream *substream)
|
||||
static int snd_imx_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
|
||||
|
|
@ -206,8 +213,9 @@ static int snd_imx_close(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
static int snd_imx_pcm_mmap(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
int ret;
|
||||
|
|
@ -222,17 +230,6 @@ static int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops imx_pcm_ops = {
|
||||
.open = snd_imx_open,
|
||||
.close = snd_imx_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = snd_imx_pcm_hw_params,
|
||||
.prepare = snd_imx_pcm_prepare,
|
||||
.trigger = snd_imx_pcm_trigger,
|
||||
.pointer = snd_imx_pcm_pointer,
|
||||
.mmap = snd_imx_pcm_mmap,
|
||||
};
|
||||
|
||||
static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
|
||||
{
|
||||
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
|
||||
|
|
@ -279,7 +276,8 @@ static int imx_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
|||
|
||||
static int ssi_irq;
|
||||
|
||||
static int imx_pcm_fiq_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int snd_imx_pcm_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
struct snd_pcm_substream *substream;
|
||||
|
|
@ -329,7 +327,8 @@ static void imx_pcm_free(struct snd_pcm *pcm)
|
|||
}
|
||||
}
|
||||
|
||||
static void imx_pcm_fiq_free(struct snd_pcm *pcm)
|
||||
static void snd_imx_pcm_free(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm)
|
||||
{
|
||||
mxc_set_irq_fiq(ssi_irq, 0);
|
||||
release_fiq(&fh);
|
||||
|
|
@ -337,9 +336,16 @@ static void imx_pcm_fiq_free(struct snd_pcm *pcm)
|
|||
}
|
||||
|
||||
static const struct snd_soc_component_driver imx_soc_component_fiq = {
|
||||
.ops = &imx_pcm_ops,
|
||||
.pcm_new = imx_pcm_fiq_new,
|
||||
.pcm_free = imx_pcm_fiq_free,
|
||||
.open = snd_imx_open,
|
||||
.close = snd_imx_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = snd_imx_pcm_hw_params,
|
||||
.prepare = snd_imx_pcm_prepare,
|
||||
.trigger = snd_imx_pcm_trigger,
|
||||
.pointer = snd_imx_pcm_pointer,
|
||||
.mmap = snd_imx_pcm_mmap,
|
||||
.pcm_construct = snd_imx_pcm_new,
|
||||
.pcm_destruct = snd_imx_pcm_free,
|
||||
};
|
||||
|
||||
int imx_pcm_fiq_init(struct platform_device *pdev,
|
||||
|
|
|
|||
|
|
@ -98,7 +98,8 @@ static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int psc_dma_hw_free(struct snd_pcm_substream *substream)
|
||||
static int psc_dma_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
snd_pcm_set_runtime_buffer(substream, NULL);
|
||||
return 0;
|
||||
|
|
@ -110,7 +111,8 @@ static int psc_dma_hw_free(struct snd_pcm_substream *substream)
|
|||
* This function is called by ALSA to start, stop, pause, and resume the DMA
|
||||
* transfer of data.
|
||||
*/
|
||||
static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
static int psc_dma_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
|
||||
|
|
@ -210,7 +212,8 @@ static const struct snd_pcm_hardware psc_dma_hardware = {
|
|||
.fifo_size = 512,
|
||||
};
|
||||
|
||||
static int psc_dma_open(struct snd_pcm_substream *substream)
|
||||
static int psc_dma_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
|
|
@ -238,7 +241,8 @@ static int psc_dma_open(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int psc_dma_close(struct snd_pcm_substream *substream)
|
||||
static int psc_dma_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
|
||||
|
|
@ -263,7 +267,8 @@ static int psc_dma_close(struct snd_pcm_substream *substream)
|
|||
}
|
||||
|
||||
static snd_pcm_uframes_t
|
||||
psc_dma_pointer(struct snd_pcm_substream *substream)
|
||||
psc_dma_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
|
||||
|
|
@ -280,29 +285,19 @@ psc_dma_pointer(struct snd_pcm_substream *substream)
|
|||
return bytes_to_frames(substream->runtime, count);
|
||||
}
|
||||
|
||||
static int
|
||||
psc_dma_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
static int psc_dma_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops psc_dma_ops = {
|
||||
.open = psc_dma_open,
|
||||
.close = psc_dma_close,
|
||||
.hw_free = psc_dma_hw_free,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.pointer = psc_dma_pointer,
|
||||
.trigger = psc_dma_trigger,
|
||||
.hw_params = psc_dma_hw_params,
|
||||
};
|
||||
|
||||
static int psc_dma_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int psc_dma_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_card *card = rtd->card->snd_card;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct snd_soc_dai *dai = rtd->cpu_dai;
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
size_t size = psc_dma_hardware.buffer_bytes_max;
|
||||
|
|
@ -341,10 +336,10 @@ static int psc_dma_new(struct snd_soc_pcm_runtime *rtd)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void psc_dma_free(struct snd_pcm *pcm)
|
||||
static void psc_dma_free(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = pcm->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct snd_pcm_substream *substream;
|
||||
int stream;
|
||||
|
||||
|
|
@ -362,9 +357,15 @@ static void psc_dma_free(struct snd_pcm *pcm)
|
|||
|
||||
static const struct snd_soc_component_driver mpc5200_audio_dma_component = {
|
||||
.name = DRV_NAME,
|
||||
.ops = &psc_dma_ops,
|
||||
.pcm_new = &psc_dma_new,
|
||||
.pcm_free = &psc_dma_free,
|
||||
.open = psc_dma_open,
|
||||
.close = psc_dma_close,
|
||||
.hw_free = psc_dma_hw_free,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.pointer = psc_dma_pointer,
|
||||
.trigger = psc_dma_trigger,
|
||||
.hw_params = psc_dma_hw_params,
|
||||
.pcm_construct = psc_dma_new,
|
||||
.pcm_destruct = psc_dma_free,
|
||||
};
|
||||
|
||||
int mpc5200_audio_dma_create(struct platform_device *op)
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
|
|||
if (li->cpu) {
|
||||
int is_single_links = 0;
|
||||
|
||||
/* BE is dummy */
|
||||
/* Codec is dummy */
|
||||
codecs->of_node = NULL;
|
||||
codecs->dai_name = "snd-soc-dummy-dai";
|
||||
codecs->name = "snd-soc-dummy";
|
||||
|
|
@ -263,7 +263,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
|
|||
} else {
|
||||
struct snd_soc_codec_conf *cconf;
|
||||
|
||||
/* FE is dummy */
|
||||
/* CPU is dummy */
|
||||
cpus->of_node = NULL;
|
||||
cpus->dai_name = "snd-soc-dummy-dai";
|
||||
cpus->name = "snd-soc-dummy";
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
|
|||
if (li->cpu) {
|
||||
int is_single_links = 0;
|
||||
|
||||
/* BE is dummy */
|
||||
/* Codec is dummy */
|
||||
codecs->of_node = NULL;
|
||||
codecs->dai_name = "snd-soc-dummy-dai";
|
||||
codecs->name = "snd-soc-dummy";
|
||||
|
|
@ -179,7 +179,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
|
|||
} else {
|
||||
struct snd_soc_codec_conf *cconf;
|
||||
|
||||
/* FE is dummy */
|
||||
/* CPU is dummy */
|
||||
cpus->of_node = NULL;
|
||||
cpus->dai_name = "snd-soc-dummy-dai";
|
||||
cpus->name = "snd-soc-dummy";
|
||||
|
|
|
|||
|
|
@ -586,7 +586,8 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static int sst_platform_open(struct snd_pcm_substream *substream)
|
||||
static int sst_soc_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime;
|
||||
|
||||
|
|
@ -598,15 +599,15 @@ static int sst_platform_open(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
|
||||
int cmd)
|
||||
static int sst_soc_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
int ret_val = 0, str_id;
|
||||
struct sst_runtime_stream *stream;
|
||||
int status;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
|
||||
dev_dbg(rtd->dev, "sst_platform_pcm_trigger called\n");
|
||||
dev_dbg(rtd->dev, "%s called\n", __func__);
|
||||
if (substream->pcm->internal)
|
||||
return 0;
|
||||
stream = substream->runtime->private_data;
|
||||
|
|
@ -646,8 +647,8 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
|
|||
}
|
||||
|
||||
|
||||
static snd_pcm_uframes_t sst_platform_pcm_pointer
|
||||
(struct snd_pcm_substream *substream)
|
||||
static snd_pcm_uframes_t sst_soc_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct sst_runtime_stream *stream;
|
||||
int ret_val, status;
|
||||
|
|
@ -668,14 +669,8 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer
|
|||
return str_info->buffer_ptr;
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops sst_platform_ops = {
|
||||
.open = sst_platform_open,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.trigger = sst_platform_pcm_trigger,
|
||||
.pointer = sst_platform_pcm_pointer,
|
||||
};
|
||||
|
||||
static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int sst_soc_pcm_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_dai *dai = rtd->cpu_dai;
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
|
|
@ -709,9 +704,12 @@ static const struct snd_soc_component_driver sst_soc_platform_drv = {
|
|||
.name = DRV_NAME,
|
||||
.probe = sst_soc_probe,
|
||||
.remove = sst_soc_remove,
|
||||
.ops = &sst_platform_ops,
|
||||
.open = sst_soc_open,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.trigger = sst_soc_trigger,
|
||||
.pointer = sst_soc_pointer,
|
||||
.compr_ops = &sst_platform_compr_ops,
|
||||
.pcm_new = sst_pcm_new,
|
||||
.pcm_construct = sst_soc_pcm_new,
|
||||
};
|
||||
|
||||
static int sst_platform_probe(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -58,11 +58,11 @@ struct sst_byt_priv_data {
|
|||
};
|
||||
|
||||
/* this may get called several times by oss emulation */
|
||||
static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
static int sst_byt_pcm_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component);
|
||||
struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
|
||||
struct sst_byt *byt = pdata->byt;
|
||||
|
|
@ -121,7 +121,8 @@ static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sst_byt_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
static int sst_byt_pcm_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
|
||||
|
|
@ -164,10 +165,10 @@ static void sst_byt_pcm_work(struct work_struct *work)
|
|||
sst_byt_pcm_restore_stream_context(pcm_data->substream);
|
||||
}
|
||||
|
||||
static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
static int sst_byt_pcm_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component);
|
||||
struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
|
||||
struct sst_byt *byt = pdata->byt;
|
||||
|
|
@ -228,11 +229,11 @@ static u32 byt_notify_pointer(struct sst_byt_stream *stream, void *data)
|
|||
return pos;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component);
|
||||
struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
|
||||
|
||||
|
|
@ -241,10 +242,10 @@ static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream
|
|||
return bytes_to_frames(runtime, pcm_data->hw_ptr);
|
||||
}
|
||||
|
||||
static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
|
||||
static int sst_byt_pcm_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component);
|
||||
struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
|
||||
struct sst_byt *byt = pdata->byt;
|
||||
|
|
@ -269,10 +270,10 @@ static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sst_byt_pcm_close(struct snd_pcm_substream *substream)
|
||||
static int sst_byt_pcm_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component);
|
||||
struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
|
||||
struct sst_byt *byt = pdata->byt;
|
||||
|
|
@ -294,7 +295,8 @@ static int sst_byt_pcm_close(struct snd_pcm_substream *substream)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream,
|
||||
static int sst_byt_pcm_mmap(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
|
|
@ -303,22 +305,11 @@ static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream,
|
|||
return snd_pcm_lib_default_mmap(substream, vma);
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops sst_byt_pcm_ops = {
|
||||
.open = sst_byt_pcm_open,
|
||||
.close = sst_byt_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = sst_byt_pcm_hw_params,
|
||||
.hw_free = sst_byt_pcm_hw_free,
|
||||
.trigger = sst_byt_pcm_trigger,
|
||||
.pointer = sst_byt_pcm_pointer,
|
||||
.mmap = sst_byt_pcm_mmap,
|
||||
};
|
||||
|
||||
static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int sst_byt_pcm_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
size_t size;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct sst_pdata *pdata = dev_get_platdata(component->dev);
|
||||
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
|
||||
|
|
@ -380,8 +371,15 @@ static int sst_byt_pcm_probe(struct snd_soc_component *component)
|
|||
static const struct snd_soc_component_driver byt_dai_component = {
|
||||
.name = DRV_NAME,
|
||||
.probe = sst_byt_pcm_probe,
|
||||
.ops = &sst_byt_pcm_ops,
|
||||
.pcm_new = sst_byt_pcm_new,
|
||||
.open = sst_byt_pcm_open,
|
||||
.close = sst_byt_pcm_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = sst_byt_pcm_hw_params,
|
||||
.hw_free = sst_byt_pcm_hw_free,
|
||||
.trigger = sst_byt_pcm_trigger,
|
||||
.pointer = sst_byt_pcm_pointer,
|
||||
.mmap = sst_byt_pcm_mmap,
|
||||
.pcm_construct = sst_byt_pcm_new,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
|
|
|||
|
|
@ -320,6 +320,7 @@ config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH
|
|||
select SND_SOC_RT5514_SPI
|
||||
select SND_SOC_MAX98927
|
||||
select SND_SOC_HDAC_HDMI
|
||||
select SND_SOC_INTEL_SKYLAKE_SSP_CLK
|
||||
help
|
||||
This adds support for ASoC Onboard Codec I2S machine driver. This will
|
||||
create an alsa sound card for RT5663 + RT5514 + MAX98927.
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ struct cht_mc_private {
|
|||
#define CHT_RT5645_SSP2_AIF2 BIT(16) /* default is using AIF1 */
|
||||
#define CHT_RT5645_SSP0_AIF1 BIT(17)
|
||||
#define CHT_RT5645_SSP0_AIF2 BIT(18)
|
||||
#define CHT_RT5645_PMC_PLT_CLK_0 BIT(19)
|
||||
|
||||
static unsigned long cht_rt5645_quirk = 0;
|
||||
|
||||
|
|
@ -59,6 +60,8 @@ static void log_quirks(struct device *dev)
|
|||
dev_info(dev, "quirk SSP0_AIF1 enabled");
|
||||
if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)
|
||||
dev_info(dev, "quirk SSP0_AIF2 enabled");
|
||||
if (cht_rt5645_quirk & CHT_RT5645_PMC_PLT_CLK_0)
|
||||
dev_info(dev, "quirk PMC_PLT_CLK_0 enabled");
|
||||
}
|
||||
|
||||
static int platform_clock_control(struct snd_soc_dapm_widget *w,
|
||||
|
|
@ -226,15 +229,21 @@ static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* uncomment when we have a real quirk
|
||||
static int cht_rt5645_quirk_cb(const struct dmi_system_id *id)
|
||||
{
|
||||
cht_rt5645_quirk = (unsigned long)id->driver_data;
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
|
||||
static const struct dmi_system_id cht_rt5645_quirk_table[] = {
|
||||
{
|
||||
/* Strago family Chromebooks */
|
||||
.callback = cht_rt5645_quirk_cb,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_Strago"),
|
||||
},
|
||||
.driver_data = (void *)CHT_RT5645_PMC_PLT_CLK_0,
|
||||
},
|
||||
{
|
||||
},
|
||||
};
|
||||
|
|
@ -526,6 +535,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
|
|||
int dai_index = 0;
|
||||
int ret_val = 0;
|
||||
int i;
|
||||
const char *mclk_name;
|
||||
|
||||
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
|
||||
if (!drv)
|
||||
|
|
@ -662,11 +672,15 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
|
|||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
|
||||
if (cht_rt5645_quirk & CHT_RT5645_PMC_PLT_CLK_0)
|
||||
mclk_name = "pmc_plt_clk_0";
|
||||
else
|
||||
mclk_name = "pmc_plt_clk_3";
|
||||
|
||||
drv->mclk = devm_clk_get(&pdev->dev, mclk_name);
|
||||
if (IS_ERR(drv->mclk)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to get MCLK from pmc_plt_clk_3: %ld\n",
|
||||
PTR_ERR(drv->mclk));
|
||||
dev_err(&pdev->dev, "Failed to get MCLK from %s: %ld\n",
|
||||
mclk_name, PTR_ERR(drv->mclk));
|
||||
return PTR_ERR(drv->mclk);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@
|
|||
#include "../../codecs/rt5514.h"
|
||||
#include "../../codecs/rt5663.h"
|
||||
#include "../../codecs/hdac_hdmi.h"
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
|
||||
#define KBL_REALTEK_CODEC_DAI "rt5663-aif"
|
||||
#define KBL_REALTEK_DMIC_CODEC_DAI "rt5514-aif1"
|
||||
|
|
@ -50,6 +53,8 @@ struct kbl_codec_private {
|
|||
struct snd_soc_jack kabylake_headset;
|
||||
struct list_head hdmi_pcm_list;
|
||||
struct snd_soc_jack kabylake_hdmi[2];
|
||||
struct clk *mclk;
|
||||
struct clk *sclk;
|
||||
};
|
||||
|
||||
enum {
|
||||
|
|
@ -71,6 +76,61 @@ static const struct snd_kcontrol_new kabylake_controls[] = {
|
|||
SOC_DAPM_PIN_SWITCH("DMIC"),
|
||||
};
|
||||
|
||||
static int platform_clock_control(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *k, int event)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = w->dapm;
|
||||
struct snd_soc_card *card = dapm->card;
|
||||
struct kbl_codec_private *priv = snd_soc_card_get_drvdata(card);
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* MCLK/SCLK need to be ON early for a successful synchronization of
|
||||
* codec internal clock. And the clocks are turned off during
|
||||
* POST_PMD after the stream is stopped.
|
||||
*/
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
/* Enable MCLK */
|
||||
ret = clk_set_rate(priv->mclk, 24000000);
|
||||
if (ret < 0) {
|
||||
dev_err(card->dev, "Can't set rate for mclk, err: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(priv->mclk);
|
||||
if (ret < 0) {
|
||||
dev_err(card->dev, "Can't enable mclk, err: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enable SCLK */
|
||||
ret = clk_set_rate(priv->sclk, 3072000);
|
||||
if (ret < 0) {
|
||||
dev_err(card->dev, "Can't set rate for sclk, err: %d\n",
|
||||
ret);
|
||||
clk_disable_unprepare(priv->mclk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(priv->sclk);
|
||||
if (ret < 0) {
|
||||
dev_err(card->dev, "Can't enable sclk, err: %d\n", ret);
|
||||
clk_disable_unprepare(priv->mclk);
|
||||
}
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
clk_disable_unprepare(priv->mclk);
|
||||
clk_disable_unprepare(priv->sclk);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget kabylake_widgets[] = {
|
||||
SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
||||
SND_SOC_DAPM_MIC("Headset Mic", NULL),
|
||||
|
|
@ -79,11 +139,15 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
|
|||
SND_SOC_DAPM_MIC("DMIC", NULL),
|
||||
SND_SOC_DAPM_SPK("HDMI1", NULL),
|
||||
SND_SOC_DAPM_SPK("HDMI2", NULL),
|
||||
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
|
||||
platform_clock_control, SND_SOC_DAPM_PRE_PMU |
|
||||
SND_SOC_DAPM_POST_PMD),
|
||||
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route kabylake_map[] = {
|
||||
/* Headphones */
|
||||
{ "Headphone Jack", NULL, "Platform Clock" },
|
||||
{ "Headphone Jack", NULL, "HPOL" },
|
||||
{ "Headphone Jack", NULL, "HPOR" },
|
||||
|
||||
|
|
@ -92,6 +156,7 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
|
|||
{ "Right Spk", NULL, "Right BE_OUT" },
|
||||
|
||||
/* other jacks */
|
||||
{ "Headset Mic", NULL, "Platform Clock" },
|
||||
{ "IN1P", NULL, "Headset Mic" },
|
||||
{ "IN1N", NULL, "Headset Mic" },
|
||||
|
||||
|
|
@ -643,6 +708,7 @@ static int kabylake_audio_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct kbl_codec_private *ctx;
|
||||
struct snd_soc_acpi_mach *mach;
|
||||
int ret = 0;
|
||||
|
||||
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
|
|
@ -658,6 +724,34 @@ static int kabylake_audio_probe(struct platform_device *pdev)
|
|||
dmic_constraints = mach->mach_params.dmic_num == 2 ?
|
||||
&constraints_dmic_2ch : &constraints_dmic_channels;
|
||||
|
||||
ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk");
|
||||
if (IS_ERR(ctx->mclk)) {
|
||||
ret = PTR_ERR(ctx->mclk);
|
||||
if (ret == -ENOENT) {
|
||||
dev_info(&pdev->dev,
|
||||
"Failed to get ssp1_mclk, defer probe\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
dev_err(&pdev->dev, "Failed to get ssp1_mclk with err:%d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ctx->sclk = devm_clk_get(&pdev->dev, "ssp1_sclk");
|
||||
if (IS_ERR(ctx->sclk)) {
|
||||
ret = PTR_ERR(ctx->sclk);
|
||||
if (ret == -ENOENT) {
|
||||
dev_info(&pdev->dev,
|
||||
"Failed to get ssp1_sclk, defer probe\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
dev_err(&pdev->dev, "Failed to get ssp1_sclk with err:%d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -458,12 +458,12 @@ static int create_adsp_page_table(struct snd_pcm_substream *substream,
|
|||
}
|
||||
|
||||
/* this may get called several times by oss emulation */
|
||||
static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
static int hsw_pcm_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component);
|
||||
struct hsw_pcm_data *pcm_data;
|
||||
struct sst_hsw *hsw = pdata->hsw;
|
||||
|
|
@ -656,16 +656,17 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int hsw_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
static int hsw_pcm_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
snd_pcm_lib_free_pages(substream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hsw_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
static int hsw_pcm_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component);
|
||||
struct hsw_pcm_data *pcm_data;
|
||||
struct sst_hsw_stream *sst_stream;
|
||||
|
|
@ -770,11 +771,11 @@ static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data)
|
|||
return pos;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component);
|
||||
struct hsw_pcm_data *pcm_data;
|
||||
struct sst_hsw *hsw = pdata->hsw;
|
||||
|
|
@ -795,10 +796,21 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream)
|
|||
return offset;
|
||||
}
|
||||
|
||||
static int hsw_pcm_open(struct snd_pcm_substream *substream)
|
||||
#ifdef CONFIG_SND_DMA_SGBUF
|
||||
static struct page *hsw_pcm_page(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
unsigned long offset)
|
||||
{
|
||||
return snd_pcm_sgbuf_ops_page(substream, offset);
|
||||
}
|
||||
#else
|
||||
#define hsw_pcm_page NULL
|
||||
#endif /* CONFIG_SND_DMA_SGBUF */
|
||||
|
||||
static int hsw_pcm_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component);
|
||||
struct hsw_pcm_data *pcm_data;
|
||||
struct sst_hsw *hsw = pdata->hsw;
|
||||
|
|
@ -828,10 +840,10 @@ static int hsw_pcm_open(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int hsw_pcm_close(struct snd_pcm_substream *substream)
|
||||
static int hsw_pcm_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component);
|
||||
struct hsw_pcm_data *pcm_data;
|
||||
struct sst_hsw *hsw = pdata->hsw;
|
||||
|
|
@ -862,17 +874,6 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops hsw_pcm_ops = {
|
||||
.open = hsw_pcm_open,
|
||||
.close = hsw_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = hsw_pcm_hw_params,
|
||||
.hw_free = hsw_pcm_hw_free,
|
||||
.trigger = hsw_pcm_trigger,
|
||||
.pointer = hsw_pcm_pointer,
|
||||
.page = snd_pcm_sgbuf_ops_page,
|
||||
};
|
||||
|
||||
static int hsw_pcm_create_modules(struct hsw_priv_data *pdata)
|
||||
{
|
||||
struct sst_hsw *hsw = pdata->hsw;
|
||||
|
|
@ -930,10 +931,10 @@ static void hsw_pcm_free_modules(struct hsw_priv_data *pdata)
|
|||
}
|
||||
}
|
||||
|
||||
static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int hsw_pcm_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct sst_pdata *pdata = dev_get_platdata(component->dev);
|
||||
struct hsw_priv_data *priv_data = dev_get_drvdata(component->dev);
|
||||
struct device *dev = pdata->dma_dev;
|
||||
|
|
@ -1121,8 +1122,15 @@ static const struct snd_soc_component_driver hsw_dai_component = {
|
|||
.name = DRV_NAME,
|
||||
.probe = hsw_pcm_probe,
|
||||
.remove = hsw_pcm_remove,
|
||||
.ops = &hsw_pcm_ops,
|
||||
.pcm_new = hsw_pcm_new,
|
||||
.open = hsw_pcm_open,
|
||||
.close = hsw_pcm_close,
|
||||
.hw_params = hsw_pcm_hw_params,
|
||||
.hw_free = hsw_pcm_hw_free,
|
||||
.trigger = hsw_pcm_trigger,
|
||||
.pointer = hsw_pcm_pointer,
|
||||
.page = hsw_pcm_page,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.pcm_construct = hsw_pcm_new,
|
||||
.controls = hsw_volume_controls,
|
||||
.num_controls = ARRAY_SIZE(hsw_volume_controls),
|
||||
.dapm_widgets = widgets,
|
||||
|
|
|
|||
|
|
@ -1081,7 +1081,8 @@ int skl_dai_load(struct snd_soc_component *cmp, int index,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int skl_platform_open(struct snd_pcm_substream *substream)
|
||||
static int skl_platform_soc_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai_link *dai_link = rtd->dai_link;
|
||||
|
|
@ -1167,8 +1168,9 @@ static int skl_coupled_trigger(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream,
|
||||
int cmd)
|
||||
static int skl_platform_soc_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
int cmd)
|
||||
{
|
||||
struct hdac_bus *bus = get_bus_ctx(substream);
|
||||
|
||||
|
|
@ -1178,8 +1180,9 @@ static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t skl_platform_pcm_pointer
|
||||
(struct snd_pcm_substream *substream)
|
||||
static snd_pcm_uframes_t skl_platform_soc_pointer(
|
||||
struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream);
|
||||
struct hdac_bus *bus = get_bus_ctx(substream);
|
||||
|
|
@ -1225,6 +1228,24 @@ static snd_pcm_uframes_t skl_platform_pcm_pointer
|
|||
return bytes_to_frames(substream->runtime, pos);
|
||||
}
|
||||
|
||||
static int skl_platform_soc_mmap(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *area)
|
||||
{
|
||||
return snd_pcm_lib_default_mmap(substream, area);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SND_DMA_SGBUF
|
||||
static struct page *skl_platform_soc_page(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
unsigned long offset)
|
||||
{
|
||||
return snd_pcm_sgbuf_ops_page(substream, offset);
|
||||
}
|
||||
#else
|
||||
#define skl_platform_soc_page NULL
|
||||
#endif /* CONFIG_SND_DMA_SGBUF */
|
||||
|
||||
static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream,
|
||||
u64 nsec)
|
||||
{
|
||||
|
|
@ -1245,7 +1266,9 @@ static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream,
|
|||
return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0;
|
||||
}
|
||||
|
||||
static int skl_get_time_info(struct snd_pcm_substream *substream,
|
||||
static int skl_platform_soc_get_time_info(
|
||||
struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct timespec *system_ts, struct timespec *audio_ts,
|
||||
struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
|
||||
struct snd_pcm_audio_tstamp_report *audio_tstamp_report)
|
||||
|
|
@ -1277,24 +1300,16 @@ static int skl_get_time_info(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops skl_platform_ops = {
|
||||
.open = skl_platform_open,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.trigger = skl_platform_pcm_trigger,
|
||||
.pointer = skl_platform_pcm_pointer,
|
||||
.get_time_info = skl_get_time_info,
|
||||
.mmap = snd_pcm_lib_default_mmap,
|
||||
.page = snd_pcm_sgbuf_ops_page,
|
||||
};
|
||||
|
||||
static void skl_pcm_free(struct snd_pcm *pcm)
|
||||
static void skl_platform_soc_free(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm)
|
||||
{
|
||||
snd_pcm_lib_preallocate_free_for_all(pcm);
|
||||
}
|
||||
|
||||
#define MAX_PREALLOC_SIZE (32 * 1024 * 1024)
|
||||
|
||||
static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int skl_platform_soc_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_dai *dai = rtd->cpu_dai;
|
||||
struct hdac_bus *bus = dev_get_drvdata(dai->dev);
|
||||
|
|
@ -1458,7 +1473,7 @@ static int skl_platform_soc_probe(struct snd_soc_component *component)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void skl_pcm_remove(struct snd_soc_component *component)
|
||||
static void skl_platform_soc_remove(struct snd_soc_component *component)
|
||||
{
|
||||
struct hdac_bus *bus = dev_get_drvdata(component->dev);
|
||||
struct skl_dev *skl = bus_to_skl(bus);
|
||||
|
|
@ -1471,10 +1486,16 @@ static void skl_pcm_remove(struct snd_soc_component *component)
|
|||
static const struct snd_soc_component_driver skl_component = {
|
||||
.name = "pcm",
|
||||
.probe = skl_platform_soc_probe,
|
||||
.remove = skl_pcm_remove,
|
||||
.ops = &skl_platform_ops,
|
||||
.pcm_new = skl_pcm_new,
|
||||
.pcm_free = skl_pcm_free,
|
||||
.remove = skl_platform_soc_remove,
|
||||
.open = skl_platform_soc_open,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.trigger = skl_platform_soc_trigger,
|
||||
.pointer = skl_platform_soc_pointer,
|
||||
.get_time_info = skl_platform_soc_get_time_info,
|
||||
.mmap = skl_platform_soc_mmap,
|
||||
.page = skl_platform_soc_page,
|
||||
.pcm_construct = skl_platform_soc_new,
|
||||
.pcm_destruct = skl_platform_soc_free,
|
||||
.module_get_upon_open = 1, /* increment refcount when a pcm is opened */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -497,15 +497,13 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev)
|
|||
struct jz4740_i2s *i2s;
|
||||
struct resource *mem;
|
||||
int ret;
|
||||
const struct of_device_id *match;
|
||||
|
||||
i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
|
||||
if (!i2s)
|
||||
return -ENOMEM;
|
||||
|
||||
match = of_match_device(jz4740_of_matches, &pdev->dev);
|
||||
if (match)
|
||||
i2s->version = (enum jz47xx_i2s_version)match->data;
|
||||
i2s->version =
|
||||
(enum jz47xx_i2s_version)of_device_get_match_data(&pdev->dev);
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
i2s->base = devm_ioremap_resource(&pdev->dev, mem);
|
||||
|
|
|
|||
|
|
@ -98,7 +98,8 @@ kirkwood_dma_conf_mbus_windows(void __iomem *base, int win,
|
|||
}
|
||||
}
|
||||
|
||||
static int kirkwood_dma_open(struct snd_pcm_substream *substream)
|
||||
static int kirkwood_dma_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
int err;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
|
@ -160,7 +161,8 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int kirkwood_dma_close(struct snd_pcm_substream *substream)
|
||||
static int kirkwood_dma_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct kirkwood_dma_data *priv = kirkwood_priv(substream);
|
||||
|
||||
|
|
@ -180,8 +182,9 @@ static int kirkwood_dma_close(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int kirkwood_dma_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
static int kirkwood_dma_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
||||
|
|
@ -191,13 +194,15 @@ static int kirkwood_dma_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int kirkwood_dma_hw_free(struct snd_pcm_substream *substream)
|
||||
static int kirkwood_dma_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
snd_pcm_set_runtime_buffer(substream, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kirkwood_dma_prepare(struct snd_pcm_substream *substream)
|
||||
static int kirkwood_dma_prepare(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct kirkwood_dma_data *priv = kirkwood_priv(substream);
|
||||
|
|
@ -222,8 +227,9 @@ static int kirkwood_dma_prepare(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream
|
||||
*substream)
|
||||
static snd_pcm_uframes_t kirkwood_dma_pointer(
|
||||
struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct kirkwood_dma_data *priv = kirkwood_priv(substream);
|
||||
snd_pcm_uframes_t count;
|
||||
|
|
@ -238,16 +244,6 @@ static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream
|
|||
return count;
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops kirkwood_dma_ops = {
|
||||
.open = kirkwood_dma_open,
|
||||
.close = kirkwood_dma_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = kirkwood_dma_hw_params,
|
||||
.hw_free = kirkwood_dma_hw_free,
|
||||
.prepare = kirkwood_dma_prepare,
|
||||
.pointer = kirkwood_dma_pointer,
|
||||
};
|
||||
|
||||
static int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm,
|
||||
int stream)
|
||||
{
|
||||
|
|
@ -267,7 +263,8 @@ static int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int kirkwood_dma_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int kirkwood_dma_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_card *card = rtd->card->snd_card;
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
|
|
@ -294,7 +291,8 @@ static int kirkwood_dma_new(struct snd_soc_pcm_runtime *rtd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void kirkwood_dma_free_dma_buffers(struct snd_pcm *pcm)
|
||||
static void kirkwood_dma_free_dma_buffers(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm)
|
||||
{
|
||||
struct snd_pcm_substream *substream;
|
||||
struct snd_dma_buffer *buf;
|
||||
|
|
@ -316,7 +314,13 @@ static void kirkwood_dma_free_dma_buffers(struct snd_pcm *pcm)
|
|||
|
||||
const struct snd_soc_component_driver kirkwood_soc_component = {
|
||||
.name = DRV_NAME,
|
||||
.ops = &kirkwood_dma_ops,
|
||||
.pcm_new = kirkwood_dma_new,
|
||||
.pcm_free = kirkwood_dma_free_dma_buffers,
|
||||
.open = kirkwood_dma_open,
|
||||
.close = kirkwood_dma_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = kirkwood_dma_hw_params,
|
||||
.hw_free = kirkwood_dma_hw_free,
|
||||
.prepare = kirkwood_dma_prepare,
|
||||
.pointer = kirkwood_dma_pointer,
|
||||
.pcm_construct = kirkwood_dma_new,
|
||||
.pcm_destruct = kirkwood_dma_free_dma_buffers,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -77,11 +77,10 @@ int mtk_afe_add_sub_dai_control(struct snd_soc_component *component)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_afe_add_sub_dai_control);
|
||||
|
||||
static snd_pcm_uframes_t mtk_afe_pcm_pointer
|
||||
(struct snd_pcm_substream *substream)
|
||||
snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
|
||||
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
|
||||
struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
|
||||
const struct mtk_base_memif_data *memif_data = memif->data;
|
||||
|
|
@ -111,18 +110,13 @@ static snd_pcm_uframes_t mtk_afe_pcm_pointer
|
|||
POINTER_RETURN_FRAMES:
|
||||
return bytes_to_frames(substream->runtime, pcm_ptr_bytes);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_afe_pcm_pointer);
|
||||
|
||||
const struct snd_pcm_ops mtk_afe_pcm_ops = {
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.pointer = mtk_afe_pcm_pointer,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(mtk_afe_pcm_ops);
|
||||
|
||||
int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
int mtk_afe_pcm_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
size_t size;
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
|
||||
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
|
||||
|
||||
size = afe->mtk_afe_hardware->buffer_bytes_max;
|
||||
|
|
@ -132,17 +126,19 @@ int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_afe_pcm_new);
|
||||
|
||||
void mtk_afe_pcm_free(struct snd_pcm *pcm)
|
||||
void mtk_afe_pcm_free(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm)
|
||||
{
|
||||
snd_pcm_lib_preallocate_free_for_all(pcm);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_afe_pcm_free);
|
||||
|
||||
const struct snd_soc_component_driver mtk_afe_pcm_platform = {
|
||||
.name = AFE_PCM_NAME,
|
||||
.ops = &mtk_afe_pcm_ops,
|
||||
.pcm_new = mtk_afe_pcm_new,
|
||||
.pcm_free = mtk_afe_pcm_free,
|
||||
.name = AFE_PCM_NAME,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.pointer = mtk_afe_pcm_pointer,
|
||||
.pcm_construct = mtk_afe_pcm_new,
|
||||
.pcm_destruct = mtk_afe_pcm_free,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(mtk_afe_pcm_platform);
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
#define _MTK_AFE_PLATFORM_DRIVER_H_
|
||||
|
||||
#define AFE_PCM_NAME "mtk-afe-pcm"
|
||||
extern const struct snd_pcm_ops mtk_afe_pcm_ops;
|
||||
extern const struct snd_soc_component_driver mtk_afe_pcm_platform;
|
||||
|
||||
struct mtk_base_afe;
|
||||
|
|
@ -18,9 +17,12 @@ struct snd_pcm;
|
|||
struct snd_soc_component;
|
||||
struct snd_soc_pcm_runtime;
|
||||
|
||||
|
||||
int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd);
|
||||
void mtk_afe_pcm_free(struct snd_pcm *pcm);
|
||||
snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream);
|
||||
int mtk_afe_pcm_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd);
|
||||
void mtk_afe_pcm_free(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm);
|
||||
|
||||
int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe);
|
||||
int mtk_afe_add_sub_dai_control(struct snd_soc_component *component);
|
||||
|
|
|
|||
|
|
@ -875,11 +875,9 @@ static const struct snd_pcm_hardware mtk_btcvsd_hardware = {
|
|||
.fifo_size = 0,
|
||||
};
|
||||
|
||||
static int mtk_pcm_btcvsd_open(struct snd_pcm_substream *substream)
|
||||
static int mtk_pcm_btcvsd_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component =
|
||||
snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME);
|
||||
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component);
|
||||
int ret;
|
||||
|
||||
|
|
@ -899,11 +897,9 @@ static int mtk_pcm_btcvsd_open(struct snd_pcm_substream *substream)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int mtk_pcm_btcvsd_close(struct snd_pcm_substream *substream)
|
||||
static int mtk_pcm_btcvsd_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component =
|
||||
snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME);
|
||||
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component);
|
||||
struct mtk_btcvsd_snd_stream *bt_stream = get_bt_stream(bt, substream);
|
||||
|
||||
|
|
@ -914,12 +910,10 @@ static int mtk_pcm_btcvsd_close(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_pcm_btcvsd_hw_params(struct snd_pcm_substream *substream,
|
||||
static int mtk_pcm_btcvsd_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component =
|
||||
snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME);
|
||||
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
|
||||
|
|
@ -934,11 +928,9 @@ static int mtk_pcm_btcvsd_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_pcm_btcvsd_hw_free(struct snd_pcm_substream *substream)
|
||||
static int mtk_pcm_btcvsd_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component =
|
||||
snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME);
|
||||
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
|
|
@ -947,11 +939,9 @@ static int mtk_pcm_btcvsd_hw_free(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_pcm_btcvsd_prepare(struct snd_pcm_substream *substream)
|
||||
static int mtk_pcm_btcvsd_prepare(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component =
|
||||
snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME);
|
||||
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component);
|
||||
struct mtk_btcvsd_snd_stream *bt_stream = get_bt_stream(bt, substream);
|
||||
|
||||
|
|
@ -961,11 +951,9 @@ static int mtk_pcm_btcvsd_prepare(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_pcm_btcvsd_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
static int mtk_pcm_btcvsd_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component =
|
||||
snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME);
|
||||
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component);
|
||||
struct mtk_btcvsd_snd_stream *bt_stream = get_bt_stream(bt, substream);
|
||||
int stream = substream->stream;
|
||||
|
|
@ -993,12 +981,10 @@ static int mtk_pcm_btcvsd_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
}
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t mtk_pcm_btcvsd_pointer
|
||||
(struct snd_pcm_substream *substream)
|
||||
static snd_pcm_uframes_t mtk_pcm_btcvsd_pointer(
|
||||
struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component =
|
||||
snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME);
|
||||
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component);
|
||||
struct mtk_btcvsd_snd_stream *bt_stream;
|
||||
snd_pcm_uframes_t frame = 0;
|
||||
|
|
@ -1044,13 +1030,11 @@ static snd_pcm_uframes_t mtk_pcm_btcvsd_pointer
|
|||
return frame;
|
||||
}
|
||||
|
||||
static int mtk_pcm_btcvsd_copy(struct snd_pcm_substream *substream,
|
||||
static int mtk_pcm_btcvsd_copy(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
int channel, unsigned long pos,
|
||||
void __user *buf, unsigned long count)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component =
|
||||
snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME);
|
||||
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
|
|
@ -1061,18 +1045,6 @@ static int mtk_pcm_btcvsd_copy(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_pcm_ops mtk_btcvsd_ops = {
|
||||
.open = mtk_pcm_btcvsd_open,
|
||||
.close = mtk_pcm_btcvsd_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = mtk_pcm_btcvsd_hw_params,
|
||||
.hw_free = mtk_pcm_btcvsd_hw_free,
|
||||
.prepare = mtk_pcm_btcvsd_prepare,
|
||||
.trigger = mtk_pcm_btcvsd_trigger,
|
||||
.pointer = mtk_pcm_btcvsd_pointer,
|
||||
.copy_user = mtk_pcm_btcvsd_copy,
|
||||
};
|
||||
|
||||
/* kcontrol */
|
||||
static const char *const btsco_band_str[] = {"NB", "WB"};
|
||||
|
||||
|
|
@ -1295,9 +1267,17 @@ static int mtk_btcvsd_snd_component_probe(struct snd_soc_component *component)
|
|||
}
|
||||
|
||||
static const struct snd_soc_component_driver mtk_btcvsd_snd_platform = {
|
||||
.name = BTCVSD_SND_NAME,
|
||||
.ops = &mtk_btcvsd_ops,
|
||||
.probe = mtk_btcvsd_snd_component_probe,
|
||||
.name = BTCVSD_SND_NAME,
|
||||
.probe = mtk_btcvsd_snd_component_probe,
|
||||
.open = mtk_pcm_btcvsd_open,
|
||||
.close = mtk_pcm_btcvsd_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = mtk_pcm_btcvsd_hw_params,
|
||||
.hw_free = mtk_pcm_btcvsd_hw_free,
|
||||
.prepare = mtk_pcm_btcvsd_prepare,
|
||||
.trigger = mtk_pcm_btcvsd_trigger,
|
||||
.pointer = mtk_pcm_btcvsd_pointer,
|
||||
.copy_user = mtk_pcm_btcvsd_copy,
|
||||
};
|
||||
|
||||
static int mtk_btcvsd_snd_probe(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -710,11 +710,12 @@ static int mt6797_afe_component_probe(struct snd_soc_component *component)
|
|||
}
|
||||
|
||||
static const struct snd_soc_component_driver mt6797_afe_component = {
|
||||
.name = AFE_PCM_NAME,
|
||||
.ops = &mtk_afe_pcm_ops,
|
||||
.pcm_new = mtk_afe_pcm_new,
|
||||
.pcm_free = mtk_afe_pcm_free,
|
||||
.probe = mt6797_afe_component_probe,
|
||||
.name = AFE_PCM_NAME,
|
||||
.probe = mt6797_afe_component_probe,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.pointer = mtk_afe_pcm_pointer,
|
||||
.pcm_construct = mtk_afe_pcm_new,
|
||||
.pcm_destruct = mtk_afe_pcm_free,
|
||||
};
|
||||
|
||||
static int mt6797_dai_memif_register(struct mtk_base_afe *afe)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include "mt8183-afe-common.h"
|
||||
#include "mt8183-afe-clk.h"
|
||||
|
|
@ -1047,11 +1048,12 @@ static int mt8183_afe_component_probe(struct snd_soc_component *component)
|
|||
}
|
||||
|
||||
static const struct snd_soc_component_driver mt8183_afe_component = {
|
||||
.name = AFE_PCM_NAME,
|
||||
.ops = &mtk_afe_pcm_ops,
|
||||
.pcm_new = mtk_afe_pcm_new,
|
||||
.pcm_free = mtk_afe_pcm_free,
|
||||
.probe = mt8183_afe_component_probe,
|
||||
.name = AFE_PCM_NAME,
|
||||
.probe = mt8183_afe_component_probe,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.pointer = mtk_afe_pcm_pointer,
|
||||
.pcm_construct = mtk_afe_pcm_new,
|
||||
.pcm_destruct = mtk_afe_pcm_free,
|
||||
};
|
||||
|
||||
static int mt8183_dai_memif_register(struct mtk_base_afe *afe)
|
||||
|
|
@ -1089,6 +1091,7 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev)
|
|||
struct mtk_base_afe *afe;
|
||||
struct mt8183_afe_private *afe_priv;
|
||||
struct device *dev;
|
||||
struct reset_control *rstc;
|
||||
int i, irq_id, ret;
|
||||
|
||||
afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
|
||||
|
|
@ -1126,6 +1129,19 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
rstc = devm_reset_control_get(dev, "audiosys");
|
||||
if (IS_ERR(rstc)) {
|
||||
ret = PTR_ERR(rstc);
|
||||
dev_err(dev, "could not get audiosys reset:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = reset_control_reset(rstc);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to trigger audio reset:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* enable clock for regcache get default value from hw */
|
||||
afe_priv->pm_runtime_bypass_reg_ctl = true;
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
|
|
|
|||
|
|
@ -70,7 +70,8 @@ static void __dma_enable(struct axg_fifo *fifo, bool enable)
|
|||
enable ? CTRL0_DMA_EN : 0);
|
||||
}
|
||||
|
||||
static int axg_fifo_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
|
||||
int axg_fifo_pcm_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *ss, int cmd)
|
||||
{
|
||||
struct axg_fifo *fifo = axg_fifo_data(ss);
|
||||
|
||||
|
|
@ -91,8 +92,10 @@ static int axg_fifo_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(axg_fifo_pcm_trigger);
|
||||
|
||||
static snd_pcm_uframes_t axg_fifo_pcm_pointer(struct snd_pcm_substream *ss)
|
||||
snd_pcm_uframes_t axg_fifo_pcm_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *ss)
|
||||
{
|
||||
struct axg_fifo *fifo = axg_fifo_data(ss);
|
||||
struct snd_pcm_runtime *runtime = ss->runtime;
|
||||
|
|
@ -102,9 +105,11 @@ static snd_pcm_uframes_t axg_fifo_pcm_pointer(struct snd_pcm_substream *ss)
|
|||
|
||||
return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(axg_fifo_pcm_pointer);
|
||||
|
||||
static int axg_fifo_pcm_hw_params(struct snd_pcm_substream *ss,
|
||||
struct snd_pcm_hw_params *params)
|
||||
int axg_fifo_pcm_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *ss,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = ss->runtime;
|
||||
struct axg_fifo *fifo = axg_fifo_data(ss);
|
||||
|
|
@ -132,15 +137,17 @@ static int axg_fifo_pcm_hw_params(struct snd_pcm_substream *ss,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(axg_fifo_pcm_hw_params);
|
||||
|
||||
static int g12a_fifo_pcm_hw_params(struct snd_pcm_substream *ss,
|
||||
struct snd_pcm_hw_params *params)
|
||||
int g12a_fifo_pcm_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *ss,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct axg_fifo *fifo = axg_fifo_data(ss);
|
||||
struct snd_pcm_runtime *runtime = ss->runtime;
|
||||
int ret;
|
||||
|
||||
ret = axg_fifo_pcm_hw_params(ss, params);
|
||||
ret = axg_fifo_pcm_hw_params(component, ss, params);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -149,8 +156,10 @@ static int g12a_fifo_pcm_hw_params(struct snd_pcm_substream *ss,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(g12a_fifo_pcm_hw_params);
|
||||
|
||||
static int axg_fifo_pcm_hw_free(struct snd_pcm_substream *ss)
|
||||
int axg_fifo_pcm_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *ss)
|
||||
{
|
||||
struct axg_fifo *fifo = axg_fifo_data(ss);
|
||||
|
||||
|
|
@ -160,6 +169,7 @@ static int axg_fifo_pcm_hw_free(struct snd_pcm_substream *ss)
|
|||
|
||||
return snd_pcm_lib_free_pages(ss);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(axg_fifo_pcm_hw_free);
|
||||
|
||||
static void axg_fifo_ack_irq(struct axg_fifo *fifo, u8 mask)
|
||||
{
|
||||
|
|
@ -194,7 +204,8 @@ static irqreturn_t axg_fifo_pcm_irq_block(int irq, void *dev_id)
|
|||
return IRQ_RETVAL(status);
|
||||
}
|
||||
|
||||
static int axg_fifo_pcm_open(struct snd_pcm_substream *ss)
|
||||
int axg_fifo_pcm_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *ss)
|
||||
{
|
||||
struct axg_fifo *fifo = axg_fifo_data(ss);
|
||||
struct device *dev = axg_fifo_dev(ss);
|
||||
|
|
@ -250,8 +261,10 @@ static int axg_fifo_pcm_open(struct snd_pcm_substream *ss)
|
|||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(axg_fifo_pcm_open);
|
||||
|
||||
static int axg_fifo_pcm_close(struct snd_pcm_substream *ss)
|
||||
int axg_fifo_pcm_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *ss)
|
||||
{
|
||||
struct axg_fifo *fifo = axg_fifo_data(ss);
|
||||
int ret;
|
||||
|
|
@ -267,28 +280,7 @@ static int axg_fifo_pcm_close(struct snd_pcm_substream *ss)
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct snd_pcm_ops axg_fifo_pcm_ops = {
|
||||
.open = axg_fifo_pcm_open,
|
||||
.close = axg_fifo_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = axg_fifo_pcm_hw_params,
|
||||
.hw_free = axg_fifo_pcm_hw_free,
|
||||
.pointer = axg_fifo_pcm_pointer,
|
||||
.trigger = axg_fifo_pcm_trigger,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(axg_fifo_pcm_ops);
|
||||
|
||||
const struct snd_pcm_ops g12a_fifo_pcm_ops = {
|
||||
.open = axg_fifo_pcm_open,
|
||||
.close = axg_fifo_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = g12a_fifo_pcm_hw_params,
|
||||
.hw_free = axg_fifo_pcm_hw_free,
|
||||
.pointer = axg_fifo_pcm_pointer,
|
||||
.trigger = axg_fifo_pcm_trigger,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(g12a_fifo_pcm_ops);
|
||||
EXPORT_SYMBOL_GPL(axg_fifo_pcm_close);
|
||||
|
||||
int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ struct reset_control;
|
|||
struct snd_soc_component_driver;
|
||||
struct snd_soc_dai;
|
||||
struct snd_soc_dai_driver;
|
||||
struct snd_pcm_ops;
|
||||
|
||||
struct snd_soc_pcm_runtime;
|
||||
|
||||
#define AXG_FIFO_CH_MAX 128
|
||||
|
|
@ -75,8 +75,22 @@ struct axg_fifo_match_data {
|
|||
struct snd_soc_dai_driver *dai_drv;
|
||||
};
|
||||
|
||||
extern const struct snd_pcm_ops axg_fifo_pcm_ops;
|
||||
extern const struct snd_pcm_ops g12a_fifo_pcm_ops;
|
||||
int axg_fifo_pcm_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *ss);
|
||||
int axg_fifo_pcm_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *ss);
|
||||
int axg_fifo_pcm_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *ss,
|
||||
struct snd_pcm_hw_params *params);
|
||||
int g12a_fifo_pcm_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *ss,
|
||||
struct snd_pcm_hw_params *params);
|
||||
int axg_fifo_pcm_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *ss);
|
||||
snd_pcm_uframes_t axg_fifo_pcm_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *ss);
|
||||
int axg_fifo_pcm_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *ss, int cmd);
|
||||
|
||||
int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type);
|
||||
int axg_fifo_probe(struct platform_device *pdev);
|
||||
|
|
|
|||
|
|
@ -149,7 +149,13 @@ static const struct snd_soc_component_driver axg_frddr_component_drv = {
|
|||
.num_dapm_widgets = ARRAY_SIZE(axg_frddr_dapm_widgets),
|
||||
.dapm_routes = axg_frddr_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(axg_frddr_dapm_routes),
|
||||
.ops = &axg_fifo_pcm_ops
|
||||
.open = axg_fifo_pcm_open,
|
||||
.close = axg_fifo_pcm_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = axg_fifo_pcm_hw_params,
|
||||
.hw_free = axg_fifo_pcm_hw_free,
|
||||
.pointer = axg_fifo_pcm_pointer,
|
||||
.trigger = axg_fifo_pcm_trigger,
|
||||
};
|
||||
|
||||
static const struct axg_fifo_match_data axg_frddr_match_data = {
|
||||
|
|
@ -267,7 +273,13 @@ static const struct snd_soc_component_driver g12a_frddr_component_drv = {
|
|||
.num_dapm_widgets = ARRAY_SIZE(g12a_frddr_dapm_widgets),
|
||||
.dapm_routes = g12a_frddr_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(g12a_frddr_dapm_routes),
|
||||
.ops = &g12a_fifo_pcm_ops
|
||||
.open = axg_fifo_pcm_open,
|
||||
.close = axg_fifo_pcm_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = g12a_fifo_pcm_hw_params,
|
||||
.hw_free = axg_fifo_pcm_hw_free,
|
||||
.pointer = axg_fifo_pcm_pointer,
|
||||
.trigger = axg_fifo_pcm_trigger,
|
||||
};
|
||||
|
||||
static const struct axg_fifo_match_data g12a_frddr_match_data = {
|
||||
|
|
@ -331,7 +343,13 @@ static const struct snd_soc_component_driver sm1_frddr_component_drv = {
|
|||
.num_dapm_widgets = ARRAY_SIZE(sm1_frddr_dapm_widgets),
|
||||
.dapm_routes = g12a_frddr_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(g12a_frddr_dapm_routes),
|
||||
.ops = &g12a_fifo_pcm_ops
|
||||
.open = axg_fifo_pcm_open,
|
||||
.close = axg_fifo_pcm_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = g12a_fifo_pcm_hw_params,
|
||||
.hw_free = axg_fifo_pcm_hw_free,
|
||||
.pointer = axg_fifo_pcm_pointer,
|
||||
.trigger = axg_fifo_pcm_trigger,
|
||||
};
|
||||
|
||||
static const struct axg_fifo_match_data sm1_frddr_match_data = {
|
||||
|
|
|
|||
|
|
@ -181,7 +181,13 @@ static const struct snd_soc_component_driver axg_toddr_component_drv = {
|
|||
.num_dapm_widgets = ARRAY_SIZE(axg_toddr_dapm_widgets),
|
||||
.dapm_routes = axg_toddr_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(axg_toddr_dapm_routes),
|
||||
.ops = &axg_fifo_pcm_ops
|
||||
.open = axg_fifo_pcm_open,
|
||||
.close = axg_fifo_pcm_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = axg_fifo_pcm_hw_params,
|
||||
.hw_free = axg_fifo_pcm_hw_free,
|
||||
.pointer = axg_fifo_pcm_pointer,
|
||||
.trigger = axg_fifo_pcm_trigger,
|
||||
};
|
||||
|
||||
static const struct axg_fifo_match_data axg_toddr_match_data = {
|
||||
|
|
@ -214,7 +220,13 @@ static const struct snd_soc_component_driver g12a_toddr_component_drv = {
|
|||
.num_dapm_widgets = ARRAY_SIZE(axg_toddr_dapm_widgets),
|
||||
.dapm_routes = axg_toddr_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(axg_toddr_dapm_routes),
|
||||
.ops = &g12a_fifo_pcm_ops
|
||||
.open = axg_fifo_pcm_open,
|
||||
.close = axg_fifo_pcm_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = g12a_fifo_pcm_hw_params,
|
||||
.hw_free = axg_fifo_pcm_hw_free,
|
||||
.pointer = axg_fifo_pcm_pointer,
|
||||
.trigger = axg_fifo_pcm_trigger,
|
||||
};
|
||||
|
||||
static const struct axg_fifo_match_data g12a_toddr_match_data = {
|
||||
|
|
@ -278,7 +290,13 @@ static const struct snd_soc_component_driver sm1_toddr_component_drv = {
|
|||
.num_dapm_widgets = ARRAY_SIZE(sm1_toddr_dapm_widgets),
|
||||
.dapm_routes = sm1_toddr_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(sm1_toddr_dapm_routes),
|
||||
.ops = &g12a_fifo_pcm_ops
|
||||
.open = axg_fifo_pcm_open,
|
||||
.close = axg_fifo_pcm_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = g12a_fifo_pcm_hw_params,
|
||||
.hw_free = axg_fifo_pcm_hw_free,
|
||||
.pointer = axg_fifo_pcm_pointer,
|
||||
.trigger = axg_fifo_pcm_trigger,
|
||||
};
|
||||
|
||||
static const struct axg_fifo_match_data sm1_toddr_match_data = {
|
||||
|
|
|
|||
|
|
@ -55,8 +55,9 @@ static struct snd_pcm_hardware mmp_pcm_hardware[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static int mmp_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
static int mmp_pcm_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
|
||||
struct dma_slave_config slave_config;
|
||||
|
|
@ -77,6 +78,18 @@ static int mmp_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mmp_pcm_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
return snd_dmaengine_pcm_trigger(substream, cmd);
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t mmp_pcm_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_dmaengine_pcm_pointer(substream);
|
||||
}
|
||||
|
||||
static bool filter(struct dma_chan *chan, void *param)
|
||||
{
|
||||
struct mmp_dma_data *dma_data = param;
|
||||
|
|
@ -94,10 +107,10 @@ static bool filter(struct dma_chan *chan, void *param)
|
|||
return found;
|
||||
}
|
||||
|
||||
static int mmp_pcm_open(struct snd_pcm_substream *substream)
|
||||
static int mmp_pcm_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct platform_device *pdev = to_platform_device(component->dev);
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct mmp_dma_data dma_data;
|
||||
|
|
@ -117,8 +130,15 @@ static int mmp_pcm_open(struct snd_pcm_substream *substream)
|
|||
&dma_data);
|
||||
}
|
||||
|
||||
static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
static int mmp_pcm_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_dmaengine_pcm_close_release_chan(substream);
|
||||
}
|
||||
|
||||
static int mmp_pcm_mmap(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
unsigned long off = vma->vm_pgoff;
|
||||
|
|
@ -129,17 +149,8 @@ static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
|
|||
vma->vm_end - vma->vm_start, vma->vm_page_prot);
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops mmp_pcm_ops = {
|
||||
.open = mmp_pcm_open,
|
||||
.close = snd_dmaengine_pcm_close_release_chan,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = mmp_pcm_hw_params,
|
||||
.trigger = snd_dmaengine_pcm_trigger,
|
||||
.pointer = snd_dmaengine_pcm_pointer,
|
||||
.mmap = mmp_pcm_mmap,
|
||||
};
|
||||
|
||||
static void mmp_pcm_free_dma_buffers(struct snd_pcm *pcm)
|
||||
static void mmp_pcm_free_dma_buffers(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm)
|
||||
{
|
||||
struct snd_pcm_substream *substream;
|
||||
struct snd_dma_buffer *buf;
|
||||
|
|
@ -188,7 +199,8 @@ static int mmp_pcm_preallocate_dma_buffer(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mmp_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int mmp_pcm_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_pcm_substream *substream;
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
|
|
@ -205,15 +217,21 @@ static int mmp_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
|||
return 0;
|
||||
|
||||
err:
|
||||
mmp_pcm_free_dma_buffers(pcm);
|
||||
mmp_pcm_free_dma_buffers(component, pcm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_soc_component_driver mmp_soc_component = {
|
||||
.name = DRV_NAME,
|
||||
.ops = &mmp_pcm_ops,
|
||||
.pcm_new = mmp_pcm_new,
|
||||
.pcm_free = mmp_pcm_free_dma_buffers,
|
||||
.open = mmp_pcm_open,
|
||||
.close = mmp_pcm_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = mmp_pcm_hw_params,
|
||||
.trigger = mmp_pcm_trigger,
|
||||
.pointer = mmp_pcm_pointer,
|
||||
.mmap = mmp_pcm_mmap,
|
||||
.pcm_construct = mmp_pcm_new,
|
||||
.pcm_destruct = mmp_pcm_free_dma_buffers,
|
||||
};
|
||||
|
||||
static int mmp_pcm_probe(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -869,9 +869,17 @@ static struct snd_soc_dai_driver pxa_ssp_dai = {
|
|||
|
||||
static const struct snd_soc_component_driver pxa_ssp_component = {
|
||||
.name = "pxa-ssp",
|
||||
.ops = &pxa2xx_pcm_ops,
|
||||
.pcm_new = pxa2xx_soc_pcm_new,
|
||||
.pcm_free = pxa2xx_pcm_free_dma_buffers,
|
||||
.pcm_construct = pxa2xx_soc_pcm_new,
|
||||
.pcm_destruct = pxa2xx_soc_pcm_free,
|
||||
.open = pxa2xx_soc_pcm_open,
|
||||
.close = pxa2xx_soc_pcm_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = pxa2xx_soc_pcm_hw_params,
|
||||
.hw_free = pxa2xx_soc_pcm_hw_free,
|
||||
.prepare = pxa2xx_soc_pcm_prepare,
|
||||
.trigger = pxa2xx_soc_pcm_trigger,
|
||||
.pointer = pxa2xx_soc_pcm_pointer,
|
||||
.mmap = pxa2xx_soc_pcm_mmap,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
|
|
|||
|
|
@ -204,9 +204,17 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = {
|
|||
|
||||
static const struct snd_soc_component_driver pxa_ac97_component = {
|
||||
.name = "pxa-ac97",
|
||||
.ops = &pxa2xx_pcm_ops,
|
||||
.pcm_new = pxa2xx_soc_pcm_new,
|
||||
.pcm_free = pxa2xx_pcm_free_dma_buffers,
|
||||
.pcm_construct = pxa2xx_soc_pcm_new,
|
||||
.pcm_destruct = pxa2xx_soc_pcm_free,
|
||||
.open = pxa2xx_soc_pcm_open,
|
||||
.close = pxa2xx_soc_pcm_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = pxa2xx_soc_pcm_hw_params,
|
||||
.hw_free = pxa2xx_soc_pcm_hw_free,
|
||||
.prepare = pxa2xx_soc_pcm_prepare,
|
||||
.trigger = pxa2xx_soc_pcm_trigger,
|
||||
.pointer = pxa2xx_soc_pcm_pointer,
|
||||
.mmap = pxa2xx_soc_pcm_mmap,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
|
|
|||
|
|
@ -360,9 +360,17 @@ static struct snd_soc_dai_driver pxa_i2s_dai = {
|
|||
|
||||
static const struct snd_soc_component_driver pxa_i2s_component = {
|
||||
.name = "pxa-i2s",
|
||||
.ops = &pxa2xx_pcm_ops,
|
||||
.pcm_new = pxa2xx_soc_pcm_new,
|
||||
.pcm_free = pxa2xx_pcm_free_dma_buffers,
|
||||
.pcm_construct = pxa2xx_soc_pcm_new,
|
||||
.pcm_destruct = pxa2xx_soc_pcm_free,
|
||||
.open = pxa2xx_soc_pcm_open,
|
||||
.close = pxa2xx_soc_pcm_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = pxa2xx_soc_pcm_hw_params,
|
||||
.hw_free = pxa2xx_soc_pcm_hw_free,
|
||||
.prepare = pxa2xx_soc_pcm_prepare,
|
||||
.trigger = pxa2xx_soc_pcm_trigger,
|
||||
.pointer = pxa2xx_soc_pcm_pointer,
|
||||
.mmap = pxa2xx_soc_pcm_mmap,
|
||||
};
|
||||
|
||||
static int pxa2xx_i2s_drv_probe(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -18,9 +18,17 @@
|
|||
#include <sound/dmaengine_pcm.h>
|
||||
|
||||
static const struct snd_soc_component_driver pxa2xx_soc_platform = {
|
||||
.ops = &pxa2xx_pcm_ops,
|
||||
.pcm_new = pxa2xx_soc_pcm_new,
|
||||
.pcm_free = pxa2xx_pcm_free_dma_buffers,
|
||||
.pcm_construct = pxa2xx_soc_pcm_new,
|
||||
.pcm_destruct = pxa2xx_soc_pcm_free,
|
||||
.open = pxa2xx_soc_pcm_open,
|
||||
.close = pxa2xx_soc_pcm_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = pxa2xx_soc_pcm_hw_params,
|
||||
.hw_free = pxa2xx_soc_pcm_hw_free,
|
||||
.prepare = pxa2xx_soc_pcm_prepare,
|
||||
.trigger = pxa2xx_soc_pcm_trigger,
|
||||
.pointer = pxa2xx_soc_pcm_pointer,
|
||||
.mmap = pxa2xx_soc_pcm_mmap,
|
||||
};
|
||||
|
||||
static int pxa2xx_soc_platform_probe(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -50,12 +50,12 @@ static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
|
|||
.fifo_size = 0,
|
||||
};
|
||||
|
||||
static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
|
||||
static int lpass_platform_pcmops_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
|
||||
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
|
||||
struct lpass_variant *v = drvdata->variant;
|
||||
int ret, dma_ch, dir = substream->stream;
|
||||
|
|
@ -105,11 +105,10 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lpass_platform_pcmops_close(struct snd_pcm_substream *substream)
|
||||
static int lpass_platform_pcmops_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
|
||||
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
|
||||
struct lpass_variant *v = drvdata->variant;
|
||||
struct lpass_pcm_data *data;
|
||||
|
|
@ -122,11 +121,11 @@ static int lpass_platform_pcmops_close(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
|
||||
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
|
||||
struct snd_pcm_runtime *rt = substream->runtime;
|
||||
struct lpass_pcm_data *pcm_data = rt->private_data;
|
||||
|
|
@ -216,10 +215,10 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
|
||||
static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
|
||||
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
|
||||
struct snd_pcm_runtime *rt = substream->runtime;
|
||||
struct lpass_pcm_data *pcm_data = rt->private_data;
|
||||
|
|
@ -236,11 +235,11 @@ static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
|
||||
static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
|
||||
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
|
||||
struct snd_pcm_runtime *rt = substream->runtime;
|
||||
struct lpass_pcm_data *pcm_data = rt->private_data;
|
||||
|
|
@ -288,11 +287,11 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
|
||||
int cmd)
|
||||
static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
int cmd)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
|
||||
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
|
||||
struct snd_pcm_runtime *rt = substream->runtime;
|
||||
struct lpass_pcm_data *pcm_data = rt->private_data;
|
||||
|
|
@ -363,10 +362,10 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
|
|||
}
|
||||
|
||||
static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
|
||||
struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
|
||||
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
|
||||
struct snd_pcm_runtime *rt = substream->runtime;
|
||||
struct lpass_pcm_data *pcm_data = rt->private_data;
|
||||
|
|
@ -395,8 +394,9 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
|
|||
return bytes_to_frames(substream->runtime, curr_addr - base_addr);
|
||||
}
|
||||
|
||||
static int lpass_platform_pcmops_mmap(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
static int lpass_platform_pcmops_mmap(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
||||
|
|
@ -405,18 +405,6 @@ static int lpass_platform_pcmops_mmap(struct snd_pcm_substream *substream,
|
|||
runtime->dma_bytes);
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops lpass_platform_pcm_ops = {
|
||||
.open = lpass_platform_pcmops_open,
|
||||
.close = lpass_platform_pcmops_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = lpass_platform_pcmops_hw_params,
|
||||
.hw_free = lpass_platform_pcmops_hw_free,
|
||||
.prepare = lpass_platform_pcmops_prepare,
|
||||
.trigger = lpass_platform_pcmops_trigger,
|
||||
.pointer = lpass_platform_pcmops_pointer,
|
||||
.mmap = lpass_platform_pcmops_mmap,
|
||||
};
|
||||
|
||||
static irqreturn_t lpass_dma_interrupt_handler(
|
||||
struct snd_pcm_substream *substream,
|
||||
struct lpass_data *drvdata,
|
||||
|
|
@ -499,11 +487,11 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
|
||||
static int lpass_platform_pcm_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *soc_runtime)
|
||||
{
|
||||
struct snd_pcm *pcm = soc_runtime->pcm;
|
||||
struct snd_pcm_substream *psubstream, *csubstream;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
|
||||
int ret = -EINVAL;
|
||||
size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
|
||||
|
||||
|
|
@ -535,7 +523,8 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void lpass_platform_pcm_free(struct snd_pcm *pcm)
|
||||
static void lpass_platform_pcm_free(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm)
|
||||
{
|
||||
struct snd_pcm_substream *substream;
|
||||
int i;
|
||||
|
|
@ -552,9 +541,18 @@ static void lpass_platform_pcm_free(struct snd_pcm *pcm)
|
|||
|
||||
static const struct snd_soc_component_driver lpass_component_driver = {
|
||||
.name = DRV_NAME,
|
||||
.pcm_new = lpass_platform_pcm_new,
|
||||
.pcm_free = lpass_platform_pcm_free,
|
||||
.ops = &lpass_platform_pcm_ops,
|
||||
.open = lpass_platform_pcmops_open,
|
||||
.close = lpass_platform_pcmops_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = lpass_platform_pcmops_hw_params,
|
||||
.hw_free = lpass_platform_pcmops_hw_free,
|
||||
.prepare = lpass_platform_pcmops_prepare,
|
||||
.trigger = lpass_platform_pcmops_trigger,
|
||||
.pointer = lpass_platform_pcmops_pointer,
|
||||
.mmap = lpass_platform_pcmops_mmap,
|
||||
.pcm_construct = lpass_platform_pcm_new,
|
||||
.pcm_destruct = lpass_platform_pcm_free,
|
||||
|
||||
};
|
||||
|
||||
int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -206,16 +206,16 @@ static void event_handler(uint32_t opcode, uint32_t token,
|
|||
}
|
||||
}
|
||||
|
||||
static int q6asm_dai_prepare(struct snd_pcm_substream *substream)
|
||||
static int q6asm_dai_prepare(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
|
||||
struct q6asm_dai_rtd *prtd = runtime->private_data;
|
||||
struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
|
||||
struct q6asm_dai_data *pdata;
|
||||
int ret, i;
|
||||
|
||||
pdata = snd_soc_component_get_drvdata(c);
|
||||
pdata = snd_soc_component_get_drvdata(component);
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -294,7 +294,8 @@ static int q6asm_dai_prepare(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int q6asm_dai_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
static int q6asm_dai_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
int ret = 0;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
|
@ -322,21 +323,21 @@ static int q6asm_dai_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int q6asm_dai_open(struct snd_pcm_substream *substream)
|
||||
static int q6asm_dai_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = soc_prtd->cpu_dai;
|
||||
struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
|
||||
struct q6asm_dai_rtd *prtd;
|
||||
struct q6asm_dai_data *pdata;
|
||||
struct device *dev = c->dev;
|
||||
struct device *dev = component->dev;
|
||||
int ret = 0;
|
||||
int stream_id;
|
||||
|
||||
stream_id = cpu_dai->driver->id;
|
||||
|
||||
pdata = snd_soc_component_get_drvdata(c);
|
||||
pdata = snd_soc_component_get_drvdata(component);
|
||||
if (!pdata) {
|
||||
pr_err("Drv data not found ..\n");
|
||||
return -EINVAL;
|
||||
|
|
@ -414,7 +415,8 @@ static int q6asm_dai_open(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int q6asm_dai_close(struct snd_pcm_substream *substream)
|
||||
static int q6asm_dai_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
|
||||
|
|
@ -435,7 +437,8 @@ static int q6asm_dai_close(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t q6asm_dai_pointer(struct snd_pcm_substream *substream)
|
||||
static snd_pcm_uframes_t q6asm_dai_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
|
@ -447,22 +450,21 @@ static snd_pcm_uframes_t q6asm_dai_pointer(struct snd_pcm_substream *substream)
|
|||
return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
|
||||
}
|
||||
|
||||
static int q6asm_dai_mmap(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
static int q6asm_dai_mmap(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
|
||||
struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
|
||||
struct device *dev = c->dev;
|
||||
struct device *dev = component->dev;
|
||||
|
||||
return dma_mmap_coherent(dev, vma,
|
||||
runtime->dma_area, runtime->dma_addr,
|
||||
runtime->dma_bytes);
|
||||
}
|
||||
|
||||
static int q6asm_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
static int q6asm_dai_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct q6asm_dai_rtd *prtd = runtime->private_data;
|
||||
|
|
@ -482,17 +484,6 @@ static int q6asm_dai_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_pcm_ops q6asm_dai_ops = {
|
||||
.open = q6asm_dai_open,
|
||||
.hw_params = q6asm_dai_hw_params,
|
||||
.close = q6asm_dai_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.prepare = q6asm_dai_prepare,
|
||||
.trigger = q6asm_dai_trigger,
|
||||
.pointer = q6asm_dai_pointer,
|
||||
.mmap = q6asm_dai_mmap,
|
||||
};
|
||||
|
||||
static void compress_event_handler(uint32_t opcode, uint32_t token,
|
||||
uint32_t *payload, void *priv)
|
||||
{
|
||||
|
|
@ -800,15 +791,15 @@ static struct snd_compr_ops q6asm_dai_compr_ops = {
|
|||
.ack = q6asm_dai_compr_ack,
|
||||
};
|
||||
|
||||
static int q6asm_dai_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int q6asm_dai_pcm_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_pcm_substream *psubstream, *csubstream;
|
||||
struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
struct device *dev;
|
||||
int size, ret;
|
||||
|
||||
dev = c->dev;
|
||||
dev = component->dev;
|
||||
size = q6asm_dai_hardware_playback.buffer_bytes_max;
|
||||
psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
|
||||
if (psubstream) {
|
||||
|
|
@ -835,7 +826,8 @@ static int q6asm_dai_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void q6asm_dai_pcm_free(struct snd_pcm *pcm)
|
||||
static void q6asm_dai_pcm_free(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm)
|
||||
{
|
||||
struct snd_pcm_substream *substream;
|
||||
int i;
|
||||
|
|
@ -852,9 +844,16 @@ static void q6asm_dai_pcm_free(struct snd_pcm *pcm)
|
|||
|
||||
static const struct snd_soc_component_driver q6asm_fe_dai_component = {
|
||||
.name = DRV_NAME,
|
||||
.ops = &q6asm_dai_ops,
|
||||
.pcm_new = q6asm_dai_pcm_new,
|
||||
.pcm_free = q6asm_dai_pcm_free,
|
||||
.open = q6asm_dai_open,
|
||||
.hw_params = q6asm_dai_hw_params,
|
||||
.close = q6asm_dai_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.prepare = q6asm_dai_prepare,
|
||||
.trigger = q6asm_dai_trigger,
|
||||
.pointer = q6asm_dai_pointer,
|
||||
.mmap = q6asm_dai_mmap,
|
||||
.pcm_construct = q6asm_dai_pcm_new,
|
||||
.pcm_destruct = q6asm_dai_pcm_free,
|
||||
.compr_ops = &q6asm_dai_compr_ops,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -939,12 +939,12 @@ static const struct snd_soc_dapm_route intercon[] = {
|
|||
|
||||
};
|
||||
|
||||
static int routing_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
static int routing_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct msm_routing_data *data = dev_get_drvdata(c->dev);
|
||||
struct msm_routing_data *data = dev_get_drvdata(component->dev);
|
||||
unsigned int be_id = rtd->cpu_dai->id;
|
||||
struct session_data *session;
|
||||
int path_type;
|
||||
|
|
@ -980,10 +980,6 @@ static int routing_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_pcm_ops q6pcm_routing_ops = {
|
||||
.hw_params = routing_hw_params,
|
||||
};
|
||||
|
||||
static int msm_routing_probe(struct snd_soc_component *c)
|
||||
{
|
||||
int i;
|
||||
|
|
@ -997,9 +993,9 @@ static int msm_routing_probe(struct snd_soc_component *c)
|
|||
}
|
||||
|
||||
static const struct snd_soc_component_driver msm_soc_routing_component = {
|
||||
.ops = &q6pcm_routing_ops,
|
||||
.probe = msm_routing_probe,
|
||||
.name = DRV_NAME,
|
||||
.hw_params = routing_hw_params,
|
||||
.dapm_widgets = msm_qdsp6_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(msm_qdsp6_widgets),
|
||||
.dapm_routes = intercon,
|
||||
|
|
|
|||
|
|
@ -194,11 +194,13 @@ config SND_SOC_ODROID
|
|||
help
|
||||
Say Y here to enable audio support for the Odroid XU3/XU4.
|
||||
|
||||
config SND_SOC_ARNDALE_RT5631_ALC5631
|
||||
tristate "Audio support for RT5631(ALC5631) on Arndale Board"
|
||||
depends on I2C
|
||||
select SND_SAMSUNG_I2S
|
||||
select SND_SOC_RT5631
|
||||
config SND_SOC_ARNDALE
|
||||
tristate "Audio support for Arndale Board"
|
||||
depends on I2C
|
||||
select SND_SAMSUNG_I2S
|
||||
select SND_SOC_RT5631
|
||||
select MFD_WM8994
|
||||
select SND_SOC_WM8994
|
||||
|
||||
config SND_SOC_SAMSUNG_TM2_WM5110
|
||||
tristate "SoC I2S Audio support for WM5110 on TM2 board"
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ snd-soc-lowland-objs := lowland.o
|
|||
snd-soc-littlemill-objs := littlemill.o
|
||||
snd-soc-bells-objs := bells.o
|
||||
snd-soc-odroid-objs := odroid.o
|
||||
snd-soc-arndale-rt5631-objs := arndale_rt5631.o
|
||||
snd-soc-arndale-objs := arndale.o
|
||||
snd-soc-tm2-wm5110-objs := tm2_wm5110.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
|
||||
|
|
@ -62,5 +62,5 @@ obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o
|
|||
obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o
|
||||
obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o
|
||||
obj-$(CONFIG_SND_SOC_ODROID) += snd-soc-odroid.o
|
||||
obj-$(CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631) += snd-soc-arndale-rt5631.o
|
||||
obj-$(CONFIG_SND_SOC_ARNDALE) += snd-soc-arndale.o
|
||||
obj-$(CONFIG_SND_SOC_SAMSUNG_TM2_WM5110) += snd-soc-tm2-wm5110.o
|
||||
|
|
|
|||
217
sound/soc/samsung/arndale.c
Normal file
217
sound/soc/samsung/arndale.c
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// Copyright (c) 2014, Insignal Co., Ltd.
|
||||
//
|
||||
// Author: Claude <claude@insginal.co.kr>
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "../codecs/wm8994.h"
|
||||
#include "i2s.h"
|
||||
|
||||
static int arndale_rt5631_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int rfs, ret;
|
||||
unsigned long rclk;
|
||||
|
||||
rfs = 256;
|
||||
|
||||
rclk = params_rate(params) * rfs;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK,
|
||||
0, SND_SOC_CLOCK_OUT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0,
|
||||
0, SND_SOC_CLOCK_OUT);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk, SND_SOC_CLOCK_OUT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_ops arndale_rt5631_ops = {
|
||||
.hw_params = arndale_rt5631_hw_params,
|
||||
};
|
||||
|
||||
static int arndale_wm1811_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
unsigned int rfs, rclk;
|
||||
|
||||
/* Ensure AIF1CLK is >= 3 MHz for optimal performance */
|
||||
if (params_width(params) == 24)
|
||||
rfs = 384;
|
||||
else if (params_rate(params) == 8000 || params_rate(params) == 11025)
|
||||
rfs = 512;
|
||||
else
|
||||
rfs = 256;
|
||||
|
||||
rclk = params_rate(params) * rfs;
|
||||
|
||||
/*
|
||||
* We add 1 to the frequency value to ensure proper EPLL setting
|
||||
* for each audio sampling rate (see epll_24mhz_tbl in drivers/clk/
|
||||
* samsung/clk-exynos5250.c for list of available EPLL rates).
|
||||
* The CODEC uses clk API and the value will be rounded hence the MCLK1
|
||||
* clock's frequency will still be exact multiple of the sample rate.
|
||||
*/
|
||||
return snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1,
|
||||
rclk + 1, SND_SOC_CLOCK_IN);
|
||||
}
|
||||
|
||||
static struct snd_soc_ops arndale_wm1811_ops = {
|
||||
.hw_params = arndale_wm1811_hw_params,
|
||||
};
|
||||
|
||||
SND_SOC_DAILINK_DEFS(rt5631_hifi,
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()),
|
||||
DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5631-aif1")),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
|
||||
static struct snd_soc_dai_link arndale_rt5631_dai[] = {
|
||||
{
|
||||
.name = "RT5631 HiFi",
|
||||
.stream_name = "Primary",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S
|
||||
| SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBS_CFS,
|
||||
.ops = &arndale_rt5631_ops,
|
||||
SND_SOC_DAILINK_REG(rt5631_hifi),
|
||||
},
|
||||
};
|
||||
|
||||
SND_SOC_DAILINK_DEFS(wm1811_hifi,
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()),
|
||||
DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif1")),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
|
||||
static struct snd_soc_dai_link arndale_wm1811_dai[] = {
|
||||
{
|
||||
.name = "WM1811 HiFi",
|
||||
.stream_name = "Primary",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S
|
||||
| SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBM_CFM,
|
||||
.ops = &arndale_wm1811_ops,
|
||||
SND_SOC_DAILINK_REG(wm1811_hifi),
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_card arndale_rt5631 = {
|
||||
.name = "Arndale RT5631",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = arndale_rt5631_dai,
|
||||
.num_links = ARRAY_SIZE(arndale_rt5631_dai),
|
||||
};
|
||||
|
||||
static struct snd_soc_card arndale_wm1811 = {
|
||||
.name = "Arndale WM1811",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = arndale_wm1811_dai,
|
||||
.num_links = ARRAY_SIZE(arndale_wm1811_dai),
|
||||
};
|
||||
|
||||
static void arndale_put_of_nodes(struct snd_soc_card *card)
|
||||
{
|
||||
struct snd_soc_dai_link *dai_link;
|
||||
int i;
|
||||
|
||||
for_each_card_prelinks(card, i, dai_link) {
|
||||
of_node_put(dai_link->cpus->of_node);
|
||||
of_node_put(dai_link->codecs->of_node);
|
||||
}
|
||||
}
|
||||
|
||||
static int arndale_audio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct snd_soc_card *card;
|
||||
struct snd_soc_dai_link *dai_link;
|
||||
int ret;
|
||||
|
||||
card = (struct snd_soc_card *)of_device_get_match_data(&pdev->dev);
|
||||
card->dev = &pdev->dev;
|
||||
dai_link = card->dai_link;
|
||||
|
||||
dai_link->cpus->of_node = of_parse_phandle(np, "samsung,audio-cpu", 0);
|
||||
if (!dai_link->cpus->of_node) {
|
||||
dev_err(&pdev->dev,
|
||||
"Property 'samsung,audio-cpu' missing or invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!dai_link->platforms->name)
|
||||
dai_link->platforms->of_node = dai_link->cpus->of_node;
|
||||
|
||||
dai_link->codecs->of_node = of_parse_phandle(np, "samsung,audio-codec", 0);
|
||||
if (!dai_link->codecs->of_node) {
|
||||
dev_err(&pdev->dev,
|
||||
"Property 'samsung,audio-codec' missing or invalid\n");
|
||||
ret = -EINVAL;
|
||||
goto err_put_of_nodes;
|
||||
}
|
||||
|
||||
ret = devm_snd_soc_register_card(card->dev, card);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
|
||||
goto err_put_of_nodes;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_put_of_nodes:
|
||||
arndale_put_of_nodes(card);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int arndale_audio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
|
||||
arndale_put_of_nodes(card);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id arndale_audio_of_match[] = {
|
||||
{ .compatible = "samsung,arndale-rt5631", .data = &arndale_rt5631 },
|
||||
{ .compatible = "samsung,arndale-alc5631", .data = &arndale_rt5631 },
|
||||
{ .compatible = "samsung,arndale-wm1811", .data = &arndale_wm1811 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, arndale_audio_of_match);
|
||||
|
||||
static struct platform_driver arndale_audio_driver = {
|
||||
.driver = {
|
||||
.name = "arndale-audio",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
.of_match_table = arndale_audio_of_match,
|
||||
},
|
||||
.probe = arndale_audio_probe,
|
||||
.remove = arndale_audio_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(arndale_audio_driver);
|
||||
|
||||
MODULE_AUTHOR("Claude <claude@insignal.co.kr>");
|
||||
MODULE_DESCRIPTION("ALSA SoC Driver for Arndale Board");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// Copyright (c) 2014, Insignal Co., Ltd.
|
||||
//
|
||||
// Author: Claude <claude@insginal.co.kr>
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "i2s.h"
|
||||
|
||||
static int arndale_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int rfs, ret;
|
||||
unsigned long rclk;
|
||||
|
||||
rfs = 256;
|
||||
|
||||
rclk = params_rate(params) * rfs;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK,
|
||||
0, SND_SOC_CLOCK_OUT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0,
|
||||
0, SND_SOC_CLOCK_OUT);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk, SND_SOC_CLOCK_OUT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_ops arndale_ops = {
|
||||
.hw_params = arndale_hw_params,
|
||||
};
|
||||
|
||||
SND_SOC_DAILINK_DEFS(rt5631_hifi,
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()),
|
||||
DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5631-hifi")),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
|
||||
static struct snd_soc_dai_link arndale_rt5631_dai[] = {
|
||||
{
|
||||
.name = "RT5631 HiFi",
|
||||
.stream_name = "Primary",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S
|
||||
| SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBS_CFS,
|
||||
.ops = &arndale_ops,
|
||||
SND_SOC_DAILINK_REG(rt5631_hifi),
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_card arndale_rt5631 = {
|
||||
.name = "Arndale RT5631",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = arndale_rt5631_dai,
|
||||
.num_links = ARRAY_SIZE(arndale_rt5631_dai),
|
||||
};
|
||||
|
||||
static void arndale_put_of_nodes(struct snd_soc_card *card)
|
||||
{
|
||||
struct snd_soc_dai_link *dai_link;
|
||||
int i;
|
||||
|
||||
for_each_card_prelinks(card, i, dai_link) {
|
||||
of_node_put(dai_link->cpus->of_node);
|
||||
of_node_put(dai_link->codecs->of_node);
|
||||
}
|
||||
}
|
||||
|
||||
static int arndale_audio_probe(struct platform_device *pdev)
|
||||
{
|
||||
int n, ret;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct snd_soc_card *card = &arndale_rt5631;
|
||||
|
||||
card->dev = &pdev->dev;
|
||||
|
||||
for (n = 0; np && n < ARRAY_SIZE(arndale_rt5631_dai); n++) {
|
||||
if (!arndale_rt5631_dai[n].cpus->dai_name) {
|
||||
arndale_rt5631_dai[n].cpus->of_node = of_parse_phandle(np,
|
||||
"samsung,audio-cpu", n);
|
||||
|
||||
if (!arndale_rt5631_dai[n].cpus->of_node) {
|
||||
dev_err(&pdev->dev,
|
||||
"Property 'samsung,audio-cpu' missing or invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
if (!arndale_rt5631_dai[n].platforms->name)
|
||||
arndale_rt5631_dai[n].platforms->of_node =
|
||||
arndale_rt5631_dai[n].cpus->of_node;
|
||||
|
||||
arndale_rt5631_dai[n].codecs->name = NULL;
|
||||
arndale_rt5631_dai[n].codecs->of_node = of_parse_phandle(np,
|
||||
"samsung,audio-codec", n);
|
||||
if (!arndale_rt5631_dai[0].codecs->of_node) {
|
||||
dev_err(&pdev->dev,
|
||||
"Property 'samsung,audio-codec' missing or invalid\n");
|
||||
ret = -EINVAL;
|
||||
goto err_put_of_nodes;
|
||||
}
|
||||
}
|
||||
|
||||
ret = devm_snd_soc_register_card(card->dev, card);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
|
||||
goto err_put_of_nodes;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_put_of_nodes:
|
||||
arndale_put_of_nodes(card);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int arndale_audio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
|
||||
arndale_put_of_nodes(card);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id samsung_arndale_rt5631_of_match[] __maybe_unused = {
|
||||
{ .compatible = "samsung,arndale-rt5631", },
|
||||
{ .compatible = "samsung,arndale-alc5631", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, samsung_arndale_rt5631_of_match);
|
||||
|
||||
static struct platform_driver arndale_audio_driver = {
|
||||
.driver = {
|
||||
.name = "arndale-audio",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
.of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match),
|
||||
},
|
||||
.probe = arndale_audio_probe,
|
||||
.remove = arndale_audio_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(arndale_audio_driver);
|
||||
|
||||
MODULE_AUTHOR("Claude <claude@insignal.co.kr>");
|
||||
MODULE_DESCRIPTION("ALSA SoC Driver for Arndale Board");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -137,8 +137,9 @@ static void idma_done(void *id, int bytes_xfer)
|
|||
snd_pcm_period_elapsed(substream);
|
||||
}
|
||||
|
||||
static int idma_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
static int idma_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct idma_ctrl *prtd = substream->runtime->private_data;
|
||||
|
|
@ -163,14 +164,16 @@ static int idma_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int idma_hw_free(struct snd_pcm_substream *substream)
|
||||
static int idma_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
snd_pcm_set_runtime_buffer(substream, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int idma_prepare(struct snd_pcm_substream *substream)
|
||||
static int idma_prepare(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct idma_ctrl *prtd = substream->runtime->private_data;
|
||||
|
||||
|
|
@ -183,7 +186,8 @@ static int idma_prepare(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int idma_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
static int idma_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct idma_ctrl *prtd = substream->runtime->private_data;
|
||||
int ret = 0;
|
||||
|
|
@ -216,7 +220,8 @@ static int idma_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
}
|
||||
|
||||
static snd_pcm_uframes_t
|
||||
idma_pointer(struct snd_pcm_substream *substream)
|
||||
idma_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct idma_ctrl *prtd = runtime->private_data;
|
||||
|
|
@ -233,7 +238,8 @@ static snd_pcm_uframes_t
|
|||
return bytes_to_frames(substream->runtime, res);
|
||||
}
|
||||
|
||||
static int idma_mmap(struct snd_pcm_substream *substream,
|
||||
static int idma_mmap(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
|
@ -278,7 +284,8 @@ static irqreturn_t iis_irq(int irqno, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int idma_open(struct snd_pcm_substream *substream)
|
||||
static int idma_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct idma_ctrl *prtd;
|
||||
|
|
@ -304,7 +311,8 @@ static int idma_open(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int idma_close(struct snd_pcm_substream *substream)
|
||||
static int idma_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct idma_ctrl *prtd = runtime->private_data;
|
||||
|
|
@ -319,19 +327,8 @@ static int idma_close(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops idma_ops = {
|
||||
.open = idma_open,
|
||||
.close = idma_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.trigger = idma_trigger,
|
||||
.pointer = idma_pointer,
|
||||
.mmap = idma_mmap,
|
||||
.hw_params = idma_hw_params,
|
||||
.hw_free = idma_hw_free,
|
||||
.prepare = idma_prepare,
|
||||
};
|
||||
|
||||
static void idma_free(struct snd_pcm *pcm)
|
||||
static void idma_free(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm)
|
||||
{
|
||||
struct snd_pcm_substream *substream;
|
||||
struct snd_dma_buffer *buf;
|
||||
|
|
@ -367,7 +364,8 @@ static int preallocate_idma_buffer(struct snd_pcm *pcm, int stream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int idma_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int idma_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_card *card = rtd->card->snd_card;
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
|
|
@ -394,9 +392,17 @@ void idma_reg_addr_init(void __iomem *regs, dma_addr_t addr)
|
|||
EXPORT_SYMBOL_GPL(idma_reg_addr_init);
|
||||
|
||||
static const struct snd_soc_component_driver asoc_idma_platform = {
|
||||
.ops = &idma_ops,
|
||||
.pcm_new = idma_new,
|
||||
.pcm_free = idma_free,
|
||||
.open = idma_open,
|
||||
.close = idma_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.trigger = idma_trigger,
|
||||
.pointer = idma_pointer,
|
||||
.mmap = idma_mmap,
|
||||
.hw_params = idma_hw_params,
|
||||
.hw_free = idma_hw_free,
|
||||
.prepare = idma_prepare,
|
||||
.pcm_construct = idma_new,
|
||||
.pcm_destruct = idma_free,
|
||||
};
|
||||
|
||||
static int asoc_idma_platform_probe(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -115,7 +115,8 @@ static void camelot_rxdma(void *data)
|
|||
snd_pcm_period_elapsed(cam->rx_ss);
|
||||
}
|
||||
|
||||
static int camelot_pcm_open(struct snd_pcm_substream *substream)
|
||||
static int camelot_pcm_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
|
||||
|
|
@ -148,7 +149,8 @@ static int camelot_pcm_open(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int camelot_pcm_close(struct snd_pcm_substream *substream)
|
||||
static int camelot_pcm_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
|
||||
|
|
@ -168,7 +170,8 @@ static int camelot_pcm_close(struct snd_pcm_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int camelot_hw_params(struct snd_pcm_substream *substream,
|
||||
static int camelot_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
|
|
@ -191,12 +194,14 @@ static int camelot_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int camelot_hw_free(struct snd_pcm_substream *substream)
|
||||
static int camelot_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_pcm_lib_free_pages(substream);
|
||||
}
|
||||
|
||||
static int camelot_prepare(struct snd_pcm_substream *substream)
|
||||
static int camelot_prepare(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
|
|
@ -244,7 +249,8 @@ static inline void dmabrg_rec_dma_stop(struct camelot_pcm *cam)
|
|||
BRGREG(BRGACR) = acr | ACR_RDS;
|
||||
}
|
||||
|
||||
static int camelot_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
static int camelot_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
|
||||
|
|
@ -270,7 +276,8 @@ static int camelot_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t camelot_pos(struct snd_pcm_substream *substream)
|
||||
static snd_pcm_uframes_t camelot_pos(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
|
|
@ -292,18 +299,8 @@ static snd_pcm_uframes_t camelot_pos(struct snd_pcm_substream *substream)
|
|||
return bytes_to_frames(runtime, pos);
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops camelot_pcm_ops = {
|
||||
.open = camelot_pcm_open,
|
||||
.close = camelot_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = camelot_hw_params,
|
||||
.hw_free = camelot_hw_free,
|
||||
.prepare = camelot_prepare,
|
||||
.trigger = camelot_trigger,
|
||||
.pointer = camelot_pos,
|
||||
};
|
||||
|
||||
static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int camelot_pcm_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
|
||||
|
|
@ -319,8 +316,15 @@ static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
|||
}
|
||||
|
||||
static const struct snd_soc_component_driver sh7760_soc_component = {
|
||||
.ops = &camelot_pcm_ops,
|
||||
.pcm_new = camelot_pcm_new,
|
||||
.open = camelot_pcm_open,
|
||||
.close = camelot_pcm_close,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = camelot_hw_params,
|
||||
.hw_free = camelot_hw_free,
|
||||
.prepare = camelot_prepare,
|
||||
.trigger = camelot_trigger,
|
||||
.pointer = camelot_pos,
|
||||
.pcm_construct = camelot_pcm_new,
|
||||
};
|
||||
|
||||
static int sh7760_soc_platform_probe(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -1718,7 +1718,8 @@ static const struct snd_pcm_hardware fsi_pcm_hardware = {
|
|||
.fifo_size = 256,
|
||||
};
|
||||
|
||||
static int fsi_pcm_open(struct snd_pcm_substream *substream)
|
||||
static int fsi_pcm_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
int ret = 0;
|
||||
|
|
@ -1731,19 +1732,22 @@ static int fsi_pcm_open(struct snd_pcm_substream *substream)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int fsi_hw_params(struct snd_pcm_substream *substream,
|
||||
static int fsi_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
{
|
||||
return snd_pcm_lib_malloc_pages(substream,
|
||||
params_buffer_bytes(hw_params));
|
||||
}
|
||||
|
||||
static int fsi_hw_free(struct snd_pcm_substream *substream)
|
||||
static int fsi_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_pcm_lib_free_pages(substream);
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream)
|
||||
static snd_pcm_uframes_t fsi_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct fsi_priv *fsi = fsi_get_priv(substream);
|
||||
struct fsi_stream *io = fsi_stream_get(fsi, substream);
|
||||
|
|
@ -1751,14 +1755,6 @@ static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream)
|
|||
return fsi_sample2frame(fsi, io->buff_sample_pos);
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops fsi_pcm_ops = {
|
||||
.open = fsi_pcm_open,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = fsi_hw_params,
|
||||
.hw_free = fsi_hw_free,
|
||||
.pointer = fsi_pointer,
|
||||
};
|
||||
|
||||
/*
|
||||
* snd_soc_component
|
||||
*/
|
||||
|
|
@ -1766,7 +1762,8 @@ static const struct snd_pcm_ops fsi_pcm_ops = {
|
|||
#define PREALLOC_BUFFER (32 * 1024)
|
||||
#define PREALLOC_BUFFER_MAX (32 * 1024)
|
||||
|
||||
static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
static int fsi_pcm_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
snd_pcm_lib_preallocate_pages_for_all(
|
||||
rtd->pcm,
|
||||
|
|
@ -1817,8 +1814,12 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = {
|
|||
|
||||
static const struct snd_soc_component_driver fsi_soc_component = {
|
||||
.name = "fsi",
|
||||
.ops = &fsi_pcm_ops,
|
||||
.pcm_new = fsi_pcm_new,
|
||||
.open = fsi_pcm_open,
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = fsi_hw_params,
|
||||
.hw_free = fsi_hw_free,
|
||||
.pointer = fsi_pointer,
|
||||
.pcm_construct = fsi_pcm_new,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1373,8 +1373,9 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
|
|||
/*
|
||||
* pcm ops
|
||||
*/
|
||||
static int rsnd_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
static int rsnd_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
{
|
||||
struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
|
||||
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
|
||||
|
|
@ -1421,7 +1422,8 @@ static int rsnd_hw_params(struct snd_pcm_substream *substream,
|
|||
params_buffer_bytes(hw_params));
|
||||
}
|
||||
|
||||
static int rsnd_hw_free(struct snd_pcm_substream *substream)
|
||||
static int rsnd_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
|
||||
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
|
||||
|
|
@ -1435,7 +1437,8 @@ static int rsnd_hw_free(struct snd_pcm_substream *substream)
|
|||
return snd_pcm_lib_free_pages(substream);
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream)
|
||||
static snd_pcm_uframes_t rsnd_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
|
||||
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
|
||||
|
|
@ -1447,13 +1450,6 @@ static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream)
|
|||
return pointer;
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops rsnd_pcm_ops = {
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = rsnd_hw_params,
|
||||
.hw_free = rsnd_hw_free,
|
||||
.pointer = rsnd_pointer,
|
||||
};
|
||||
|
||||
/*
|
||||
* snd_kcontrol
|
||||
*/
|
||||
|
|
@ -1647,8 +1643,11 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
|
|||
* snd_soc_component
|
||||
*/
|
||||
static const struct snd_soc_component_driver rsnd_soc_component = {
|
||||
.ops = &rsnd_pcm_ops,
|
||||
.name = "rsnd",
|
||||
.ioctl = snd_soc_pcm_lib_ioctl,
|
||||
.hw_params = rsnd_hw_params,
|
||||
.hw_free = rsnd_hw_free,
|
||||
.pointer = rsnd_pointer,
|
||||
};
|
||||
|
||||
static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user