forked from Minki/linux
ASoC: Updates for v3.15
A few more updates for the merge window: - Fixes for the simple-card DAI format DT mess. - A new driver for Cirrus cs42xx8 devices. - DT support for a couple more devices. - A revert of a previous buggy fix for soc-pcm, plus a few more fixes and cleanups. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJTLxIrAAoJELSic+t+oim9jcYQAJ1SGB0kG8yHvvuY1L6hxfWS VyeP63VYaETBUKQZFgLfwwmzCmHKFiK6wW5nclOoKP6akzDe1cVmeePj2vi6P+Et TzaTrJZDnHPwTHfkjznMCqBXlmnyJI05aP7zeClnBjBVV07VekRn1C4n82qCfDAH PnOsG7fPC4zvX55OAkwXf2yShsVJ4zL7X8rfmgH7EaJoOLTBwfqjey0VyoO9CPHk yRRYpgBUJGLErA14c4Ve+ErfqnAPju3KKGHpAezxbTKxa1Z2Ri47yxUx7TnFLVKz m1f02dbnkwnD5MI0vJ1SibFiswWMa+tdtLE7i0QOxIRGKdWgtGdYlPxo6bXjrUAR M9WHR755idWhoHiBoYBuKFHScBfG62pHsfSfySwlS35DGes4k7C6WWWAjxPRiG5M 7sTrqGyH4TSFVFvGYZFq68eVvFBzWeJ4H0KGEsvg49AK9/wscURrCkh241PN50kw mKbG1ZldwcBpeNcOARnGBxm7tuciQzyyOZPa7h7Ydkb/VpX7p5XsNQLxlZMcU2PH M4cqs64f3/4+1zjXZ9p14Jqv97e+SPCHI3udM9Nenh5MDeOilvemlhUTIjC1Cnzr 76EH0d8mmQ+As+kLjRuz4rozipl9UcFMrx/mpaoK/mnnc5a1M243HCO/6LAvhlyG RpbuRr6RuKVQ2iLh5tpB =wKyT -----END PGP SIGNATURE----- Merge tag 'asoc-v3.15-3' into asoc-next ASoC: Updates for v3.15 A few more updates for the merge window: - Fixes for the simple-card DAI format DT mess. - A new driver for Cirrus cs42xx8 devices. - DT support for a couple more devices. - A revert of a previous buggy fix for soc-pcm, plus a few more fixes and cleanups. # gpg: Signature made Sun 23 Mar 2014 16:56:11 GMT using RSA key ID 7EA229BD # gpg: Good signature from "Mark Brown <broonie@sirena.org.uk>" # gpg: aka "Mark Brown <broonie@debian.org>" # gpg: aka "Mark Brown <broonie@kernel.org>" # gpg: aka "Mark Brown <broonie@tardis.ed.ac.uk>" # gpg: aka "Mark Brown <broonie@linaro.org>" # gpg: aka "Mark Brown <Mark.Brown@linaro.org>"
This commit is contained in:
commit
8efe588b0f
@ -11,14 +11,17 @@ Mandatory properties:
|
||||
* marvell,audio-controller: a phandle that points to the audio
|
||||
controller of the Armada 370 SoC.
|
||||
|
||||
* marvell,audio-codec: a phandle that points to the analog audio
|
||||
codec connected to the Armada 370 SoC.
|
||||
* marvell,audio-codec: a set of three phandles that points to:
|
||||
|
||||
1/ the analog audio codec connected to the Armada 370 SoC
|
||||
2/ the S/PDIF transceiver
|
||||
3/ the S/PDIF receiver
|
||||
|
||||
Example:
|
||||
|
||||
sound {
|
||||
compatible = "marvell,a370db-audio";
|
||||
marvell,audio-controller = <&audio_controller>;
|
||||
marvell,audio-codec = <&audio_codec>;
|
||||
marvell,audio-codec = <&audio_codec &spdif_out &spdif_in>;
|
||||
status = "okay";
|
||||
};
|
||||
|
28
Documentation/devicetree/bindings/sound/cs42xx8.txt
Normal file
28
Documentation/devicetree/bindings/sound/cs42xx8.txt
Normal file
@ -0,0 +1,28 @@
|
||||
CS42448/CS42888 audio CODEC
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : must contain one of "cirrus,cs42448" and "cirrus,cs42888"
|
||||
|
||||
- reg : the I2C address of the device for I2C
|
||||
|
||||
- clocks : a list of phandles + clock-specifiers, one for each entry in
|
||||
clock-names
|
||||
|
||||
- clock-names : must contain "mclk"
|
||||
|
||||
- VA-supply, VD-supply, VLS-supply, VLC-supply: power supplies for the device,
|
||||
as covered in Documentation/devicetree/bindings/regulator/regulator.txt
|
||||
|
||||
Example:
|
||||
|
||||
codec: cs42888@48 {
|
||||
compatible = "cirrus,cs42888";
|
||||
reg = <0x48>;
|
||||
clocks = <&codec_mclk 0>;
|
||||
clock-names = "mclk";
|
||||
VA-supply = <®_audio>;
|
||||
VD-supply = <®_audio>;
|
||||
VLS-supply = <®_audio>;
|
||||
VLC-supply = <®_audio>;
|
||||
};
|
96
Documentation/devicetree/bindings/sound/renesas,rsnd.txt
Normal file
96
Documentation/devicetree/bindings/sound/renesas,rsnd.txt
Normal file
@ -0,0 +1,96 @@
|
||||
Renesas R-Car sound
|
||||
|
||||
Required properties:
|
||||
- compatible : "renesas,rcar_sound-gen1" if generation1
|
||||
"renesas,rcar_sound-gen2" if generation2
|
||||
- reg : Should contain the register physical address.
|
||||
required register is
|
||||
SRU/ADG/SSI if generation1
|
||||
SRU/ADG/SSIU/SSI if generation2
|
||||
- rcar_sound,ssi : SSI subnode
|
||||
- rcar_sound,scu : SCU subnode
|
||||
- rcar_sound,dai : DAI subnode
|
||||
|
||||
SSI subnode properties:
|
||||
- interrupts : Should contain SSI interrupt for PIO transfer
|
||||
- shared-pin : if shared clock pin
|
||||
|
||||
DAI subnode properties:
|
||||
- playback : list of playback modules
|
||||
- capture : list of capture modules
|
||||
|
||||
Example:
|
||||
|
||||
rcar_sound: rcar_sound@0xffd90000 {
|
||||
#sound-dai-cells = <1>;
|
||||
compatible = "renesas,rcar_sound-gen2";
|
||||
reg = <0 0xec500000 0 0x1000>, /* SCU */
|
||||
<0 0xec5a0000 0 0x100>, /* ADG */
|
||||
<0 0xec540000 0 0x1000>, /* SSIU */
|
||||
<0 0xec541000 0 0x1280>; /* SSI */
|
||||
|
||||
rcar_sound,src {
|
||||
src0: src@0 { };
|
||||
src1: src@1 { };
|
||||
src2: src@2 { };
|
||||
src3: src@3 { };
|
||||
src4: src@4 { };
|
||||
src5: src@5 { };
|
||||
src6: src@6 { };
|
||||
src7: src@7 { };
|
||||
src8: src@8 { };
|
||||
src9: src@9 { };
|
||||
};
|
||||
|
||||
rcar_sound,ssi {
|
||||
ssi0: ssi@0 {
|
||||
interrupts = <0 370 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
ssi1: ssi@1 {
|
||||
interrupts = <0 371 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
ssi2: ssi@2 {
|
||||
interrupts = <0 372 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
ssi3: ssi@3 {
|
||||
interrupts = <0 373 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
ssi4: ssi@4 {
|
||||
interrupts = <0 374 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
ssi5: ssi@5 {
|
||||
interrupts = <0 375 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
ssi6: ssi@6 {
|
||||
interrupts = <0 376 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
ssi7: ssi@7 {
|
||||
interrupts = <0 377 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
ssi8: ssi@8 {
|
||||
interrupts = <0 378 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
ssi9: ssi@9 {
|
||||
interrupts = <0 379 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
||||
|
||||
rcar_sound,dai {
|
||||
dai0 {
|
||||
playback = <&ssi5 &src5>;
|
||||
capture = <&ssi6>;
|
||||
};
|
||||
dai1 {
|
||||
playback = <&ssi3>;
|
||||
};
|
||||
dai2 {
|
||||
capture = <&ssi4>;
|
||||
};
|
||||
dai3 {
|
||||
playback = <&ssi7>;
|
||||
};
|
||||
dai4 {
|
||||
capture = <&ssi8>;
|
||||
};
|
||||
};
|
||||
};
|
@ -43,6 +43,12 @@ Optional CPU/CODEC subnodes properties:
|
||||
clock node (= common clock), or "system-clock-frequency"
|
||||
(if system doens't support common clock)
|
||||
|
||||
Note:
|
||||
* For 'format', 'frame-master', 'bitclock-master', 'bitclock-inversion' and
|
||||
'frame-inversion', the simple card will use the settings of CODEC for both
|
||||
CPU and CODEC sides as we need to keep the settings identical for both ends
|
||||
of the link.
|
||||
|
||||
Example:
|
||||
|
||||
sound {
|
||||
|
@ -1107,6 +1107,19 @@ struct soc_enum {
|
||||
const unsigned int *values;
|
||||
};
|
||||
|
||||
/**
|
||||
* snd_soc_component_to_codec() - Casts a component to the CODEC it is embedded in
|
||||
* @component: The component to cast to a CODEC
|
||||
*
|
||||
* This function must only be used on components that are known to be CODECs.
|
||||
* Otherwise the behavior is undefined.
|
||||
*/
|
||||
static inline struct snd_soc_codec *snd_soc_component_to_codec(
|
||||
struct snd_soc_component *component)
|
||||
{
|
||||
return container_of(component, struct snd_soc_codec, component);
|
||||
}
|
||||
|
||||
/* codec IO */
|
||||
unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
|
||||
unsigned int snd_soc_write(struct snd_soc_codec *codec,
|
||||
|
@ -44,6 +44,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_CS42L73 if I2C
|
||||
select SND_SOC_CS4270 if I2C
|
||||
select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_CS42XX8_I2C if I2C
|
||||
select SND_SOC_CX20442 if TTY
|
||||
select SND_SOC_DA7210 if I2C
|
||||
select SND_SOC_DA7213 if I2C
|
||||
@ -304,6 +305,15 @@ config SND_SOC_CS4271
|
||||
tristate "Cirrus Logic CS4271 CODEC"
|
||||
depends on SND_SOC_I2C_AND_SPI
|
||||
|
||||
config SND_SOC_CS42XX8
|
||||
tristate
|
||||
|
||||
config SND_SOC_CS42XX8_I2C
|
||||
tristate "Cirrus Logic CS42448/CS42888 CODEC (I2C)"
|
||||
depends on I2C
|
||||
select SND_SOC_CS42XX8
|
||||
select REGMAP_I2C
|
||||
|
||||
config SND_SOC_CX20442
|
||||
tristate
|
||||
depends on TTY
|
||||
|
@ -30,6 +30,8 @@ snd-soc-cs42l52-objs := cs42l52.o
|
||||
snd-soc-cs42l73-objs := cs42l73.o
|
||||
snd-soc-cs4270-objs := cs4270.o
|
||||
snd-soc-cs4271-objs := cs4271.o
|
||||
snd-soc-cs42xx8-objs := cs42xx8.o
|
||||
snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
|
||||
snd-soc-cx20442-objs := cx20442.o
|
||||
snd-soc-da7210-objs := da7210.o
|
||||
snd-soc-da7213-objs := da7213.o
|
||||
@ -179,6 +181,8 @@ obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o
|
||||
obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o
|
||||
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
|
||||
obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o
|
||||
obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o
|
||||
obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
|
||||
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
|
||||
obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o
|
||||
|
64
sound/soc/codecs/cs42xx8-i2c.c
Normal file
64
sound/soc/codecs/cs42xx8-i2c.c
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Cirrus Logic CS42448/CS42888 Audio CODEC DAI I2C driver
|
||||
*
|
||||
* Copyright (C) 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* Author: Nicolin Chen <Guangyu.Chen@freescale.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "cs42xx8.h"
|
||||
|
||||
static int cs42xx8_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
u32 ret = cs42xx8_probe(&i2c->dev,
|
||||
devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pm_runtime_enable(&i2c->dev);
|
||||
pm_request_idle(&i2c->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs42xx8_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
snd_soc_unregister_codec(&i2c->dev);
|
||||
pm_runtime_disable(&i2c->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_device_id cs42xx8_i2c_id[] = {
|
||||
{"cs42448", (kernel_ulong_t)&cs42448_data},
|
||||
{"cs42888", (kernel_ulong_t)&cs42888_data},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cs42xx8_i2c_id);
|
||||
|
||||
static struct i2c_driver cs42xx8_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "cs42xx8",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &cs42xx8_pm,
|
||||
},
|
||||
.probe = cs42xx8_i2c_probe,
|
||||
.remove = cs42xx8_i2c_remove,
|
||||
.id_table = cs42xx8_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(cs42xx8_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec I2C Driver");
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_LICENSE("GPL");
|
602
sound/soc/codecs/cs42xx8.c
Normal file
602
sound/soc/codecs/cs42xx8.c
Normal file
@ -0,0 +1,602 @@
|
||||
/*
|
||||
* Cirrus Logic CS42448/CS42888 Audio CODEC Digital Audio Interface (DAI) driver
|
||||
*
|
||||
* Copyright (C) 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* Author: Nicolin Chen <Guangyu.Chen@freescale.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "cs42xx8.h"
|
||||
|
||||
#define CS42XX8_NUM_SUPPLIES 4
|
||||
static const char *const cs42xx8_supply_names[CS42XX8_NUM_SUPPLIES] = {
|
||||
"VA",
|
||||
"VD",
|
||||
"VLS",
|
||||
"VLC",
|
||||
};
|
||||
|
||||
#define CS42XX8_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE | \
|
||||
SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
/* codec private data */
|
||||
struct cs42xx8_priv {
|
||||
struct regulator_bulk_data supplies[CS42XX8_NUM_SUPPLIES];
|
||||
const struct cs42xx8_driver_data *drvdata;
|
||||
struct regmap *regmap;
|
||||
struct clk *clk;
|
||||
|
||||
bool slave_mode;
|
||||
unsigned long sysclk;
|
||||
};
|
||||
|
||||
/* -127.5dB to 0dB with step of 0.5dB */
|
||||
static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
|
||||
/* -64dB to 24dB with step of 0.5dB */
|
||||
static const DECLARE_TLV_DB_SCALE(adc_tlv, -6400, 50, 0);
|
||||
|
||||
static const char *const cs42xx8_adc_single[] = { "Differential", "Single-Ended" };
|
||||
static const char *const cs42xx8_szc[] = { "Immediate Change", "Zero Cross",
|
||||
"Soft Ramp", "Soft Ramp on Zero Cross" };
|
||||
|
||||
static const struct soc_enum adc1_single_enum =
|
||||
SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 4, 2, cs42xx8_adc_single);
|
||||
static const struct soc_enum adc2_single_enum =
|
||||
SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 3, 2, cs42xx8_adc_single);
|
||||
static const struct soc_enum adc3_single_enum =
|
||||
SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 2, 2, cs42xx8_adc_single);
|
||||
static const struct soc_enum dac_szc_enum =
|
||||
SOC_ENUM_SINGLE(CS42XX8_TXCTL, 5, 4, cs42xx8_szc);
|
||||
static const struct soc_enum adc_szc_enum =
|
||||
SOC_ENUM_SINGLE(CS42XX8_TXCTL, 0, 4, cs42xx8_szc);
|
||||
|
||||
static const struct snd_kcontrol_new cs42xx8_snd_controls[] = {
|
||||
SOC_DOUBLE_R_TLV("DAC1 Playback Volume", CS42XX8_VOLAOUT1,
|
||||
CS42XX8_VOLAOUT2, 0, 0xff, 1, dac_tlv),
|
||||
SOC_DOUBLE_R_TLV("DAC2 Playback Volume", CS42XX8_VOLAOUT3,
|
||||
CS42XX8_VOLAOUT4, 0, 0xff, 1, dac_tlv),
|
||||
SOC_DOUBLE_R_TLV("DAC3 Playback Volume", CS42XX8_VOLAOUT5,
|
||||
CS42XX8_VOLAOUT6, 0, 0xff, 1, dac_tlv),
|
||||
SOC_DOUBLE_R_TLV("DAC4 Playback Volume", CS42XX8_VOLAOUT7,
|
||||
CS42XX8_VOLAOUT8, 0, 0xff, 1, dac_tlv),
|
||||
SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", CS42XX8_VOLAIN1,
|
||||
CS42XX8_VOLAIN2, 0, -0x80, 0x30, 7, 0, adc_tlv),
|
||||
SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", CS42XX8_VOLAIN3,
|
||||
CS42XX8_VOLAIN4, 0, -0x80, 0x30, 7, 0, adc_tlv),
|
||||
SOC_DOUBLE("DAC1 Invert Switch", CS42XX8_DACINV, 0, 1, 1, 0),
|
||||
SOC_DOUBLE("DAC2 Invert Switch", CS42XX8_DACINV, 2, 3, 1, 0),
|
||||
SOC_DOUBLE("DAC3 Invert Switch", CS42XX8_DACINV, 4, 5, 1, 0),
|
||||
SOC_DOUBLE("DAC4 Invert Switch", CS42XX8_DACINV, 6, 7, 1, 0),
|
||||
SOC_DOUBLE("ADC1 Invert Switch", CS42XX8_ADCINV, 0, 1, 1, 0),
|
||||
SOC_DOUBLE("ADC2 Invert Switch", CS42XX8_ADCINV, 2, 3, 1, 0),
|
||||
SOC_SINGLE("ADC High-Pass Filter Switch", CS42XX8_ADCCTL, 7, 1, 1),
|
||||
SOC_SINGLE("DAC De-emphasis Switch", CS42XX8_ADCCTL, 5, 1, 0),
|
||||
SOC_ENUM("ADC1 Single Ended Mode Switch", adc1_single_enum),
|
||||
SOC_ENUM("ADC2 Single Ended Mode Switch", adc2_single_enum),
|
||||
SOC_SINGLE("DAC Single Volume Control Switch", CS42XX8_TXCTL, 7, 1, 0),
|
||||
SOC_ENUM("DAC Soft Ramp & Zero Cross Control Switch", dac_szc_enum),
|
||||
SOC_SINGLE("DAC Auto Mute Switch", CS42XX8_TXCTL, 4, 1, 0),
|
||||
SOC_SINGLE("Mute ADC Serial Port Switch", CS42XX8_TXCTL, 3, 1, 0),
|
||||
SOC_SINGLE("ADC Single Volume Control Switch", CS42XX8_TXCTL, 2, 1, 0),
|
||||
SOC_ENUM("ADC Soft Ramp & Zero Cross Control Switch", adc_szc_enum),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new cs42xx8_adc3_snd_controls[] = {
|
||||
SOC_DOUBLE_R_S_TLV("ADC3 Capture Volume", CS42XX8_VOLAIN5,
|
||||
CS42XX8_VOLAIN6, 0, -0x80, 0x30, 7, 0, adc_tlv),
|
||||
SOC_DOUBLE("ADC3 Invert Switch", CS42XX8_ADCINV, 4, 5, 1, 0),
|
||||
SOC_ENUM("ADC3 Single Ended Mode Switch", adc3_single_enum),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget cs42xx8_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_DAC("DAC1", "Playback", CS42XX8_PWRCTL, 1, 1),
|
||||
SND_SOC_DAPM_DAC("DAC2", "Playback", CS42XX8_PWRCTL, 2, 1),
|
||||
SND_SOC_DAPM_DAC("DAC3", "Playback", CS42XX8_PWRCTL, 3, 1),
|
||||
SND_SOC_DAPM_DAC("DAC4", "Playback", CS42XX8_PWRCTL, 4, 1),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("AOUT1L"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUT1R"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUT2L"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUT2R"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUT3L"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUT3R"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUT4L"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUT4R"),
|
||||
|
||||
SND_SOC_DAPM_ADC("ADC1", "Capture", CS42XX8_PWRCTL, 5, 1),
|
||||
SND_SOC_DAPM_ADC("ADC2", "Capture", CS42XX8_PWRCTL, 6, 1),
|
||||
|
||||
SND_SOC_DAPM_INPUT("AIN1L"),
|
||||
SND_SOC_DAPM_INPUT("AIN1R"),
|
||||
SND_SOC_DAPM_INPUT("AIN2L"),
|
||||
SND_SOC_DAPM_INPUT("AIN2R"),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("PWR", CS42XX8_PWRCTL, 0, 1, NULL, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget cs42xx8_adc3_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_ADC("ADC3", "Capture", CS42XX8_PWRCTL, 7, 1),
|
||||
|
||||
SND_SOC_DAPM_INPUT("AIN3L"),
|
||||
SND_SOC_DAPM_INPUT("AIN3R"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cs42xx8_dapm_routes[] = {
|
||||
/* Playback */
|
||||
{ "AOUT1L", NULL, "DAC1" },
|
||||
{ "AOUT1R", NULL, "DAC1" },
|
||||
{ "DAC1", NULL, "PWR" },
|
||||
|
||||
{ "AOUT2L", NULL, "DAC2" },
|
||||
{ "AOUT2R", NULL, "DAC2" },
|
||||
{ "DAC2", NULL, "PWR" },
|
||||
|
||||
{ "AOUT3L", NULL, "DAC3" },
|
||||
{ "AOUT3R", NULL, "DAC3" },
|
||||
{ "DAC3", NULL, "PWR" },
|
||||
|
||||
{ "AOUT4L", NULL, "DAC4" },
|
||||
{ "AOUT4R", NULL, "DAC4" },
|
||||
{ "DAC4", NULL, "PWR" },
|
||||
|
||||
/* Capture */
|
||||
{ "ADC1", NULL, "AIN1L" },
|
||||
{ "ADC1", NULL, "AIN1R" },
|
||||
{ "ADC1", NULL, "PWR" },
|
||||
|
||||
{ "ADC2", NULL, "AIN2L" },
|
||||
{ "ADC2", NULL, "AIN2R" },
|
||||
{ "ADC2", NULL, "PWR" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = {
|
||||
/* Capture */
|
||||
{ "ADC3", NULL, "AIN3L" },
|
||||
{ "ADC3", NULL, "AIN3R" },
|
||||
{ "ADC3", NULL, "PWR" },
|
||||
};
|
||||
|
||||
struct cs42xx8_ratios {
|
||||
unsigned int ratio;
|
||||
unsigned char speed;
|
||||
unsigned char mclk;
|
||||
};
|
||||
|
||||
static const struct cs42xx8_ratios cs42xx8_ratios[] = {
|
||||
{ 64, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_256(4) },
|
||||
{ 96, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_384(4) },
|
||||
{ 128, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_512(4) },
|
||||
{ 192, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_768(4) },
|
||||
{ 256, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_256(1) },
|
||||
{ 384, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_384(1) },
|
||||
{ 512, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_512(1) },
|
||||
{ 768, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_768(1) },
|
||||
{ 1024, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_1024(1) }
|
||||
};
|
||||
|
||||
static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
cs42xx8->sysclk = freq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int format)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
|
||||
u32 val;
|
||||
|
||||
/* Set DAI format */
|
||||
switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
val = CS42XX8_INTF_DAC_DIF_LEFTJ | CS42XX8_INTF_ADC_DIF_LEFTJ;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
val = CS42XX8_INTF_DAC_DIF_I2S | CS42XX8_INTF_ADC_DIF_I2S;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
val = CS42XX8_INTF_DAC_DIF_RIGHTJ | CS42XX8_INTF_ADC_DIF_RIGHTJ;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "unsupported dai format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(cs42xx8->regmap, CS42XX8_INTF,
|
||||
CS42XX8_INTF_DAC_DIF_MASK |
|
||||
CS42XX8_INTF_ADC_DIF_MASK, val);
|
||||
|
||||
/* Set master/slave audio interface */
|
||||
switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
cs42xx8->slave_mode = true;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
cs42xx8->slave_mode = false;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "unsupported master/slave mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
|
||||
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||
u32 ratio = cs42xx8->sysclk / params_rate(params);
|
||||
u32 i, fm, val, mask;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) {
|
||||
if (cs42xx8_ratios[i].ratio == ratio)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(cs42xx8_ratios)) {
|
||||
dev_err(codec->dev, "unsupported sysclk ratio\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mask = CS42XX8_FUNCMOD_MFREQ_MASK;
|
||||
val = cs42xx8_ratios[i].mclk;
|
||||
|
||||
fm = cs42xx8->slave_mode ? CS42XX8_FM_AUTO : cs42xx8_ratios[i].speed;
|
||||
|
||||
regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,
|
||||
CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask,
|
||||
CS42XX8_FUNCMOD_xC_FM(tx, fm) | val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs42xx8_digital_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
regmap_update_bits(cs42xx8->regmap, CS42XX8_DACMUTE,
|
||||
CS42XX8_DACMUTE_ALL, mute ? CS42XX8_DACMUTE_ALL : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops cs42xx8_dai_ops = {
|
||||
.set_fmt = cs42xx8_set_dai_fmt,
|
||||
.set_sysclk = cs42xx8_set_dai_sysclk,
|
||||
.hw_params = cs42xx8_hw_params,
|
||||
.digital_mute = cs42xx8_digital_mute,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver cs42xx8_dai = {
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = CS42XX8_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = CS42XX8_FORMATS,
|
||||
},
|
||||
.ops = &cs42xx8_dai_ops,
|
||||
};
|
||||
|
||||
static const struct reg_default cs42xx8_reg[] = {
|
||||
{ 0x01, 0x01 }, /* Chip I.D. and Revision Register */
|
||||
{ 0x02, 0x00 }, /* Power Control */
|
||||
{ 0x03, 0xF0 }, /* Functional Mode */
|
||||
{ 0x04, 0x46 }, /* Interface Formats */
|
||||
{ 0x05, 0x00 }, /* ADC Control & DAC De-Emphasis */
|
||||
{ 0x06, 0x10 }, /* Transition Control */
|
||||
{ 0x07, 0x00 }, /* DAC Channel Mute */
|
||||
{ 0x08, 0x00 }, /* Volume Control AOUT1 */
|
||||
{ 0x09, 0x00 }, /* Volume Control AOUT2 */
|
||||
{ 0x0a, 0x00 }, /* Volume Control AOUT3 */
|
||||
{ 0x0b, 0x00 }, /* Volume Control AOUT4 */
|
||||
{ 0x0c, 0x00 }, /* Volume Control AOUT5 */
|
||||
{ 0x0d, 0x00 }, /* Volume Control AOUT6 */
|
||||
{ 0x0e, 0x00 }, /* Volume Control AOUT7 */
|
||||
{ 0x0f, 0x00 }, /* Volume Control AOUT8 */
|
||||
{ 0x10, 0x00 }, /* DAC Channel Invert */
|
||||
{ 0x11, 0x00 }, /* Volume Control AIN1 */
|
||||
{ 0x12, 0x00 }, /* Volume Control AIN2 */
|
||||
{ 0x13, 0x00 }, /* Volume Control AIN3 */
|
||||
{ 0x14, 0x00 }, /* Volume Control AIN4 */
|
||||
{ 0x15, 0x00 }, /* Volume Control AIN5 */
|
||||
{ 0x16, 0x00 }, /* Volume Control AIN6 */
|
||||
{ 0x17, 0x00 }, /* ADC Channel Invert */
|
||||
{ 0x18, 0x00 }, /* Status Control */
|
||||
{ 0x1a, 0x00 }, /* Status Mask */
|
||||
{ 0x1b, 0x00 }, /* MUTEC Pin Control */
|
||||
};
|
||||
|
||||
static bool cs42xx8_volatile_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case CS42XX8_STATUS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool cs42xx8_writeable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case CS42XX8_CHIPID:
|
||||
case CS42XX8_STATUS:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const struct regmap_config cs42xx8_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = CS42XX8_LASTREG,
|
||||
.reg_defaults = cs42xx8_reg,
|
||||
.num_reg_defaults = ARRAY_SIZE(cs42xx8_reg),
|
||||
.volatile_reg = cs42xx8_volatile_register,
|
||||
.writeable_reg = cs42xx8_writeable_register,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cs42xx8_regmap_config);
|
||||
|
||||
static int cs42xx8_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
|
||||
switch (cs42xx8->drvdata->num_adcs) {
|
||||
case 3:
|
||||
snd_soc_add_codec_controls(codec, cs42xx8_adc3_snd_controls,
|
||||
ARRAY_SIZE(cs42xx8_adc3_snd_controls));
|
||||
snd_soc_dapm_new_controls(dapm, cs42xx8_adc3_dapm_widgets,
|
||||
ARRAY_SIZE(cs42xx8_adc3_dapm_widgets));
|
||||
snd_soc_dapm_add_routes(dapm, cs42xx8_adc3_dapm_routes,
|
||||
ARRAY_SIZE(cs42xx8_adc3_dapm_routes));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Mute all DAC channels */
|
||||
regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE, CS42XX8_DACMUTE_ALL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_codec_driver cs42xx8_driver = {
|
||||
.probe = cs42xx8_codec_probe,
|
||||
.idle_bias_off = true,
|
||||
|
||||
.controls = cs42xx8_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(cs42xx8_snd_controls),
|
||||
.dapm_widgets = cs42xx8_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(cs42xx8_dapm_widgets),
|
||||
.dapm_routes = cs42xx8_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(cs42xx8_dapm_routes),
|
||||
};
|
||||
|
||||
const struct cs42xx8_driver_data cs42448_data = {
|
||||
.name = "cs42448",
|
||||
.num_adcs = 3,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cs42448_data);
|
||||
|
||||
const struct cs42xx8_driver_data cs42888_data = {
|
||||
.name = "cs42888",
|
||||
.num_adcs = 2,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cs42888_data);
|
||||
|
||||
const struct of_device_id cs42xx8_of_match[] = {
|
||||
{ .compatible = "cirrus,cs42448", .data = &cs42448_data, },
|
||||
{ .compatible = "cirrus,cs42888", .data = &cs42888_data, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
|
||||
EXPORT_SYMBOL_GPL(cs42xx8_of_match);
|
||||
|
||||
int cs42xx8_probe(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
const struct of_device_id *of_id = of_match_device(cs42xx8_of_match, dev);
|
||||
struct cs42xx8_priv *cs42xx8;
|
||||
int ret, val, i;
|
||||
|
||||
cs42xx8 = devm_kzalloc(dev, sizeof(*cs42xx8), GFP_KERNEL);
|
||||
if (cs42xx8 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(dev, cs42xx8);
|
||||
|
||||
if (of_id)
|
||||
cs42xx8->drvdata = of_id->data;
|
||||
|
||||
if (!cs42xx8->drvdata) {
|
||||
dev_err(dev, "failed to find driver data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cs42xx8->clk = devm_clk_get(dev, "mclk");
|
||||
if (IS_ERR(cs42xx8->clk)) {
|
||||
dev_err(dev, "failed to get the clock: %ld\n",
|
||||
PTR_ERR(cs42xx8->clk));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cs42xx8->sysclk = clk_get_rate(cs42xx8->clk);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cs42xx8->supplies); i++)
|
||||
cs42xx8->supplies[i].supply = cs42xx8_supply_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(dev,
|
||||
ARRAY_SIZE(cs42xx8->supplies), cs42xx8->supplies);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to request supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
|
||||
cs42xx8->supplies);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Make sure hardware reset done */
|
||||
msleep(5);
|
||||
|
||||
cs42xx8->regmap = regmap;
|
||||
if (IS_ERR(cs42xx8->regmap)) {
|
||||
ret = PTR_ERR(cs42xx8->regmap);
|
||||
dev_err(dev, "failed to allocate regmap: %d\n", ret);
|
||||
goto err_enable;
|
||||
}
|
||||
|
||||
/*
|
||||
* We haven't marked the chip revision as volatile due to
|
||||
* sharing a register with the right input volume; explicitly
|
||||
* bypass the cache to read it.
|
||||
*/
|
||||
regcache_cache_bypass(cs42xx8->regmap, true);
|
||||
|
||||
/* Validate the chip ID */
|
||||
regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val);
|
||||
if (val < 0) {
|
||||
dev_err(dev, "failed to get device ID: %x", val);
|
||||
ret = -EINVAL;
|
||||
goto err_enable;
|
||||
}
|
||||
|
||||
/* The top four bits of the chip ID should be 0000 */
|
||||
if ((val & CS42XX8_CHIPID_CHIP_ID_MASK) != 0x00) {
|
||||
dev_err(dev, "unmatched chip ID: %d\n",
|
||||
val & CS42XX8_CHIPID_CHIP_ID_MASK);
|
||||
ret = -EINVAL;
|
||||
goto err_enable;
|
||||
}
|
||||
|
||||
dev_info(dev, "found device, revision %X\n",
|
||||
val & CS42XX8_CHIPID_REV_ID_MASK);
|
||||
|
||||
regcache_cache_bypass(cs42xx8->regmap, false);
|
||||
|
||||
cs42xx8_dai.name = cs42xx8->drvdata->name;
|
||||
|
||||
/* Each adc supports stereo input */
|
||||
cs42xx8_dai.capture.channels_max = cs42xx8->drvdata->num_adcs * 2;
|
||||
|
||||
ret = snd_soc_register_codec(dev, &cs42xx8_driver, &cs42xx8_dai, 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register codec:%d\n", ret);
|
||||
goto err_enable;
|
||||
}
|
||||
|
||||
regcache_cache_only(cs42xx8->regmap, true);
|
||||
|
||||
err_enable:
|
||||
regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
|
||||
cs42xx8->supplies);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cs42xx8_probe);
|
||||
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
static int cs42xx8_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(cs42xx8->clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable mclk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
|
||||
cs42xx8->supplies);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable supplies: %d\n", ret);
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
/* Make sure hardware reset done */
|
||||
msleep(5);
|
||||
|
||||
regcache_cache_only(cs42xx8->regmap, false);
|
||||
|
||||
ret = regcache_sync(cs42xx8->regmap);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to sync regmap: %d\n", ret);
|
||||
goto err_bulk;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_bulk:
|
||||
regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
|
||||
cs42xx8->supplies);
|
||||
err_clk:
|
||||
clk_disable_unprepare(cs42xx8->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cs42xx8_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
|
||||
|
||||
regcache_cache_only(cs42xx8->regmap, true);
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
|
||||
cs42xx8->supplies);
|
||||
|
||||
clk_disable_unprepare(cs42xx8->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
const struct dev_pm_ops cs42xx8_pm = {
|
||||
SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL)
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cs42xx8_pm);
|
||||
|
||||
MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec Driver");
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_LICENSE("GPL");
|
238
sound/soc/codecs/cs42xx8.h
Normal file
238
sound/soc/codecs/cs42xx8.h
Normal file
@ -0,0 +1,238 @@
|
||||
/*
|
||||
* cs42xx8.h - Cirrus Logic CS42448/CS42888 Audio CODEC driver header file
|
||||
*
|
||||
* Copyright (C) 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* Author: Nicolin Chen <Guangyu.Chen@freescale.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#ifndef _CS42XX8_H
|
||||
#define _CS42XX8_H
|
||||
|
||||
struct cs42xx8_driver_data {
|
||||
char name[32];
|
||||
int num_adcs;
|
||||
};
|
||||
|
||||
extern const struct dev_pm_ops cs42xx8_pm;
|
||||
extern const struct cs42xx8_driver_data cs42448_data;
|
||||
extern const struct cs42xx8_driver_data cs42888_data;
|
||||
extern const struct regmap_config cs42xx8_regmap_config;
|
||||
int cs42xx8_probe(struct device *dev, struct regmap *regmap);
|
||||
|
||||
/* CS42888 register map */
|
||||
#define CS42XX8_CHIPID 0x01 /* Chip ID */
|
||||
#define CS42XX8_PWRCTL 0x02 /* Power Control */
|
||||
#define CS42XX8_FUNCMOD 0x03 /* Functional Mode */
|
||||
#define CS42XX8_INTF 0x04 /* Interface Formats */
|
||||
#define CS42XX8_ADCCTL 0x05 /* ADC Control */
|
||||
#define CS42XX8_TXCTL 0x06 /* Transition Control */
|
||||
#define CS42XX8_DACMUTE 0x07 /* DAC Mute Control */
|
||||
#define CS42XX8_VOLAOUT1 0x08 /* Volume Control AOUT1 */
|
||||
#define CS42XX8_VOLAOUT2 0x09 /* Volume Control AOUT2 */
|
||||
#define CS42XX8_VOLAOUT3 0x0A /* Volume Control AOUT3 */
|
||||
#define CS42XX8_VOLAOUT4 0x0B /* Volume Control AOUT4 */
|
||||
#define CS42XX8_VOLAOUT5 0x0C /* Volume Control AOUT5 */
|
||||
#define CS42XX8_VOLAOUT6 0x0D /* Volume Control AOUT6 */
|
||||
#define CS42XX8_VOLAOUT7 0x0E /* Volume Control AOUT7 */
|
||||
#define CS42XX8_VOLAOUT8 0x0F /* Volume Control AOUT8 */
|
||||
#define CS42XX8_DACINV 0x10 /* DAC Channel Invert */
|
||||
#define CS42XX8_VOLAIN1 0x11 /* Volume Control AIN1 */
|
||||
#define CS42XX8_VOLAIN2 0x12 /* Volume Control AIN2 */
|
||||
#define CS42XX8_VOLAIN3 0x13 /* Volume Control AIN3 */
|
||||
#define CS42XX8_VOLAIN4 0x14 /* Volume Control AIN4 */
|
||||
#define CS42XX8_VOLAIN5 0x15 /* Volume Control AIN5 */
|
||||
#define CS42XX8_VOLAIN6 0x16 /* Volume Control AIN6 */
|
||||
#define CS42XX8_ADCINV 0x17 /* ADC Channel Invert */
|
||||
#define CS42XX8_STATUSCTL 0x18 /* Status Control */
|
||||
#define CS42XX8_STATUS 0x19 /* Status */
|
||||
#define CS42XX8_STATUSM 0x1A /* Status Mask */
|
||||
#define CS42XX8_MUTEC 0x1B /* MUTEC Pin Control */
|
||||
|
||||
#define CS42XX8_FIRSTREG CS42XX8_CHIPID
|
||||
#define CS42XX8_LASTREG CS42XX8_MUTEC
|
||||
#define CS42XX8_NUMREGS (CS42XX8_LASTREG - CS42XX8_FIRSTREG + 1)
|
||||
#define CS42XX8_I2C_INCR 0x80
|
||||
|
||||
/* Chip I.D. and Revision Register (Address 01h) */
|
||||
#define CS42XX8_CHIPID_CHIP_ID_MASK 0xF0
|
||||
#define CS42XX8_CHIPID_REV_ID_MASK 0x0F
|
||||
|
||||
/* Power Control (Address 02h) */
|
||||
#define CS42XX8_PWRCTL_PDN_ADC3_SHIFT 7
|
||||
#define CS42XX8_PWRCTL_PDN_ADC3_MASK (1 << CS42XX8_PWRCTL_PDN_ADC3_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_ADC3 (1 << CS42XX8_PWRCTL_PDN_ADC3_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_ADC2_SHIFT 6
|
||||
#define CS42XX8_PWRCTL_PDN_ADC2_MASK (1 << CS42XX8_PWRCTL_PDN_ADC2_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_ADC2 (1 << CS42XX8_PWRCTL_PDN_ADC2_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_ADC1_SHIFT 5
|
||||
#define CS42XX8_PWRCTL_PDN_ADC1_MASK (1 << CS42XX8_PWRCTL_PDN_ADC1_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_ADC1 (1 << CS42XX8_PWRCTL_PDN_ADC1_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_DAC4_SHIFT 4
|
||||
#define CS42XX8_PWRCTL_PDN_DAC4_MASK (1 << CS42XX8_PWRCTL_PDN_DAC4_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_DAC4 (1 << CS42XX8_PWRCTL_PDN_DAC4_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_DAC3_SHIFT 3
|
||||
#define CS42XX8_PWRCTL_PDN_DAC3_MASK (1 << CS42XX8_PWRCTL_PDN_DAC3_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_DAC3 (1 << CS42XX8_PWRCTL_PDN_DAC3_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_DAC2_SHIFT 2
|
||||
#define CS42XX8_PWRCTL_PDN_DAC2_MASK (1 << CS42XX8_PWRCTL_PDN_DAC2_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_DAC2 (1 << CS42XX8_PWRCTL_PDN_DAC2_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_DAC1_SHIFT 1
|
||||
#define CS42XX8_PWRCTL_PDN_DAC1_MASK (1 << CS42XX8_PWRCTL_PDN_DAC1_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_DAC1 (1 << CS42XX8_PWRCTL_PDN_DAC1_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_SHIFT 0
|
||||
#define CS42XX8_PWRCTL_PDN_MASK (1 << CS42XX8_PWRCTL_PDN_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN (1 << CS42XX8_PWRCTL_PDN_SHIFT)
|
||||
|
||||
/* Functional Mode (Address 03h) */
|
||||
#define CS42XX8_FUNCMOD_DAC_FM_SHIFT 6
|
||||
#define CS42XX8_FUNCMOD_DAC_FM_WIDTH 2
|
||||
#define CS42XX8_FUNCMOD_DAC_FM_MASK (((1 << CS42XX8_FUNCMOD_DAC_FM_WIDTH) - 1) << CS42XX8_FUNCMOD_DAC_FM_SHIFT)
|
||||
#define CS42XX8_FUNCMOD_DAC_FM(v) ((v) << CS42XX8_FUNCMOD_DAC_FM_SHIFT)
|
||||
#define CS42XX8_FUNCMOD_ADC_FM_SHIFT 4
|
||||
#define CS42XX8_FUNCMOD_ADC_FM_WIDTH 2
|
||||
#define CS42XX8_FUNCMOD_ADC_FM_MASK (((1 << CS42XX8_FUNCMOD_ADC_FM_WIDTH) - 1) << CS42XX8_FUNCMOD_ADC_FM_SHIFT)
|
||||
#define CS42XX8_FUNCMOD_ADC_FM(v) ((v) << CS42XX8_FUNCMOD_ADC_FM_SHIFT)
|
||||
#define CS42XX8_FUNCMOD_xC_FM_MASK(x) ((x) ? CS42XX8_FUNCMOD_DAC_FM_MASK : CS42XX8_FUNCMOD_ADC_FM_MASK)
|
||||
#define CS42XX8_FUNCMOD_xC_FM(x, v) ((x) ? CS42XX8_FUNCMOD_DAC_FM(v) : CS42XX8_FUNCMOD_ADC_FM(v))
|
||||
#define CS42XX8_FUNCMOD_MFREQ_SHIFT 1
|
||||
#define CS42XX8_FUNCMOD_MFREQ_WIDTH 3
|
||||
#define CS42XX8_FUNCMOD_MFREQ_MASK (((1 << CS42XX8_FUNCMOD_MFREQ_WIDTH) - 1) << CS42XX8_FUNCMOD_MFREQ_SHIFT)
|
||||
#define CS42XX8_FUNCMOD_MFREQ_256(s) ((0 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
|
||||
#define CS42XX8_FUNCMOD_MFREQ_384(s) ((1 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
|
||||
#define CS42XX8_FUNCMOD_MFREQ_512(s) ((2 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
|
||||
#define CS42XX8_FUNCMOD_MFREQ_768(s) ((3 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
|
||||
#define CS42XX8_FUNCMOD_MFREQ_1024(s) ((4 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
|
||||
|
||||
#define CS42XX8_FM_SINGLE 0
|
||||
#define CS42XX8_FM_DOUBLE 1
|
||||
#define CS42XX8_FM_QUAD 2
|
||||
#define CS42XX8_FM_AUTO 3
|
||||
|
||||
/* Interface Formats (Address 04h) */
|
||||
#define CS42XX8_INTF_FREEZE_SHIFT 7
|
||||
#define CS42XX8_INTF_FREEZE_MASK (1 << CS42XX8_INTF_FREEZE_SHIFT)
|
||||
#define CS42XX8_INTF_FREEZE (1 << CS42XX8_INTF_FREEZE_SHIFT)
|
||||
#define CS42XX8_INTF_AUX_DIF_SHIFT 6
|
||||
#define CS42XX8_INTF_AUX_DIF_MASK (1 << CS42XX8_INTF_AUX_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_AUX_DIF (1 << CS42XX8_INTF_AUX_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_DAC_DIF_SHIFT 3
|
||||
#define CS42XX8_INTF_DAC_DIF_WIDTH 3
|
||||
#define CS42XX8_INTF_DAC_DIF_MASK (((1 << CS42XX8_INTF_DAC_DIF_WIDTH) - 1) << CS42XX8_INTF_DAC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_DAC_DIF_LEFTJ (0 << CS42XX8_INTF_DAC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_DAC_DIF_I2S (1 << CS42XX8_INTF_DAC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_DAC_DIF_RIGHTJ (2 << CS42XX8_INTF_DAC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_DAC_DIF_RIGHTJ_16 (3 << CS42XX8_INTF_DAC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_DAC_DIF_ONELINE_20 (4 << CS42XX8_INTF_DAC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_DAC_DIF_ONELINE_24 (6 << CS42XX8_INTF_DAC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_DAC_DIF_TDM (7 << CS42XX8_INTF_DAC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_ADC_DIF_SHIFT 0
|
||||
#define CS42XX8_INTF_ADC_DIF_WIDTH 3
|
||||
#define CS42XX8_INTF_ADC_DIF_MASK (((1 << CS42XX8_INTF_ADC_DIF_WIDTH) - 1) << CS42XX8_INTF_ADC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_ADC_DIF_LEFTJ (0 << CS42XX8_INTF_ADC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_ADC_DIF_I2S (1 << CS42XX8_INTF_ADC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_ADC_DIF_RIGHTJ (2 << CS42XX8_INTF_ADC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_ADC_DIF_RIGHTJ_16 (3 << CS42XX8_INTF_ADC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_ADC_DIF_ONELINE_20 (4 << CS42XX8_INTF_ADC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_ADC_DIF_ONELINE_24 (6 << CS42XX8_INTF_ADC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_ADC_DIF_TDM (7 << CS42XX8_INTF_ADC_DIF_SHIFT)
|
||||
|
||||
/* ADC Control & DAC De-Emphasis (Address 05h) */
|
||||
#define CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT 7
|
||||
#define CS42XX8_ADCCTL_ADC_HPF_FREEZE_MASK (1 << CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT)
|
||||
#define CS42XX8_ADCCTL_ADC_HPF_FREEZE (1 << CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT)
|
||||
#define CS42XX8_ADCCTL_DAC_DEM_SHIFT 5
|
||||
#define CS42XX8_ADCCTL_DAC_DEM_MASK (1 << CS42XX8_ADCCTL_DAC_DEM_SHIFT)
|
||||
#define CS42XX8_ADCCTL_DAC_DEM (1 << CS42XX8_ADCCTL_DAC_DEM_SHIFT)
|
||||
#define CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT 4
|
||||
#define CS42XX8_ADCCTL_ADC1_SINGLE_MASK (1 << CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT)
|
||||
#define CS42XX8_ADCCTL_ADC1_SINGLE (1 << CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT)
|
||||
#define CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT 3
|
||||
#define CS42XX8_ADCCTL_ADC2_SINGLE_MASK (1 << CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT)
|
||||
#define CS42XX8_ADCCTL_ADC2_SINGLE (1 << CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT)
|
||||
#define CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT 2
|
||||
#define CS42XX8_ADCCTL_ADC3_SINGLE_MASK (1 << CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT)
|
||||
#define CS42XX8_ADCCTL_ADC3_SINGLE (1 << CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT)
|
||||
#define CS42XX8_ADCCTL_AIN5_MUX_SHIFT 1
|
||||
#define CS42XX8_ADCCTL_AIN5_MUX_MASK (1 << CS42XX8_ADCCTL_AIN5_MUX_SHIFT)
|
||||
#define CS42XX8_ADCCTL_AIN5_MUX (1 << CS42XX8_ADCCTL_AIN5_MUX_SHIFT)
|
||||
#define CS42XX8_ADCCTL_AIN6_MUX_SHIFT 0
|
||||
#define CS42XX8_ADCCTL_AIN6_MUX_MASK (1 << CS42XX8_ADCCTL_AIN6_MUX_SHIFT)
|
||||
#define CS42XX8_ADCCTL_AIN6_MUX (1 << CS42XX8_ADCCTL_AIN6_MUX_SHIFT)
|
||||
|
||||
/* Transition Control (Address 06h) */
|
||||
#define CS42XX8_TXCTL_DAC_SNGVOL_SHIFT 7
|
||||
#define CS42XX8_TXCTL_DAC_SNGVOL_MASK (1 << CS42XX8_TXCTL_DAC_SNGVOL_SHIFT)
|
||||
#define CS42XX8_TXCTL_DAC_SNGVOL (1 << CS42XX8_TXCTL_DAC_SNGVOL_SHIFT)
|
||||
#define CS42XX8_TXCTL_DAC_SZC_SHIFT 5
|
||||
#define CS42XX8_TXCTL_DAC_SZC_WIDTH 2
|
||||
#define CS42XX8_TXCTL_DAC_SZC_MASK (((1 << CS42XX8_TXCTL_DAC_SZC_WIDTH) - 1) << CS42XX8_TXCTL_DAC_SZC_SHIFT)
|
||||
#define CS42XX8_TXCTL_DAC_SZC_IC (0 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
|
||||
#define CS42XX8_TXCTL_DAC_SZC_ZC (1 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
|
||||
#define CS42XX8_TXCTL_DAC_SZC_SR (2 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
|
||||
#define CS42XX8_TXCTL_DAC_SZC_SRZC (3 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
|
||||
#define CS42XX8_TXCTL_AMUTE_SHIFT 4
|
||||
#define CS42XX8_TXCTL_AMUTE_MASK (1 << CS42XX8_TXCTL_AMUTE_SHIFT)
|
||||
#define CS42XX8_TXCTL_AMUTE (1 << CS42XX8_TXCTL_AMUTE_SHIFT)
|
||||
#define CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT 3
|
||||
#define CS42XX8_TXCTL_MUTE_ADC_SP_MASK (1 << CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT)
|
||||
#define CS42XX8_TXCTL_MUTE_ADC_SP (1 << CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT)
|
||||
#define CS42XX8_TXCTL_ADC_SNGVOL_SHIFT 2
|
||||
#define CS42XX8_TXCTL_ADC_SNGVOL_MASK (1 << CS42XX8_TXCTL_ADC_SNGVOL_SHIFT)
|
||||
#define CS42XX8_TXCTL_ADC_SNGVOL (1 << CS42XX8_TXCTL_ADC_SNGVOL_SHIFT)
|
||||
#define CS42XX8_TXCTL_ADC_SZC_SHIFT 0
|
||||
#define CS42XX8_TXCTL_ADC_SZC_MASK (((1 << CS42XX8_TXCTL_ADC_SZC_WIDTH) - 1) << CS42XX8_TXCTL_ADC_SZC_SHIFT)
|
||||
#define CS42XX8_TXCTL_ADC_SZC_IC (0 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
|
||||
#define CS42XX8_TXCTL_ADC_SZC_ZC (1 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
|
||||
#define CS42XX8_TXCTL_ADC_SZC_SR (2 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
|
||||
#define CS42XX8_TXCTL_ADC_SZC_SRZC (3 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
|
||||
|
||||
/* DAC Channel Mute (Address 07h) */
|
||||
#define CS42XX8_DACMUTE_AOUT(n) (0x1 << n)
|
||||
#define CS42XX8_DACMUTE_ALL 0xff
|
||||
|
||||
/* Status Control (Address 18h)*/
|
||||
#define CS42XX8_STATUSCTL_INI_SHIFT 2
|
||||
#define CS42XX8_STATUSCTL_INI_WIDTH 2
|
||||
#define CS42XX8_STATUSCTL_INI_MASK (((1 << CS42XX8_STATUSCTL_INI_WIDTH) - 1) << CS42XX8_STATUSCTL_INI_SHIFT)
|
||||
#define CS42XX8_STATUSCTL_INT_ACTIVE_HIGH (0 << CS42XX8_STATUSCTL_INI_SHIFT)
|
||||
#define CS42XX8_STATUSCTL_INT_ACTIVE_LOW (1 << CS42XX8_STATUSCTL_INI_SHIFT)
|
||||
#define CS42XX8_STATUSCTL_INT_OPEN_DRAIN (2 << CS42XX8_STATUSCTL_INI_SHIFT)
|
||||
|
||||
/* Status (Address 19h)*/
|
||||
#define CS42XX8_STATUS_DAC_CLK_ERR_SHIFT 4
|
||||
#define CS42XX8_STATUS_DAC_CLK_ERR_MASK (1 << CS42XX8_STATUS_DAC_CLK_ERR_SHIFT)
|
||||
#define CS42XX8_STATUS_ADC_CLK_ERR_SHIFT 3
|
||||
#define CS42XX8_STATUS_ADC_CLK_ERR_MASK (1 << CS42XX8_STATUS_ADC_CLK_ERR_SHIFT)
|
||||
#define CS42XX8_STATUS_ADC3_OVFL_SHIFT 2
|
||||
#define CS42XX8_STATUS_ADC3_OVFL_MASK (1 << CS42XX8_STATUS_ADC3_OVFL_SHIFT)
|
||||
#define CS42XX8_STATUS_ADC2_OVFL_SHIFT 1
|
||||
#define CS42XX8_STATUS_ADC2_OVFL_MASK (1 << CS42XX8_STATUS_ADC2_OVFL_SHIFT)
|
||||
#define CS42XX8_STATUS_ADC1_OVFL_SHIFT 0
|
||||
#define CS42XX8_STATUS_ADC1_OVFL_MASK (1 << CS42XX8_STATUS_ADC1_OVFL_SHIFT)
|
||||
|
||||
/* Status Mask (Address 1Ah) */
|
||||
#define CS42XX8_STATUS_DAC_CLK_ERR_M_SHIFT 4
|
||||
#define CS42XX8_STATUS_DAC_CLK_ERR_M_MASK (1 << CS42XX8_STATUS_DAC_CLK_ERR_M_SHIFT)
|
||||
#define CS42XX8_STATUS_ADC_CLK_ERR_M_SHIFT 3
|
||||
#define CS42XX8_STATUS_ADC_CLK_ERR_M_MASK (1 << CS42XX8_STATUS_ADC_CLK_ERR_M_SHIFT)
|
||||
#define CS42XX8_STATUS_ADC3_OVFL_M_SHIFT 2
|
||||
#define CS42XX8_STATUS_ADC3_OVFL_M_MASK (1 << CS42XX8_STATUS_ADC3_OVFL_M_SHIFT)
|
||||
#define CS42XX8_STATUS_ADC2_OVFL_M_SHIFT 1
|
||||
#define CS42XX8_STATUS_ADC2_OVFL_M_MASK (1 << CS42XX8_STATUS_ADC2_OVFL_M_SHIFT)
|
||||
#define CS42XX8_STATUS_ADC1_OVFL_M_SHIFT 0
|
||||
#define CS42XX8_STATUS_ADC1_OVFL_M_MASK (1 << CS42XX8_STATUS_ADC1_OVFL_M_SHIFT)
|
||||
|
||||
/* MUTEC Pin Control (Address 1Bh) */
|
||||
#define CS42XX8_MUTEC_MCPOLARITY_SHIFT 1
|
||||
#define CS42XX8_MUTEC_MCPOLARITY_MASK (1 << CS42XX8_MUTEC_MCPOLARITY_SHIFT)
|
||||
#define CS42XX8_MUTEC_MCPOLARITY_ACTIVE_LOW (0 << CS42XX8_MUTEC_MCPOLARITY_SHIFT)
|
||||
#define CS42XX8_MUTEC_MCPOLARITY_ACTIVE_HIGH (1 << CS42XX8_MUTEC_MCPOLARITY_SHIFT)
|
||||
#define CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT 0
|
||||
#define CS42XX8_MUTEC_MUTEC_ACTIVE_MASK (1 << CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT)
|
||||
#define CS42XX8_MUTEC_MUTEC_ACTIVE (1 << CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT)
|
||||
#endif /* _CS42XX8_H */
|
@ -918,8 +918,7 @@ static int isabelle_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
u16 aif = 0;
|
||||
unsigned int fs_val = 0;
|
||||
|
||||
|
@ -2343,7 +2343,6 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
|
||||
|
||||
max98090->devtype = id->driver_data;
|
||||
i2c_set_clientdata(i2c, max98090);
|
||||
max98090->control_data = i2c;
|
||||
max98090->pdata = i2c->dev.platform_data;
|
||||
max98090->irq = i2c->irq;
|
||||
|
||||
|
@ -1523,7 +1523,6 @@ struct max98090_priv {
|
||||
struct regmap *regmap;
|
||||
struct snd_soc_codec *codec;
|
||||
enum max98090_type devtype;
|
||||
void *control_data;
|
||||
struct max98090_pdata *pdata;
|
||||
unsigned int sysclk;
|
||||
unsigned int bclk;
|
||||
|
@ -106,8 +106,7 @@ static int mc13783_pcm_hw_params_dac(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
unsigned int rate = params_rate(params);
|
||||
int i;
|
||||
|
||||
@ -126,8 +125,7 @@ static int mc13783_pcm_hw_params_codec(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
unsigned int rate = params_rate(params);
|
||||
unsigned int val;
|
||||
|
||||
|
@ -1594,8 +1594,7 @@ static int get_clk_info(int sclk, int rate)
|
||||
static int rt5640_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int val_len = 0, val_clk, mask_clk;
|
||||
int dai_sel, pre_div, bclk_ms, frame_size;
|
||||
|
@ -337,18 +337,9 @@ struct snd_soc_dai_driver sirf_audio_codec_dai = {
|
||||
|
||||
static int sirf_audio_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
int ret;
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
pm_runtime_enable(codec->dev);
|
||||
codec->control_data = sirf_audio_codec->regmap;
|
||||
|
||||
ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (of_device_is_compatible(codec->dev->of_node, "sirf,prima2-audio-codec")) {
|
||||
snd_soc_dapm_new_controls(dapm,
|
||||
|
@ -193,8 +193,7 @@ static int sta529_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
int pdata, play_freq_val, record_freq_val;
|
||||
int bclk_to_fs_ratio;
|
||||
|
||||
|
@ -129,7 +129,7 @@ static const struct regmap_range_cfg aic31xx_ranges[] = {
|
||||
},
|
||||
};
|
||||
|
||||
struct regmap_config aic31xx_i2c_regmap = {
|
||||
static const struct regmap_config aic31xx_i2c_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.writeable_reg = aic31xx_writeable,
|
||||
@ -321,9 +321,9 @@ static const struct snd_kcontrol_new ldac_in_control =
|
||||
static const struct snd_kcontrol_new rdac_in_control =
|
||||
SOC_DAPM_ENUM("DAC Right Input", rdac_in_enum);
|
||||
|
||||
int aic31xx_wait_bits(struct aic31xx_priv *aic31xx, unsigned int reg,
|
||||
unsigned int mask, unsigned int wbits, int sleep,
|
||||
int count)
|
||||
static int aic31xx_wait_bits(struct aic31xx_priv *aic31xx, unsigned int reg,
|
||||
unsigned int mask, unsigned int wbits, int sleep,
|
||||
int count)
|
||||
{
|
||||
unsigned int bits;
|
||||
int counter = count;
|
||||
@ -753,10 +753,9 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec,
|
||||
|
||||
static int aic31xx_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *tmp)
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
u8 data = 0;
|
||||
|
||||
dev_dbg(codec->dev, "## %s: format %d width %d rate %d\n",
|
||||
@ -943,7 +942,6 @@ static void aic31xx_clk_on(struct snd_soc_codec *codec)
|
||||
|
||||
static void aic31xx_clk_off(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
|
||||
u8 mask = AIC31XX_PM_MASK;
|
||||
u8 off = 0;
|
||||
|
||||
@ -1021,7 +1019,8 @@ static int aic31xx_set_bias_level(struct snd_soc_codec *codec,
|
||||
}
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
aic31xx_power_off(codec);
|
||||
if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
|
||||
aic31xx_power_off(codec);
|
||||
break;
|
||||
}
|
||||
codec->dapm.bias_level = level;
|
||||
@ -1050,18 +1049,9 @@ static int aic31xx_codec_probe(struct snd_soc_codec *codec)
|
||||
dev_dbg(aic31xx->dev, "## %s\n", __func__);
|
||||
|
||||
aic31xx = snd_soc_codec_get_drvdata(codec);
|
||||
codec->control_data = aic31xx->regmap;
|
||||
|
||||
aic31xx->codec = codec;
|
||||
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
|
||||
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "snd_soc_codec_set_cache_io failed %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) {
|
||||
aic31xx->disable_nb[i].nb.notifier_call =
|
||||
aic31xx_regulator_event;
|
||||
@ -1187,7 +1177,7 @@ static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx)
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
void aic31xx_device_init(struct aic31xx_priv *aic31xx)
|
||||
static void aic31xx_device_init(struct aic31xx_priv *aic31xx)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
@ -1238,7 +1228,6 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
|
||||
return -ENOMEM;
|
||||
|
||||
aic31xx->regmap = devm_regmap_init_i2c(i2c, regmap_config);
|
||||
|
||||
if (IS_ERR(aic31xx->regmap)) {
|
||||
ret = PTR_ERR(aic31xx->regmap);
|
||||
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
|
||||
@ -1251,18 +1240,14 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
|
||||
|
||||
aic31xx_device_init(aic31xx);
|
||||
|
||||
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx,
|
||||
return snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx,
|
||||
aic31xx_dai_driver,
|
||||
ARRAY_SIZE(aic31xx_dai_driver));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aic31xx_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
struct aic31xx_priv *aic31xx = dev_get_drvdata(&i2c->dev);
|
||||
|
||||
kfree(aic31xx);
|
||||
snd_soc_unregister_codec(&i2c->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1284,7 +1269,7 @@ static struct i2c_driver aic31xx_i2c_driver = {
|
||||
.of_match_table = of_match_ptr(tlv320aic31xx_of_match),
|
||||
},
|
||||
.probe = aic31xx_i2c_probe,
|
||||
.remove = (aic31xx_i2c_remove),
|
||||
.remove = aic31xx_i2c_remove,
|
||||
.id_table = aic31xx_i2c_id,
|
||||
};
|
||||
|
||||
|
@ -203,8 +203,7 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
|
||||
u8 hw_params;
|
||||
|
||||
|
@ -566,8 +566,7 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
|
||||
|
||||
/* shut down WSPLL power if running from this clock */
|
||||
|
@ -504,8 +504,7 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 paifa = 0;
|
||||
u16 paifb = 0;
|
||||
|
@ -123,35 +123,29 @@ static const struct snd_soc_dapm_route audio_map[] = {
|
||||
/* Logic for a aic3x as connected on a davinci-evm */
|
||||
static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
struct device_node *np = codec->card->dev->of_node;
|
||||
int ret;
|
||||
|
||||
/* Add davinci-evm specific widgets */
|
||||
snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets,
|
||||
snd_soc_dapm_new_controls(&card->dapm, aic3x_dapm_widgets,
|
||||
ARRAY_SIZE(aic3x_dapm_widgets));
|
||||
|
||||
if (np) {
|
||||
ret = snd_soc_of_parse_audio_routing(codec->card,
|
||||
"ti,audio-routing");
|
||||
ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
/* Set up davinci-evm specific audio path audio_map */
|
||||
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
|
||||
snd_soc_dapm_add_routes(&card->dapm, audio_map,
|
||||
ARRAY_SIZE(audio_map));
|
||||
}
|
||||
|
||||
/* not connected */
|
||||
snd_soc_dapm_disable_pin(dapm, "MONO_LOUT");
|
||||
snd_soc_dapm_disable_pin(dapm, "HPLCOM");
|
||||
snd_soc_dapm_disable_pin(dapm, "HPRCOM");
|
||||
|
||||
/* always connected */
|
||||
snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
|
||||
snd_soc_dapm_enable_pin(dapm, "Line Out");
|
||||
snd_soc_dapm_enable_pin(dapm, "Mic Jack");
|
||||
snd_soc_dapm_enable_pin(dapm, "Line In");
|
||||
snd_soc_dapm_nc_pin(&codec->dapm, "MONO_LOUT");
|
||||
snd_soc_dapm_nc_pin(&codec->dapm, "HPLCOM");
|
||||
snd_soc_dapm_nc_pin(&codec->dapm, "HPRCOM");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1026,6 +1026,7 @@ nodata:
|
||||
static int davinci_mcasp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct davinci_pcm_dma_params *dma_params;
|
||||
struct snd_dmaengine_dai_dma_data *dma_data;
|
||||
struct resource *mem, *ioarea, *res, *dat;
|
||||
struct davinci_mcasp_pdata *pdata;
|
||||
struct davinci_mcasp *mcasp;
|
||||
@ -1095,6 +1096,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
|
||||
mcasp->dat_port = true;
|
||||
|
||||
dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
|
||||
dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
|
||||
dma_params->asp_chan_q = pdata->asp_chan_q;
|
||||
dma_params->ram_chan_q = pdata->ram_chan_q;
|
||||
dma_params->sram_pool = pdata->sram_pool;
|
||||
@ -1105,7 +1107,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
|
||||
dma_params->dma_addr = mem->start + pdata->tx_dma_offset;
|
||||
|
||||
/* Unconditional dmaengine stuff */
|
||||
mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = dma_params->dma_addr;
|
||||
dma_data->addr = dma_params->dma_addr;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
if (res)
|
||||
@ -1113,7 +1115,14 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
|
||||
else
|
||||
dma_params->channel = pdata->tx_dma_channel;
|
||||
|
||||
/* dmaengine filter data for DT and non-DT boot */
|
||||
if (pdev->dev.of_node)
|
||||
dma_data->filter_data = "tx";
|
||||
else
|
||||
dma_data->filter_data = &dma_params->channel;
|
||||
|
||||
dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE];
|
||||
dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
|
||||
dma_params->asp_chan_q = pdata->asp_chan_q;
|
||||
dma_params->ram_chan_q = pdata->ram_chan_q;
|
||||
dma_params->sram_pool = pdata->sram_pool;
|
||||
@ -1124,7 +1133,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
|
||||
dma_params->dma_addr = mem->start + pdata->rx_dma_offset;
|
||||
|
||||
/* Unconditional dmaengine stuff */
|
||||
mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = dma_params->dma_addr;
|
||||
dma_data->addr = dma_params->dma_addr;
|
||||
|
||||
if (mcasp->version < MCASP_VERSION_3) {
|
||||
mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE;
|
||||
@ -1140,9 +1149,11 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
|
||||
else
|
||||
dma_params->channel = pdata->rx_dma_channel;
|
||||
|
||||
/* Unconditional dmaengine stuff */
|
||||
mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = "tx";
|
||||
mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = "rx";
|
||||
/* dmaengine filter data for DT and non-DT boot */
|
||||
if (pdev->dev.of_node)
|
||||
dma_data->filter_data = "rx";
|
||||
else
|
||||
dma_data->filter_data = &dma_params->channel;
|
||||
|
||||
dev_set_drvdata(&pdev->dev, mcasp);
|
||||
|
||||
|
57
sound/soc/davinci/edma-pcm.c
Normal file
57
sound/soc/davinci/edma-pcm.c
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* edma-pcm.c - eDMA PCM driver using dmaengine for AM3xxx, AM4xxx
|
||||
*
|
||||
* Copyright (C) 2014 Texas Instruments, Inc.
|
||||
*
|
||||
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
*
|
||||
* Based on: sound/soc/tegra/tegra_pcm.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
#include <linux/edma.h>
|
||||
|
||||
static const struct snd_pcm_hardware edma_pcm_hardware = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_BATCH |
|
||||
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
|
||||
SNDRV_PCM_INFO_INTERLEAVED,
|
||||
.buffer_bytes_max = 128 * 1024,
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 64 * 1024,
|
||||
.periods_min = 2,
|
||||
.periods_max = 19, /* Limit by edma dmaengine driver */
|
||||
};
|
||||
|
||||
static const struct snd_dmaengine_pcm_config edma_dmaengine_pcm_config = {
|
||||
.pcm_hardware = &edma_pcm_hardware,
|
||||
.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
|
||||
.compat_filter_fn = edma_filter_fn,
|
||||
.prealloc_buffer_size = 128 * 1024,
|
||||
};
|
||||
|
||||
int edma_pcm_platform_register(struct device *dev)
|
||||
{
|
||||
return devm_snd_dmaengine_pcm_register(dev, &edma_dmaengine_pcm_config,
|
||||
SND_DMAENGINE_PCM_FLAG_COMPAT);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(edma_pcm_platform_register);
|
||||
|
||||
MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
|
||||
MODULE_DESCRIPTION("eDMA PCM ASoC platform driver");
|
||||
MODULE_LICENSE("GPL");
|
25
sound/soc/davinci/edma-pcm.h
Normal file
25
sound/soc/davinci/edma-pcm.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* edma-pcm.h - eDMA PCM driver using dmaengine for AM3xxx, AM4xxx
|
||||
*
|
||||
* Copyright (C) 2014 Texas Instruments, Inc.
|
||||
*
|
||||
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
*
|
||||
* Based on: sound/soc/tegra/tegra_pcm.h
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __EDMA_PCM_H__
|
||||
#define __EDMA_PCM_H__
|
||||
|
||||
int edma_pcm_platform_register(struct device *dev);
|
||||
|
||||
#endif /* __EDMA_PCM_H__ */
|
@ -20,7 +20,6 @@
|
||||
|
||||
struct simple_card_data {
|
||||
struct snd_soc_card snd_card;
|
||||
unsigned int daifmt;
|
||||
struct asoc_simple_dai cpu_dai;
|
||||
struct asoc_simple_dai codec_dai;
|
||||
struct snd_soc_dai_link snd_link;
|
||||
@ -105,12 +104,12 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
|
||||
/* get dai->name */
|
||||
ret = snd_soc_of_get_dai_name(np, name);
|
||||
if (ret < 0)
|
||||
goto parse_error;
|
||||
return ret;
|
||||
|
||||
/* parse TDM slot */
|
||||
ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width);
|
||||
if (ret)
|
||||
goto parse_error;
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* bitclock-inversion, frame-inversion
|
||||
@ -130,7 +129,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
|
||||
clk = of_clk_get(np, 0);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
goto parse_error;
|
||||
return ret;
|
||||
}
|
||||
|
||||
dai->sysclk = clk_get_rate(clk);
|
||||
@ -144,12 +143,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
|
||||
dai->sysclk = clk_get_rate(clk);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
parse_error:
|
||||
of_node_put(node);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int asoc_simple_card_parse_of(struct device_node *node,
|
||||
@ -157,15 +151,18 @@ static int asoc_simple_card_parse_of(struct device_node *node,
|
||||
struct device *dev)
|
||||
{
|
||||
struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link;
|
||||
struct asoc_simple_dai *codec_dai = &priv->codec_dai;
|
||||
struct asoc_simple_dai *cpu_dai = &priv->cpu_dai;
|
||||
struct device_node *np;
|
||||
char *name;
|
||||
unsigned int daifmt;
|
||||
int ret;
|
||||
|
||||
/* parsing the card name from DT */
|
||||
snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name");
|
||||
|
||||
/* get CPU/CODEC common format via simple-audio-card,format */
|
||||
priv->daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") &
|
||||
daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") &
|
||||
(SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK);
|
||||
|
||||
/* off-codec widgets */
|
||||
@ -187,25 +184,35 @@ static int asoc_simple_card_parse_of(struct device_node *node,
|
||||
/* CPU sub-node */
|
||||
ret = -EINVAL;
|
||||
np = of_get_child_by_name(node, "simple-audio-card,cpu");
|
||||
if (np)
|
||||
ret = asoc_simple_card_sub_parse_of(np, priv->daifmt,
|
||||
&priv->cpu_dai,
|
||||
if (np) {
|
||||
ret = asoc_simple_card_sub_parse_of(np, daifmt,
|
||||
cpu_dai,
|
||||
&dai_link->cpu_of_node,
|
||||
&dai_link->cpu_dai_name);
|
||||
of_node_put(np);
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* CODEC sub-node */
|
||||
ret = -EINVAL;
|
||||
np = of_get_child_by_name(node, "simple-audio-card,codec");
|
||||
if (np)
|
||||
ret = asoc_simple_card_sub_parse_of(np, priv->daifmt,
|
||||
&priv->codec_dai,
|
||||
if (np) {
|
||||
ret = asoc_simple_card_sub_parse_of(np, daifmt,
|
||||
codec_dai,
|
||||
&dai_link->codec_of_node,
|
||||
&dai_link->codec_dai_name);
|
||||
of_node_put(np);
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* overwrite cpu_dai->fmt as its DAIFMT_MASTER bit is based on CODEC
|
||||
* while the other bits should be identical unless buggy SW/HW design.
|
||||
*/
|
||||
cpu_dai->fmt = codec_dai->fmt;
|
||||
|
||||
if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name)
|
||||
return -EINVAL;
|
||||
|
||||
@ -224,15 +231,15 @@ static int asoc_simple_card_parse_of(struct device_node *node,
|
||||
dai_link->platform_of_node = dai_link->cpu_of_node;
|
||||
|
||||
dev_dbg(dev, "card-name : %s\n", name);
|
||||
dev_dbg(dev, "platform : %04x\n", priv->daifmt);
|
||||
dev_dbg(dev, "platform : %04x\n", daifmt);
|
||||
dev_dbg(dev, "cpu : %s / %04x / %d\n",
|
||||
dai_link->cpu_dai_name,
|
||||
priv->cpu_dai.fmt,
|
||||
priv->cpu_dai.sysclk);
|
||||
cpu_dai->fmt,
|
||||
cpu_dai->sysclk);
|
||||
dev_dbg(dev, "codec : %s / %04x / %d\n",
|
||||
dai_link->codec_dai_name,
|
||||
priv->codec_dai.fmt,
|
||||
priv->codec_dai.sysclk);
|
||||
codec_dai->fmt,
|
||||
codec_dai->sysclk);
|
||||
|
||||
/*
|
||||
* soc_bind_dai_link() will check cpu name
|
||||
@ -248,6 +255,27 @@ static int asoc_simple_card_parse_of(struct device_node *node,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* update the reference count of the devices nodes at end of probe */
|
||||
static int asoc_simple_card_unref(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
struct snd_soc_dai_link *dai_link;
|
||||
struct device_node *np;
|
||||
int num_links;
|
||||
|
||||
for (num_links = 0, dai_link = card->dai_link;
|
||||
num_links < card->num_links;
|
||||
num_links++, dai_link++) {
|
||||
np = (struct device_node *) dai_link->cpu_of_node;
|
||||
if (np)
|
||||
of_node_put(np);
|
||||
np = (struct device_node *) dai_link->codec_of_node;
|
||||
if (np)
|
||||
of_node_put(np);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int asoc_simple_card_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct simple_card_data *priv;
|
||||
@ -275,7 +303,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
|
||||
if (ret < 0) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "parse error %d\n", ret);
|
||||
return ret;
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
struct asoc_simple_card_info *cinfo;
|
||||
@ -318,7 +346,11 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
|
||||
|
||||
snd_soc_card_set_drvdata(&priv->snd_card, priv);
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
|
||||
ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
|
||||
|
||||
err:
|
||||
asoc_simple_card_unref(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id asoc_simple_of_match[] = {
|
||||
|
@ -53,6 +53,7 @@ enum soc_mic_bias_zones {
|
||||
|
||||
static unsigned int hs_switch;
|
||||
static unsigned int lo_dac;
|
||||
static struct snd_soc_codec *mfld_codec;
|
||||
|
||||
struct mfld_mc_private {
|
||||
void __iomem *int_base;
|
||||
@ -100,8 +101,8 @@ static int headset_get_switch(struct snd_kcontrol *kcontrol,
|
||||
static int headset_set_switch(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
|
||||
struct snd_soc_dapm_context *dapm = &card->dapm;
|
||||
|
||||
if (ucontrol->value.integer.value[0] == hs_switch)
|
||||
return 0;
|
||||
@ -127,10 +128,8 @@ static int headset_set_switch(struct snd_kcontrol *kcontrol,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lo_enable_out_pins(struct snd_soc_codec *codec)
|
||||
static void lo_enable_out_pins(struct snd_soc_dapm_context *dapm)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
|
||||
snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTL");
|
||||
snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTR");
|
||||
snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTL");
|
||||
@ -156,8 +155,8 @@ static int lo_get_switch(struct snd_kcontrol *kcontrol,
|
||||
static int lo_set_switch(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
|
||||
struct snd_soc_dapm_context *dapm = &card->dapm;
|
||||
|
||||
if (ucontrol->value.integer.value[0] == lo_dac)
|
||||
return 0;
|
||||
@ -167,35 +166,35 @@ static int lo_set_switch(struct snd_kcontrol *kcontrol,
|
||||
/* we dont want to work with last state of lineout so just enable all
|
||||
* pins and then disable pins not required
|
||||
*/
|
||||
lo_enable_out_pins(codec);
|
||||
lo_enable_out_pins(dapm);
|
||||
|
||||
switch (ucontrol->value.integer.value[0]) {
|
||||
case 0:
|
||||
pr_debug("set vibra path\n");
|
||||
snd_soc_dapm_disable_pin_unlocked(dapm, "VIB1OUT");
|
||||
snd_soc_dapm_disable_pin_unlocked(dapm, "VIB2OUT");
|
||||
snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0);
|
||||
snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
pr_debug("set hs path\n");
|
||||
snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
|
||||
snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
|
||||
snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x22);
|
||||
snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x22);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
pr_debug("set spkr path\n");
|
||||
snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTL");
|
||||
snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTR");
|
||||
snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x44);
|
||||
snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x44);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
pr_debug("set null path\n");
|
||||
snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTL");
|
||||
snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTR");
|
||||
snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x66);
|
||||
snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x66);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -238,26 +237,11 @@ static void mfld_jack_check(unsigned int intr_status)
|
||||
|
||||
static int mfld_init(struct snd_soc_pcm_runtime *runtime)
|
||||
{
|
||||
struct snd_soc_codec *codec = runtime->codec;
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
struct snd_soc_dapm_context *dapm = &runtime->card->dapm;
|
||||
int ret_val;
|
||||
|
||||
/* Add jack sense widgets */
|
||||
snd_soc_dapm_new_controls(dapm, mfld_widgets, ARRAY_SIZE(mfld_widgets));
|
||||
mfld_codec = runtime->codec;
|
||||
|
||||
/* Set up the map */
|
||||
snd_soc_dapm_add_routes(dapm, mfld_map, ARRAY_SIZE(mfld_map));
|
||||
|
||||
/* always connected */
|
||||
snd_soc_dapm_enable_pin(dapm, "Headphones");
|
||||
snd_soc_dapm_enable_pin(dapm, "Mic");
|
||||
|
||||
ret_val = snd_soc_add_codec_controls(codec, mfld_snd_controls,
|
||||
ARRAY_SIZE(mfld_snd_controls));
|
||||
if (ret_val) {
|
||||
pr_err("soc_add_controls failed %d", ret_val);
|
||||
return ret_val;
|
||||
}
|
||||
/* default is earpiece pin, userspace sets it explcitly */
|
||||
snd_soc_dapm_disable_pin(dapm, "Headphones");
|
||||
/* default is lineout NC, userspace sets it explcitly */
|
||||
@ -270,7 +254,7 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
|
||||
snd_soc_dapm_disable_pin(dapm, "LINEINR");
|
||||
|
||||
/* Headset and button jack detection */
|
||||
ret_val = snd_soc_jack_new(codec, "Intel(R) MID Audio Jack",
|
||||
ret_val = snd_soc_jack_new(mfld_codec, "Intel(R) MID Audio Jack",
|
||||
SND_JACK_HEADSET | SND_JACK_BTN_0 |
|
||||
SND_JACK_BTN_1, &mfld_jack);
|
||||
if (ret_val) {
|
||||
@ -352,6 +336,13 @@ static struct snd_soc_card snd_soc_card_mfld = {
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = mfld_msic_dailink,
|
||||
.num_links = ARRAY_SIZE(mfld_msic_dailink),
|
||||
|
||||
.controls = mfld_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(mfld_snd_controls),
|
||||
.dapm_widgets = mfld_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(mfld_widgets),
|
||||
.dapm_routes = mfld_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(mfld_map),
|
||||
};
|
||||
|
||||
static irqreturn_t snd_mfld_jack_intr_handler(int irq, void *dev)
|
||||
|
@ -10,6 +10,7 @@ config SND_KIRKWOOD_SOC_ARMADA370_DB
|
||||
tristate "SoC Audio support for Armada 370 DB"
|
||||
depends on SND_KIRKWOOD_SOC && (ARCH_MVEBU || COMPILE_TEST) && I2C
|
||||
select SND_SOC_CS42L51
|
||||
select SND_SOC_SPDIF
|
||||
help
|
||||
Say Y if you want to add support for SoC audio on
|
||||
the Armada 370 Development Board.
|
||||
|
@ -67,6 +67,20 @@ static struct snd_soc_dai_link a370db_dai[] = {
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
|
||||
.ops = &a370db_ops,
|
||||
},
|
||||
{
|
||||
.name = "S/PDIF out",
|
||||
.stream_name = "spdif-out",
|
||||
.cpu_dai_name = "spdif",
|
||||
.codec_dai_name = "dit-hifi",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
|
||||
},
|
||||
{
|
||||
.name = "S/PDIF in",
|
||||
.stream_name = "spdif-in",
|
||||
.cpu_dai_name = "spdif",
|
||||
.codec_dai_name = "dir-hifi",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_card a370db = {
|
||||
@ -95,6 +109,20 @@ static int a370db_probe(struct platform_device *pdev)
|
||||
of_parse_phandle(pdev->dev.of_node,
|
||||
"marvell,audio-codec", 0);
|
||||
|
||||
a370db_dai[1].cpu_of_node = a370db_dai[0].cpu_of_node;
|
||||
a370db_dai[1].platform_of_node = a370db_dai[0].cpu_of_node;
|
||||
|
||||
a370db_dai[1].codec_of_node =
|
||||
of_parse_phandle(pdev->dev.of_node,
|
||||
"marvell,audio-codec", 1);
|
||||
|
||||
a370db_dai[2].cpu_of_node = a370db_dai[0].cpu_of_node;
|
||||
a370db_dai[2].platform_of_node = a370db_dai[0].cpu_of_node;
|
||||
|
||||
a370db_dai[2].codec_of_node =
|
||||
of_parse_phandle(pdev->dev.of_node,
|
||||
"marvell,audio-codec", 2);
|
||||
|
||||
return devm_snd_soc_register_card(card->dev, card);
|
||||
}
|
||||
|
||||
|
@ -203,8 +203,7 @@ static const struct snd_soc_dapm_route dmic_audio_map[] = {
|
||||
|
||||
static int omap_abe_dmic_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
|
||||
|
||||
return snd_soc_dapm_add_routes(dapm, dmic_audio_map,
|
||||
ARRAY_SIZE(dmic_audio_map));
|
||||
|
@ -392,6 +392,7 @@ static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg)
|
||||
}
|
||||
|
||||
int rsnd_adg_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_adg *adg;
|
||||
|
@ -100,6 +100,21 @@
|
||||
#define RSND_RATES SNDRV_PCM_RATE_8000_96000
|
||||
#define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
|
||||
|
||||
static struct rsnd_of_data rsnd_of_data_gen1 = {
|
||||
.flags = RSND_GEN1,
|
||||
};
|
||||
|
||||
static struct rsnd_of_data rsnd_of_data_gen2 = {
|
||||
.flags = RSND_GEN2,
|
||||
};
|
||||
|
||||
static struct of_device_id rsnd_of_match[] = {
|
||||
{ .compatible = "renesas,rcar_sound-gen1", .data = &rsnd_of_data_gen1 },
|
||||
{ .compatible = "renesas,rcar_sound-gen2", .data = &rsnd_of_data_gen2 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rsnd_of_match);
|
||||
|
||||
/*
|
||||
* rsnd_platform functions
|
||||
*/
|
||||
@ -620,7 +635,92 @@ static int rsnd_path_init(struct rsnd_priv *priv,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rsnd_of_parse_dai(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct device_node *dai_node, *dai_np;
|
||||
struct device_node *ssi_node, *ssi_np;
|
||||
struct device_node *src_node, *src_np;
|
||||
struct device_node *playback, *capture;
|
||||
struct rsnd_dai_platform_info *dai_info;
|
||||
struct rcar_snd_info *info = rsnd_priv_to_info(priv);
|
||||
struct device *dev = &pdev->dev;
|
||||
int nr, i;
|
||||
int dai_i, ssi_i, src_i;
|
||||
|
||||
if (!of_data)
|
||||
return;
|
||||
|
||||
dai_node = of_get_child_by_name(dev->of_node, "rcar_sound,dai");
|
||||
if (!dai_node)
|
||||
return;
|
||||
|
||||
nr = of_get_child_count(dai_node);
|
||||
if (!nr)
|
||||
return;
|
||||
|
||||
dai_info = devm_kzalloc(dev,
|
||||
sizeof(struct rsnd_dai_platform_info) * nr,
|
||||
GFP_KERNEL);
|
||||
if (!dai_info) {
|
||||
dev_err(dev, "dai info allocation error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
info->dai_info_nr = nr;
|
||||
info->dai_info = dai_info;
|
||||
|
||||
ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi");
|
||||
src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
|
||||
|
||||
#define mod_parse(name) \
|
||||
if (name##_node) { \
|
||||
struct rsnd_##name##_platform_info *name##_info; \
|
||||
\
|
||||
name##_i = 0; \
|
||||
for_each_child_of_node(name##_node, name##_np) { \
|
||||
name##_info = info->name##_info + name##_i; \
|
||||
\
|
||||
if (name##_np == playback) \
|
||||
dai_info->playback.name = name##_info; \
|
||||
if (name##_np == capture) \
|
||||
dai_info->capture.name = name##_info; \
|
||||
\
|
||||
name##_i++; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*
|
||||
* parse all dai
|
||||
*/
|
||||
dai_i = 0;
|
||||
for_each_child_of_node(dai_node, dai_np) {
|
||||
dai_info = info->dai_info + dai_i;
|
||||
|
||||
for (i = 0;; i++) {
|
||||
|
||||
playback = of_parse_phandle(dai_np, "playback", i);
|
||||
capture = of_parse_phandle(dai_np, "capture", i);
|
||||
|
||||
if (!playback && !capture)
|
||||
break;
|
||||
|
||||
mod_parse(ssi);
|
||||
mod_parse(src);
|
||||
|
||||
if (playback)
|
||||
of_node_put(playback);
|
||||
if (capture)
|
||||
of_node_put(capture);
|
||||
}
|
||||
|
||||
dai_i++;
|
||||
}
|
||||
}
|
||||
|
||||
static int rsnd_dai_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct snd_soc_dai_driver *drv;
|
||||
@ -628,13 +728,16 @@ static int rsnd_dai_probe(struct platform_device *pdev,
|
||||
struct rsnd_dai *rdai;
|
||||
struct rsnd_mod *pmod, *cmod;
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
int dai_nr = info->dai_info_nr;
|
||||
int dai_nr;
|
||||
int i;
|
||||
|
||||
rsnd_of_parse_dai(pdev, of_data, priv);
|
||||
|
||||
/*
|
||||
* dai_nr should be set via dai_info_nr,
|
||||
* but allow it to keeping compatible
|
||||
*/
|
||||
dai_nr = info->dai_info_nr;
|
||||
if (!dai_nr) {
|
||||
/* get max dai nr */
|
||||
for (dai_nr = 0; dai_nr < 32; dai_nr++) {
|
||||
@ -802,7 +905,10 @@ static int rsnd_probe(struct platform_device *pdev)
|
||||
struct rsnd_priv *priv;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rsnd_dai *rdai;
|
||||
const struct of_device_id *of_id = of_match_device(rsnd_of_match, dev);
|
||||
const struct rsnd_of_data *of_data;
|
||||
int (*probe_func[])(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv) = {
|
||||
rsnd_gen_probe,
|
||||
rsnd_ssi_probe,
|
||||
@ -812,7 +918,16 @@ static int rsnd_probe(struct platform_device *pdev)
|
||||
};
|
||||
int ret, i;
|
||||
|
||||
info = pdev->dev.platform_data;
|
||||
info = NULL;
|
||||
of_data = NULL;
|
||||
if (of_id) {
|
||||
info = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct rcar_snd_info), GFP_KERNEL);
|
||||
of_data = of_id->data;
|
||||
} else {
|
||||
info = pdev->dev.platform_data;
|
||||
}
|
||||
|
||||
if (!info) {
|
||||
dev_err(dev, "driver needs R-Car sound information\n");
|
||||
return -ENODEV;
|
||||
@ -835,7 +950,7 @@ static int rsnd_probe(struct platform_device *pdev)
|
||||
* init each module
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(probe_func); i++) {
|
||||
ret = probe_func[i](pdev, priv);
|
||||
ret = probe_func[i](pdev, of_data, priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -903,6 +1018,7 @@ static int rsnd_remove(struct platform_device *pdev)
|
||||
static struct platform_driver rsnd_driver = {
|
||||
.driver = {
|
||||
.name = "rcar_sound",
|
||||
.of_match_table = rsnd_of_match,
|
||||
},
|
||||
.probe = rsnd_probe,
|
||||
.remove = rsnd_remove,
|
||||
|
@ -359,13 +359,28 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
|
||||
/*
|
||||
* Gen
|
||||
*/
|
||||
static void rsnd_of_parse_gen(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct rcar_snd_info *info = priv->info;
|
||||
|
||||
if (!of_data)
|
||||
return;
|
||||
|
||||
info->flags = of_data->flags;
|
||||
}
|
||||
|
||||
int rsnd_gen_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct rsnd_gen *gen;
|
||||
int ret;
|
||||
|
||||
rsnd_of_parse_gen(pdev, of_data, priv);
|
||||
|
||||
gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
|
||||
if (!gen) {
|
||||
dev_err(dev, "GEN allocate failed\n");
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/sh_dma.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <sound/rcar_snd.h>
|
||||
@ -113,6 +115,7 @@ enum rsnd_reg {
|
||||
#define RSND_REG_SRCOUT_TIMSEL4 RSND_REG_SHARE18
|
||||
#define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19
|
||||
|
||||
struct rsnd_of_data;
|
||||
struct rsnd_priv;
|
||||
struct rsnd_mod;
|
||||
struct rsnd_dai;
|
||||
@ -260,6 +263,7 @@ int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
|
||||
* R-Car Gen1/Gen2
|
||||
*/
|
||||
int rsnd_gen_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv);
|
||||
void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
|
||||
struct rsnd_mod *mod,
|
||||
@ -273,6 +277,7 @@ void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
|
||||
int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod);
|
||||
int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate);
|
||||
int rsnd_adg_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv);
|
||||
int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
|
||||
struct rsnd_mod *mod,
|
||||
@ -290,6 +295,10 @@ int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod,
|
||||
/*
|
||||
* R-Car sound priv
|
||||
*/
|
||||
struct rsnd_of_data {
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
struct rsnd_priv {
|
||||
|
||||
struct device *dev;
|
||||
@ -348,6 +357,7 @@ struct rsnd_priv {
|
||||
* R-Car SRC
|
||||
*/
|
||||
int rsnd_src_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv);
|
||||
struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id);
|
||||
unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
|
||||
@ -366,6 +376,7 @@ int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod,
|
||||
* R-Car SSI
|
||||
*/
|
||||
int rsnd_ssi_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv);
|
||||
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
|
||||
struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv,
|
||||
|
@ -628,7 +628,41 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
|
||||
return &((struct rsnd_src *)(priv->src) + id)->mod;
|
||||
}
|
||||
|
||||
static void rsnd_of_parse_src(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct device_node *src_node;
|
||||
struct rcar_snd_info *info = rsnd_priv_to_info(priv);
|
||||
struct rsnd_src_platform_info *src_info;
|
||||
struct device *dev = &pdev->dev;
|
||||
int nr;
|
||||
|
||||
if (!of_data)
|
||||
return;
|
||||
|
||||
src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
|
||||
if (!src_node)
|
||||
return;
|
||||
|
||||
nr = of_get_child_count(src_node);
|
||||
if (!nr)
|
||||
return;
|
||||
|
||||
src_info = devm_kzalloc(dev,
|
||||
sizeof(struct rsnd_src_platform_info) * nr,
|
||||
GFP_KERNEL);
|
||||
if (!src_info) {
|
||||
dev_err(dev, "src info allocation error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
info->src_info = src_info;
|
||||
info->src_info_nr = nr;
|
||||
}
|
||||
|
||||
int rsnd_src_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct rcar_snd_info *info = rsnd_priv_to_info(priv);
|
||||
@ -639,6 +673,8 @@ int rsnd_src_probe(struct platform_device *pdev,
|
||||
char name[RSND_SRC_NAME_SIZE];
|
||||
int i, nr;
|
||||
|
||||
rsnd_of_parse_src(pdev, of_data, priv);
|
||||
|
||||
/*
|
||||
* init SRC
|
||||
*/
|
||||
|
@ -588,7 +588,61 @@ static void rsnd_ssi_parent_clk_setup(struct rsnd_priv *priv, struct rsnd_ssi *s
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void rsnd_of_parse_ssi(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct device_node *node;
|
||||
struct device_node *np;
|
||||
struct rsnd_ssi_platform_info *ssi_info;
|
||||
struct rcar_snd_info *info = rsnd_priv_to_info(priv);
|
||||
struct device *dev = &pdev->dev;
|
||||
int nr, i;
|
||||
|
||||
if (!of_data)
|
||||
return;
|
||||
|
||||
node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi");
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
nr = of_get_child_count(node);
|
||||
if (!nr)
|
||||
return;
|
||||
|
||||
ssi_info = devm_kzalloc(dev,
|
||||
sizeof(struct rsnd_ssi_platform_info) * nr,
|
||||
GFP_KERNEL);
|
||||
if (!ssi_info) {
|
||||
dev_err(dev, "ssi info allocation error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
info->ssi_info = ssi_info;
|
||||
info->ssi_info_nr = nr;
|
||||
|
||||
i = -1;
|
||||
for_each_child_of_node(node, np) {
|
||||
i++;
|
||||
|
||||
ssi_info = info->ssi_info + i;
|
||||
|
||||
/*
|
||||
* pin settings
|
||||
*/
|
||||
if (of_get_property(np, "shared-pin", NULL))
|
||||
ssi_info->flags |= RSND_SSI_CLK_PIN_SHARE;
|
||||
|
||||
/*
|
||||
* irq
|
||||
*/
|
||||
ssi_info->pio_irq = irq_of_parse_and_map(np, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int rsnd_ssi_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct rcar_snd_info *info = rsnd_priv_to_info(priv);
|
||||
@ -600,6 +654,8 @@ int rsnd_ssi_probe(struct platform_device *pdev,
|
||||
char name[RSND_SSI_NAME_SIZE];
|
||||
int i, nr;
|
||||
|
||||
rsnd_of_parse_ssi(pdev, of_data, priv);
|
||||
|
||||
/*
|
||||
* init SSI
|
||||
*/
|
||||
|
@ -23,21 +23,6 @@
|
||||
static int hw_write(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!snd_soc_codec_volatile_register(codec, reg) &&
|
||||
reg < codec->driver->reg_cache_size &&
|
||||
!codec->cache_bypass) {
|
||||
ret = snd_soc_cache_write(codec, reg, value);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (codec->cache_only) {
|
||||
codec->cache_sync = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return regmap_write(codec->control_data, reg, value);
|
||||
}
|
||||
|
||||
@ -46,23 +31,11 @@ static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg)
|
||||
int ret;
|
||||
unsigned int val;
|
||||
|
||||
if (reg >= codec->driver->reg_cache_size ||
|
||||
snd_soc_codec_volatile_register(codec, reg) ||
|
||||
codec->cache_bypass) {
|
||||
if (codec->cache_only)
|
||||
return -1;
|
||||
|
||||
ret = regmap_read(codec->control_data, reg, &val);
|
||||
if (ret == 0)
|
||||
return val;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = snd_soc_cache_read(codec, reg, &val);
|
||||
if (ret < 0)
|
||||
ret = regmap_read(codec->control_data, reg, &val);
|
||||
if (ret == 0)
|
||||
return val;
|
||||
else
|
||||
return -1;
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user