Merge branch 'asoc-4.20' into asoc-next

This commit is contained in:
Mark Brown 2018-10-21 16:59:23 +01:00
commit 65dfb6d6dd
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
192 changed files with 8337 additions and 1527 deletions

View File

@ -0,0 +1,54 @@
Analog Devices ADAU1977/ADAU1978/ADAU1979
Datasheets:
http://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1977.pdf
http://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1978.pdf
http://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1979.pdf
This driver supports both the I2C and SPI bus.
Required properties:
- compatible: Should contain one of the following:
"adi,adau1977"
"adi,adau1978"
"adi,adau1979"
- AVDD-supply: analog power supply for the device, please consult
Documentation/devicetree/bindings/regulator/regulator.txt
Optional properties:
- reset-gpio: the reset pin for the chip, for more details consult
Documentation/devicetree/bindings/gpio/gpio.txt
- DVDD-supply: supply voltage for the digital core, please consult
Documentation/devicetree/bindings/regulator/regulator.txt
For required properties on SPI, please consult
Documentation/devicetree/bindings/spi/spi-bus.txt
Required properties on I2C:
- reg: The i2c address. Value depends on the state of ADDR0
and ADDR1, as wired in hardware.
Examples:
adau1977_spi: adau1977@0 {
compatible = "adi,adau1977";
spi-max-frequency = <600000>;
AVDD-supply = <&regulator>;
DVDD-supply = <&regulator_digital>;
reset_gpio = <&gpio 10 GPIO_ACTIVE_LOW>;
};
adau1977_i2c: adau1977@11 {
compatible = "adi,adau1977";
reg = <0x11>;
AVDD-supply = <&regulator>;
DVDD-supply = <&regulator_digital>;
reset_gpio = <&gpio 10 GPIO_ACTIVE_LOW>;
};

View File

@ -0,0 +1,24 @@
* Amlogic Audio PDM input
Required properties:
- compatible: 'amlogic,axg-pdm'
- reg: physical base address of the controller and length of memory
mapped region.
- clocks: list of clock phandle, one for each entry clock-names.
- clock-names: should contain the following:
* "pclk" : peripheral clock.
* "dclk" : pdm digital clock
* "sysclk" : dsp system clock
- #sound-dai-cells: must be 0.
Example of PDM on the A113 SoC:
pdm: audio-controller@ff632000 {
compatible = "amlogic,axg-pdm";
reg = <0x0 0xff632000 0x0 0x34>;
#sound-dai-cells = <0>;
clocks = <&clkc_audio AUD_CLKID_PDM>,
<&clkc_audio AUD_CLKID_PDM_DCLK>,
<&clkc_audio AUD_CLKID_PDM_SYSCLK>;
clock-names = "pclk", "dclk", "sysclk";
};

View File

@ -0,0 +1,17 @@
CS42L51 audio CODEC
Optional properties:
- clocks : a list of phandles + clock-specifiers, one for each entry in
clock-names
- clock-names : must contain "MCLK"
Example:
cs42l51: cs42l51@4a {
compatible = "cirrus,cs42l51";
reg = <0x4a>;
clocks = <&mclk_prov>;
clock-names = "MCLK";
};

View File

@ -0,0 +1,23 @@
MAX98088 audio CODEC
This device supports I2C only.
Required properties:
- compatible: "maxim,max98088" or "maxim,max98089".
- reg: The I2C address of the device.
Optional properties:
- clocks: the clock provider of MCLK, see ../clock/clock-bindings.txt section
"consumer" for more information.
- clock-names: must be set to "mclk"
Example:
max98089: codec@10 {
compatible = "maxim,max98089";
reg = <0x10>;
clocks = <&clks IMX6QDL_CLK_CKO2>;
clock-names = "mclk";
};

View File

@ -0,0 +1,23 @@
Mikroe-PROTO audio board
Required properties:
- compatible: "mikroe,mikroe-proto"
- dai-format: Must be "i2s".
- i2s-controller: The phandle of the I2S controller.
- audio-codec: The phandle of the WM8731 audio codec.
Optional properties:
- model: The user-visible name of this sound complex.
- bitclock-master: Indicates dai-link bit clock master; for details see simple-card.txt (1).
- frame-master: Indicates dai-link frame master; for details see simple-card.txt (1).
(1) : There must be the same master for both bit and frame clocks.
Example:
sound {
compatible = "mikroe,mikroe-proto";
model = "wm8731 @ sama5d2_xplained";
i2s-controller = <&i2s0>;
audio-codec = <&wm8731>;
dai-format = "i2s";
};
};

View File

@ -0,0 +1,16 @@
NAU8822 audio CODEC
This device supports I2C only.
Required properties:
- compatible : "nuvoton,nau8822"
- reg : the I2C address of the device.
Example:
codec: nau8822@1a {
compatible = "nuvoton,nau8822";
reg = <0x1a>;
};

View File

@ -0,0 +1,17 @@
PCM3060 audio CODEC
This driver supports both I2C and SPI.
Required properties:
- compatible: "ti,pcm3060"
- reg : the I2C address of the device for I2C, the chip select
number for SPI.
Examples:
pcm3060: pcm3060@46 {
compatible = "ti,pcm3060";
reg = <0x46>;
};

View File

@ -49,7 +49,7 @@ configuration of each dai. Must contain the following properties.
Usage: required for mi2s interface
Value type: <prop-encoded-array>
Definition: Must be list of serial data lines used by this dai.
should be one or more of the 1-4 sd lines.
should be one or more of the 0-3 sd lines.
- qcom,tdm-sync-mode:
Usage: required for tdm interface
@ -137,42 +137,42 @@ q6afe@4 {
prim-mi2s-rx@16 {
reg = <16>;
qcom,sd-lines = <1 3>;
qcom,sd-lines = <0 2>;
};
prim-mi2s-tx@17 {
reg = <17>;
qcom,sd-lines = <2>;
qcom,sd-lines = <1>;
};
sec-mi2s-rx@18 {
reg = <18>;
qcom,sd-lines = <1 4>;
qcom,sd-lines = <0 3>;
};
sec-mi2s-tx@19 {
reg = <19>;
qcom,sd-lines = <2>;
qcom,sd-lines = <1>;
};
tert-mi2s-rx@20 {
reg = <20>;
qcom,sd-lines = <2 4>;
qcom,sd-lines = <1 3>;
};
tert-mi2s-tx@21 {
reg = <21>;
qcom,sd-lines = <1>;
qcom,sd-lines = <0>;
};
quat-mi2s-rx@22 {
reg = <22>;
qcom,sd-lines = <1>;
qcom,sd-lines = <0>;
};
quat-mi2s-tx@23 {
reg = <23>;
qcom,sd-lines = <2>;
qcom,sd-lines = <1>;
};
};
};

View File

@ -340,10 +340,12 @@ Required properties:
- compatible : "renesas,rcar_sound-<soctype>", fallbacks
"renesas,rcar_sound-gen1" if generation1, and
"renesas,rcar_sound-gen2" if generation2 (or RZ/G1)
"renesas,rcar_sound-gen3" if generation3
"renesas,rcar_sound-gen3" if generation3 (or RZ/G2)
Examples with soctypes are:
- "renesas,rcar_sound-r8a7743" (RZ/G1M)
- "renesas,rcar_sound-r8a7744" (RZ/G1N)
- "renesas,rcar_sound-r8a7745" (RZ/G1E)
- "renesas,rcar_sound-r8a774a1" (RZ/G2M)
- "renesas,rcar_sound-r8a7778" (R-Car M1A)
- "renesas,rcar_sound-r8a7779" (R-Car H1)
- "renesas,rcar_sound-r8a7790" (R-Car H2)
@ -353,6 +355,7 @@ Required properties:
- "renesas,rcar_sound-r8a7795" (R-Car H3)
- "renesas,rcar_sound-r8a7796" (R-Car M3-W)
- "renesas,rcar_sound-r8a77965" (R-Car M3-N)
- "renesas,rcar_sound-r8a77990" (R-Car E3)
- reg : Should contain the register physical address.
required register is
SRU/ADG/SSI if generation1

View File

@ -19,6 +19,10 @@ Required properties:
Optional properties:
- clocks, clock-names: Clock specifier for XTI input clock.
If specified, the clock will be enabled when the codec is probed,
and disabled when it is removed. The 'clock-names' must be set to 'xti'.
- st,output-conf: number, Selects the output configuration:
0: 2-channel (full-bridge) power, 2-channel data-out
1: 2 (half-bridge). 1 (full-bridge) on-board power
@ -39,6 +43,9 @@ Optional properties:
- st,thermal-warning-recover:
If present, thermal warning recovery is enabled.
- st,fault-detect-recovery:
If present, fault detect recovery is enabled.
- st,thermal-warning-adjustment:
If present, thermal warning adjustment is enabled.
@ -76,6 +83,8 @@ Example:
codec: sta32x@38 {
compatible = "st,sta32x";
reg = <0x1c>;
clocks = <&clock>;
clock-names = "xti";
reset-gpios = <&gpio1 19 0>;
power-down-gpios = <&gpio1 16 0>;
st,output-conf = /bits/ 8 <0x3>; // set output to 2-channel

View File

@ -31,7 +31,11 @@ SAI subnodes required properties:
- reg: Base address and size of SAI sub-block register set.
- clocks: Must contain one phandle and clock specifier pair
for sai_ck which feeds the internal clock generator.
If the SAI shares a master clock, with another SAI set as MCLK
clock provider, SAI provider phandle must be specified here.
- clock-names: Must contain "sai_ck".
Must also contain "MCLK", if SAI shares a master clock,
with a SAI set as MCLK clock provider.
- dmas: see Documentation/devicetree/bindings/dma/stm32-dma.txt
- dma-names: identifier string for each DMA request line
"tx": if sai sub-block is configured as playback DAI
@ -51,6 +55,9 @@ SAI subnodes Optional properties:
configured according to protocol defined in related DAI link node,
such as i2s, left justified, right justified, dsp and pdm protocols.
Note: ac97 protocol is not supported by SAI driver
- #clock-cells: should be 0. This property must be present if the SAI device
is a master clock provider, according to clocks bindings, described in
Documentation/devicetree/bindings/clock/clock-bindings.txt.
The device node should contain one 'port' child node with one child 'endpoint'
node, according to the bindings defined in Documentation/devicetree/bindings/

View File

@ -10,6 +10,7 @@ Required properties:
- "allwinner,sun6i-a31-i2s"
- "allwinner,sun8i-a83t-i2s"
- "allwinner,sun8i-h3-i2s"
- "allwinner,sun50i-a64-codec-i2s"
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: should contain the I2S interrupt.
@ -26,6 +27,7 @@ Required properties for the following compatibles:
- "allwinner,sun6i-a31-i2s"
- "allwinner,sun8i-a83t-i2s"
- "allwinner,sun8i-h3-i2s"
- "allwinner,sun50i-a64-codec-i2s"
- resets: phandle to the reset line for this codec
Example:

View File

@ -0,0 +1,12 @@
* Allwinner A64 Codec Analog Controls
Required properties:
- compatible: must be one of the following compatibles:
- "allwinner,sun50i-a64-codec-analog"
- reg: must contain the registers location and length
Example:
codec_analog: codec-analog@1f015c0 {
compatible = "allwinner,sun50i-a64-codec-analog";
reg = <0x01f015c0 0x4>;
};

View File

@ -14,7 +14,7 @@ Required properties:
Optional properies:
- ti,micbias: Intended MICBIAS voltage (datasheet section 9.6.7).
Select 0/1/2/3/4/5/6/7 to specify MACBIAS voltage
Select 0/1/2/3/4/5/6/7 to specify MICBIAS voltage
2.1V/2.2V/2.3V/2.4V/2.5V/2.6V/2.7V/2.8V
Default value is "1" (2.2V).

View File

@ -0,0 +1,17 @@
WM8782 stereo ADC
This device does not have any control interface or reset pins.
Required properties:
- compatible : "wlf,wm8782"
- Vdda-supply : phandle to a regulator for the analog power supply (2.7V - 5.5V)
- Vdd-supply : phandle to a regulator for the digital power supply (2.7V - 3.6V)
Example:
wm8782: stereo-adc {
compatible = "wlf,wm8782";
Vdda-supply = <&vdda_supply>;
Vdd-supply = <&vdd_supply>;
};

View File

@ -35,7 +35,6 @@ at,24c08 i2c serial eeprom (24cxx)
atmel,at97sc3204t i2c trusted platform module (TPM)
capella,cm32181 CM32181: Ambient Light Sensor
capella,cm3232 CM3232: Ambient Light Sensor
cirrus,cs42l51 Cirrus Logic CS42L51 audio codec
dallas,ds1374 I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output
dallas,ds1631 High-Precision Digital Thermometer
dallas,ds1672 Dallas DS1672 Real-time Clock

View File

@ -235,6 +235,7 @@ micrel Micrel Inc.
microchip Microchip Technology Inc.
microcrystal Micro Crystal AG
micron Micron Technology Inc.
mikroe MikroElektronika d.o.o.
minix MINIX Technology Ltd.
miramems MiraMEMS Sensing Technology Co., Ltd.
mitsubishi Mitsubishi Electric Corporation

View File

@ -14619,6 +14619,13 @@ L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/ti/netcp*
TI PCM3060 ASoC CODEC DRIVER
M: Kirill Marinushkin <kmarinushkin@birdec.tech>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/sound/pcm3060.txt
F: sound/soc/codecs/pcm3060*
TI TAS571X FAMILY ASoC CODEC DRIVER
M: Kevin Cernekee <cernekee@chromium.org>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)

View File

@ -51,29 +51,35 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
#define asoc_simple_card_parse_clk_cpu(dev, node, dai_link, simple_dai) \
asoc_simple_card_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai, \
dai_link->cpu_dai_name)
dai_link->cpu_dai_name, NULL)
#define asoc_simple_card_parse_clk_codec(dev, node, dai_link, simple_dai) \
asoc_simple_card_parse_clk(dev, node, dai_link->codec_of_node, simple_dai,\
dai_link->codec_dai_name)
dai_link->codec_dai_name, dai_link->codecs)
int asoc_simple_card_parse_clk(struct device *dev,
struct device_node *node,
struct device_node *dai_of_node,
struct asoc_simple_dai *simple_dai,
const char *name);
const char *dai_name,
struct snd_soc_dai_link_component *dlc);
int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai);
void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai);
#define asoc_simple_card_parse_cpu(node, dai_link, \
list_name, cells_name, is_single_link) \
asoc_simple_card_parse_dai(node, &dai_link->cpu_of_node, \
asoc_simple_card_parse_dai(node, NULL, \
&dai_link->cpu_of_node, \
&dai_link->cpu_dai_name, list_name, cells_name, is_single_link)
#define asoc_simple_card_parse_codec(node, dai_link, list_name, cells_name) \
asoc_simple_card_parse_dai(node, &dai_link->codec_of_node, \
&dai_link->codec_dai_name, list_name, cells_name, NULL)
asoc_simple_card_parse_dai(node, dai_link->codecs, \
&dai_link->codec_of_node, \
&dai_link->codec_dai_name, \
list_name, cells_name, NULL)
#define asoc_simple_card_parse_platform(node, dai_link, list_name, cells_name) \
asoc_simple_card_parse_dai(node, &dai_link->platform_of_node, \
asoc_simple_card_parse_dai(node, dai_link->platform, \
&dai_link->platform_of_node, \
NULL, list_name, cells_name, NULL)
int asoc_simple_card_parse_dai(struct device_node *node,
struct snd_soc_dai_link_component *dlc,
struct device_node **endpoint_np,
const char **dai_name,
const char *list_name,
@ -81,12 +87,15 @@ int asoc_simple_card_parse_dai(struct device_node *node,
int *is_single_links);
#define asoc_simple_card_parse_graph_cpu(ep, dai_link) \
asoc_simple_card_parse_graph_dai(ep, &dai_link->cpu_of_node, \
asoc_simple_card_parse_graph_dai(ep, NULL, \
&dai_link->cpu_of_node, \
&dai_link->cpu_dai_name)
#define asoc_simple_card_parse_graph_codec(ep, dai_link) \
asoc_simple_card_parse_graph_dai(ep, &dai_link->codec_of_node, \
asoc_simple_card_parse_graph_dai(ep, dai_link->codecs, \
&dai_link->codec_of_node, \
&dai_link->codec_dai_name)
int asoc_simple_card_parse_graph_dai(struct device_node *ep,
struct snd_soc_dai_link_component *dlc,
struct device_node **endpoint_np,
const char **dai_name);

View File

@ -25,4 +25,10 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[];
/*
* generic table used for HDA codec-based platforms, possibly with
* additional ACPI-enumerated codecs
*/
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_hda_machines[];
#endif

View File

@ -406,12 +406,6 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
struct snd_soc_dai *dai);
int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card);
int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *rtd,
const struct snd_soc_pcm_stream *params,
unsigned int num_params,
struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink);
/* dapm path setup */
int snd_soc_dapm_new_widgets(struct snd_soc_card *card);
@ -590,9 +584,6 @@ struct snd_soc_dapm_widget {
void *priv; /* widget specific data */
struct regulator *regulator; /* attached regulator */
struct pinctrl *pinctrl; /* attached pinctrl */
const struct snd_soc_pcm_stream *params; /* params for dai links */
unsigned int num_params; /* number of params for dai links */
unsigned int params_select; /* currently selected param for dai link */
/* dapm control */
int reg; /* negative reg = no direct dapm */

View File

@ -103,6 +103,16 @@ struct snd_soc_dpcm_runtime {
int trigger_pending; /* trigger cmd + 1 if pending, 0 if not */
};
#define for_each_dpcm_fe(be, stream, dpcm) \
list_for_each_entry(dpcm, &(be)->dpcm[stream].fe_clients, list_fe)
#define for_each_dpcm_be(fe, stream, dpcm) \
list_for_each_entry(dpcm, &(fe)->dpcm[stream].be_clients, list_be)
#define for_each_dpcm_be_safe(fe, stream, dpcm, _dpcm) \
list_for_each_entry_safe(dpcm, _dpcm, &(fe)->dpcm[stream].be_clients, list_be)
#define for_each_dpcm_be_rollback(fe, stream, dpcm) \
list_for_each_entry_continue_reverse(dpcm, &(fe)->dpcm[stream].be_clients, list_be)
/* can this BE stop and free */
int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
struct snd_soc_pcm_runtime *be, int stream);

View File

@ -372,6 +372,11 @@
#define SND_SOC_COMP_ORDER_LATE 1
#define SND_SOC_COMP_ORDER_LAST 2
#define for_each_comp_order(order) \
for (order = SND_SOC_COMP_ORDER_FIRST; \
order <= SND_SOC_COMP_ORDER_LAST; \
order++)
/*
* Bias levels
*
@ -859,6 +864,11 @@ struct snd_soc_component {
#endif
};
#define for_each_component_dais(component, dai)\
list_for_each_entry(dai, &(component)->dai_list, list)
#define for_each_component_dais_safe(component, dai, _dai)\
list_for_each_entry_safe(dai, _dai, &(component)->dai_list, list)
struct snd_soc_rtdcom_list {
struct snd_soc_component *component;
struct list_head list; /* rtd::component_list */
@ -915,6 +925,8 @@ struct snd_soc_dai_link {
*/
const char *platform_name;
struct device_node *platform_of_node;
struct snd_soc_dai_link_component *platform;
int id; /* optional ID for machine driver link identification */
const struct snd_soc_pcm_stream *params;
@ -976,6 +988,10 @@ struct snd_soc_dai_link {
struct list_head list; /* DAI link list of the soc card */
struct snd_soc_dobj dobj; /* For topology */
};
#define for_each_link_codecs(link, i, codec) \
for ((i) = 0; \
((i) < link->num_codecs) && ((codec) = &link->codecs[i]); \
(i)++)
struct snd_soc_codec_conf {
/*
@ -1054,7 +1070,6 @@ struct snd_soc_card {
struct snd_soc_dai_link *dai_link; /* predefined links only */
int num_links; /* predefined links only */
struct list_head dai_link_list; /* all links */
int num_dai_links;
struct list_head rtd_list;
int num_rtd;
@ -1092,6 +1107,7 @@ struct snd_soc_card {
/* lists of probed devices belonging to this card */
struct list_head component_dev_list;
struct list_head list;
struct list_head widgets;
struct list_head paths;
@ -1114,6 +1130,23 @@ struct snd_soc_card {
void *drvdata;
};
#define for_each_card_prelinks(card, i, link) \
for ((i) = 0; \
((i) < (card)->num_links) && ((link) = &(card)->dai_link[i]); \
(i)++)
#define for_each_card_links(card, link) \
list_for_each_entry(dai_link, &(card)->dai_link_list, list)
#define for_each_card_links_safe(card, link, _link) \
list_for_each_entry_safe(link, _link, &(card)->dai_link_list, list)
#define for_each_card_rtds(card, rtd) \
list_for_each_entry(rtd, &(card)->rtd_list, list)
#define for_each_card_rtds_safe(card, rtd, _rtd) \
list_for_each_entry_safe(rtd, _rtd, &(card)->rtd_list, list)
#define for_each_card_components(card, component) \
list_for_each_entry(component, &(card)->component_dev_list, card_list)
/* SoC machine DAI configuration, glues a codec and cpu DAI together */
struct snd_soc_pcm_runtime {
@ -1124,6 +1157,8 @@ struct snd_soc_pcm_runtime {
enum snd_soc_pcm_subclass pcm_subclass;
struct snd_pcm_ops ops;
unsigned int params_select; /* currently selected param for dai link */
/* Dynamic PCM BE runtime data */
struct snd_soc_dpcm_runtime dpcm[2];
int fe_compr;
@ -1152,6 +1187,13 @@ struct snd_soc_pcm_runtime {
unsigned int dev_registered:1;
unsigned int pop_wait:1;
};
#define for_each_rtd_codec_dai(rtd, i, dai)\
for ((i) = 0; \
((i) < rtd->num_codecs) && ((dai) = rtd->codec_dais[i]); \
(i)++)
#define for_each_rtd_codec_dai_rollback(rtd, i, dai) \
for (; ((i--) >= 0) && ((dai) = rtd->codec_dais[i]);)
/* mixer control */
struct soc_mixer_control {
@ -1359,6 +1401,7 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
INIT_LIST_HEAD(&card->dapm_list);
INIT_LIST_HEAD(&card->aux_comp_list);
INIT_LIST_HEAD(&card->component_dev_list);
INIT_LIST_HEAD(&card->list);
}
static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)

View File

@ -31,7 +31,6 @@ endif # SND_ARM
config SND_PXA2XX_LIB
tristate
select SND_AC97_CODEC if SND_PXA2XX_LIB_AC97
select SND_DMAENGINE_PCM
config SND_PXA2XX_LIB_AC97

View File

@ -13,7 +13,7 @@
#include <linux/export.h>
#include <linux/sort.h>
#include <sound/core.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"

View File

@ -9,7 +9,7 @@
#ifndef __SOUND_HDA_BEEP_H
#define __SOUND_HDA_BEEP_H
#include "hda_codec.h"
#include <sound/hda_codec.h>
#define HDA_BEEP_MODE_OFF 0
#define HDA_BEEP_MODE_ON 1

View File

@ -11,7 +11,7 @@
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <sound/core.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_local.h"
/*
@ -81,6 +81,12 @@ static int hda_codec_driver_probe(struct device *dev)
hda_codec_patch_t patch;
int err;
if (codec->bus->core.ext_ops) {
if (WARN_ON(!codec->bus->core.ext_ops->hdev_attach))
return -EINVAL;
return codec->bus->core.ext_ops->hdev_attach(&codec->core);
}
if (WARN_ON(!codec->preset))
return -EINVAL;
@ -134,6 +140,12 @@ static int hda_codec_driver_remove(struct device *dev)
{
struct hda_codec *codec = dev_to_hda_codec(dev);
if (codec->bus->core.ext_ops) {
if (WARN_ON(!codec->bus->core.ext_ops->hdev_detach))
return -EINVAL;
return codec->bus->core.ext_ops->hdev_detach(&codec->core);
}
if (codec->patch_ops.free)
codec->patch_ops.free(codec);
snd_hda_codec_cleanup_for_unbind(codec);

View File

@ -27,7 +27,7 @@
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <sound/core.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include <sound/asoundef.h>
#include <sound/tlv.h>
#include <sound/initval.h>

View File

@ -20,7 +20,7 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/initval.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include <sound/hda_register.h>
#define AZX_MAX_CODECS HDA_MAX_CODECS

View File

@ -27,7 +27,7 @@
#include <sound/core.h>
#include <asm/unaligned.h>
#include <sound/hda_chmap.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_local.h"
enum eld_versions {

View File

@ -32,7 +32,7 @@
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/tlv.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"

View File

@ -23,7 +23,7 @@
#include <linux/compat.h>
#include <linux/nospec.h>
#include <sound/core.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_local.h"
#include <sound/hda_hwdep.h>
#include <sound/minors.h>

View File

@ -63,7 +63,7 @@
#include <linux/vgaarb.h>
#include <linux/vga_switcheroo.h>
#include <linux/firmware.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_controller.h"
#include "hda_intel.h"

View File

@ -15,7 +15,7 @@
#include <sound/core.h>
#include <sound/control.h>
#include <sound/jack.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"

View File

@ -25,7 +25,7 @@
#include <linux/slab.h>
#include <sound/core.h>
#include <linux/module.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_local.h"
static int dump_coef = -1;

View File

@ -14,7 +14,7 @@
#include <linux/string.h>
#include <linux/export.h>
#include <sound/core.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_local.h"
#include <sound/hda_hwdep.h>
#include <sound/minors.h>

View File

@ -35,7 +35,7 @@
#include <sound/core.h>
#include <sound/initval.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_controller.h"
/* Defines for Nvidia Tegra HDA support */

View File

@ -24,7 +24,7 @@
#include <linux/module.h>
#include <sound/core.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_beep.h"

View File

@ -22,7 +22,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <sound/core.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"

View File

@ -31,8 +31,9 @@
#include <linux/types.h>
#include <linux/io.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <sound/core.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"

View File

@ -23,7 +23,7 @@
#include <linux/module.h>
#include <sound/core.h>
#include <sound/tlv.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"

View File

@ -25,7 +25,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <sound/core.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"

View File

@ -27,7 +27,7 @@
#include <sound/core.h>
#include <sound/jack.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_beep.h"

View File

@ -41,7 +41,7 @@
#include <sound/hdaudio.h>
#include <sound/hda_i915.h>
#include <sound/hda_chmap.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_jack.h"

View File

@ -32,7 +32,7 @@
#include <linux/input.h>
#include <sound/core.h>
#include <sound/jack.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"

View File

@ -27,7 +27,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <sound/core.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_local.h"
/* si3054 verbs */

View File

@ -32,7 +32,7 @@
#include <linux/module.h>
#include <sound/core.h>
#include <sound/jack.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_beep.h"

View File

@ -52,7 +52,7 @@
#include <linux/module.h>
#include <sound/core.h>
#include <sound/asoundef.h>
#include "hda_codec.h"
#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"

View File

@ -42,7 +42,7 @@
#include "../codecs/da7219.h"
#include "../codecs/da7219-aad.h"
#define CZ_PLAT_CLK 25000000
#define CZ_PLAT_CLK 48000000
#define DUAL_CHANNEL 2
static struct snd_soc_jack cz_jack;
@ -75,7 +75,7 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
da7219_dai_clk = clk_get(component->dev, "da7219-dai-clks");
ret = snd_soc_card_jack_new(card, "Headset Jack",
SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
SND_JACK_HEADSET | SND_JACK_LINEOUT |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3,
&cz_jack, NULL, 0);
@ -133,7 +133,7 @@ static const struct snd_pcm_hw_constraint_list constraints_channels = {
.mask = 0,
};
static int cz_da7219_startup(struct snd_pcm_substream *substream)
static int cz_da7219_play_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@ -150,7 +150,28 @@ static int cz_da7219_startup(struct snd_pcm_substream *substream)
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
machine->i2s_instance = I2S_SP_INSTANCE;
machine->play_i2s_instance = I2S_SP_INSTANCE;
return da7219_clk_enable(substream);
}
static int cz_da7219_cap_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
/*
* On this platform for PCM device we support stereo
*/
runtime->hw.channels_max = DUAL_CHANNEL;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_channels);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
machine->cap_i2s_instance = I2S_SP_INSTANCE;
machine->capture_channel = CAP_CHANNEL1;
return da7219_clk_enable(substream);
}
@ -162,11 +183,22 @@ static void cz_da7219_shutdown(struct snd_pcm_substream *substream)
static int cz_max_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
machine->i2s_instance = I2S_BT_INSTANCE;
/*
* On this platform for PCM device we support stereo
*/
runtime->hw.channels_max = DUAL_CHANNEL;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_channels);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
machine->play_i2s_instance = I2S_BT_INSTANCE;
return da7219_clk_enable(substream);
}
@ -177,21 +209,43 @@ static void cz_max_shutdown(struct snd_pcm_substream *substream)
static int cz_dmic0_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
machine->i2s_instance = I2S_BT_INSTANCE;
/*
* On this platform for PCM device we support stereo
*/
runtime->hw.channels_max = DUAL_CHANNEL;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_channels);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
machine->cap_i2s_instance = I2S_BT_INSTANCE;
return da7219_clk_enable(substream);
}
static int cz_dmic1_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
machine->i2s_instance = I2S_SP_INSTANCE;
/*
* On this platform for PCM device we support stereo
*/
runtime->hw.channels_max = DUAL_CHANNEL;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_channels);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
machine->cap_i2s_instance = I2S_SP_INSTANCE;
machine->capture_channel = CAP_CHANNEL0;
return da7219_clk_enable(substream);
}
@ -201,8 +255,13 @@ static void cz_dmic_shutdown(struct snd_pcm_substream *substream)
da7219_clk_disable();
}
static const struct snd_soc_ops cz_da7219_play_ops = {
.startup = cz_da7219_play_startup,
.shutdown = cz_da7219_shutdown,
};
static const struct snd_soc_ops cz_da7219_cap_ops = {
.startup = cz_da7219_startup,
.startup = cz_da7219_cap_startup,
.shutdown = cz_da7219_shutdown,
};
@ -233,7 +292,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
| SND_SOC_DAIFMT_CBM_CFM,
.init = cz_da7219_init,
.dpcm_playback = 1,
.ops = &cz_da7219_cap_ops,
.ops = &cz_da7219_play_ops,
},
{
.name = "amd-da7219-cap",

View File

@ -867,8 +867,12 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
if (pinfo) {
rtd->i2s_instance = pinfo->i2s_instance;
rtd->capture_channel = pinfo->capture_channel;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
rtd->i2s_instance = pinfo->play_i2s_instance;
} else {
rtd->i2s_instance = pinfo->cap_i2s_instance;
rtd->capture_channel = pinfo->capture_channel;
}
}
if (adata->asic_type == CHIP_STONEY) {
val = acp_reg_read(adata->acp_mmio,

View File

@ -158,7 +158,8 @@ struct audio_drv_data {
* and dma driver
*/
struct acp_platform_info {
u16 i2s_instance;
u16 play_i2s_instance;
u16 cap_i2s_instance;
u16 capture_channel;
};

View File

@ -97,4 +97,16 @@ config SND_ATMEL_SOC_I2S
help
Say Y or M if you want to add support for Atmel ASoc driver for boards
using I2S.
config SND_SOC_MIKROE_PROTO
tristate "Support for Mikroe-PROTO board"
depends on OF
depends on SND_SOC_I2C_AND_SPI
select SND_SOC_WM8731
help
Say Y or M if you want to add support for MikroElektronika PROTO Audio
Board. This board contains the WM8731 codec, which can be configured
using I2C over SDA (MPU Data Input) and SCL (MPU Clock Input) pins.
Both playback and capture are supported.
endif

View File

@ -17,6 +17,7 @@ snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o
snd-atmel-soc-classd-objs := atmel-classd.o
snd-atmel-soc-pdmic-objs := atmel-pdmic.o
snd-atmel-soc-tse850-pcm5142-objs := tse850-pcm5142.o
snd-soc-mikroe-proto-objs := mikroe-proto.o
obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
@ -24,3 +25,4 @@ obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o
obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o
obj-$(CONFIG_SND_ATMEL_SOC_PDMIC) += snd-atmel-soc-pdmic.o
obj-$(CONFIG_SND_ATMEL_SOC_TSE850_PCM5142) += snd-atmel-soc-tse850-pcm5142.o
obj-$(CONFIG_SND_SOC_MIKROE_PROTO) += snd-soc-mikroe-proto.o

View File

@ -1005,11 +1005,11 @@ static int asoc_ssc_init(struct device *dev)
struct ssc_device *ssc = dev_get_drvdata(dev);
int ret;
ret = snd_soc_register_component(dev, &atmel_ssc_component,
ret = devm_snd_soc_register_component(dev, &atmel_ssc_component,
&atmel_ssc_dai, 1);
if (ret) {
dev_err(dev, "Could not register DAI: %d\n", ret);
goto err;
return ret;
}
if (ssc->pdata->use_dma)
@ -1019,15 +1019,10 @@ static int asoc_ssc_init(struct device *dev)
if (ret) {
dev_err(dev, "Could not register PCM: %d\n", ret);
goto err_unregister_dai;
return ret;
}
return 0;
err_unregister_dai:
snd_soc_unregister_component(dev);
err:
return ret;
}
static void asoc_ssc_exit(struct device *dev)
@ -1038,8 +1033,6 @@ static void asoc_ssc_exit(struct device *dev)
atmel_pcm_dma_platform_unregister(dev);
else
atmel_pcm_pdc_platform_unregister(dev);
snd_soc_unregister_component(dev);
}
/**

View File

@ -0,0 +1,165 @@
/*
* ASoC driver for PROTO AudioCODEC (with a WM8731)
*
* Author: Florian Meier, <koalo@koalo.de>
* Copyright 2013
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/jack.h>
#include "../codecs/wm8731.h"
#define XTAL_RATE 12288000 /* This is fixed on this board */
static int snd_proto_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
/* Set proto sysclk */
int ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
XTAL_RATE, SND_SOC_CLOCK_IN);
if (ret < 0) {
dev_err(card->dev, "Failed to set WM8731 SYSCLK: %d\n",
ret);
return ret;
}
return 0;
}
static const struct snd_soc_dapm_widget snd_proto_widget[] = {
SND_SOC_DAPM_MIC("Microphone Jack", NULL),
SND_SOC_DAPM_HP("Headphone Jack", NULL),
};
static const struct snd_soc_dapm_route snd_proto_route[] = {
/* speaker connected to LHPOUT/RHPOUT */
{"Headphone Jack", NULL, "LHPOUT"},
{"Headphone Jack", NULL, "RHPOUT"},
/* mic is connected to Mic Jack, with WM8731 Mic Bias */
{"MICIN", NULL, "Mic Bias"},
{"Mic Bias", NULL, "Microphone Jack"},
};
/* audio machine driver */
static struct snd_soc_card snd_proto = {
.name = "snd_mikroe_proto",
.owner = THIS_MODULE,
.dapm_widgets = snd_proto_widget,
.num_dapm_widgets = ARRAY_SIZE(snd_proto_widget),
.dapm_routes = snd_proto_route,
.num_dapm_routes = ARRAY_SIZE(snd_proto_route),
};
static int snd_proto_probe(struct platform_device *pdev)
{
struct snd_soc_dai_link *dai;
struct device_node *np = pdev->dev.of_node;
struct device_node *codec_np, *cpu_np;
struct device_node *bitclkmaster = NULL;
struct device_node *framemaster = NULL;
unsigned int dai_fmt;
int ret = 0;
if (!np) {
dev_err(&pdev->dev, "No device node supplied\n");
return -EINVAL;
}
snd_proto.dev = &pdev->dev;
ret = snd_soc_of_parse_card_name(&snd_proto, "model");
if (ret)
return ret;
dai = devm_kzalloc(&pdev->dev, sizeof(*dai), GFP_KERNEL);
if (!dai)
return -ENOMEM;
snd_proto.dai_link = dai;
snd_proto.num_links = 1;
dai->name = "WM8731";
dai->stream_name = "WM8731 HiFi";
dai->codec_dai_name = "wm8731-hifi";
dai->init = &snd_proto_init;
codec_np = of_parse_phandle(np, "audio-codec", 0);
if (!codec_np) {
dev_err(&pdev->dev, "audio-codec node missing\n");
return -EINVAL;
}
dai->codec_of_node = codec_np;
cpu_np = of_parse_phandle(np, "i2s-controller", 0);
if (!cpu_np) {
dev_err(&pdev->dev, "i2s-controller missing\n");
return -EINVAL;
}
dai->cpu_of_node = cpu_np;
dai->platform_of_node = cpu_np;
dai_fmt = snd_soc_of_parse_daifmt(np, NULL,
&bitclkmaster, &framemaster);
if (bitclkmaster != framemaster) {
dev_err(&pdev->dev, "Must be the same bitclock and frame master\n");
return -EINVAL;
}
if (bitclkmaster) {
dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
if (codec_np == bitclkmaster)
dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
else
dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
}
of_node_put(bitclkmaster);
of_node_put(framemaster);
dai->dai_fmt = dai_fmt;
of_node_put(codec_np);
of_node_put(cpu_np);
ret = snd_soc_register_card(&snd_proto);
if (ret && ret != -EPROBE_DEFER)
dev_err(&pdev->dev,
"snd_soc_register_card() failed: %d\n", ret);
return ret;
}
static int snd_proto_remove(struct platform_device *pdev)
{
return snd_soc_unregister_card(&snd_proto);
}
static const struct of_device_id snd_proto_of_match[] = {
{ .compatible = "mikroe,mikroe-proto", },
{},
};
MODULE_DEVICE_TABLE(of, snd_proto_of_match);
static struct platform_driver snd_proto_driver = {
.driver = {
.name = "snd-mikroe-proto",
.of_match_table = snd_proto_of_match,
},
.probe = snd_proto_probe,
.remove = snd_proto_remove,
};
module_platform_driver(snd_proto_driver);
MODULE_AUTHOR("Florian Meier");
MODULE_DESCRIPTION("ASoC Driver for PROTO board (WM8731)");
MODULE_LICENSE("GPL");

View File

@ -1,44 +1,38 @@
/*
* TSE-850 audio - ASoC driver for the Axentia TSE-850 with a PCM5142 codec
*
* Copyright (C) 2016 Axentia Technologies AB
*
* Author: Peter Rosin <peda@axentia.se>
*
* 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.
*/
/*
* loop1 relays
* IN1 +---o +------------+ o---+ OUT1
* \ /
* + +
* | / |
* +--o +--. |
* | add | |
* | V |
* | .---. |
* DAC +----------->|Sum|---+
* | '---' |
* | |
* + +
*
* IN2 +---o--+------------+--o---+ OUT2
* loop2 relays
*
* The 'loop1' gpio pin controlls two relays, which are either in loop
* position, meaning that input and output are directly connected, or
* they are in mixer position, meaning that the signal is passed through
* the 'Sum' mixer. Similarly for 'loop2'.
*
* In the above, the 'loop1' relays are inactive, thus feeding IN1 to the
* mixer (if 'add' is active) and feeding the mixer output to OUT1. The
* 'loop2' relays are active, short-cutting the TSE-850 from channel 2.
* IN1, IN2, OUT1 and OUT2 are TSE-850 connectors and DAC is the PCB name
* of the (filtered) output from the PCM5142 codec.
*/
// SPDX-License-Identifier: GPL-2.0
//
// TSE-850 audio - ASoC driver for the Axentia TSE-850 with a PCM5142 codec
//
// Copyright (C) 2016 Axentia Technologies AB
//
// Author: Peter Rosin <peda@axentia.se>
//
// loop1 relays
// IN1 +---o +------------+ o---+ OUT1
// \ /
// + +
// | / |
// +--o +--. |
// | add | |
// | V |
// | .---. |
// DAC +----------->|Sum|---+
// | '---' |
// | |
// + +
//
// IN2 +---o--+------------+--o---+ OUT2
// loop2 relays
//
// The 'loop1' gpio pin controlls two relays, which are either in loop
// position, meaning that input and output are directly connected, or
// they are in mixer position, meaning that the signal is passed through
// the 'Sum' mixer. Similarly for 'loop2'.
//
// In the above, the 'loop1' relays are inactive, thus feeding IN1 to the
// mixer (if 'add' is active) and feeding the mixer output to OUT1. The
// 'loop2' relays are active, short-cutting the TSE-850 from channel 2.
// IN1, IN2, OUT1 and OUT2 are TSE-850 connectors and DAC is the PCB name
// of the (filtered) output from the PCM5142 codec.
#include <linux/clk.h>
#include <linux/gpio.h>
@ -452,4 +446,4 @@ module_platform_driver(tse850_driver);
/* Module information */
MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
MODULE_DESCRIPTION("ALSA SoC driver for TSE-850 with PCM5142 codec");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");

View File

@ -1334,7 +1334,7 @@ static int cygnus_ssp_probe(struct platform_device *pdev)
cygaud->active_ports = 0;
dev_dbg(dev, "Registering %d DAIs\n", active_port_count);
err = snd_soc_register_component(dev, &cygnus_ssp_component,
err = devm_snd_soc_register_component(dev, &cygnus_ssp_component,
cygnus_ssp_dai, active_port_count);
if (err) {
dev_err(dev, "snd_soc_register_dai failed\n");
@ -1345,32 +1345,27 @@ static int cygnus_ssp_probe(struct platform_device *pdev)
if (cygaud->irq_num <= 0) {
dev_err(dev, "platform_get_irq failed\n");
err = cygaud->irq_num;
goto err_irq;
return err;
}
err = audio_clk_init(pdev, cygaud);
if (err) {
dev_err(dev, "audio clock initialization failed\n");
goto err_irq;
return err;
}
err = cygnus_soc_platform_register(dev, cygaud);
if (err) {
dev_err(dev, "platform reg error %d\n", err);
goto err_irq;
return err;
}
return 0;
err_irq:
snd_soc_unregister_component(dev);
return err;
}
static int cygnus_ssp_remove(struct platform_device *pdev)
{
cygnus_soc_platform_unregister(&pdev->dev);
snd_soc_unregister_component(&pdev->dev);
return 0;
}

View File

@ -82,6 +82,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ES7241
select SND_SOC_GTM601
select SND_SOC_HDAC_HDMI
select SND_SOC_HDAC_HDA
select SND_SOC_ICS43432
select SND_SOC_INNO_RK3036
select SND_SOC_ISABELLE if I2C
@ -109,6 +110,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_MT6351 if MTK_PMIC_WRAP
select SND_SOC_NAU8540 if I2C
select SND_SOC_NAU8810 if I2C
select SND_SOC_NAU8822 if I2C
select SND_SOC_NAU8824 if I2C
select SND_SOC_NAU8825 if I2C
select SND_SOC_HDMI_CODEC
@ -119,6 +121,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_PCM186X_I2C if I2C
select SND_SOC_PCM186X_SPI if SPI_MASTER
select SND_SOC_PCM3008
select SND_SOC_PCM3060_I2C if I2C
select SND_SOC_PCM3060_SPI if SPI_MASTER
select SND_SOC_PCM3168A_I2C if I2C
select SND_SOC_PCM3168A_SPI if SPI_MASTER
select SND_SOC_PCM5102A
@ -575,7 +579,11 @@ config SND_SOC_DA9055
tristate
config SND_SOC_DMIC
tristate
tristate "Generic Digital Microphone CODEC"
depends on GPIOLIB
help
Enable support for the Generic Digital Microphone CODEC.
Select this if your sound card has DMICs.
config SND_SOC_HDMI_CODEC
tristate
@ -615,6 +623,10 @@ config SND_SOC_HDAC_HDMI
select SND_PCM_ELD
select HDMI
config SND_SOC_HDAC_HDA
tristate
select SND_HDA
config SND_SOC_ICS43432
tristate
@ -629,7 +641,8 @@ config SND_SOC_LM49453
tristate
config SND_SOC_MAX98088
tristate
tristate "Maxim MAX98088/9 Low-Power, Stereo Audio Codec"
depends on I2C
config SND_SOC_MAX98090
tristate
@ -732,6 +745,21 @@ config SND_SOC_PCM186X_SPI
config SND_SOC_PCM3008
tristate
config SND_SOC_PCM3060
tristate
config SND_SOC_PCM3060_I2C
tristate "Texas Instruments PCM3060 CODEC - I2C"
depends on I2C
select SND_SOC_PCM3060
select REGMAP_I2C
config SND_SOC_PCM3060_SPI
tristate "Texas Instruments PCM3060 CODEC - SPI"
depends on SPI_MASTER
select SND_SOC_PCM3060
select REGMAP_SPI
config SND_SOC_PCM3168A
tristate
@ -1299,6 +1327,10 @@ config SND_SOC_NAU8810
tristate "Nuvoton Technology Corporation NAU88C10 CODEC"
depends on I2C
config SND_SOC_NAU8822
tristate "Nuvoton Technology Corporation NAU88C22 CODEC"
depends on I2C
config SND_SOC_NAU8824
tristate "Nuvoton Technology Corporation NAU88L24 CODEC"
depends on I2C

View File

@ -78,6 +78,7 @@ snd-soc-es8328-i2c-objs := es8328-i2c.o
snd-soc-es8328-spi-objs := es8328-spi.o
snd-soc-gtm601-objs := gtm601.o
snd-soc-hdac-hdmi-objs := hdac_hdmi.o
snd-soc-hdac-hda-objs := hdac_hda.o
snd-soc-ics43432-objs := ics43432.o
snd-soc-inno-rk3036-objs := inno_rk3036.o
snd-soc-isabelle-objs := isabelle.o
@ -106,6 +107,7 @@ snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o
snd-soc-mt6351-objs := mt6351.o
snd-soc-nau8540-objs := nau8540.o
snd-soc-nau8810-objs := nau8810.o
snd-soc-nau8822-objs := nau8822.o
snd-soc-nau8824-objs := nau8824.o
snd-soc-nau8825-objs := nau8825.o
snd-soc-hdmi-codec-objs := hdmi-codec.o
@ -119,6 +121,9 @@ snd-soc-pcm186x-objs := pcm186x.o
snd-soc-pcm186x-i2c-objs := pcm186x-i2c.o
snd-soc-pcm186x-spi-objs := pcm186x-spi.o
snd-soc-pcm3008-objs := pcm3008.o
snd-soc-pcm3060-objs := pcm3060.o
snd-soc-pcm3060-i2c-objs := pcm3060-i2c.o
snd-soc-pcm3060-spi-objs := pcm3060-spi.o
snd-soc-pcm3168a-objs := pcm3168a.o
snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o
snd-soc-pcm3168a-spi-objs := pcm3168a-spi.o
@ -338,6 +343,7 @@ obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o
obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o
obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o
obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o
obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o
obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
@ -366,6 +372,7 @@ obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o
obj-$(CONFIG_SND_SOC_MT6351) += snd-soc-mt6351.o
obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o
obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o
obj-$(CONFIG_SND_SOC_NAU8822) += snd-soc-nau8822.o
obj-$(CONFIG_SND_SOC_NAU8824) += snd-soc-nau8824.o
obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o
obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
@ -379,6 +386,9 @@ obj-$(CONFIG_SND_SOC_PCM186X) += snd-soc-pcm186x.o
obj-$(CONFIG_SND_SOC_PCM186X_I2C) += snd-soc-pcm186x-i2c.o
obj-$(CONFIG_SND_SOC_PCM186X_SPI) += snd-soc-pcm186x-spi.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
obj-$(CONFIG_SND_SOC_PCM3060) += snd-soc-pcm3060.o
obj-$(CONFIG_SND_SOC_PCM3060_I2C) += snd-soc-pcm3060-i2c.o
obj-$(CONFIG_SND_SOC_PCM3060_SPI) += snd-soc-pcm3060-spi.o
obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o
obj-$(CONFIG_SND_SOC_PCM3168A_I2C) += snd-soc-pcm3168a-i2c.o
obj-$(CONFIG_SND_SOC_PCM3168A_SPI) += snd-soc-pcm3168a-spi.o

View File

@ -518,7 +518,8 @@ static int adau1761_setup_digmic_jackdetect(struct snd_soc_component *component)
ARRAY_SIZE(adau1761_jack_detect_controls));
if (ret)
return ret;
case ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE: /* fallthrough */
/* fall through */
case ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE:
ret = snd_soc_dapm_add_routes(dapm, adau1761_no_dmic_routes,
ARRAY_SIZE(adau1761_no_dmic_routes));
if (ret)

View File

@ -21,11 +21,18 @@
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
#include <asm/unaligned.h>
#include "sigmadsp.h"
#include "adau17x1.h"
#include "adau-utils.h"
#define ADAU17X1_SAFELOAD_TARGET_ADDRESS 0x0006
#define ADAU17X1_SAFELOAD_TRIGGER 0x0007
#define ADAU17X1_SAFELOAD_DATA 0x0001
#define ADAU17X1_SAFELOAD_DATA_SIZE 20
#define ADAU17X1_WORD_SIZE 4
static const char * const adau17x1_capture_mixer_boost_text[] = {
"Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3",
};
@ -60,6 +67,9 @@ static const struct snd_kcontrol_new adau17x1_controls[] = {
SOC_ENUM("Mic Bias Mode", adau17x1_mic_bias_mode_enum),
};
static int adau17x1_setup_firmware(struct snd_soc_component *component,
unsigned int rate);
static int adau17x1_pll_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@ -313,7 +323,7 @@ static const struct snd_soc_dapm_route adau17x1_no_dsp_dapm_routes[] = {
{ "Capture", NULL, "Right Decimator" },
};
bool adau17x1_has_dsp(struct adau *adau)
static bool adau17x1_has_dsp(struct adau *adau)
{
switch (adau->type) {
case ADAU1761:
@ -324,7 +334,17 @@ bool adau17x1_has_dsp(struct adau *adau)
return false;
}
}
EXPORT_SYMBOL_GPL(adau17x1_has_dsp);
static bool adau17x1_has_safeload(struct adau *adau)
{
switch (adau->type) {
case ADAU1761:
case ADAU1781:
return true;
default:
return false;
}
}
static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
int source, unsigned int freq_in, unsigned int freq_out)
@ -836,7 +856,7 @@ bool adau17x1_volatile_register(struct device *dev, unsigned int reg)
}
EXPORT_SYMBOL_GPL(adau17x1_volatile_register);
int adau17x1_setup_firmware(struct snd_soc_component *component,
static int adau17x1_setup_firmware(struct snd_soc_component *component,
unsigned int rate)
{
int ret;
@ -880,7 +900,6 @@ err:
return ret;
}
EXPORT_SYMBOL_GPL(adau17x1_setup_firmware);
int adau17x1_add_widgets(struct snd_soc_component *component)
{
@ -957,6 +976,56 @@ int adau17x1_resume(struct snd_soc_component *component)
}
EXPORT_SYMBOL_GPL(adau17x1_resume);
static int adau17x1_safeload(struct sigmadsp *sigmadsp, unsigned int addr,
const uint8_t bytes[], size_t len)
{
uint8_t buf[ADAU17X1_WORD_SIZE];
uint8_t data[ADAU17X1_SAFELOAD_DATA_SIZE];
unsigned int addr_offset;
unsigned int nbr_words;
int ret;
/* write data to safeload addresses. Check if len is not a multiple of
* 4 bytes, if so we need to zero pad.
*/
nbr_words = len / ADAU17X1_WORD_SIZE;
if ((len - nbr_words * ADAU17X1_WORD_SIZE) == 0) {
ret = regmap_raw_write(sigmadsp->control_data,
ADAU17X1_SAFELOAD_DATA, bytes, len);
} else {
nbr_words++;
memset(data, 0, ADAU17X1_SAFELOAD_DATA_SIZE);
memcpy(data, bytes, len);
ret = regmap_raw_write(sigmadsp->control_data,
ADAU17X1_SAFELOAD_DATA, data,
nbr_words * ADAU17X1_WORD_SIZE);
}
if (ret < 0)
return ret;
/* Write target address, target address is offset by 1 */
addr_offset = addr - 1;
put_unaligned_be32(addr_offset, buf);
ret = regmap_raw_write(sigmadsp->control_data,
ADAU17X1_SAFELOAD_TARGET_ADDRESS, buf, ADAU17X1_WORD_SIZE);
if (ret < 0)
return ret;
/* write nbr of words to trigger address */
put_unaligned_be32(nbr_words, buf);
ret = regmap_raw_write(sigmadsp->control_data,
ADAU17X1_SAFELOAD_TRIGGER, buf, ADAU17X1_WORD_SIZE);
if (ret < 0)
return ret;
return 0;
}
static const struct sigmadsp_ops adau17x1_sigmadsp_ops = {
.safeload = adau17x1_safeload,
};
int adau17x1_probe(struct device *dev, struct regmap *regmap,
enum adau17x1_type type, void (*switch_mode)(struct device *dev),
const char *firmware_name)
@ -1002,8 +1071,13 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
dev_set_drvdata(dev, adau);
if (firmware_name) {
adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, NULL,
firmware_name);
if (adau17x1_has_safeload(adau)) {
adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap,
&adau17x1_sigmadsp_ops, firmware_name);
} else {
adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap,
NULL, firmware_name);
}
if (IS_ERR(adau->sigmadsp)) {
dev_warn(dev, "Could not find firmware file: %ld\n",
PTR_ERR(adau->sigmadsp));

View File

@ -68,10 +68,6 @@ int adau17x1_resume(struct snd_soc_component *component);
extern const struct snd_soc_dai_ops adau17x1_dai_ops;
int adau17x1_setup_firmware(struct snd_soc_component *component,
unsigned int rate);
bool adau17x1_has_dsp(struct adau *adau);
#define ADAU17X1_CLOCK_CONTROL 0x4000
#define ADAU17X1_PLL_CONTROL 0x4002
#define ADAU17X1_REC_POWER_MGMT 0x4009

View File

@ -154,11 +154,11 @@ static const struct snd_kcontrol_new cs4265_snd_controls[] = {
SOC_SINGLE("E to F Buffer Disable Switch", CS4265_SPDIF_CTL1,
6, 1, 0),
SOC_ENUM("C Data Access", cam_mode_enum),
SOC_SINGLE("SPDIF Switch", CS4265_SPDIF_CTL2, 5, 1, 1),
SOC_SINGLE("Validity Bit Control Switch", CS4265_SPDIF_CTL2,
3, 1, 0),
SOC_ENUM("SPDIF Mono/Stereo", spdif_mono_stereo_enum),
SOC_SINGLE("MMTLR Data Switch", CS4265_SPDIF_CTL2,
0, 1, 0),
SOC_SINGLE("MMTLR Data Switch", CS4265_SPDIF_CTL2, 0, 1, 0),
SOC_ENUM("Mono Channel Select", spdif_mono_select_enum),
SND_SOC_BYTES("C Data Buffer", CS4265_C_DATA_BUFF, 24),
};
@ -221,10 +221,11 @@ static const struct snd_soc_dapm_route cs4265_audio_map[] = {
{"LINEOUTR", NULL, "DAC"},
{"SPDIFOUT", NULL, "SPDIF"},
{"Pre-amp MIC", NULL, "MICL"},
{"Pre-amp MIC", NULL, "MICR"},
{"ADC Mux", "MIC", "Pre-amp MIC"},
{"ADC Mux", "LINEIN", "LINEINL"},
{"ADC Mux", "LINEIN", "LINEINR"},
{"ADC Mux", "MIC", "MICL"},
{"ADC Mux", "MIC", "MICR"},
{"ADC", NULL, "ADC Mux"},
{"DOUT", NULL, "ADC"},
{"DAI1 Capture", NULL, "DOUT"},
@ -496,7 +497,8 @@ static int cs4265_set_bias_level(struct snd_soc_component *component,
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
#define CS4265_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE)
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE | \
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE)
static const struct snd_soc_dai_ops cs4265_ops = {
.hw_params = cs4265_pcm_hw_params,

View File

@ -21,6 +21,7 @@
* - master mode *NOT* supported
*/
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <sound/core.h>
@ -41,6 +42,7 @@ enum master_slave_mode {
struct cs42l51_private {
unsigned int mclk;
struct clk *mclk_handle;
unsigned int audio_mode; /* The mode (I2S or left-justified) */
enum master_slave_mode func;
};
@ -237,6 +239,10 @@ static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = {
&cs42l51_adcr_mux_controls),
};
static const struct snd_soc_dapm_widget cs42l51_dapm_mclk_widgets[] = {
SND_SOC_DAPM_CLOCK_SUPPLY("MCLK")
};
static const struct snd_soc_dapm_route cs42l51_routes[] = {
{"HPL", NULL, "Left DAC"},
{"HPR", NULL, "Right DAC"},
@ -487,6 +493,14 @@ static struct snd_soc_dai_driver cs42l51_dai = {
static int cs42l51_component_probe(struct snd_soc_component *component)
{
int ret, reg;
struct snd_soc_dapm_context *dapm;
struct cs42l51_private *cs42l51;
cs42l51 = snd_soc_component_get_drvdata(component);
dapm = snd_soc_component_get_dapm(component);
if (cs42l51->mclk_handle)
snd_soc_dapm_new_controls(dapm, cs42l51_dapm_mclk_widgets, 1);
/*
* DAC configuration
@ -540,6 +554,13 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap)
dev_set_drvdata(dev, cs42l51);
cs42l51->mclk_handle = devm_clk_get(dev, "MCLK");
if (IS_ERR(cs42l51->mclk_handle)) {
if (PTR_ERR(cs42l51->mclk_handle) != -ENOENT)
return PTR_ERR(cs42l51->mclk_handle);
cs42l51->mclk_handle = NULL;
}
/* Verify that we have a CS42L51 */
ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val);
if (ret < 0) {

View File

@ -148,6 +148,7 @@ static const struct of_device_id dmic_dev_match[] = {
{.compatible = "dmic-codec"},
{}
};
MODULE_DEVICE_TABLE(of, dmic_dev_match);
static struct platform_driver dmic_driver = {
.driver = {

View File

@ -566,14 +566,14 @@ static int es8328_set_sysclk(struct snd_soc_dai *codec_dai,
break;
case 22579200:
mclkdiv2 = 1;
/* fallthru */
/* fall through */
case 11289600:
es8328->sysclk_constraints = &constraints_11289;
es8328->mclk_ratios = ratios_11289;
break;
case 24576000:
mclkdiv2 = 1;
/* fallthru */
/* fall through */
case 12288000:
es8328->sysclk_constraints = &constraints_12288;
es8328->mclk_ratios = ratios_12288;

483
sound/soc/codecs/hdac_hda.c Normal file
View File

@ -0,0 +1,483 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright(c) 2015-18 Intel Corporation.
/*
* hdac_hda.c - ASoC extensions to reuse the legacy HDA codec drivers
* with ASoC platform drivers. These APIs are called by the legacy HDA
* codec drivers using hdac_ext_bus_ops ops.
*/
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/hdaudio_ext.h>
#include <sound/hda_codec.h>
#include <sound/hda_register.h>
#include "hdac_hda.h"
#define HDAC_ANALOG_DAI_ID 0
#define HDAC_DIGITAL_DAI_ID 1
#define HDAC_ALT_ANALOG_DAI_ID 2
#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
SNDRV_PCM_FMTBIT_U8 | \
SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_U16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_U24_LE | \
SNDRV_PCM_FMTBIT_S32_LE | \
SNDRV_PCM_FMTBIT_U32_LE | \
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
static int hdac_hda_dai_open(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai);
static void hdac_hda_dai_close(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai);
static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai);
static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai);
static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai,
unsigned int tx_mask, unsigned int rx_mask,
int slots, int slot_width);
static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt,
struct snd_soc_dai *dai);
static struct snd_soc_dai_ops hdac_hda_dai_ops = {
.startup = hdac_hda_dai_open,
.shutdown = hdac_hda_dai_close,
.prepare = hdac_hda_dai_prepare,
.hw_free = hdac_hda_dai_hw_free,
.set_tdm_slot = hdac_hda_dai_set_tdm_slot,
};
static struct snd_soc_dai_driver hdac_hda_dais[] = {
{
.id = HDAC_ANALOG_DAI_ID,
.name = "Analog Codec DAI",
.ops = &hdac_hda_dai_ops,
.playback = {
.stream_name = "Analog Codec Playback",
.channels_min = 1,
.channels_max = 16,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = STUB_FORMATS,
.sig_bits = 24,
},
.capture = {
.stream_name = "Analog Codec Capture",
.channels_min = 1,
.channels_max = 16,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = STUB_FORMATS,
.sig_bits = 24,
},
},
{
.id = HDAC_DIGITAL_DAI_ID,
.name = "Digital Codec DAI",
.ops = &hdac_hda_dai_ops,
.playback = {
.stream_name = "Digital Codec Playback",
.channels_min = 1,
.channels_max = 16,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = STUB_FORMATS,
.sig_bits = 24,
},
.capture = {
.stream_name = "Digital Codec Capture",
.channels_min = 1,
.channels_max = 16,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = STUB_FORMATS,
.sig_bits = 24,
},
},
{
.id = HDAC_ALT_ANALOG_DAI_ID,
.name = "Alt Analog Codec DAI",
.ops = &hdac_hda_dai_ops,
.playback = {
.stream_name = "Alt Analog Codec Playback",
.channels_min = 1,
.channels_max = 16,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = STUB_FORMATS,
.sig_bits = 24,
},
.capture = {
.stream_name = "Alt Analog Codec Capture",
.channels_min = 1,
.channels_max = 16,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = STUB_FORMATS,
.sig_bits = 24,
},
}
};
static int hdac_hda_dai_set_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 hdac_hda_priv *hda_pvt;
struct hdac_hda_pcm *pcm;
hda_pvt = snd_soc_component_get_drvdata(component);
pcm = &hda_pvt->pcm[dai->id];
if (tx_mask)
pcm[dai->id].stream_tag[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask;
else
pcm[dai->id].stream_tag[SNDRV_PCM_STREAM_CAPTURE] = rx_mask;
return 0;
}
static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct hdac_hda_priv *hda_pvt;
struct hda_pcm_stream *hda_stream;
struct hda_pcm *pcm;
hda_pvt = snd_soc_component_get_drvdata(component);
pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
if (!pcm)
return -EINVAL;
hda_stream = &pcm->stream[substream->stream];
snd_hda_codec_cleanup(&hda_pvt->codec, hda_stream, substream);
return 0;
}
static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct hdac_hda_priv *hda_pvt;
struct snd_pcm_runtime *runtime = substream->runtime;
struct hdac_device *hdev;
struct hda_pcm_stream *hda_stream;
unsigned int format_val;
struct hda_pcm *pcm;
unsigned int stream;
int ret = 0;
hda_pvt = snd_soc_component_get_drvdata(component);
hdev = &hda_pvt->codec.core;
pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
if (!pcm)
return -EINVAL;
hda_stream = &pcm->stream[substream->stream];
format_val = snd_hdac_calc_stream_format(runtime->rate,
runtime->channels,
runtime->format,
hda_stream->maxbps,
0);
if (!format_val) {
dev_err(&hdev->dev,
"invalid format_val, rate=%d, ch=%d, format=%d\n",
runtime->rate, runtime->channels, runtime->format);
return -EINVAL;
}
stream = hda_pvt->pcm[dai->id].stream_tag[substream->stream];
ret = snd_hda_codec_prepare(&hda_pvt->codec, hda_stream,
stream, format_val, substream);
if (ret < 0)
dev_err(&hdev->dev, "codec prepare failed %d\n", ret);
return ret;
}
static int hdac_hda_dai_open(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct hdac_hda_priv *hda_pvt;
struct hda_pcm_stream *hda_stream;
struct hda_pcm *pcm;
int ret;
hda_pvt = snd_soc_component_get_drvdata(component);
pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
if (!pcm)
return -EINVAL;
snd_hda_codec_pcm_get(pcm);
hda_stream = &pcm->stream[substream->stream];
ret = hda_stream->ops.open(hda_stream, &hda_pvt->codec, substream);
if (ret < 0)
snd_hda_codec_pcm_put(pcm);
return ret;
}
static void hdac_hda_dai_close(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct hdac_hda_priv *hda_pvt;
struct hda_pcm_stream *hda_stream;
struct hda_pcm *pcm;
hda_pvt = snd_soc_component_get_drvdata(component);
pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
if (!pcm)
return;
hda_stream = &pcm->stream[substream->stream];
hda_stream->ops.close(hda_stream, &hda_pvt->codec, substream);
snd_hda_codec_pcm_put(pcm);
}
static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt,
struct snd_soc_dai *dai)
{
struct hda_codec *hcodec = &hda_pvt->codec;
struct hda_pcm *cpcm;
const char *pcm_name;
switch (dai->id) {
case HDAC_ANALOG_DAI_ID:
pcm_name = "Analog";
break;
case HDAC_DIGITAL_DAI_ID:
pcm_name = "Digital";
break;
case HDAC_ALT_ANALOG_DAI_ID:
pcm_name = "Alt Analog";
break;
default:
dev_err(&hcodec->core.dev, "invalid dai id %d\n", dai->id);
return NULL;
}
list_for_each_entry(cpcm, &hcodec->pcm_list_head, list) {
if (strpbrk(cpcm->name, pcm_name))
return cpcm;
}
dev_err(&hcodec->core.dev, "didn't find PCM for DAI %s\n", dai->name);
return NULL;
}
static int hdac_hda_codec_probe(struct snd_soc_component *component)
{
struct hdac_hda_priv *hda_pvt =
snd_soc_component_get_drvdata(component);
struct snd_soc_dapm_context *dapm =
snd_soc_component_get_dapm(component);
struct hdac_device *hdev = &hda_pvt->codec.core;
struct hda_codec *hcodec = &hda_pvt->codec;
struct hdac_ext_link *hlink;
hda_codec_patch_t patch;
int ret;
hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return -EIO;
}
snd_hdac_ext_bus_link_get(hdev->bus, hlink);
ret = snd_hda_codec_device_new(hcodec->bus, component->card->snd_card,
hdev->addr, hcodec);
if (ret < 0) {
dev_err(&hdev->dev, "failed to create hda codec %d\n", ret);
goto error_no_pm;
}
/*
* snd_hda_codec_device_new decrements the usage count so call get pm
* else the device will be powered off
*/
pm_runtime_get_noresume(&hdev->dev);
hcodec->bus->card = dapm->card->snd_card;
ret = snd_hda_codec_set_name(hcodec, hcodec->preset->name);
if (ret < 0) {
dev_err(&hdev->dev, "name failed %s\n", hcodec->preset->name);
goto error;
}
ret = snd_hdac_regmap_init(&hcodec->core);
if (ret < 0) {
dev_err(&hdev->dev, "regmap init failed\n");
goto error;
}
patch = (hda_codec_patch_t)hcodec->preset->driver_data;
if (patch) {
ret = patch(hcodec);
if (ret < 0) {
dev_err(&hdev->dev, "patch failed %d\n", ret);
goto error;
}
} else {
dev_dbg(&hdev->dev, "no patch file found\n");
}
ret = snd_hda_codec_parse_pcms(hcodec);
if (ret < 0) {
dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret);
goto error;
}
ret = snd_hda_codec_build_controls(hcodec);
if (ret < 0) {
dev_err(&hdev->dev, "unable to create controls %d\n", ret);
goto error;
}
hcodec->core.lazy_cache = true;
/*
* hdac_device core already sets the state to active and calls
* get_noresume. So enable runtime and set the device to suspend.
* pm_runtime_enable is also called during codec registeration
*/
pm_runtime_put(&hdev->dev);
pm_runtime_suspend(&hdev->dev);
return 0;
error:
pm_runtime_put(&hdev->dev);
error_no_pm:
snd_hdac_ext_bus_link_put(hdev->bus, hlink);
return ret;
}
static void hdac_hda_codec_remove(struct snd_soc_component *component)
{
struct hdac_hda_priv *hda_pvt =
snd_soc_component_get_drvdata(component);
struct hdac_device *hdev = &hda_pvt->codec.core;
struct hdac_ext_link *hlink = NULL;
hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return;
}
snd_hdac_ext_bus_link_put(hdev->bus, hlink);
pm_runtime_disable(&hdev->dev);
}
static const struct snd_soc_dapm_route hdac_hda_dapm_routes[] = {
{"AIF1TX", NULL, "Codec Input Pin1"},
{"AIF2TX", NULL, "Codec Input Pin2"},
{"AIF3TX", NULL, "Codec Input Pin3"},
{"Codec Output Pin1", NULL, "AIF1RX"},
{"Codec Output Pin2", NULL, "AIF2RX"},
{"Codec Output Pin3", NULL, "AIF3RX"},
};
static const struct snd_soc_dapm_widget hdac_hda_dapm_widgets[] = {
/* Audio Interface */
SND_SOC_DAPM_AIF_IN("AIF1RX", "Analog Codec Playback", 0,
SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("AIF2RX", "Digital Codec Playback", 0,
SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("AIF3RX", "Alt Analog Codec Playback", 0,
SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX", "Analog Codec Capture", 0,
SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("AIF2TX", "Digital Codec Capture", 0,
SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("AIF3TX", "Alt Analog Codec Capture", 0,
SND_SOC_NOPM, 0, 0),
/* Input Pins */
SND_SOC_DAPM_INPUT("Codec Input Pin1"),
SND_SOC_DAPM_INPUT("Codec Input Pin2"),
SND_SOC_DAPM_INPUT("Codec Input Pin3"),
/* Output Pins */
SND_SOC_DAPM_OUTPUT("Codec Output Pin1"),
SND_SOC_DAPM_OUTPUT("Codec Output Pin2"),
SND_SOC_DAPM_OUTPUT("Codec Output Pin3"),
};
static const struct snd_soc_component_driver hdac_hda_codec = {
.probe = hdac_hda_codec_probe,
.remove = hdac_hda_codec_remove,
.idle_bias_on = false,
.dapm_widgets = hdac_hda_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(hdac_hda_dapm_widgets),
.dapm_routes = hdac_hda_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(hdac_hda_dapm_routes),
};
static int hdac_hda_dev_probe(struct hdac_device *hdev)
{
struct hdac_ext_link *hlink;
struct hdac_hda_priv *hda_pvt;
int ret;
/* hold the ref while we probe */
hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return -EIO;
}
snd_hdac_ext_bus_link_get(hdev->bus, hlink);
hda_pvt = hdac_to_hda_priv(hdev);
if (!hda_pvt)
return -ENOMEM;
/* ASoC specific initialization */
ret = devm_snd_soc_register_component(&hdev->dev,
&hdac_hda_codec, hdac_hda_dais,
ARRAY_SIZE(hdac_hda_dais));
if (ret < 0) {
dev_err(&hdev->dev, "failed to register HDA codec %d\n", ret);
return ret;
}
dev_set_drvdata(&hdev->dev, hda_pvt);
snd_hdac_ext_bus_link_put(hdev->bus, hlink);
return ret;
}
static int hdac_hda_dev_remove(struct hdac_device *hdev)
{
return 0;
}
static struct hdac_ext_bus_ops hdac_ops = {
.hdev_attach = hdac_hda_dev_probe,
.hdev_detach = hdac_hda_dev_remove,
};
struct hdac_ext_bus_ops *snd_soc_hdac_hda_get_ops(void)
{
return &hdac_ops;
}
EXPORT_SYMBOL_GPL(snd_soc_hdac_hda_get_ops);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("ASoC Extensions for legacy HDA Drivers");
MODULE_AUTHOR("Rakesh Ughreja<rakesh.a.ughreja@intel.com>");

View File

@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright(c) 2015-18 Intel Corporation.
*/
#ifndef __HDAC_HDA_H__
#define __HDAC_HDA_H__
struct hdac_hda_pcm {
int stream_tag[2];
};
struct hdac_hda_priv {
struct hda_codec codec;
struct hdac_hda_pcm pcm[2];
};
#define hdac_to_hda_priv(_hdac) \
container_of(_hdac, struct hdac_hda_priv, codec.core)
#define hdac_to_hda_codec(_hdac) container_of(_hdac, struct hda_codec, core)
struct hdac_ext_bus_ops *snd_soc_hdac_hda_get_ops(void);
#endif /* __HDAC_HDA_H__ */

View File

@ -1410,6 +1410,12 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdev,
if (ret)
return ret;
/* Filter out 44.1, 88.2 and 176.4Khz */
rates &= ~(SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |
SNDRV_PCM_RATE_176400);
if (!rates)
return -EINVAL;
sprintf(dai_name, "intel-hdmi-hifi%d", i+1);
hdmi_dais[i].name = devm_kstrdup(&hdev->dev,
dai_name, GFP_KERNEL);
@ -1598,7 +1604,7 @@ static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card,
{
struct snd_soc_pcm_runtime *rtd;
list_for_each_entry(rtd, &card->rtd_list, list) {
for_each_card_rtds(card, rtd) {
if (rtd->pcm && (rtd->pcm->device == device))
return rtd->pcm;
}
@ -1961,9 +1967,6 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdev, int pcm_idx)
port = list_first_entry(&pcm->port_list, struct hdac_hdmi_port, head);
if (!port)
return 0;
if (!port || !port->eld.eld_valid)
return 0;

View File

@ -16,6 +16,7 @@
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/clk.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@ -42,6 +43,7 @@ struct max98088_priv {
struct regmap *regmap;
enum max98088_type devtype;
struct max98088_pdata *pdata;
struct clk *mclk;
unsigned int sysclk;
struct max98088_cdata dai[2];
int eq_textcnt;
@ -1103,6 +1105,11 @@ static int max98088_dai_set_sysclk(struct snd_soc_dai *dai,
if (freq == max98088->sysclk)
return 0;
if (!IS_ERR(max98088->mclk)) {
freq = clk_round_rate(max98088->mclk, freq);
clk_set_rate(max98088->mclk, freq);
}
/* Setup clocks for slave mode, and using the PLL
* PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
* 0x02 (when master clk is 20MHz to 30MHz)..
@ -1310,6 +1317,20 @@ static int max98088_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_PREPARE:
/*
* SND_SOC_BIAS_PREPARE is called while preparing for a
* transition to ON or away from ON. If current bias_level
* is SND_SOC_BIAS_ON, then it is preparing for a transition
* away from ON. Disable the clock in that case, otherwise
* enable it.
*/
if (!IS_ERR(max98088->mclk)) {
if (snd_soc_component_get_bias_level(component) ==
SND_SOC_BIAS_ON)
clk_disable_unprepare(max98088->mclk);
else
clk_prepare_enable(max98088->mclk);
}
break;
case SND_SOC_BIAS_STANDBY:
@ -1725,6 +1746,11 @@ static int max98088_i2c_probe(struct i2c_client *i2c,
if (IS_ERR(max98088->regmap))
return PTR_ERR(max98088->regmap);
max98088->mclk = devm_clk_get(&i2c->dev, "mclk");
if (IS_ERR(max98088->mclk))
if (PTR_ERR(max98088->mclk) == -EPROBE_DEFER)
return PTR_ERR(max98088->mclk);
max98088->devtype = id->driver_data;
i2c_set_clientdata(i2c, max98088);
@ -1742,9 +1768,19 @@ static const struct i2c_device_id max98088_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, max98088_i2c_id);
#if defined(CONFIG_OF)
static const struct of_device_id max98088_of_match[] = {
{ .compatible = "maxim,max98088" },
{ .compatible = "maxim,max98089" },
{ }
};
MODULE_DEVICE_TABLE(of, max98088_of_match);
#endif
static struct i2c_driver max98088_i2c_driver = {
.driver = {
.name = "max98088",
.of_match_table = of_match_ptr(max98088_of_match),
},
.probe = max98088_i2c_probe,
.id_table = max98088_i2c_id,

View File

@ -2,6 +2,7 @@
// Copyright (c) 2017, Maxim Integrated
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
@ -454,7 +455,7 @@ SND_SOC_DAPM_SIGGEN("IMON"),
SND_SOC_DAPM_SIGGEN("FBMON"),
};
static DECLARE_TLV_DB_SCALE(max98373_digital_tlv, 0, -50, 0);
static DECLARE_TLV_DB_SCALE(max98373_digital_tlv, -6350, 50, 1);
static const DECLARE_TLV_DB_RANGE(max98373_spk_tlv,
0, 8, TLV_DB_SCALE_ITEM(0, 50, 0),
9, 10, TLV_DB_SCALE_ITEM(500, 100, 0),
@ -470,19 +471,19 @@ static const DECLARE_TLV_DB_RANGE(max98373_dht_spkgain_min_tlv,
0, 9, TLV_DB_SCALE_ITEM(800, 100, 0),
);
static const DECLARE_TLV_DB_RANGE(max98373_dht_rotation_point_tlv,
0, 1, TLV_DB_SCALE_ITEM(-50, -50, 0),
2, 7, TLV_DB_SCALE_ITEM(-200, -100, 0),
8, 9, TLV_DB_SCALE_ITEM(-1000, -200, 0),
10, 11, TLV_DB_SCALE_ITEM(-1500, -300, 0),
12, 13, TLV_DB_SCALE_ITEM(-2000, -200, 0),
14, 15, TLV_DB_SCALE_ITEM(-2500, -500, 0),
0, 1, TLV_DB_SCALE_ITEM(-3000, 500, 0),
2, 4, TLV_DB_SCALE_ITEM(-2200, 200, 0),
5, 6, TLV_DB_SCALE_ITEM(-1500, 300, 0),
7, 9, TLV_DB_SCALE_ITEM(-1000, 200, 0),
10, 13, TLV_DB_SCALE_ITEM(-500, 100, 0),
14, 15, TLV_DB_SCALE_ITEM(-100, 50, 0),
);
static const DECLARE_TLV_DB_RANGE(max98373_limiter_thresh_tlv,
0, 15, TLV_DB_SCALE_ITEM(0, -100, 0),
0, 15, TLV_DB_SCALE_ITEM(-1500, 100, 0),
);
static const DECLARE_TLV_DB_RANGE(max98373_bde_gain_tlv,
0, 60, TLV_DB_SCALE_ITEM(0, -25, 0),
0, 60, TLV_DB_SCALE_ITEM(-1500, 25, 0),
);
static bool max98373_readable_register(struct device *dev, unsigned int reg)
@ -604,7 +605,7 @@ SOC_SINGLE("Dither Switch", MAX98373_R203F_AMP_DSP_CFG,
SOC_SINGLE("DC Blocker Switch", MAX98373_R203F_AMP_DSP_CFG,
MAX98373_AMP_DSP_CFG_DCBLK_SHIFT, 1, 0),
SOC_SINGLE_TLV("Digital Volume", MAX98373_R203D_AMP_DIG_VOL_CTRL,
0, 0x7F, 0, max98373_digital_tlv),
0, 0x7F, 1, max98373_digital_tlv),
SOC_SINGLE_TLV("Speaker Volume", MAX98373_R203E_AMP_PATH_GAIN,
MAX98373_SPK_DIGI_GAIN_SHIFT, 10, 0, max98373_spk_tlv),
SOC_SINGLE_TLV("FS Max Volume", MAX98373_R203E_AMP_PATH_GAIN,
@ -616,7 +617,7 @@ SOC_SINGLE("DHT Switch", MAX98373_R20D4_DHT_EN,
SOC_SINGLE_TLV("DHT Min Volume", MAX98373_R20D1_DHT_CFG,
MAX98373_DHT_SPK_GAIN_MIN_SHIFT, 9, 0, max98373_dht_spkgain_min_tlv),
SOC_SINGLE_TLV("DHT Rot Pnt Volume", MAX98373_R20D1_DHT_CFG,
MAX98373_DHT_ROT_PNT_SHIFT, 15, 0, max98373_dht_rotation_point_tlv),
MAX98373_DHT_ROT_PNT_SHIFT, 15, 1, max98373_dht_rotation_point_tlv),
SOC_SINGLE_TLV("DHT Attack Step Volume", MAX98373_R20D2_DHT_ATTACK_CFG,
MAX98373_DHT_ATTACK_STEP_SHIFT, 4, 0, max98373_dht_step_size_tlv),
SOC_SINGLE_TLV("DHT Release Step Volume", MAX98373_R20D3_DHT_RELEASE_CFG,
@ -653,29 +654,29 @@ SOC_SINGLE("BDE Hold Time", MAX98373_R2090_BDE_LVL_HOLD, 0, 0xFF, 0),
SOC_SINGLE("BDE Attack Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 4, 0xF, 0),
SOC_SINGLE("BDE Release Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 0, 0xF, 0),
SOC_SINGLE_TLV("BDE LVL1 Clip Thresh Volume", MAX98373_R20A9_BDE_L1_CFG_2,
0, 0x3C, 0, max98373_bde_gain_tlv),
0, 0x3C, 1, max98373_bde_gain_tlv),
SOC_SINGLE_TLV("BDE LVL2 Clip Thresh Volume", MAX98373_R20AC_BDE_L2_CFG_2,
0, 0x3C, 0, max98373_bde_gain_tlv),
0, 0x3C, 1, max98373_bde_gain_tlv),
SOC_SINGLE_TLV("BDE LVL3 Clip Thresh Volume", MAX98373_R20AF_BDE_L3_CFG_2,
0, 0x3C, 0, max98373_bde_gain_tlv),
0, 0x3C, 1, max98373_bde_gain_tlv),
SOC_SINGLE_TLV("BDE LVL4 Clip Thresh Volume", MAX98373_R20B2_BDE_L4_CFG_2,
0, 0x3C, 0, max98373_bde_gain_tlv),
0, 0x3C, 1, max98373_bde_gain_tlv),
SOC_SINGLE_TLV("BDE LVL1 Clip Reduction Volume", MAX98373_R20AA_BDE_L1_CFG_3,
0, 0x3C, 0, max98373_bde_gain_tlv),
0, 0x3C, 1, max98373_bde_gain_tlv),
SOC_SINGLE_TLV("BDE LVL2 Clip Reduction Volume", MAX98373_R20AD_BDE_L2_CFG_3,
0, 0x3C, 0, max98373_bde_gain_tlv),
0, 0x3C, 1, max98373_bde_gain_tlv),
SOC_SINGLE_TLV("BDE LVL3 Clip Reduction Volume", MAX98373_R20B0_BDE_L3_CFG_3,
0, 0x3C, 0, max98373_bde_gain_tlv),
0, 0x3C, 1, max98373_bde_gain_tlv),
SOC_SINGLE_TLV("BDE LVL4 Clip Reduction Volume", MAX98373_R20B3_BDE_L4_CFG_3,
0, 0x3C, 0, max98373_bde_gain_tlv),
0, 0x3C, 1, max98373_bde_gain_tlv),
SOC_SINGLE_TLV("BDE LVL1 Limiter Thresh Volume", MAX98373_R20A8_BDE_L1_CFG_1,
0, 0xF, 0, max98373_limiter_thresh_tlv),
0, 0xF, 1, max98373_limiter_thresh_tlv),
SOC_SINGLE_TLV("BDE LVL2 Limiter Thresh Volume", MAX98373_R20AB_BDE_L2_CFG_1,
0, 0xF, 0, max98373_limiter_thresh_tlv),
0, 0xF, 1, max98373_limiter_thresh_tlv),
SOC_SINGLE_TLV("BDE LVL3 Limiter Thresh Volume", MAX98373_R20AE_BDE_L3_CFG_1,
0, 0xF, 0, max98373_limiter_thresh_tlv),
0, 0xF, 1, max98373_limiter_thresh_tlv),
SOC_SINGLE_TLV("BDE LVL4 Limiter Thresh Volume", MAX98373_R20B1_BDE_L4_CFG_1,
0, 0xF, 0, max98373_limiter_thresh_tlv),
0, 0xF, 1, max98373_limiter_thresh_tlv),
/* Limiter */
SOC_SINGLE("Limiter Switch", MAX98373_R20E2_LIMITER_EN,
MAX98373_LIMITER_EN_SHIFT, 1, 0),

1136
sound/soc/codecs/nau8822.c Normal file

File diff suppressed because it is too large Load Diff

204
sound/soc/codecs/nau8822.h Normal file
View File

@ -0,0 +1,204 @@
/*
* nau8822.h -- NAU8822 Soc Audio Codec driver
*
* Author: David Lin <ctlin0@nuvoton.com>
* Co-author: John Hsu <kchsu0@nuvoton.com>
* Co-author: Seven Li <wtli@nuvoton.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 __NAU8822_H__
#define __NAU8822_H__
#define NAU8822_REG_RESET 0x00
#define NAU8822_REG_POWER_MANAGEMENT_1 0x01
#define NAU8822_REG_POWER_MANAGEMENT_2 0x02
#define NAU8822_REG_POWER_MANAGEMENT_3 0x03
#define NAU8822_REG_AUDIO_INTERFACE 0x04
#define NAU8822_REG_COMPANDING_CONTROL 0x05
#define NAU8822_REG_CLOCKING 0x06
#define NAU8822_REG_ADDITIONAL_CONTROL 0x07
#define NAU8822_REG_GPIO_CONTROL 0x08
#define NAU8822_REG_JACK_DETECT_CONTROL_1 0x09
#define NAU8822_REG_DAC_CONTROL 0x0A
#define NAU8822_REG_LEFT_DAC_DIGITAL_VOLUME 0x0B
#define NAU8822_REG_RIGHT_DAC_DIGITAL_VOLUME 0x0C
#define NAU8822_REG_JACK_DETECT_CONTROL_2 0x0D
#define NAU8822_REG_ADC_CONTROL 0x0E
#define NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME 0x0F
#define NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME 0x10
#define NAU8822_REG_EQ1 0x12
#define NAU8822_REG_EQ2 0x13
#define NAU8822_REG_EQ3 0x14
#define NAU8822_REG_EQ4 0x15
#define NAU8822_REG_EQ5 0x16
#define NAU8822_REG_DAC_LIMITER_1 0x18
#define NAU8822_REG_DAC_LIMITER_2 0x19
#define NAU8822_REG_NOTCH_FILTER_1 0x1B
#define NAU8822_REG_NOTCH_FILTER_2 0x1C
#define NAU8822_REG_NOTCH_FILTER_3 0x1D
#define NAU8822_REG_NOTCH_FILTER_4 0x1E
#define NAU8822_REG_ALC_CONTROL_1 0x20
#define NAU8822_REG_ALC_CONTROL_2 0x21
#define NAU8822_REG_ALC_CONTROL_3 0x22
#define NAU8822_REG_NOISE_GATE 0x23
#define NAU8822_REG_PLL_N 0x24
#define NAU8822_REG_PLL_K1 0x25
#define NAU8822_REG_PLL_K2 0x26
#define NAU8822_REG_PLL_K3 0x27
#define NAU8822_REG_3D_CONTROL 0x29
#define NAU8822_REG_RIGHT_SPEAKER_CONTROL 0x2B
#define NAU8822_REG_INPUT_CONTROL 0x2C
#define NAU8822_REG_LEFT_INP_PGA_CONTROL 0x2D
#define NAU8822_REG_RIGHT_INP_PGA_CONTROL 0x2E
#define NAU8822_REG_LEFT_ADC_BOOST_CONTROL 0x2F
#define NAU8822_REG_RIGHT_ADC_BOOST_CONTROL 0x30
#define NAU8822_REG_OUTPUT_CONTROL 0x31
#define NAU8822_REG_LEFT_MIXER_CONTROL 0x32
#define NAU8822_REG_RIGHT_MIXER_CONTROL 0x33
#define NAU8822_REG_LHP_VOLUME 0x34
#define NAU8822_REG_RHP_VOLUME 0x35
#define NAU8822_REG_LSPKOUT_VOLUME 0x36
#define NAU8822_REG_RSPKOUT_VOLUME 0x37
#define NAU8822_REG_AUX2_MIXER 0x38
#define NAU8822_REG_AUX1_MIXER 0x39
#define NAU8822_REG_POWER_MANAGEMENT_4 0x3A
#define NAU8822_REG_LEFT_TIME_SLOT 0x3B
#define NAU8822_REG_MISC 0x3C
#define NAU8822_REG_RIGHT_TIME_SLOT 0x3D
#define NAU8822_REG_DEVICE_REVISION 0x3E
#define NAU8822_REG_DEVICE_ID 0x3F
#define NAU8822_REG_DAC_DITHER 0x41
#define NAU8822_REG_ALC_ENHANCE_1 0x46
#define NAU8822_REG_ALC_ENHANCE_2 0x47
#define NAU8822_REG_192KHZ_SAMPLING 0x48
#define NAU8822_REG_MISC_CONTROL 0x49
#define NAU8822_REG_INPUT_TIEOFF 0x4A
#define NAU8822_REG_POWER_REDUCTION 0x4B
#define NAU8822_REG_AGC_PEAK2PEAK 0x4C
#define NAU8822_REG_AGC_PEAK_DETECT 0x4D
#define NAU8822_REG_AUTOMUTE_CONTROL 0x4E
#define NAU8822_REG_OUTPUT_TIEOFF 0x4F
#define NAU8822_REG_MAX_REGISTER NAU8822_REG_OUTPUT_TIEOFF
/* NAU8822_REG_POWER_MANAGEMENT_1 (0x1) */
#define NAU8822_REFIMP_MASK 0x3
#define NAU8822_REFIMP_80K 0x1
#define NAU8822_REFIMP_300K 0x2
#define NAU8822_REFIMP_3K 0x3
#define NAU8822_IOBUF_EN (0x1 << 2)
#define NAU8822_ABIAS_EN (0x1 << 3)
/* NAU8822_REG_AUDIO_INTERFACE (0x4) */
#define NAU8822_AIFMT_MASK (0x3 << 3)
#define NAU8822_WLEN_MASK (0x3 << 5)
#define NAU8822_WLEN_20 (0x1 << 5)
#define NAU8822_WLEN_24 (0x2 << 5)
#define NAU8822_WLEN_32 (0x3 << 5)
#define NAU8822_LRP_MASK (0x1 << 7)
#define NAU8822_BCLKP_MASK (0x1 << 8)
/* NAU8822_REG_COMPANDING_CONTROL (0x5) */
#define NAU8822_ADDAP_SFT 0
#define NAU8822_ADCCM_SFT 1
#define NAU8822_DACCM_SFT 3
/* NAU8822_REG_CLOCKING (0x6) */
#define NAU8822_CLKIOEN_MASK 0x1
#define NAU8822_MCLKSEL_SFT 5
#define NAU8822_MCLKSEL_MASK (0x7 << 5)
#define NAU8822_BCLKSEL_SFT 2
#define NAU8822_BCLKSEL_MASK (0x7 << 2)
#define NAU8822_CLKM_MASK (0x1 << 8)
#define NAU8822_CLKM_MCLK (0x0 << 8)
#define NAU8822_CLKM_PLL (0x1 << 8)
/* NAU8822_REG_ADDITIONAL_CONTROL (0x08) */
#define NAU8822_SMPLR_SFT 1
#define NAU8822_SMPLR_MASK (0x7 << 1)
#define NAU8822_SMPLR_48K (0x0 << 1)
#define NAU8822_SMPLR_32K (0x1 << 1)
#define NAU8822_SMPLR_24K (0x2 << 1)
#define NAU8822_SMPLR_16K (0x3 << 1)
#define NAU8822_SMPLR_12K (0x4 << 1)
#define NAU8822_SMPLR_8K (0x5 << 1)
/* NAU8822_REG_EQ1 (0x12) */
#define NAU8822_EQ1GC_SFT 0
#define NAU8822_EQ1CF_SFT 5
#define NAU8822_EQM_SFT 8
/* NAU8822_REG_EQ2 (0x13) */
#define NAU8822_EQ2GC_SFT 0
#define NAU8822_EQ2CF_SFT 5
#define NAU8822_EQ2BW_SFT 8
/* NAU8822_REG_EQ3 (0x14) */
#define NAU8822_EQ3GC_SFT 0
#define NAU8822_EQ3CF_SFT 5
#define NAU8822_EQ3BW_SFT 8
/* NAU8822_REG_EQ4 (0x15) */
#define NAU8822_EQ4GC_SFT 0
#define NAU8822_EQ4CF_SFT 5
#define NAU8822_EQ4BW_SFT 8
/* NAU8822_REG_EQ5 (0x16) */
#define NAU8822_EQ5GC_SFT 0
#define NAU8822_EQ5CF_SFT 5
/* NAU8822_REG_ALC_CONTROL_1 (0x20) */
#define NAU8822_ALCMINGAIN_SFT 0
#define NAU8822_ALCMXGAIN_SFT 3
#define NAU8822_ALCEN_SFT 7
/* NAU8822_REG_ALC_CONTROL_2 (0x21) */
#define NAU8822_ALCSL_SFT 0
#define NAU8822_ALCHT_SFT 4
/* NAU8822_REG_ALC_CONTROL_3 (0x22) */
#define NAU8822_ALCATK_SFT 0
#define NAU8822_ALCDCY_SFT 4
#define NAU8822_ALCM_SFT 8
/* NAU8822_REG_PLL_N (0x24) */
#define NAU8822_PLLMCLK_DIV2 (0x1 << 4)
#define NAU8822_PLLN_MASK 0xF
#define NAU8822_PLLK1_SFT 18
#define NAU8822_PLLK1_MASK 0x3F
/* NAU8822_REG_PLL_K2 (0x26) */
#define NAU8822_PLLK2_SFT 9
#define NAU8822_PLLK2_MASK 0x1FF
/* NAU8822_REG_PLL_K3 (0x27) */
#define NAU8822_PLLK3_MASK 0x1FF
/* System Clock Source */
enum {
NAU8822_CLK_MCLK,
NAU8822_CLK_PLL,
};
struct nau8822_pll {
int pre_factor;
int mclk_scaler;
int pll_frac;
int pll_int;
};
/* Codec Private Data */
struct nau8822 {
struct device *dev;
struct regmap *regmap;
int mclk_idx;
struct nau8822_pll pll;
int sysclk;
int div_id;
};
#endif /* __NAU8822_H__ */

View File

@ -401,7 +401,8 @@ static int pcm186x_set_fmt(struct snd_soc_dai *dai, unsigned int format)
break;
case SND_SOC_DAIFMT_DSP_A:
priv->tdm_offset += 1;
/* Fall through... DSP_A uses the same basic config as DSP_B
/* fall through */
/* DSP_A uses the same basic config as DSP_B
* except we need to shift the TDM output by one BCK cycle
*/
case SND_SOC_DAIFMT_DSP_B:

View File

@ -0,0 +1,60 @@
// SPDX-License-Identifier: GPL-2.0
//
// PCM3060 I2C driver
//
// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech>
#include <linux/i2c.h>
#include <linux/module.h>
#include <sound/soc.h>
#include "pcm3060.h"
static int pcm3060_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct pcm3060_priv *priv;
priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
i2c_set_clientdata(i2c, priv);
priv->regmap = devm_regmap_init_i2c(i2c, &pcm3060_regmap);
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
return pcm3060_probe(&i2c->dev);
}
static const struct i2c_device_id pcm3060_i2c_id[] = {
{ .name = "pcm3060" },
{ },
};
MODULE_DEVICE_TABLE(i2c, pcm3060_i2c_id);
#ifdef CONFIG_OF
static const struct of_device_id pcm3060_of_match[] = {
{ .compatible = "ti,pcm3060" },
{ },
};
MODULE_DEVICE_TABLE(of, pcm3060_of_match);
#endif /* CONFIG_OF */
static struct i2c_driver pcm3060_i2c_driver = {
.driver = {
.name = "pcm3060",
#ifdef CONFIG_OF
.of_match_table = pcm3060_of_match,
#endif /* CONFIG_OF */
},
.id_table = pcm3060_i2c_id,
.probe = pcm3060_i2c_probe,
};
module_i2c_driver(pcm3060_i2c_driver);
MODULE_DESCRIPTION("PCM3060 I2C driver");
MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.tech>");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,59 @@
// SPDX-License-Identifier: GPL-2.0
//
// PCM3060 SPI driver
//
// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <sound/soc.h>
#include "pcm3060.h"
static int pcm3060_spi_probe(struct spi_device *spi)
{
struct pcm3060_priv *priv;
priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
spi_set_drvdata(spi, priv);
priv->regmap = devm_regmap_init_spi(spi, &pcm3060_regmap);
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
return pcm3060_probe(&spi->dev);
}
static const struct spi_device_id pcm3060_spi_id[] = {
{ .name = "pcm3060" },
{ },
};
MODULE_DEVICE_TABLE(spi, pcm3060_spi_id);
#ifdef CONFIG_OF
static const struct of_device_id pcm3060_of_match[] = {
{ .compatible = "ti,pcm3060" },
{ },
};
MODULE_DEVICE_TABLE(of, pcm3060_of_match);
#endif /* CONFIG_OF */
static struct spi_driver pcm3060_spi_driver = {
.driver = {
.name = "pcm3060",
#ifdef CONFIG_OF
.of_match_table = pcm3060_of_match,
#endif /* CONFIG_OF */
},
.id_table = pcm3060_spi_id,
.probe = pcm3060_spi_probe,
};
module_spi_driver(pcm3060_spi_driver);
MODULE_DESCRIPTION("PCM3060 SPI driver");
MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.tech>");
MODULE_LICENSE("GPL v2");

295
sound/soc/codecs/pcm3060.c Normal file
View File

@ -0,0 +1,295 @@
// SPDX-License-Identifier: GPL-2.0
//
// PCM3060 codec driver
//
// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech>
#include <linux/module.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/tlv.h>
#include "pcm3060.h"
/* dai */
static int pcm3060_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
struct snd_soc_component *comp = dai->component;
struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp);
if (dir != SND_SOC_CLOCK_IN) {
dev_err(comp->dev, "unsupported sysclock dir: %d\n", dir);
return -EINVAL;
}
priv->dai[dai->id].sclk_freq = freq;
return 0;
}
static int pcm3060_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_component *comp = dai->component;
struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp);
unsigned int reg;
unsigned int val;
if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
dev_err(comp->dev, "unsupported DAI polarity: 0x%x\n", fmt);
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
priv->dai[dai->id].is_master = true;
break;
case SND_SOC_DAIFMT_CBS_CFS:
priv->dai[dai->id].is_master = false;
break;
default:
dev_err(comp->dev, "unsupported DAI master mode: 0x%x\n", fmt);
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
val = PCM3060_REG_FMT_I2S;
break;
case SND_SOC_DAIFMT_RIGHT_J:
val = PCM3060_REG_FMT_RJ;
break;
case SND_SOC_DAIFMT_LEFT_J:
val = PCM3060_REG_FMT_LJ;
break;
default:
dev_err(comp->dev, "unsupported DAI format: 0x%x\n", fmt);
return -EINVAL;
}
if (dai->id == PCM3060_DAI_ID_DAC)
reg = PCM3060_REG67;
else
reg = PCM3060_REG72;
regmap_update_bits(priv->regmap, reg, PCM3060_REG_MASK_FMT, val);
return 0;
}
static int pcm3060_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_component *comp = dai->component;
struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp);
unsigned int rate;
unsigned int ratio;
unsigned int reg;
unsigned int val;
if (!priv->dai[dai->id].is_master) {
val = PCM3060_REG_MS_S;
goto val_ready;
}
rate = params_rate(params);
if (!rate) {
dev_err(comp->dev, "rate is not configured\n");
return -EINVAL;
}
ratio = priv->dai[dai->id].sclk_freq / rate;
switch (ratio) {
case 768:
val = PCM3060_REG_MS_M768;
break;
case 512:
val = PCM3060_REG_MS_M512;
break;
case 384:
val = PCM3060_REG_MS_M384;
break;
case 256:
val = PCM3060_REG_MS_M256;
break;
case 192:
val = PCM3060_REG_MS_M192;
break;
case 128:
val = PCM3060_REG_MS_M128;
break;
default:
dev_err(comp->dev, "unsupported ratio: %d\n", ratio);
return -EINVAL;
}
val_ready:
if (dai->id == PCM3060_DAI_ID_DAC)
reg = PCM3060_REG67;
else
reg = PCM3060_REG72;
regmap_update_bits(priv->regmap, reg, PCM3060_REG_MASK_MS, val);
return 0;
}
static const struct snd_soc_dai_ops pcm3060_dai_ops = {
.set_sysclk = pcm3060_set_sysclk,
.set_fmt = pcm3060_set_fmt,
.hw_params = pcm3060_hw_params,
};
#define PCM3060_DAI_RATES_ADC (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | \
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
#define PCM3060_DAI_RATES_DAC (PCM3060_DAI_RATES_ADC | \
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
static struct snd_soc_dai_driver pcm3060_dai[] = {
{
.name = "pcm3060-dac",
.id = PCM3060_DAI_ID_DAC,
.playback = {
.stream_name = "Playback",
.channels_min = 2,
.channels_max = 2,
.rates = PCM3060_DAI_RATES_DAC,
.formats = SNDRV_PCM_FMTBIT_S24_LE,
},
.ops = &pcm3060_dai_ops,
},
{
.name = "pcm3060-adc",
.id = PCM3060_DAI_ID_ADC,
.capture = {
.stream_name = "Capture",
.channels_min = 2,
.channels_max = 2,
.rates = PCM3060_DAI_RATES_ADC,
.formats = SNDRV_PCM_FMTBIT_S24_LE,
},
.ops = &pcm3060_dai_ops,
},
};
/* dapm */
static DECLARE_TLV_DB_SCALE(pcm3060_dapm_tlv, -10050, 50, 1);
static const struct snd_kcontrol_new pcm3060_dapm_controls[] = {
SOC_DOUBLE_R_RANGE_TLV("Master Playback Volume",
PCM3060_REG65, PCM3060_REG66, 0,
PCM3060_REG_AT2_MIN, PCM3060_REG_AT2_MAX,
0, pcm3060_dapm_tlv),
SOC_DOUBLE("Master Playback Switch", PCM3060_REG68,
PCM3060_REG_SHIFT_MUT21, PCM3060_REG_SHIFT_MUT22, 1, 1),
SOC_DOUBLE_R_RANGE_TLV("Master Capture Volume",
PCM3060_REG70, PCM3060_REG71, 0,
PCM3060_REG_AT1_MIN, PCM3060_REG_AT1_MAX,
0, pcm3060_dapm_tlv),
SOC_DOUBLE("Master Capture Switch", PCM3060_REG73,
PCM3060_REG_SHIFT_MUT11, PCM3060_REG_SHIFT_MUT12, 1, 1),
};
static const struct snd_soc_dapm_widget pcm3060_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("OUTL+"),
SND_SOC_DAPM_OUTPUT("OUTR+"),
SND_SOC_DAPM_OUTPUT("OUTL-"),
SND_SOC_DAPM_OUTPUT("OUTR-"),
SND_SOC_DAPM_INPUT("INL"),
SND_SOC_DAPM_INPUT("INR"),
};
static const struct snd_soc_dapm_route pcm3060_dapm_map[] = {
{ "OUTL+", NULL, "Playback" },
{ "OUTR+", NULL, "Playback" },
{ "OUTL-", NULL, "Playback" },
{ "OUTR-", NULL, "Playback" },
{ "Capture", NULL, "INL" },
{ "Capture", NULL, "INR" },
};
/* soc component */
static const struct snd_soc_component_driver pcm3060_soc_comp_driver = {
.controls = pcm3060_dapm_controls,
.num_controls = ARRAY_SIZE(pcm3060_dapm_controls),
.dapm_widgets = pcm3060_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(pcm3060_dapm_widgets),
.dapm_routes = pcm3060_dapm_map,
.num_dapm_routes = ARRAY_SIZE(pcm3060_dapm_map),
};
/* regmap */
static bool pcm3060_reg_writeable(struct device *dev, unsigned int reg)
{
return (reg >= PCM3060_REG64);
}
static bool pcm3060_reg_readable(struct device *dev, unsigned int reg)
{
return (reg >= PCM3060_REG64);
}
static bool pcm3060_reg_volatile(struct device *dev, unsigned int reg)
{
/* PCM3060_REG64 is volatile */
return (reg == PCM3060_REG64);
}
static const struct reg_default pcm3060_reg_defaults[] = {
{ PCM3060_REG64, 0xF0 },
{ PCM3060_REG65, 0xFF },
{ PCM3060_REG66, 0xFF },
{ PCM3060_REG67, 0x00 },
{ PCM3060_REG68, 0x00 },
{ PCM3060_REG69, 0x00 },
{ PCM3060_REG70, 0xD7 },
{ PCM3060_REG71, 0xD7 },
{ PCM3060_REG72, 0x00 },
{ PCM3060_REG73, 0x00 },
};
const struct regmap_config pcm3060_regmap = {
.reg_bits = 8,
.val_bits = 8,
.writeable_reg = pcm3060_reg_writeable,
.readable_reg = pcm3060_reg_readable,
.volatile_reg = pcm3060_reg_volatile,
.max_register = PCM3060_REG73,
.reg_defaults = pcm3060_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(pcm3060_reg_defaults),
.cache_type = REGCACHE_RBTREE,
};
EXPORT_SYMBOL(pcm3060_regmap);
/* device */
int pcm3060_probe(struct device *dev)
{
int rc;
rc = devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver,
pcm3060_dai,
ARRAY_SIZE(pcm3060_dai));
if (rc) {
dev_err(dev, "failed to register component, rc=%d\n", rc);
return rc;
}
return 0;
}
EXPORT_SYMBOL(pcm3060_probe);
MODULE_DESCRIPTION("PCM3060 codec driver");
MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.tech>");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,88 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* PCM3060 codec driver
*
* Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech>
*/
#ifndef _SND_SOC_PCM3060_H
#define _SND_SOC_PCM3060_H
#include <linux/device.h>
#include <linux/regmap.h>
extern const struct regmap_config pcm3060_regmap;
#define PCM3060_DAI_ID_DAC 0
#define PCM3060_DAI_ID_ADC 1
#define PCM3060_DAI_IDS_NUM 2
struct pcm3060_priv_dai {
bool is_master;
unsigned int sclk_freq;
};
struct pcm3060_priv {
struct regmap *regmap;
struct pcm3060_priv_dai dai[PCM3060_DAI_IDS_NUM];
};
int pcm3060_probe(struct device *dev);
int pcm3060_remove(struct device *dev);
/* registers */
#define PCM3060_REG64 0x40
#define PCM3060_REG_MRST 0x80
#define PCM3060_REG_SRST 0x40
#define PCM3060_REG_ADPSV 0x20
#define PCM3060_REG_DAPSV 0x10
#define PCM3060_REG_SE 0x01
#define PCM3060_REG65 0x41
#define PCM3060_REG66 0x42
#define PCM3060_REG_AT2_MIN 0x36
#define PCM3060_REG_AT2_MAX 0xFF
#define PCM3060_REG67 0x43
#define PCM3060_REG72 0x48
#define PCM3060_REG_CSEL 0x80
#define PCM3060_REG_MASK_MS 0x70
#define PCM3060_REG_MS_S 0x00
#define PCM3060_REG_MS_M768 (0x01 << 4)
#define PCM3060_REG_MS_M512 (0x02 << 4)
#define PCM3060_REG_MS_M384 (0x03 << 4)
#define PCM3060_REG_MS_M256 (0x04 << 4)
#define PCM3060_REG_MS_M192 (0x05 << 4)
#define PCM3060_REG_MS_M128 (0x06 << 4)
#define PCM3060_REG_MASK_FMT 0x03
#define PCM3060_REG_FMT_I2S 0x00
#define PCM3060_REG_FMT_LJ 0x01
#define PCM3060_REG_FMT_RJ 0x02
#define PCM3060_REG68 0x44
#define PCM3060_REG_OVER 0x40
#define PCM3060_REG_DREV2 0x04
#define PCM3060_REG_SHIFT_MUT21 0x00
#define PCM3060_REG_SHIFT_MUT22 0x01
#define PCM3060_REG69 0x45
#define PCM3060_REG_FLT 0x80
#define PCM3060_REG_MASK_DMF 0x60
#define PCM3060_REG_DMC 0x10
#define PCM3060_REG_ZREV 0x02
#define PCM3060_REG_AZRO 0x01
#define PCM3060_REG70 0x46
#define PCM3060_REG71 0x47
#define PCM3060_REG_AT1_MIN 0x0E
#define PCM3060_REG_AT1_MAX 0xFF
#define PCM3060_REG73 0x49
#define PCM3060_REG_ZCDD 0x10
#define PCM3060_REG_BYP 0x08
#define PCM3060_REG_DREV1 0x04
#define PCM3060_REG_SHIFT_MUT11 0x00
#define PCM3060_REG_SHIFT_MUT12 0x01
#endif /* _SND_SOC_PCM3060_H */

View File

@ -33,6 +33,8 @@
#define PCM3168A_FMT_RIGHT_J_16 0x3
#define PCM3168A_FMT_DSP_A 0x4
#define PCM3168A_FMT_DSP_B 0x5
#define PCM3168A_FMT_I2S_TDM 0x6
#define PCM3168A_FMT_LEFT_J_TDM 0x7
#define PCM3168A_FMT_DSP_MASK 0x4
#define PCM3168A_NUM_SUPPLIES 6
@ -401,9 +403,11 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
bool tx, master_mode;
u32 val, mask, shift, reg;
unsigned int rate, fmt, ratio, max_ratio;
unsigned int chan;
int i, min_frame_size;
rate = params_rate(params);
chan = params_channels(params);
ratio = pcm3168a->sysclk / rate;
@ -456,6 +460,21 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
/* for TDM */
if (chan > 2) {
switch (fmt) {
case PCM3168A_FMT_I2S:
fmt = PCM3168A_FMT_I2S_TDM;
break;
case PCM3168A_FMT_LEFT_J:
fmt = PCM3168A_FMT_LEFT_J_TDM;
break;
default:
dev_err(component->dev, "TDM is supported under I2S/Left_J only\n");
return -EINVAL;
}
}
if (master_mode)
val = ((i + 1) << shift);
else
@ -476,7 +495,69 @@ 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);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
unsigned int fmt;
unsigned int sample_min;
unsigned int channel_max;
if (tx)
fmt = pcm3168a->dac_fmt;
else
fmt = pcm3168a->adc_fmt;
/*
* Available Data Bits
*
* RIGHT_J : 24 / 16
* LEFT_J : 24
* I2S : 24
*
* TDM available
*
* I2S
* LEFT_J
*/
switch (fmt) {
case PCM3168A_FMT_RIGHT_J:
sample_min = 16;
channel_max = 2;
break;
case PCM3168A_FMT_LEFT_J:
sample_min = 24;
if (tx)
channel_max = 8;
else
channel_max = 6;
break;
case PCM3168A_FMT_I2S:
sample_min = 24;
if (tx)
channel_max = 8;
else
channel_max = 6;
break;
default:
sample_min = 24;
channel_max = 2;
}
snd_pcm_hw_constraint_minmax(substream->runtime,
SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
sample_min, 32);
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_dac_dai_ops = {
.startup = pcm3168a_startup,
.set_fmt = pcm3168a_set_dai_fmt_dac,
.set_sysclk = pcm3168a_set_dai_sysclk,
.hw_params = pcm3168a_hw_params,
@ -484,6 +565,7 @@ static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = {
};
static const struct snd_soc_dai_ops pcm3168a_adc_dai_ops = {
.startup = pcm3168a_startup,
.set_fmt = pcm3168a_set_dai_fmt_adc,
.set_sysclk = pcm3168a_set_dai_sysclk,
.hw_params = pcm3168a_hw_params

View File

@ -755,6 +755,7 @@ static int rt274_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
break;
default:
dev_warn(component->dev, "invalid pll source, use BCLK\n");
/* fall through */
case RT274_PLL2_S_BCLK:
snd_soc_component_update_bits(component, RT274_PLL2_CTRL,
RT274_PLL2_SRC_MASK, RT274_PLL2_SRC_BCLK);
@ -782,6 +783,7 @@ static int rt274_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
break;
default:
dev_warn(component->dev, "invalid freq_in, assume 4.8M\n");
/* fall through */
case 100:
snd_soc_component_write(component, 0x7a, 0xaab6);
snd_soc_component_write(component, 0x7b, 0x0301);

View File

@ -10,7 +10,6 @@
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>

View File

@ -72,6 +72,7 @@ struct rt5663_priv {
static const struct reg_sequence rt5663_patch_list[] = {
{ 0x002a, 0x8020 },
{ 0x0086, 0x0028 },
{ 0x0100, 0xa020 },
{ 0x0117, 0x0f28 },
{ 0x02fb, 0x8089 },
};
@ -580,7 +581,7 @@ static const struct reg_default rt5663_reg[] = {
{ 0x00fd, 0x0001 },
{ 0x00fe, 0x10ec },
{ 0x00ff, 0x6406 },
{ 0x0100, 0xa0a0 },
{ 0x0100, 0xa020 },
{ 0x0108, 0x4444 },
{ 0x0109, 0x4444 },
{ 0x010a, 0xaaaa },
@ -2337,6 +2338,8 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w,
0x8000);
snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x3000,
0x3000);
snd_soc_component_update_bits(component,
RT5663_DIG_VOL_ZCD, 0x00c0, 0x0080);
}
break;
@ -2351,6 +2354,8 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w,
RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_EN);
snd_soc_component_update_bits(component,
RT5663_DACREF_LDO, 0x3e0e, 0);
snd_soc_component_update_bits(component,
RT5663_DIG_VOL_ZCD, 0x00c0, 0);
}
break;

View File

@ -2587,17 +2587,10 @@ static int rt5668_i2c_probe(struct i2c_client *i2c,
}
return snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5668,
return devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5668,
rt5668_dai, ARRAY_SIZE(rt5668_dai));
}
static int rt5668_i2c_remove(struct i2c_client *i2c)
{
snd_soc_unregister_component(&i2c->dev);
return 0;
}
static void rt5668_i2c_shutdown(struct i2c_client *client)
{
struct rt5668_priv *rt5668 = i2c_get_clientdata(client);
@ -2628,7 +2621,6 @@ static struct i2c_driver rt5668_i2c_driver = {
.acpi_match_table = ACPI_PTR(rt5668_acpi_match),
},
.probe = rt5668_i2c_probe,
.remove = rt5668_i2c_remove,
.shutdown = rt5668_i2c_shutdown,
.id_table = rt5668_i2c_id,
};

View File

@ -2875,6 +2875,18 @@ static const struct dmi_system_id dmi_platform_intel_quirks[] = {
RT5670_DEV_GPIO |
RT5670_JD_MODE1),
},
{
.callback = rt5670_quirk_cb,
.ident = "Lenovo Thinkpad Tablet 8",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 8"),
},
.driver_data = (unsigned long *)(RT5670_DMIC_EN |
RT5670_DMIC2_INR |
RT5670_DEV_GPIO |
RT5670_JD_MODE1),
},
{
.callback = rt5670_quirk_cb,
.ident = "Lenovo Thinkpad Tablet 10",

View File

@ -18,7 +18,6 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/regulator/consumer.h>

View File

@ -67,7 +67,8 @@ struct rt5682_priv {
};
static const struct reg_sequence patch_list[] = {
{0x01c1, 0x1000},
{RT5682_HP_IMP_SENS_CTRL_19, 0x1000},
{RT5682_DAC_ADC_DIG_VOL1, 0xa020},
};
static const struct reg_default rt5682_reg[] = {
@ -1432,6 +1433,28 @@ static const struct snd_kcontrol_new hpor_switch =
SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5682_HP_CTRL_1,
RT5682_R_MUTE_SFT, 1, 1);
static int rt5682_charge_pump_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);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
snd_soc_component_update_bits(component,
RT5682_HP_CHARGE_PUMP_1, RT5682_PM_HP_MASK, RT5682_PM_HP_HV);
break;
case SND_SOC_DAPM_POST_PMD:
snd_soc_component_update_bits(component,
RT5682_HP_CHARGE_PUMP_1, RT5682_PM_HP_MASK, RT5682_PM_HP_LV);
break;
default:
return 0;
}
return 0;
}
static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@ -1444,10 +1467,10 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
RT5682_HP_LOGIC_CTRL_2, 0x0012);
snd_soc_component_write(component,
RT5682_HP_CTRL_2, 0x6000);
snd_soc_component_update_bits(component, RT5682_STO_NG2_CTRL_1,
RT5682_NG2_EN_MASK, RT5682_NG2_EN);
snd_soc_component_update_bits(component,
RT5682_DEPOP_1, 0x60, 0x60);
snd_soc_component_update_bits(component,
RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0080);
break;
case SND_SOC_DAPM_POST_PMD:
@ -1455,6 +1478,8 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
RT5682_DEPOP_1, 0x60, 0x0);
snd_soc_component_write(component,
RT5682_HP_CTRL_2, 0x0000);
snd_soc_component_update_bits(component,
RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0000);
break;
default:
@ -1718,7 +1743,8 @@ static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("HP Amp R", RT5682_PWR_ANLG_1,
RT5682_PWR_HA_R_BIT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("Charge Pump", 1, RT5682_DEPOP_1,
RT5682_PUMP_EN_SFT, 0, NULL, 0),
RT5682_PUMP_EN_SFT, 0, rt5682_charge_pump_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY_S("Capless", 2, RT5682_DEPOP_1,
RT5682_CAPLESS_EN_SFT, 0, NULL, 0),
@ -1879,6 +1905,7 @@ static const struct snd_soc_dapm_route rt5682_dapm_routes[] = {
{"HP Amp", NULL, "Charge Pump"},
{"HP Amp", NULL, "CLKDET SYS"},
{"HP Amp", NULL, "CBJ Power"},
{"HP Amp", NULL, "Vref1"},
{"HP Amp", NULL, "Vref2"},
{"HPOL Playback", "Switch", "HP Amp"},
{"HPOR Playback", "Switch", "HP Amp"},
@ -2446,30 +2473,23 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682)
mutex_lock(&rt5682->calibrate_mutex);
rt5682_reset(rt5682->regmap);
regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xa2bf);
regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xa2af);
usleep_range(15000, 20000);
regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xf2bf);
regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0380);
regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x8001);
regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000);
regmap_write(rt5682->regmap, RT5682_STO1_DAC_MIXER, 0x2080);
regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x4040);
regmap_write(rt5682->regmap, RT5682_DEPOP_1, 0x0069);
regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xf2af);
regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0300);
regmap_write(rt5682->regmap, RT5682_GLB_CLK, 0x8000);
regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0100);
regmap_write(rt5682->regmap, RT5682_HP_IMP_SENS_CTRL_19, 0x3800);
regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x3000);
regmap_write(rt5682->regmap, RT5682_HP_CTRL_2, 0x6000);
regmap_write(rt5682->regmap, RT5682_HP_CHARGE_PUMP_1, 0x0f26);
regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x7f05);
regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x7005);
regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x686c);
regmap_write(rt5682->regmap, RT5682_CAL_REC, 0x0d0d);
regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_9, 0x000f);
regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x8d01);
regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_2, 0x0321);
regmap_write(rt5682->regmap, RT5682_HP_LOGIC_CTRL_2, 0x0004);
regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00);
regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_3, 0x06a1);
regmap_write(rt5682->regmap, RT5682_A_DAC1_MUX, 0x0311);
regmap_write(rt5682->regmap, RT5682_RESET_HPF_CTRL, 0x0000);
regmap_write(rt5682->regmap, RT5682_ADC_STO1_HP_CTRL_1, 0x3320);
regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00);
regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0xfc00);
@ -2485,8 +2505,12 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682)
pr_err("HP Calibration Failure\n");
/* restore settings */
regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0xc0c4);
regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0x02af);
regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0080);
regmap_write(rt5682->regmap, RT5682_GLB_CLK, 0x0000);
regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0000);
regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x2000);
regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x2005);
mutex_unlock(&rt5682->calibrate_mutex);
@ -2560,7 +2584,7 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
rt5682_calibrate(rt5682);
ret = regmap_register_patch(rt5682->regmap, patch_list,
ret = regmap_multi_reg_write(rt5682->regmap, patch_list,
ARRAY_SIZE(patch_list));
if (ret != 0)
dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
@ -2614,6 +2638,10 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
RT5682_GP4_PIN_MASK | RT5682_GP5_PIN_MASK,
RT5682_GP4_PIN_ADCDAT1 | RT5682_GP5_PIN_DACDAT1);
regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000);
regmap_update_bits(rt5682->regmap, RT5682_BIAS_CUR_CTRL_8,
RT5682_HPA_CP_BIAS_CTRL_MASK, RT5682_HPA_CP_BIAS_3UA);
regmap_update_bits(rt5682->regmap, RT5682_CHARGE_PUMP_1,
RT5682_CP_CLK_HP_MASK, RT5682_CP_CLK_HP_300KHZ);
INIT_DELAYED_WORK(&rt5682->jack_detect_work,
rt5682_jack_detect_handler);
@ -2631,11 +2659,17 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
}
return devm_snd_soc_register_component(&i2c->dev,
&soc_component_dev_rt5682,
return snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5682,
rt5682_dai, ARRAY_SIZE(rt5682_dai));
}
static int rt5682_i2c_remove(struct i2c_client *i2c)
{
snd_soc_unregister_component(&i2c->dev);
return 0;
}
static void rt5682_i2c_shutdown(struct i2c_client *client)
{
struct rt5682_priv *rt5682 = i2c_get_clientdata(client);
@ -2666,6 +2700,7 @@ static struct i2c_driver rt5682_i2c_driver = {
.acpi_match_table = ACPI_PTR(rt5682_acpi_match),
},
.probe = rt5682_i2c_probe,
.remove = rt5682_i2c_remove,
.shutdown = rt5682_i2c_shutdown,
.id_table = rt5682_i2c_id,
};

View File

@ -1214,6 +1214,20 @@
#define RT5682_JDH_NO_PLUG (0x1 << 4)
#define RT5682_JDH_PLUG (0x0 << 4)
/* Bias current control 8 (0x0111) */
#define RT5682_HPA_CP_BIAS_CTRL_MASK (0x3 << 2)
#define RT5682_HPA_CP_BIAS_2UA (0x0 << 2)
#define RT5682_HPA_CP_BIAS_3UA (0x1 << 2)
#define RT5682_HPA_CP_BIAS_4UA (0x2 << 2)
#define RT5682_HPA_CP_BIAS_6UA (0x3 << 2)
/* Charge Pump Internal Register1 (0x0125) */
#define RT5682_CP_CLK_HP_MASK (0x3 << 4)
#define RT5682_CP_CLK_HP_100KHZ (0x0 << 4)
#define RT5682_CP_CLK_HP_200KHZ (0x1 << 4)
#define RT5682_CP_CLK_HP_300KHZ (0x2 << 4)
#define RT5682_CP_CLK_HP_600KHZ (0x3 << 4)
/* Chopper and Clock control for DAC (0x013a)*/
#define RT5682_CKXEN_DAC1_MASK (0x1 << 13)
#define RT5682_CKXEN_DAC1_SFT 13

View File

@ -1218,7 +1218,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_component *component)
* Searching for a suitable index solving this formula:
* idx = 40 * log10(vag_val / lo_cagcntrl) + 15
*/
vol_quot = (vag * 100) / lo_vag;
vol_quot = lo_vag ? (vag * 100) / lo_vag : 0;
lo_vol = 0;
for (i = 0; i < ARRAY_SIZE(vol_quot_table); i++) {
if (vol_quot >= vol_quot_table[i])

View File

@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
@ -142,6 +143,7 @@ static const char *sta32x_supply_names[] = {
/* codec private data */
struct sta32x_priv {
struct regmap *regmap;
struct clk *xti_clk;
struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)];
struct snd_soc_component *component;
struct sta32x_platform_data *pdata;
@ -882,6 +884,15 @@ static int sta32x_probe(struct snd_soc_component *component)
sta32x->component = component;
if (sta32x->xti_clk) {
ret = clk_prepare_enable(sta32x->xti_clk);
if (ret != 0) {
dev_err(component->dev,
"Failed to enable clock: %d\n", ret);
return ret;
}
}
ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
sta32x->supplies);
if (ret != 0) {
@ -984,6 +995,9 @@ static void sta32x_remove(struct snd_soc_component *component)
sta32x_watchdog_stop(sta32x);
regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
if (sta32x->xti_clk)
clk_disable_unprepare(sta32x->xti_clk);
}
static const struct snd_soc_component_driver sta32x_component = {
@ -1041,6 +1055,8 @@ static int sta32x_probe_dt(struct device *dev, struct sta32x_priv *sta32x)
of_property_read_u8(np, "st,ch3-output-mapping",
&pdata->ch3_output_mapping);
if (of_get_property(np, "st,fault-detect-recovery", NULL))
pdata->fault_detect_recovery = 1;
if (of_get_property(np, "st,thermal-warning-recovery", NULL))
pdata->thermal_warning_recovery = 1;
if (of_get_property(np, "st,thermal-warning-adjustment", NULL))
@ -1098,6 +1114,17 @@ static int sta32x_i2c_probe(struct i2c_client *i2c,
}
#endif
/* Clock */
sta32x->xti_clk = devm_clk_get(dev, "xti");
if (IS_ERR(sta32x->xti_clk)) {
ret = PTR_ERR(sta32x->xti_clk);
if (ret == -EPROBE_DEFER)
return ret;
sta32x->xti_clk = NULL;
}
/* GPIOs */
sta32x->gpiod_nreset = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_LOW);

View File

@ -152,6 +152,7 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai,
int slots, int slot_width)
{
struct snd_soc_component *component = dai->component;
struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
unsigned int first_slot;
int ret;
@ -185,6 +186,20 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai,
if (ret < 0)
goto error_snd_soc_component_update_bits;
/* Configure TDM slot width. This is only applicable to TAS5722. */
switch (tas5720->devtype) {
case TAS5722:
ret = snd_soc_component_update_bits(component, TAS5722_DIGITAL_CTRL2_REG,
TAS5722_TDM_SLOT_16B,
slot_width == 16 ?
TAS5722_TDM_SLOT_16B : 0);
if (ret < 0)
goto error_snd_soc_component_update_bits;
break;
default:
break;
}
return 0;
error_snd_soc_component_update_bits:
@ -485,15 +500,56 @@ static const DECLARE_TLV_DB_RANGE(dac_analog_tlv,
);
/*
* DAC digital volumes. From -103.5 to 24 dB in 0.5 dB steps. Note that
* setting the gain below -100 dB (register value <0x7) is effectively a MUTE
* as per device datasheet.
* DAC digital volumes. From -103.5 to 24 dB in 0.5 dB or 0.25 dB steps
* depending on the device. Note that setting the gain below -100 dB
* (register value <0x7) is effectively a MUTE as per device datasheet.
*
* Note that for the TAS5722 the digital volume controls are actually split
* over two registers, so we need custom getters/setters for access.
*/
static DECLARE_TLV_DB_SCALE(dac_tlv, -10350, 50, 0);
static DECLARE_TLV_DB_SCALE(tas5720_dac_tlv, -10350, 50, 0);
static DECLARE_TLV_DB_SCALE(tas5722_dac_tlv, -10350, 25, 0);
static int tas5722_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
unsigned int val;
snd_soc_component_read(component, TAS5720_VOLUME_CTRL_REG, &val);
ucontrol->value.integer.value[0] = val << 1;
snd_soc_component_read(component, TAS5722_DIGITAL_CTRL2_REG, &val);
ucontrol->value.integer.value[0] |= val & TAS5722_VOL_CONTROL_LSB;
return 0;
}
static int tas5722_volume_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
unsigned int sel = ucontrol->value.integer.value[0];
snd_soc_component_write(component, TAS5720_VOLUME_CTRL_REG, sel >> 1);
snd_soc_component_update_bits(component, TAS5722_DIGITAL_CTRL2_REG,
TAS5722_VOL_CONTROL_LSB, sel);
return 0;
}
static const struct snd_kcontrol_new tas5720_snd_controls[] = {
SOC_SINGLE_TLV("Speaker Driver Playback Volume",
TAS5720_VOLUME_CTRL_REG, 0, 0xff, 0, dac_tlv),
TAS5720_VOLUME_CTRL_REG, 0, 0xff, 0, tas5720_dac_tlv),
SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG,
TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv),
};
static const struct snd_kcontrol_new tas5722_snd_controls[] = {
SOC_SINGLE_EXT_TLV("Speaker Driver Playback Volume",
0, 0, 511, 0,
tas5722_volume_get, tas5722_volume_set,
tas5722_dac_tlv),
SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG,
TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv),
};
@ -527,6 +583,23 @@ static const struct snd_soc_component_driver soc_component_dev_tas5720 = {
.non_legacy_dai_naming = 1,
};
static const struct snd_soc_component_driver soc_component_dev_tas5722 = {
.probe = tas5720_codec_probe,
.remove = tas5720_codec_remove,
.suspend = tas5720_suspend,
.resume = tas5720_resume,
.controls = tas5722_snd_controls,
.num_controls = ARRAY_SIZE(tas5722_snd_controls),
.dapm_widgets = tas5720_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(tas5720_dapm_widgets),
.dapm_routes = tas5720_audio_map,
.num_dapm_routes = ARRAY_SIZE(tas5720_audio_map),
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
/* PCM rates supported by the TAS5720 driver */
#define TAS5720_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
@ -613,9 +686,23 @@ static int tas5720_probe(struct i2c_client *client,
dev_set_drvdata(dev, data);
ret = devm_snd_soc_register_component(&client->dev,
&soc_component_dev_tas5720,
tas5720_dai, ARRAY_SIZE(tas5720_dai));
switch (id->driver_data) {
case TAS5720:
ret = devm_snd_soc_register_component(&client->dev,
&soc_component_dev_tas5720,
tas5720_dai,
ARRAY_SIZE(tas5720_dai));
break;
case TAS5722:
ret = devm_snd_soc_register_component(&client->dev,
&soc_component_dev_tas5722,
tas5720_dai,
ARRAY_SIZE(tas5720_dai));
break;
default:
dev_err(dev, "unexpected private driver data\n");
return -EINVAL;
}
if (ret < 0) {
dev_err(dev, "failed to register component: %d\n", ret);
return ret;

View File

@ -41,6 +41,7 @@ struct tas6424_data {
struct regmap *regmap;
struct regulator_bulk_data supplies[TAS6424_NUM_SUPPLIES];
struct delayed_work fault_check_work;
unsigned int last_cfault;
unsigned int last_fault1;
unsigned int last_fault2;
unsigned int last_warn;
@ -406,9 +407,54 @@ static void tas6424_fault_check_work(struct work_struct *work)
unsigned int reg;
int ret;
ret = regmap_read(tas6424->regmap, TAS6424_CHANNEL_FAULT, &reg);
if (ret < 0) {
dev_err(dev, "failed to read CHANNEL_FAULT register: %d\n", ret);
goto out;
}
if (!reg) {
tas6424->last_cfault = reg;
goto check_global_fault1_reg;
}
/*
* Only flag errors once for a given occurrence. This is needed as
* the TAS6424 will take time clearing the fault condition internally
* during which we don't want to bombard the system with the same
* error message over and over.
*/
if ((reg & TAS6424_FAULT_OC_CH1) && !(tas6424->last_cfault & TAS6424_FAULT_OC_CH1))
dev_crit(dev, "experienced a channel 1 overcurrent fault\n");
if ((reg & TAS6424_FAULT_OC_CH2) && !(tas6424->last_cfault & TAS6424_FAULT_OC_CH2))
dev_crit(dev, "experienced a channel 2 overcurrent fault\n");
if ((reg & TAS6424_FAULT_OC_CH3) && !(tas6424->last_cfault & TAS6424_FAULT_OC_CH3))
dev_crit(dev, "experienced a channel 3 overcurrent fault\n");
if ((reg & TAS6424_FAULT_OC_CH4) && !(tas6424->last_cfault & TAS6424_FAULT_OC_CH4))
dev_crit(dev, "experienced a channel 4 overcurrent fault\n");
if ((reg & TAS6424_FAULT_DC_CH1) && !(tas6424->last_cfault & TAS6424_FAULT_DC_CH1))
dev_crit(dev, "experienced a channel 1 DC fault\n");
if ((reg & TAS6424_FAULT_DC_CH2) && !(tas6424->last_cfault & TAS6424_FAULT_DC_CH2))
dev_crit(dev, "experienced a channel 2 DC fault\n");
if ((reg & TAS6424_FAULT_DC_CH3) && !(tas6424->last_cfault & TAS6424_FAULT_DC_CH3))
dev_crit(dev, "experienced a channel 3 DC fault\n");
if ((reg & TAS6424_FAULT_DC_CH4) && !(tas6424->last_cfault & TAS6424_FAULT_DC_CH4))
dev_crit(dev, "experienced a channel 4 DC fault\n");
/* Store current fault1 value so we can detect any changes next time */
tas6424->last_cfault = reg;
check_global_fault1_reg:
ret = regmap_read(tas6424->regmap, TAS6424_GLOB_FAULT1, &reg);
if (ret < 0) {
dev_err(dev, "failed to read FAULT1 register: %d\n", ret);
dev_err(dev, "failed to read GLOB_FAULT1 register: %d\n", ret);
goto out;
}
@ -429,12 +475,6 @@ static void tas6424_fault_check_work(struct work_struct *work)
goto check_global_fault2_reg;
}
/*
* Only flag errors once for a given occurrence. This is needed as
* the TAS6424 will take time clearing the fault condition internally
* during which we don't want to bombard the system with the same
* error message over and over.
*/
if ((reg & TAS6424_FAULT_PVDD_OV) && !(tas6424->last_fault1 & TAS6424_FAULT_PVDD_OV))
dev_crit(dev, "experienced a PVDD overvoltage fault\n");
@ -453,7 +493,7 @@ static void tas6424_fault_check_work(struct work_struct *work)
check_global_fault2_reg:
ret = regmap_read(tas6424->regmap, TAS6424_GLOB_FAULT2, &reg);
if (ret < 0) {
dev_err(dev, "failed to read FAULT2 register: %d\n", ret);
dev_err(dev, "failed to read GLOB_FAULT2 register: %d\n", ret);
goto out;
}
@ -530,7 +570,7 @@ check_warn_reg:
/* Store current warn value so we can detect any changes next time */
tas6424->last_warn = reg;
/* Clear any faults by toggling the CLEAR_FAULT control bit */
/* Clear any warnings by toggling the CLEAR_FAULT control bit */
ret = regmap_write_bits(tas6424->regmap, TAS6424_MISC_CTRL3,
TAS6424_CLEAR_FAULT, TAS6424_CLEAR_FAULT);
if (ret < 0)

View File

@ -115,6 +115,16 @@
#define TAS6424_LDGBYPASS_SHIFT 0
#define TAS6424_LDGBYPASS_MASK BIT(TAS6424_LDGBYPASS_SHIFT)
/* TAS6424_GLOB_FAULT1_REG */
#define TAS6424_FAULT_OC_CH1 BIT(7)
#define TAS6424_FAULT_OC_CH2 BIT(6)
#define TAS6424_FAULT_OC_CH3 BIT(5)
#define TAS6424_FAULT_OC_CH4 BIT(4)
#define TAS6424_FAULT_DC_CH1 BIT(3)
#define TAS6424_FAULT_DC_CH2 BIT(2)
#define TAS6424_FAULT_DC_CH3 BIT(1)
#define TAS6424_FAULT_DC_CH4 BIT(0)
/* TAS6424_GLOB_FAULT1_REG */
#define TAS6424_FAULT_CLOCK BIT(4)
#define TAS6424_FAULT_PVDD_OV BIT(3)

View File

@ -167,6 +167,7 @@ struct aic31xx_priv {
u8 p_div;
int rate_div_line;
bool master_dapm_route_applied;
int irq;
};
struct aic31xx_rate_divs {
@ -1391,6 +1392,69 @@ static const struct acpi_device_id aic31xx_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match);
#endif
static irqreturn_t aic31xx_irq(int irq, void *data)
{
struct aic31xx_priv *aic31xx = data;
struct device *dev = aic31xx->dev;
unsigned int value;
bool handled = false;
int ret;
ret = regmap_read(aic31xx->regmap, AIC31XX_INTRDACFLAG, &value);
if (ret) {
dev_err(dev, "Failed to read interrupt mask: %d\n", ret);
goto exit;
}
if (value)
handled = true;
else
goto read_overflow;
if (value & AIC31XX_HPLSCDETECT)
dev_err(dev, "Short circuit on Left output is detected\n");
if (value & AIC31XX_HPRSCDETECT)
dev_err(dev, "Short circuit on Right output is detected\n");
if (value & ~(AIC31XX_HPLSCDETECT |
AIC31XX_HPRSCDETECT))
dev_err(dev, "Unknown DAC interrupt flags: 0x%08x\n", value);
read_overflow:
ret = regmap_read(aic31xx->regmap, AIC31XX_OFFLAG, &value);
if (ret) {
dev_err(dev, "Failed to read overflow flag: %d\n", ret);
goto exit;
}
if (value)
handled = true;
else
goto exit;
if (value & AIC31XX_DAC_OF_LEFT)
dev_warn(dev, "Left-channel DAC overflow has occurred\n");
if (value & AIC31XX_DAC_OF_RIGHT)
dev_warn(dev, "Right-channel DAC overflow has occurred\n");
if (value & AIC31XX_DAC_OF_SHIFTER)
dev_warn(dev, "DAC barrel shifter overflow has occurred\n");
if (value & AIC31XX_ADC_OF)
dev_warn(dev, "ADC overflow has occurred\n");
if (value & AIC31XX_ADC_OF_SHIFTER)
dev_warn(dev, "ADC barrel shifter overflow has occurred\n");
if (value & ~(AIC31XX_DAC_OF_LEFT |
AIC31XX_DAC_OF_RIGHT |
AIC31XX_DAC_OF_SHIFTER |
AIC31XX_ADC_OF |
AIC31XX_ADC_OF_SHIFTER))
dev_warn(dev, "Unknown overflow interrupt flags: 0x%08x\n", value);
exit:
if (handled)
return IRQ_HANDLED;
else
return IRQ_NONE;
}
static int aic31xx_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@ -1413,6 +1477,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
return ret;
}
aic31xx->dev = &i2c->dev;
aic31xx->irq = i2c->irq;
aic31xx->codec_type = id->driver_data;
@ -1456,6 +1521,26 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
return ret;
}
if (aic31xx->irq > 0) {
regmap_update_bits(aic31xx->regmap, AIC31XX_GPIO1,
AIC31XX_GPIO1_FUNC_MASK,
AIC31XX_GPIO1_INT1 <<
AIC31XX_GPIO1_FUNC_SHIFT);
regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL,
AIC31XX_SC |
AIC31XX_ENGINE);
ret = devm_request_threaded_irq(aic31xx->dev, aic31xx->irq,
NULL, aic31xx_irq,
IRQF_ONESHOT, "aic31xx-irq",
aic31xx);
if (ret) {
dev_err(aic31xx->dev, "Unable to request IRQ\n");
return ret;
}
}
if (aic31xx->codec_type & DAC31XX_BIT)
return devm_snd_soc_register_component(&i2c->dev,
&soc_codec_driver_aic31xx,

View File

@ -173,6 +173,13 @@ struct aic31xx_pdata {
#define AIC31XX_HPRDRVPWRSTATUS_MASK BIT(1)
#define AIC31XX_SPRDRVPWRSTATUS_MASK BIT(0)
/* AIC31XX_OFFLAG */
#define AIC31XX_DAC_OF_LEFT BIT(7)
#define AIC31XX_DAC_OF_RIGHT BIT(6)
#define AIC31XX_DAC_OF_SHIFTER BIT(5)
#define AIC31XX_ADC_OF BIT(3)
#define AIC31XX_ADC_OF_SHIFTER BIT(1)
/* AIC31XX_INTRDACFLAG */
#define AIC31XX_HPLSCDETECT BIT(7)
#define AIC31XX_HPRSCDETECT BIT(6)
@ -191,6 +198,22 @@ struct aic31xx_pdata {
#define AIC31XX_SC BIT(3)
#define AIC31XX_ENGINE BIT(2)
/* AIC31XX_GPIO1 */
#define AIC31XX_GPIO1_FUNC_MASK GENMASK(5, 2)
#define AIC31XX_GPIO1_FUNC_SHIFT 2
#define AIC31XX_GPIO1_DISABLED 0x00
#define AIC31XX_GPIO1_INPUT 0x01
#define AIC31XX_GPIO1_GPI 0x02
#define AIC31XX_GPIO1_GPO 0x03
#define AIC31XX_GPIO1_CLKOUT 0x04
#define AIC31XX_GPIO1_INT1 0x05
#define AIC31XX_GPIO1_INT2 0x06
#define AIC31XX_GPIO1_ADC_WCLK 0x07
#define AIC31XX_GPIO1_SBCLK 0x08
#define AIC31XX_GPIO1_SWCLK 0x09
#define AIC31XX_GPIO1_ADC_MOD_CLK 0x10
#define AIC31XX_GPIO1_SDOUT 0x11
/* AIC31XX_DACSETUP */
#define AIC31XX_SOFTSTEP_MASK GENMASK(1, 0)

View File

@ -3459,7 +3459,7 @@ static int tscs454_i2c_probe(struct i2c_client *i2c,
/* Sync pg sel reg with cache */
regmap_write(tscs454->regmap, R_PAGESEL, 0x00);
ret = snd_soc_register_component(&i2c->dev, &soc_component_dev_tscs454,
ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_tscs454,
tscs454_dais, ARRAY_SIZE(tscs454_dais));
if (ret) {
dev_err(&i2c->dev, "Failed to register component (%d)\n", ret);

View File

@ -88,19 +88,6 @@ static int wm2000_write(struct i2c_client *i2c, unsigned int reg,
return regmap_write(wm2000->regmap, reg, value);
}
static unsigned int wm2000_read(struct i2c_client *i2c, unsigned int r)
{
struct wm2000_priv *wm2000 = i2c_get_clientdata(i2c);
unsigned int val;
int ret;
ret = regmap_read(wm2000->regmap, r, &val);
if (ret < 0)
return -1;
return val;
}
static void wm2000_reset(struct wm2000_priv *wm2000)
{
struct i2c_client *i2c = wm2000->i2c;
@ -115,14 +102,15 @@ static void wm2000_reset(struct wm2000_priv *wm2000)
static int wm2000_poll_bit(struct i2c_client *i2c,
unsigned int reg, u8 mask)
{
struct wm2000_priv *wm2000 = i2c_get_clientdata(i2c);
int timeout = 4000;
int val;
unsigned int val;
val = wm2000_read(i2c, reg);
regmap_read(wm2000->regmap, reg, &val);
while (!(val & mask) && --timeout) {
msleep(1);
val = wm2000_read(i2c, reg);
regmap_read(wm2000->regmap, reg, &val);
}
if (timeout == 0)
@ -135,6 +123,7 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
{
struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
unsigned long rate;
unsigned int val;
int ret;
if (WARN_ON(wm2000->anc_mode != ANC_OFF))
@ -213,12 +202,17 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
WM2000_MODE_THERMAL_ENABLE);
}
ret = wm2000_read(i2c, WM2000_REG_SPEECH_CLARITY);
ret = regmap_read(wm2000->regmap, WM2000_REG_SPEECH_CLARITY, &val);
if (ret != 0) {
dev_err(&i2c->dev, "Unable to read Speech Clarity: %d\n", ret);
regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
return ret;
}
if (wm2000->speech_clarity)
ret |= WM2000_SPEECH_CLARITY;
val |= WM2000_SPEECH_CLARITY;
else
ret &= ~WM2000_SPEECH_CLARITY;
wm2000_write(i2c, WM2000_REG_SPEECH_CLARITY, ret);
val &= ~WM2000_SPEECH_CLARITY;
wm2000_write(i2c, WM2000_REG_SPEECH_CLARITY, val);
wm2000_write(i2c, WM2000_REG_SYS_START0, 0x33);
wm2000_write(i2c, WM2000_REG_SYS_START1, 0x02);
@ -824,7 +818,7 @@ static int wm2000_i2c_probe(struct i2c_client *i2c,
const char *filename;
const struct firmware *fw = NULL;
int ret, i;
int reg;
unsigned int reg;
u16 id;
wm2000 = devm_kzalloc(&i2c->dev, sizeof(*wm2000), GFP_KERNEL);
@ -860,9 +854,17 @@ static int wm2000_i2c_probe(struct i2c_client *i2c,
}
/* Verify that this is a WM2000 */
reg = wm2000_read(i2c, WM2000_REG_ID1);
ret = regmap_read(wm2000->regmap, WM2000_REG_ID1, &reg);
if (ret != 0) {
dev_err(&i2c->dev, "Unable to read ID1: %d\n", ret);
return ret;
}
id = reg << 8;
reg = wm2000_read(i2c, WM2000_REG_ID2);
ret = regmap_read(wm2000->regmap, WM2000_REG_ID2, &reg);
if (ret != 0) {
dev_err(&i2c->dev, "Unable to read ID2: %d\n", ret);
return ret;
}
id |= reg & 0xff;
if (id != 0x2000) {
@ -871,7 +873,11 @@ static int wm2000_i2c_probe(struct i2c_client *i2c,
goto err_supplies;
}
reg = wm2000_read(i2c, WM2000_REG_REVISON);
ret = regmap_read(wm2000->regmap, WM2000_REG_REVISON, &reg);
if (ret != 0) {
dev_err(&i2c->dev, "Unable to read Revision: %d\n", ret);
return ret;
}
dev_info(&i2c->dev, "revision %c\n", reg + 'A');
wm2000->mclk = devm_clk_get(&i2c->dev, "MCLK");

View File

@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/regulator/consumer.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
@ -50,7 +51,51 @@ static struct snd_soc_dai_driver wm8782_dai = {
},
};
/* regulator power supply names */
static const char *supply_names[] = {
"Vdda", /* analog supply, 2.7V - 3.6V */
"Vdd", /* digital supply, 2.7V - 5.5V */
};
struct wm8782_priv {
struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
};
static int wm8782_soc_probe(struct snd_soc_component *component)
{
struct wm8782_priv *priv = snd_soc_component_get_drvdata(component);
return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
}
static void wm8782_soc_remove(struct snd_soc_component *component)
{
struct wm8782_priv *priv = snd_soc_component_get_drvdata(component);
regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
}
#ifdef CONFIG_PM
static int wm8782_soc_suspend(struct snd_soc_component *component)
{
struct wm8782_priv *priv = snd_soc_component_get_drvdata(component);
regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
return 0;
}
static int wm8782_soc_resume(struct snd_soc_component *component)
{
struct wm8782_priv *priv = snd_soc_component_get_drvdata(component);
return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
}
#else
#define wm8782_soc_suspend NULL
#define wm8782_soc_resume NULL
#endif /* CONFIG_PM */
static const struct snd_soc_component_driver soc_component_dev_wm8782 = {
.probe = wm8782_soc_probe,
.remove = wm8782_soc_remove,
.suspend = wm8782_soc_suspend,
.resume = wm8782_soc_resume,
.dapm_widgets = wm8782_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm8782_dapm_widgets),
.dapm_routes = wm8782_dapm_routes,
@ -63,6 +108,24 @@ static const struct snd_soc_component_driver soc_component_dev_wm8782 = {
static int wm8782_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct wm8782_priv *priv;
int ret, i;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
dev_set_drvdata(dev, priv);
for (i = 0; i < ARRAY_SIZE(supply_names); i++)
priv->supplies[i].supply = supply_names[i];
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies),
priv->supplies);
if (ret < 0)
return ret;
return devm_snd_soc_register_component(&pdev->dev,
&soc_component_dev_wm8782, &wm8782_dai, 1);
}

View File

@ -13,7 +13,6 @@
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>

View File

@ -11,7 +11,6 @@
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>

Some files were not shown because too many files have changed in this diff Show More