Commit 53ccd1aa authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/arizona', 'asoc/topic/atmel',...

Merge remote-tracking branches 'asoc/topic/arizona', 'asoc/topic/atmel', 'asoc/topic/bd28623', 'asoc/topic/blackfin' and 'asoc/topic/bt-sco' into asoc-next
ROHM BD28623MUV Class D speaker amplifier for digital input
This codec does not have any control buses such as I2C, it detect format and
rate of I2S signal automatically. It has two signals that can be connected
to GPIOs: reset and mute.
Required properties:
- compatible : should be "rohm,bd28623"
- #sound-dai-cells: should be 0.
- VCCA-supply : regulator phandle for the VCCA supply
- VCCP1-supply : regulator phandle for the VCCP1 supply
- VCCP2-supply : regulator phandle for the VCCP2 supply
Optional properties:
- reset-gpios : GPIO specifier for the active low reset line
- mute-gpios : GPIO specifier for the active low mute line
Example:
codec {
compatible = "rohm,bd28623";
#sound-dai-cells = <0>;
VCCA-supply = <&vcc_reg>;
VCCP1-supply = <&vcc_reg>;
VCCP2-supply = <&vcc_reg>;
reset-gpios = <&gpio 0 GPIO_ACTIVE_LOW>;
mute-gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
};
......@@ -841,13 +841,6 @@ F: sound/soc/codecs/ad7*
F: sound/soc/codecs/ssm*
F: sound/soc/codecs/sigmadsp.*
ANALOG DEVICES INC ASOC DRIVERS
L: adi-buildroot-devel@lists.sourceforge.net (moderated for non-subscribers)
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
W: http://blackfin.uclinux.org/
S: Supported
F: sound/soc/blackfin/*
ANALOG DEVICES INC DMA DRIVERS
M: Lars-Peter Clausen <lars@metafoo.de>
W: http://ez.analog.com/community/linux-device-drivers
......
......@@ -45,7 +45,6 @@ source "sound/soc/amd/Kconfig"
source "sound/soc/atmel/Kconfig"
source "sound/soc/au1x/Kconfig"
source "sound/soc/bcm/Kconfig"
source "sound/soc/blackfin/Kconfig"
source "sound/soc/cirrus/Kconfig"
source "sound/soc/davinci/Kconfig"
source "sound/soc/dwc/Kconfig"
......
......@@ -29,7 +29,6 @@ obj-$(CONFIG_SND_SOC) += amd/
obj-$(CONFIG_SND_SOC) += atmel/
obj-$(CONFIG_SND_SOC) += au1x/
obj-$(CONFIG_SND_SOC) += bcm/
obj-$(CONFIG_SND_SOC) += blackfin/
obj-$(CONFIG_SND_SOC) += cirrus/
obj-$(CONFIG_SND_SOC) += davinci/
obj-$(CONFIG_SND_SOC) += dwc/
......
......@@ -248,9 +248,9 @@ static const char * const pwm_type[] = {
"Single ended", "Differential"
};
static int atmel_classd_codec_probe(struct snd_soc_codec *codec)
static int atmel_classd_component_probe(struct snd_soc_component *component)
{
struct snd_soc_card *card = snd_soc_codec_get_drvdata(codec);
struct snd_soc_card *card = snd_soc_component_get_drvdata(component);
struct atmel_classd *dd = snd_soc_card_get_drvdata(card);
const struct atmel_classd_pdata *pdata = dd->pdata;
u32 mask, val;
......@@ -284,16 +284,16 @@ static int atmel_classd_codec_probe(struct snd_soc_codec *codec)
default:
val |= (CLASSD_MR_NOVR_VAL_10NS
<< CLASSD_MR_NOVR_VAL_SHIFT);
dev_warn(codec->dev,
dev_warn(component->dev,
"non-overlapping value %d is invalid, the default value 10 is specified\n",
pdata->non_overlap_time);
break;
}
}
snd_soc_update_bits(codec, CLASSD_MR, mask, val);
snd_soc_component_update_bits(component, CLASSD_MR, mask, val);
dev_info(codec->dev,
dev_info(component->dev,
"PWM modulation type is %s, non-overlapping is %s\n",
pwm_type[pdata->pwm_type],
pdata->non_overlap_enable?"enabled":"disabled");
......@@ -301,21 +301,23 @@ static int atmel_classd_codec_probe(struct snd_soc_codec *codec)
return 0;
}
static int atmel_classd_codec_resume(struct snd_soc_codec *codec)
static int atmel_classd_component_resume(struct snd_soc_component *component)
{
struct snd_soc_card *card = snd_soc_codec_get_drvdata(codec);
struct snd_soc_card *card = snd_soc_component_get_drvdata(component);
struct atmel_classd *dd = snd_soc_card_get_drvdata(card);
return regcache_sync(dd->regmap);
}
static struct snd_soc_codec_driver soc_codec_dev_classd = {
.probe = atmel_classd_codec_probe,
.resume = atmel_classd_codec_resume,
.component_driver = {
.controls = atmel_classd_snd_controls,
.num_controls = ARRAY_SIZE(atmel_classd_snd_controls),
},
static struct snd_soc_component_driver soc_component_dev_classd = {
.probe = atmel_classd_component_probe,
.resume = atmel_classd_component_resume,
.controls = atmel_classd_snd_controls,
.num_controls = ARRAY_SIZE(atmel_classd_snd_controls),
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
/* codec dai component */
......@@ -331,7 +333,7 @@ static int atmel_classd_codec_dai_startup(struct snd_pcm_substream *substream,
static int atmel_classd_codec_dai_digital_mute(struct snd_soc_dai *codec_dai,
int mute)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct snd_soc_component *component = codec_dai->component;
u32 mask, val;
mask = CLASSD_MR_LMUTE_MASK | CLASSD_MR_RMUTE_MASK;
......@@ -341,7 +343,7 @@ static int atmel_classd_codec_dai_digital_mute(struct snd_soc_dai *codec_dai,
else
val = 0;
snd_soc_update_bits(codec, CLASSD_MR, mask, val);
snd_soc_component_update_bits(component, CLASSD_MR, mask, val);
return 0;
}
......@@ -380,7 +382,7 @@ atmel_classd_codec_dai_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_codec *codec = codec_dai->codec;
struct snd_soc_component *component = codec_dai->component;
int fs;
int i, best, best_val, cur_val, ret;
u32 mask, val;
......@@ -398,7 +400,7 @@ atmel_classd_codec_dai_hw_params(struct snd_pcm_substream *substream,
}
}
dev_dbg(codec->dev,
dev_dbg(component->dev,
"Selected SAMPLE_RATE of %dHz, GCLK_RATE of %ldHz\n",
sample_rates[best].rate, sample_rates[best].gclk_rate);
......@@ -412,7 +414,7 @@ atmel_classd_codec_dai_hw_params(struct snd_pcm_substream *substream,
val = (sample_rates[best].dsp_clk << CLASSD_INTPMR_DSP_CLK_FREQ_SHIFT)
| (sample_rates[best].sample_rate << CLASSD_INTPMR_FRAME_SHIFT);
snd_soc_update_bits(codec, CLASSD_INTPMR, mask, val);
snd_soc_component_update_bits(component, CLASSD_INTPMR, mask, val);
return clk_prepare_enable(dd->gclk);
}
......@@ -430,9 +432,9 @@ atmel_classd_codec_dai_shutdown(struct snd_pcm_substream *substream,
static int atmel_classd_codec_dai_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *codec_dai)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct snd_soc_component *component = codec_dai->component;
snd_soc_update_bits(codec, CLASSD_MR,
snd_soc_component_update_bits(component, CLASSD_MR,
CLASSD_MR_LEN_MASK | CLASSD_MR_REN_MASK,
(CLASSD_MR_LEN_DIS << CLASSD_MR_LEN_SHIFT)
|(CLASSD_MR_REN_DIS << CLASSD_MR_REN_SHIFT));
......@@ -443,7 +445,7 @@ static int atmel_classd_codec_dai_prepare(struct snd_pcm_substream *substream,
static int atmel_classd_codec_dai_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *codec_dai)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct snd_soc_component *component = codec_dai->component;
u32 mask, val;
mask = CLASSD_MR_LEN_MASK | CLASSD_MR_REN_MASK;
......@@ -464,7 +466,7 @@ static int atmel_classd_codec_dai_trigger(struct snd_pcm_substream *substream,
return -EINVAL;
}
snd_soc_update_bits(codec, CLASSD_MR, mask, val);
snd_soc_component_update_bits(component, CLASSD_MR, mask, val);
return 0;
}
......@@ -581,11 +583,8 @@ static int atmel_classd_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
io_base = devm_ioremap_resource(dev, res);
if (IS_ERR(io_base)) {
ret = PTR_ERR(io_base);
dev_err(dev, "failed to remap register memory: %d\n", ret);
return ret;
}
if (IS_ERR(io_base))
return PTR_ERR(io_base);
dd->phy_base = res->start;
dd->dev = dev;
......@@ -614,10 +613,10 @@ static int atmel_classd_probe(struct platform_device *pdev)
return ret;
}
ret = snd_soc_register_codec(dev, &soc_codec_dev_classd,
ret = devm_snd_soc_register_component(dev, &soc_component_dev_classd,
&atmel_classd_codec_dai, 1);
if (ret) {
dev_err(dev, "could not register codec: %d\n", ret);
dev_err(dev, "could not register component: %d\n", ret);
return ret;
}
......@@ -645,13 +644,11 @@ static int atmel_classd_probe(struct platform_device *pdev)
return 0;
unregister_codec:
snd_soc_unregister_codec(dev);
return ret;
}
static int atmel_classd_remove(struct platform_device *pdev)
{
snd_soc_unregister_codec(&pdev->dev);
return 0;
}
......
......@@ -289,14 +289,14 @@ static const DECLARE_TLV_DB_RANGE(mic_gain_tlv,
static int pdmic_get_mic_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
unsigned int dgain_val, scale_val;
int i;
dgain_val = (snd_soc_read(codec, PDMIC_DSPR1) & PDMIC_DSPR1_DGAIN_MASK)
dgain_val = (snd_soc_component_read32(component, PDMIC_DSPR1) & PDMIC_DSPR1_DGAIN_MASK)
>> PDMIC_DSPR1_DGAIN_SHIFT;
scale_val = (snd_soc_read(codec, PDMIC_DSPR0) & PDMIC_DSPR0_SCALE_MASK)
scale_val = (snd_soc_component_read32(component, PDMIC_DSPR0) & PDMIC_DSPR0_SCALE_MASK)
>> PDMIC_DSPR0_SCALE_SHIFT;
for (i = 0; i < ARRAY_SIZE(mic_gain_table); i++) {
......@@ -313,7 +313,7 @@ static int pdmic_put_mic_volsw(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
int max = mc->max;
unsigned int val;
int ret;
......@@ -323,12 +323,12 @@ static int pdmic_put_mic_volsw(struct snd_kcontrol *kcontrol,
if (val > max)
return -EINVAL;
ret = snd_soc_update_bits(codec, PDMIC_DSPR1, PDMIC_DSPR1_DGAIN_MASK,
ret = snd_soc_component_update_bits(component, PDMIC_DSPR1, PDMIC_DSPR1_DGAIN_MASK,
mic_gain_table[val].dgain << PDMIC_DSPR1_DGAIN_SHIFT);
if (ret < 0)
return ret;
ret = snd_soc_update_bits(codec, PDMIC_DSPR0, PDMIC_DSPR0_SCALE_MASK,
ret = snd_soc_component_update_bits(component, PDMIC_DSPR0, PDMIC_DSPR0_SCALE_MASK,
mic_gain_table[val].scale << PDMIC_DSPR0_SCALE_SHIFT);
if (ret < 0)
return ret;
......@@ -347,23 +347,25 @@ SOC_SINGLE("High Pass Filter Switch", PDMIC_DSPR0,
SOC_SINGLE("SINCC Filter Switch", PDMIC_DSPR0, PDMIC_DSPR0_SINBYP_SHIFT, 1, 1),
};
static int atmel_pdmic_codec_probe(struct snd_soc_codec *codec)
static int atmel_pdmic_component_probe(struct snd_soc_component *component)
{
struct snd_soc_card *card = snd_soc_codec_get_drvdata(codec);
struct snd_soc_card *card = snd_soc_component_get_drvdata(component);
struct atmel_pdmic *dd = snd_soc_card_get_drvdata(card);
snd_soc_update_bits(codec, PDMIC_DSPR1, PDMIC_DSPR1_OFFSET_MASK,
snd_soc_component_update_bits(component, PDMIC_DSPR1, PDMIC_DSPR1_OFFSET_MASK,
(u32)(dd->pdata->mic_offset << PDMIC_DSPR1_OFFSET_SHIFT));
return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_pdmic = {
.probe = atmel_pdmic_codec_probe,
.component_driver = {
.controls = atmel_pdmic_snd_controls,
.num_controls = ARRAY_SIZE(atmel_pdmic_snd_controls),
},
static struct snd_soc_component_driver soc_component_dev_pdmic = {
.probe = atmel_pdmic_component_probe,
.controls = atmel_pdmic_snd_controls,
.num_controls = ARRAY_SIZE(atmel_pdmic_snd_controls),
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
/* codec dai component */
......@@ -376,7 +378,7 @@ atmel_pdmic_codec_dai_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_codec *codec = codec_dai->codec;
struct snd_soc_component *component = codec_dai->component;
unsigned int rate_min = substream->runtime->hw.rate_min;
unsigned int rate_max = substream->runtime->hw.rate_max;
int fs = params_rate(params);
......@@ -386,13 +388,13 @@ atmel_pdmic_codec_dai_hw_params(struct snd_pcm_substream *substream,
u32 mr_val, dspr0_val, pclk_prescal, gclk_prescal;
if (params_channels(params) != 1) {
dev_err(codec->dev,
dev_err(component->dev,
"only supports one channel\n");
return -EINVAL;
}
if ((fs < rate_min) || (fs > rate_max)) {
dev_err(codec->dev,
dev_err(component->dev,
"sample rate is %dHz, min rate is %dHz, max rate is %dHz\n",
fs, rate_min, rate_max);
......@@ -437,10 +439,10 @@ atmel_pdmic_codec_dai_hw_params(struct snd_pcm_substream *substream,
mr_val |= PDMIC_MR_CLKS_PCK << PDMIC_MR_CLKS_SHIFT;
}
snd_soc_update_bits(codec, PDMIC_MR,
snd_soc_component_update_bits(component, PDMIC_MR,
PDMIC_MR_PRESCAL_MASK | PDMIC_MR_CLKS_MASK, mr_val);
snd_soc_update_bits(codec, PDMIC_DSPR0,
snd_soc_component_update_bits(component, PDMIC_DSPR0,
PDMIC_DSPR0_OSR_MASK | PDMIC_DSPR0_SIZE_MASK, dspr0_val);
return 0;
......@@ -449,9 +451,9 @@ atmel_pdmic_codec_dai_hw_params(struct snd_pcm_substream *substream,
static int atmel_pdmic_codec_dai_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *codec_dai)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct snd_soc_component *component = codec_dai->component;
snd_soc_update_bits(codec, PDMIC_CR, PDMIC_CR_ENPDM_MASK,
snd_soc_component_update_bits(component, PDMIC_CR, PDMIC_CR_ENPDM_MASK,
PDMIC_CR_ENPDM_DIS << PDMIC_CR_ENPDM_SHIFT);
return 0;
......@@ -460,7 +462,7 @@ static int atmel_pdmic_codec_dai_prepare(struct snd_pcm_substream *substream,
static int atmel_pdmic_codec_dai_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *codec_dai)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct snd_soc_component *component = codec_dai->component;
u32 val;
switch (cmd) {
......@@ -478,7 +480,7 @@ static int atmel_pdmic_codec_dai_trigger(struct snd_pcm_substream *substream,
return -EINVAL;
}
snd_soc_update_bits(codec, PDMIC_CR, PDMIC_CR_ENPDM_MASK, val);
snd_soc_component_update_bits(component, PDMIC_CR, PDMIC_CR_ENPDM_MASK, val);
return 0;
}
......@@ -631,11 +633,8 @@ static int atmel_pdmic_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
io_base = devm_ioremap_resource(dev, res);
if (IS_ERR(io_base)) {
ret = PTR_ERR(io_base);
dev_err(dev, "failed to remap register memory: %d\n", ret);
return ret;
}
if (IS_ERR(io_base))
return PTR_ERR(io_base);
dd->phy_base = res->start;
......@@ -681,10 +680,10 @@ static int atmel_pdmic_probe(struct platform_device *pdev)
/* register codec and codec dai */
atmel_pdmic_codec_dai.capture.rate_min = rate_min;
atmel_pdmic_codec_dai.capture.rate_max = rate_max;
ret = snd_soc_register_codec(dev, &soc_codec_dev_pdmic,
ret = devm_snd_soc_register_component(dev, &soc_component_dev_pdmic,
&atmel_pdmic_codec_dai, 1);
if (ret) {
dev_err(dev, "could not register codec: %d\n", ret);
dev_err(dev, "could not register component: %d\n", ret);
return ret;
}
......@@ -712,13 +711,11 @@ static int atmel_pdmic_probe(struct platform_device *pdev)
return 0;
unregister_codec:
snd_soc_unregister_codec(dev);
return ret;
}
static int atmel_pdmic_remove(struct platform_device *pdev)
{
snd_soc_unregister_codec(&pdev->dev);
return 0;
}
......
config SND_BF5XX_I2S
tristate "SoC I2S Audio for the ADI Blackfin chip"
depends on BLACKFIN
select SND_BF5XX_SOC_SPORT if !BF60x
select SND_BF6XX_SOC_SPORT if BF60x
help
Say Y or M if you want to add support for codecs attached to
the Blackfin SPORT (synchronous serial ports) interface in I2S
mode (supports single stereo In/Out).
You will also need to select the audio interfaces to support below.
config SND_BF5XX_SOC_SSM2602
tristate "SoC SSM2602 Audio Codec Add-On Card support"
depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
select SND_BF5XX_SOC_I2S if !BF60x
select SND_BF6XX_SOC_I2S if BF60x
select SND_SOC_SSM2602_SPI if SPI_MASTER
select SND_SOC_SSM2602_I2C if I2C
help
Say Y if you want to add support for the Analog Devices
SSM2602 Audio Codec Add-On Card.
config SND_SOC_BFIN_EVAL_ADAU1701
tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards"
depends on SND_BF5XX_I2S && I2C
select SND_BF5XX_SOC_I2S
select SND_SOC_ADAU1701
help
Say Y if you want to add support for the Analog Devices EVAL-ADAU1701MINIZ
board connected to one of the Blackfin evaluation boards like the
BF5XX-STAMP or BF5XX-EZKIT.
config SND_SOC_BFIN_EVAL_ADAU1373
tristate "Support for the EVAL-ADAU1373 board on Blackfin eval boards"
depends on SND_BF5XX_I2S && I2C
select SND_BF5XX_SOC_I2S
select SND_SOC_ADAU1373
help
Say Y if you want to add support for the Analog Devices EVAL-ADAU1373
board connected to one of the Blackfin evaluation boards like the
BF5XX-STAMP or BF5XX-EZKIT.
Note: This driver assumes that first ADAU1373 DAI is connected to the
first SPORT port on the BF5XX board.
config SND_SOC_BFIN_EVAL_ADAU1X61
tristate "Support for the EVAL-ADAU1X61 board on Blackfin eval boards"
depends on SND_BF5XX_I2S && I2C
select SND_BF5XX_SOC_I2S
select SND_SOC_ADAU1761_I2C
help
Say Y if you want to add support for the Analog Devices EVAL-ADAU1X61
board connected to one of the Blackfin evaluation boards like the
BF5XX-STAMP or BF5XX-EZKIT.
Note: This driver assumes that the ADAU1X61 is connected to the
first SPORT port on the BF5XX board.
config SND_SOC_BFIN_EVAL_ADAU1X81
tristate "Support for the EVAL-ADAU1X81 boards on Blackfin eval boards"
depends on SND_BF5XX_I2S && I2C
select SND_BF5XX_SOC_I2S
select SND_SOC_ADAU1781_I2C
help
Say Y if you want to add support for the Analog Devices EVAL-ADAU1X81
board connected to one of the Blackfin evaluation boards like the
BF5XX-STAMP or BF5XX-EZKIT.
Note: This driver assumes that the ADAU1X81 is connected to the
first SPORT port on the BF5XX board.
config SND_SOC_BFIN_EVAL_ADAV80X
tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards"
depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
select SND_BF5XX_SOC_I2S
select SND_SOC_ADAV801 if SPI_MASTER
select SND_SOC_ADAV803 if I2C
help
Say Y if you want to add support for the Analog Devices EVAL-ADAV801 or
EVAL-ADAV803 board connected to one of the Blackfin evaluation boards
like the BF5XX-STAMP or BF5XX-EZKIT.
Note: This driver assumes that the ADAV80X digital record and playback
interfaces are connected to the first SPORT port on the BF5XX board.
config SND_BF5XX_SOC_AD1836
tristate "SoC AD1836 Audio support for BF5xx"
depends on SND_BF5XX_I2S && SPI_MASTER
select SND_BF5XX_SOC_I2S
select SND_SOC_AD1836
help
Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT.
config SND_BF5XX_SOC_AD193X
tristate "SoC AD193X Audio support for Blackfin"
depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
select SND_BF5XX_SOC_I2S
select SND_SOC_AD193X_I2C if I2C
select SND_SOC_AD193X_SPI if SPI_MASTER
help
Say Y if you want to add support for AD193X codec on Blackfin.
This driver supports AD1936, AD1937, AD1938 and AD1939.
config SND_BF5XX_SOC_AD73311
tristate "SoC AD73311 Audio support for Blackfin"
depends on SND_BF5XX_I2S
select SND_BF5XX_SOC_I2S
select SND_SOC_AD73311
help
Say Y if you want to add support for AD73311 codec on Blackfin.
config SND_BFIN_AD73311_SE
int "PF pin for AD73311L Chip Select"
depends on SND_BF5XX_SOC_AD73311
default 4
help
Enter the GPIO used to control AD73311's SE pin. Acceptable
values are 0 to 7
config SND_BF5XX_AC97
tristate "SoC AC97 Audio for the ADI BF5xx chip"
depends on BLACKFIN
select AC97_BUS
select SND_SOC_AC97_BUS
select SND_BF5XX_SOC_SPORT
select SND_BF5XX_SOC_AC97
help
Say Y or M if you want to add support for codecs attached to
the Blackfin SPORT (synchronous serial ports) interface in slot 16
mode (pseudo AC97 interface).
You will also need to select the audio interfaces to support below.
Note:
AC97 codecs which do not implement the slot-16 mode will not function
properly with this driver. This driver is known to work with the
Analog Devices line of AC97 codecs.
config SND_BF5XX_MMAP_SUPPORT
bool "Enable MMAP Support"
depends on SND_BF5XX_AC97
default y
help
Say y if you want AC97 driver to support mmap mode.
We introduce an intermediate buffer to simulate mmap.
config SND_BF5XX_MULTICHAN_SUPPORT
bool "Enable Multichannel Support"
depends on SND_BF5XX_AC97
default n
help
Say y if you want AC97 driver to support up to 5.1 channel audio.
this mode will consume much more memory for DMA.
config SND_BF5XX_HAVE_COLD_RESET
bool "BOARD has COLD Reset GPIO"
depends on SND_BF5XX_AC97
default y if BFIN548_EZKIT
default n if !BFIN548_EZKIT
config SND_BF5XX_RESET_GPIO_NUM
int "Set a GPIO for cold reset"
depends on SND_BF5XX_HAVE_COLD_RESET
range 0 159
default 19 if BFIN548_EZKIT
default 5 if BFIN537_STAMP
default 0
help
Set the correct GPIO for RESET the sound chip.
config SND_BF5XX_SOC_AD1980
tristate "SoC AD1980/1 Audio support for BF5xx (Obsolete)"
depends on SND_BF5XX_AC97
select SND_BF5XX_SOC_AC97
select SND_SOC_AD1980
help
Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT.
Warning:
Because Analog Devices Inc. discontinued the ad1980 sound chip since
Sep. 2009, this ad1980 driver is not maintained, tested and supported
by ADI now.
config SND_BF5XX_SOC_SPORT
tristate
config SND_BF6XX_SOC_SPORT
tristate
config SND_BF5XX_SOC_I2S
tristate
config SND_BF6XX_SOC_I2S
tristate
config SND_BF5XX_SOC_AC97
tristate
config SND_BF5XX_SPORT_NUM
int "Set a SPORT for Sound chip"
depends on (SND_BF5XX_SOC_SPORT || SND_BF6XX_SOC_SPORT)
range 0 3 if BF54x
range 0 1 if !BF54x
default 0
help
Set the correct SPORT for sound chip.
# SPDX-License-Identifier: GPL-2.0
# Blackfin Platform Support
snd-bf5xx-ac97-objs := bf5xx-ac97-pcm.o
snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o
snd-soc-bf5xx-sport-objs := bf5xx-sport.o
snd-soc-bf6xx-sport-objs := bf6xx-sport.o
snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o
snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o
snd-soc-bf6xx-i2s-objs := bf6xx-i2s.o
obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o
obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o
obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o
obj-$(CONFIG_SND_BF6XX_SOC_SPORT) += snd-soc-bf6xx-sport.o
obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o
obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o
obj-$(CONFIG_SND_BF6XX_SOC_I2S) += snd-soc-bf6xx-i2s.o
# Blackfin Machine Support
snd-ad1836-objs := bf5xx-ad1836.o
snd-ad1980-objs := bf5xx-ad1980.o
snd-ssm2602-objs := bf5xx-ssm2602.o
snd-ad73311-objs := bf5xx-ad73311.o
snd-ad193x-objs := bf5xx-ad193x.o
snd-soc-bfin-eval-adau1373-objs := bfin-eval-adau1373.o
snd-soc-bfin-eval-adau1x61-objs := bfin-eval-adau1x61.o
snd-soc-bfin-eval-adau1x81-objs := bfin-eval-adau1x81.o
snd-soc-bfin-eval-adau1701-objs := bfin-eval-adau1701.o
snd-soc-bfin-eval-adav80x-objs := bfin-eval-adav80x.o
obj-$(CONFIG_SND_BF5XX_SOC_AD1836) += snd-ad1836.o
obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o
obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o
obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o
obj-$(CONFIG_SND_BF5XX_SOC_AD193X) += snd-ad193x.o
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1373) += snd-soc-bfin-eval-adau1373.o
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X61) += snd-soc-bfin-eval-adau1x61.o
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X81) += snd-soc-bfin-eval-adau1x81.o
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1701) += snd-soc-bfin-eval-adau1701.o
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAV80X) += snd-soc-bfin-eval-adav80x.o
/*
* File: sound/soc/blackfin/bf5xx-ac97-pcm.c
* Author: Cliff Cai <Cliff.Cai@analog.com>
*
* Created: Tue June 06 2008
* Description: DMA Driver for AC97 sound chip
*
* Modified:
* Copyright 2008 Analog Devices Inc.
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see the file COPYING, or write
* to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/gfp.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <asm/dma.h>
#include "bf5xx-ac97.h"
#include "bf5xx-sport.h"
static unsigned int ac97_chan_mask[] = {
SP_FL, /* Mono */
SP_STEREO, /* Stereo */
SP_2DOT1, /* 2.1*/
SP_QUAD,/*Quadraquic*/
SP_FL | SP_FR | SP_FC | SP_SL | SP_SR,/*5 channels */
SP_5DOT1, /* 5.1 */
};
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
static void bf5xx_mmap_copy(struct snd_pcm_substream *substream,
snd_pcm_uframes_t count)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct sport_device *sport = runtime->private_data;
unsigned int chan_mask = ac97_chan_mask[runtime->channels - 1];
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
bf5xx_pcm_to_ac97((struct ac97_frame *)sport->tx_dma_buf +
sport->tx_pos, (__u16 *)runtime->dma_area + sport->tx_pos *
runtime->channels, count, chan_mask);
sport->tx_pos += runtime->period_size;
if (sport->tx_pos >= runtime->buffer_size)
sport->tx_pos %= runtime->buffer_size;
sport->tx_delay_pos = sport->tx_pos;
} else {
bf5xx_ac97_to_pcm((struct ac97_frame *)sport->rx_dma_buf +
sport->rx_pos, (__u16 *)runtime->dma_area + sport->rx_pos *
runtime->channels, count);
sport->rx_pos += runtime->period_size;
if (sport->rx_pos >= runtime->buffer_size)
sport->rx_pos %= runtime->buffer_size;
}
}
#endif
static void bf5xx_dma_irq(void *data)
{
struct snd_pcm_substream *pcm = data;
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
struct snd_pcm_runtime *runtime = pcm->runtime;
struct sport_device *sport = runtime->private_data;
bf5xx_mmap_copy(pcm, runtime->period_size);
if (pcm->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (sport->once == 0) {
snd_pcm_period_elapsed(pcm);
bf5xx_mmap_copy(pcm, runtime->period_size);
sport->once = 1;
}
}
#endif
snd_pcm_period_elapsed(pcm);
}
/* The memory size for pure pcm data is 128*1024 = 0x20000 bytes.
* The total rx/tx buffer is for ac97 frame to hold all pcm data
* is 0x20000 * sizeof(struct ac97_frame) / 4.
*/
static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
#endif
SNDRV_PCM_INFO_BLOCK_TRANSFER,
.period_bytes_min = 32,
.period_bytes_max = 0x10000,
.periods_min = 1,
.periods_max = PAGE_SIZE/32,
.buffer_bytes_max = 0x20000, /* 128 kbytes */
.fifo_size = 16,
};
static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
size_t size = bf5xx_pcm_hardware.buffer_bytes_max
* sizeof(struct ac97_frame) / 4;
snd_pcm_lib_malloc_pages(substream, size);
return 0;
}
static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
{
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
struct snd_pcm_runtime *runtime = substream->runtime;
struct sport_device *sport = runtime->private_data;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
sport->once = 0;
if (runtime->dma_area)
memset(runtime->dma_area, 0, runtime->buffer_size);
memset(sport->tx_dma_buf, 0, runtime->buffer_size *
sizeof(struct ac97_frame));
} else
memset(sport->rx_dma_buf, 0, runtime->buffer_size *
sizeof(struct ac97_frame));
#endif
snd_pcm_lib_free_pages(substream);
return 0;
}
static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct sport_device *sport = runtime->private_data;
/* An intermediate buffer is introduced for implementing mmap for
* SPORT working in TMD mode(include AC97).
*/
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods,
runtime->period_size * sizeof(struct ac97_frame));
} else {
sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
sport_config_rx_dma(sport, sport->rx_dma_buf, runtime->periods,
runtime->period_size * sizeof(struct ac97_frame));
}
#else
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
sport_config_tx_dma(sport, runtime->dma_area, runtime->periods,
runtime->period_size * sizeof(struct ac97_frame));
} else {
sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
sport_config_rx_dma(sport, runtime->dma_area, runtime->periods,
runtime->period_size * sizeof(struct ac97_frame));
}
#endif
return 0;
}
static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct sport_device *sport = runtime->private_data;
int ret = 0;
pr_debug("%s enter\n", __func__);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
bf5xx_mmap_copy(substream, runtime->period_size);
sport->tx_delay_pos = 0;
#endif
sport_tx_start(sport);
} else
sport_rx_start(sport);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
sport->tx_pos = 0;
#endif
sport_tx_stop(sport);
} else {
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
sport->rx_pos = 0;
#endif
sport_rx_stop(sport);
}
break;
default:
ret = -EINVAL;
}
return ret;
}
static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct sport_device *sport = runtime->private_data;
unsigned int curr;
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
curr = sport->tx_delay_pos;
else
curr = sport->rx_pos;
#else
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
curr = sport_curr_offset_tx(sport) / sizeof(struct ac97_frame);
else
curr = sport_curr_offset_rx(sport) / sizeof(struct ac97_frame);
#endif
return curr;
}
static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
struct snd_pcm_runtime *runtime = substream->runtime;
int ret;
pr_debug("%s enter\n", __func__);
snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0)
goto out;
if (sport_handle != NULL)
runtime->private_data = sport_handle;
else {
pr_err("sport_handle is NULL\n");
return -1;
}
return 0;
out:
return ret;
}
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
struct snd_pcm_runtime *runtime = substream->runtime;
size_t size = vma->vm_end - vma->vm_start;
vma->vm_start = (unsigned long)runtime->dma_area;
vma->vm_end = vma->vm_start + size;
vma->vm_flags |= VM_SHARED;
return 0 ;
}
#else
static int bf5xx_pcm_copy(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
void *buf, unsigned long count)
{
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int chan_mask = ac97_chan_mask[runtime->channels - 1];
struct ac97_frame *dst;
pr_debug("%s copy pos:0x%lx count:0x%lx\n",
substream->stream ? "Capture" : "Playback", pos, count);
dst = (struct ac97_frame *)runtime->dma_area +
bytes_to_frames(runtime, pos);
count = bytes_to_frames(runtime, count);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
bf5xx_pcm_to_ac97(dst, buf, count, chan_mask);
else
bf5xx_ac97_to_pcm(dst, buf, count);
return 0;
}
static int bf5xx_pcm_copy_user(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
void __user *buf, unsigned long count)
{
return bf5xx_pcm_copy(substream, channel, pos, (void *)buf, count);
}
#endif
static const struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
.open = bf5xx_pcm_open,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = bf5xx_pcm_hw_params,
.hw_free = bf5xx_pcm_hw_free,
.prepare = bf5xx_pcm_prepare,
.trigger = bf5xx_pcm_trigger,
.pointer = bf5xx_pcm_pointer,
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
.mmap = bf5xx_pcm_mmap,
#else
.copy_user = bf5xx_pcm_copy_user,
.copy_kernel = bf5xx_pcm_copy,
#endif
};
static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
{
struct snd_soc_pcm_runtime *rtd = pcm->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
struct snd_dma_buffer *buf = &substream->dma_buffer;
size_t size = bf5xx_pcm_hardware.buffer_bytes_max
* sizeof(struct ac97_frame) / 4;
buf->dev.type = SNDRV_DMA_TYPE_DEV;
buf->dev.dev = pcm->card->dev;
buf->private_data = NULL;
buf->area = dma_alloc_coherent(pcm->card->dev, size,
&buf->addr, GFP_KERNEL);
if (!buf->area) {
pr_err("Failed to allocate dma memory\n");
pr_err("Please increase uncached DMA memory region\n");
return -ENOMEM;
}
buf->bytes = size;
pr_debug("%s, area:%p, size:0x%08lx\n", __func__,
buf->area, buf->bytes);
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
sport_handle->tx_buf = buf->area;
else
sport_handle->rx_buf = buf->area;
/*
* Need to allocate local buffer when enable
* MMAP for SPORT working in TMD mode (include AC97).
*/
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (!sport_handle->tx_dma_buf) {
sport_handle->tx_dma_buf = dma_alloc_coherent(NULL, \
size, &sport_handle->tx_dma_phy, GFP_KERNEL);
if (!sport_handle->tx_dma_buf) {
pr_err("Failed to allocate memory for tx dma buf - Please increase uncached DMA memory region\n");
return -ENOMEM;
} else
memset(sport_handle->tx_dma_buf, 0, size);
} else
memset(sport_handle->tx_dma_buf, 0, size);
} else {
if (!sport_handle->rx_dma_buf) {
sport_handle->rx_dma_buf = dma_alloc_coherent(NULL, \
size, &sport_handle->rx_dma_phy, GFP_KERNEL);
if (!sport_handle->rx_dma_buf) {
pr_err("Failed to allocate memory for rx dma buf - Please increase uncached DMA memory region\n");
return -ENOMEM;
} else
memset(sport_handle->rx_dma_buf, 0, size);
} else
memset(sport_handle->rx_dma_buf, 0, size);
}
#endif
return 0;
}
static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
{
struct snd_pcm_substream *substream;
struct snd_dma_buffer *buf;
int stream;
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
struct snd_soc_pcm_runtime *rtd = pcm->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
size_t size = bf5xx_pcm_hardware.buffer_bytes_max *
sizeof(struct ac97_frame) / 4;
#endif
for (stream = 0; stream < 2; stream++) {
substream = pcm->streams[stream].substream;
if (!substream)
continue;
buf = &substream->dma_buffer;
if (!buf->area)
continue;
dma_free_coherent(NULL, buf->bytes, buf->area, 0);
buf->area = NULL;
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (sport_handle->tx_dma_buf)
dma_free_coherent(NULL, size, \
sport_handle->tx_dma_buf, 0);
sport_handle->tx_dma_buf = NULL;
} else {
if (sport_handle->rx_dma_buf)
dma_free_coherent(NULL, size, \
sport_handle->rx_dma_buf, 0);
sport_handle->rx_dma_buf = NULL;
}
#endif
}
}
static int bf5xx_pcm_ac97_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd->pcm;
int ret;
pr_debug("%s enter\n", __func__);
ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
if (ret)
return ret;
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
goto out;
}
out:
return ret;
}
static struct snd_soc_component_driver bf5xx_ac97_soc_component = {
.ops = &bf5xx_pcm_ac97_ops,
.pcm_new = bf5xx_pcm_ac97_new,
.pcm_free = bf5xx_pcm_free_dma_buffers,
};
static int bf5xx_soc_platform_probe(struct platform_device *pdev)
{
return devm_snd_soc_register_component(&pdev->dev,
&bf5xx_ac97_soc_component, NULL, 0);
}
static struct platform_driver bf5xx_pcm_driver = {
.driver = {
.name = "bfin-ac97-pcm-audio",
},
.probe = bf5xx_soc_platform_probe,
};
module_platform_driver(bf5xx_pcm_driver);
MODULE_AUTHOR("Cliff Cai");
MODULE_DESCRIPTION("ADI Blackfin AC97 PCM DMA module");
MODULE_LICENSE("GPL");
/*
* bf5xx-ac97.c -- AC97 support for the ADI blackfin chip.
*
* Author: Roy Huang
* Created: 11th. June 2007
* Copyright: Analog Device Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include <asm/irq.h>
#include <asm/portmux.h>
#include <linux/mutex.h>
#include <linux/gpio.h>
#include "bf5xx-sport.h"
#include "bf5xx-ac97.h"
/* Anomaly notes:
* 05000250 - AD1980 is running in TDM mode and RFS/TFS are generated by SPORT
* contrtoller. But, RFSDIV and TFSDIV are always set to 16*16-1,
* while the max AC97 data size is 13*16. The DIV is always larger
* than data size. AD73311 and ad2602 are not running in TDM mode.
* AD1836 and AD73322 depend on external RFS/TFS only. So, this
* anomaly does not affect blackfin sound drivers.
*/
static struct sport_device *ac97_sport_handle;
void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src,
size_t count, unsigned int chan_mask)
{
while (count--) {
dst->ac97_tag = TAG_VALID;
if (chan_mask & SP_FL) {
dst->ac97_pcm_r = *src++;
dst->ac97_tag |= TAG_PCM_RIGHT;
}
if (chan_mask & SP_FR) {
dst->ac97_pcm_l = *src++;
dst->ac97_tag |= TAG_PCM_LEFT;
}
#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
if (chan_mask & SP_SR) {
dst->ac97_sl = *src++;
dst->ac97_tag |= TAG_PCM_SL;
}
if (chan_mask & SP_SL) {
dst->ac97_sr = *src++;
dst->ac97_tag |= TAG_PCM_SR;
}
if (chan_mask & SP_LFE) {
dst->ac97_lfe = *src++;
dst->ac97_tag |= TAG_PCM_LFE;
}
if (chan_mask & SP_FC) {
dst->ac97_center = *src++;
dst->ac97_tag |= TAG_PCM_CENTER;
}
#endif
dst++;
}
}
EXPORT_SYMBOL(bf5xx_pcm_to_ac97);
void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst,
size_t count)
{
while (count--) {
*(dst++) = src->ac97_pcm_l;
*(dst++) = src->ac97_pcm_r;
src++;
}
}
EXPORT_SYMBOL(bf5xx_ac97_to_pcm);
static unsigned int sport_tx_curr_frag(struct sport_device *sport)
{
return sport->tx_curr_frag = sport_curr_offset_tx(sport) /
sport->tx_fragsize;
}
static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
{
struct sport_device *sport = ac97_sport_handle;
int *cmd_count = sport->private_data;
int nextfrag = sport_tx_curr_frag(sport);
struct ac97_frame *nextwrite;
sport_incfrag(sport, &nextfrag, 1);
nextwrite = (struct ac97_frame *)(sport->tx_buf +
nextfrag * sport->tx_fragsize);
pr_debug("sport->tx_buf:%p, nextfrag:0x%x nextwrite:%p, cmd_count:%d\n",
sport->tx_buf, nextfrag, nextwrite, cmd_count[nextfrag]);
nextwrite[cmd_count[nextfrag]].ac97_tag |= TAG_CMD;
nextwrite[cmd_count[nextfrag]].ac97_addr = addr;
nextwrite[cmd_count[nextfrag]].ac97_data = data;
++cmd_count[nextfrag];
pr_debug("ac97_sport: Inserting %02x/%04x into fragment %d\n",
addr >> 8, data, nextfrag);
}
static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97,
unsigned short reg)
{
struct sport_device *sport_handle = ac97_sport_handle;
struct ac97_frame out_frame[2], in_frame[2];
pr_debug("%s enter 0x%x\n", __func__, reg);
/* When dma descriptor is enabled, the register should not be read */
if (sport_handle->tx_run || sport_handle->rx_run) {
pr_err("Could you send a mail to cliff.cai@analog.com "
"to report this?\n");
return -EFAULT;
}
memset(&out_frame, 0, 2 * sizeof(struct ac97_frame));
memset(&in_frame, 0, 2 * sizeof(struct ac97_frame));
out_frame[0].ac97_tag = TAG_VALID | TAG_CMD;
out_frame[0].ac97_addr = ((reg << 8) | 0x8000);
sport_send_and_recv(sport_handle, (unsigned char *)&out_frame,
(unsigned char *)&in_frame,
2 * sizeof(struct ac97_frame));
return in_frame[1].ac97_data;
}
void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
unsigned short val)
{
struct sport_device *sport_handle = ac97_sport_handle;
pr_debug("%s enter 0x%x:0x%04x\n", __func__, reg, val);
if (sport_handle->tx_run) {
enqueue_cmd(ac97, (reg << 8), val); /* write */
enqueue_cmd(ac97, (reg << 8) | 0x8000, 0); /* read back */
} else {
struct ac97_frame frame;
memset(&frame, 0, sizeof(struct ac97_frame));
frame.ac97_tag = TAG_VALID | TAG_CMD;
frame.ac97_addr = (reg << 8);
frame.ac97_data = val;
sport_send_and_recv(sport_handle, (unsigned char *)&frame, \
NULL, sizeof(struct ac97_frame));
}
}
static void bf5xx_ac97_warm_reset(struct snd_ac97 *ac97)
{
struct sport_device *sport_handle = ac97_sport_handle;
u16 gpio = P_IDENT(sport_handle->pin_req[3]);
pr_debug("%s enter\n", __func__);
peripheral_free_list(sport_handle->pin_req);
gpio_request(gpio, "bf5xx-ac97");
gpio_direction_output(gpio, 1);
udelay(2);
gpio_set_value(gpio, 0);
udelay(1);
gpio_free(gpio);
peripheral_request_list(sport_handle->pin_req, "soc-audio");
}
static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97)
{
#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
pr_debug("%s enter\n", __func__);
/* It is specified for bf548-ezkit */
gpio_set_value(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 0);
/* Keep reset pin low for 1 ms */
mdelay(1);
gpio_set_value(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1);
/* Wait for bit clock recover */
mdelay(1);
#else
pr_info("%s: Not implemented\n", __func__);
#endif
}
static struct snd_ac97_bus_ops bf5xx_ac97_ops = {
.read = bf5xx_ac97_read,
.write = bf5xx_ac97_write,
.warm_reset = bf5xx_ac97_warm_reset,
.reset = bf5xx_ac97_cold_reset,
};
#ifdef CONFIG_PM
static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
{
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
pr_debug("%s : sport %d\n", __func__, dai->id);
if (!dai->active)
return 0;
if (dai->capture_active)
sport_rx_stop(sport);
if (dai->playback_active)
sport_tx_stop(sport);
return 0;
}
static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
{
int ret;
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
pr_debug("%s : sport %d\n", __func__, dai->id);
if (!dai->active)
return 0;
#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
ret = sport_set_multichannel(sport, 16, 0x3FF, 0x3FF, 1);
#else
ret = sport_set_multichannel(sport, 16, 0x1F, 0x1F, 1);
#endif
if (ret) {
pr_err("SPORT is busy!\n");
return -EBUSY;
}
ret = sport_config_rx(sport, IRFS, 0xF, 0, (16*16-1));
if (ret) {
pr_err("SPORT is busy!\n");
return -EBUSY;
}
ret = sport_config_tx(sport, ITFS, 0xF, 0, (16*16-1));
if (ret) {
pr_err("SPORT is busy!\n");
return -EBUSY;
}
return 0;
}
#else
#define bf5xx_ac97_suspend NULL
#define bf5xx_ac97_resume NULL
#endif
static struct snd_soc_dai_driver bfin_ac97_dai = {
.bus_control = true,
.suspend = bf5xx_ac97_suspend,
.resume = bf5xx_ac97_resume,
.playback = {
.stream_name = "AC97 Playback",
.channels_min = 2,
#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
.channels_max = 6,
#else
.channels_max = 2,
#endif
.rates = SNDRV_PCM_RATE_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE, },
.capture = {
.stream_name = "AC97 Capture",
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE, },
};
static const struct snd_soc_component_driver bfin_ac97_component = {
.name = "bfin-ac97",
};
static int asoc_bfin_ac97_probe(struct platform_device *pdev)
{
struct sport_device *sport_handle;
int ret;
#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
/* Request PB3 as reset pin */
ret = devm_gpio_request_one(&pdev->dev,
CONFIG_SND_BF5XX_RESET_GPIO_NUM,
GPIOF_OUT_INIT_HIGH, "SND_AD198x RESET");
if (ret) {
dev_err(&pdev->dev,
"Failed to request GPIO_%d for reset: %d\n",
CONFIG_SND_BF5XX_RESET_GPIO_NUM, ret);
return ret;
}
#endif
sport_handle = sport_init(pdev, 2, sizeof(struct ac97_frame),
PAGE_SIZE);
if (!sport_handle) {
ret = -ENODEV;
goto sport_err;
}
/*SPORT works in TDM mode to simulate AC97 transfers*/
#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
ret = sport_set_multichannel(sport_handle, 16, 0x3FF, 0x3FF, 1);
#else
ret = sport_set_multichannel(sport_handle, 16, 0x1F, 0x1F, 1);
#endif
if (ret) {
pr_err("SPORT is busy!\n");
ret = -EBUSY;
goto sport_config_err;
}
ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1));
if (ret) {
pr_err("SPORT is busy!\n");
ret = -EBUSY;
goto sport_config_err;
}
ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1));
if (ret) {
pr_err("SPORT is busy!\n");
ret = -EBUSY;
goto sport_config_err;
}
ret = snd_soc_set_ac97_ops(&bf5xx_ac97_ops);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
goto sport_config_err;
}
ret = snd_soc_register_component(&pdev->dev, &bfin_ac97_component,
&bfin_ac97_dai, 1);
if (ret) {
pr_err("Failed to register DAI: %d\n", ret);
goto sport_config_err;
}
ac97_sport_handle = sport_handle;
return 0;
sport_config_err:
sport_done(sport_handle);
sport_err:
snd_soc_set_ac97_ops(NULL);
return ret;
}
static int asoc_bfin_ac97_remove(struct platform_device *pdev)
{
struct sport_device *sport_handle = platform_get_drvdata(pdev);
snd_soc_unregister_component(&pdev->dev);
sport_done(sport_handle);
snd_soc_set_ac97_ops(NULL);
return 0;
}
static struct platform_driver asoc_bfin_ac97_driver = {
.driver = {
.name = "bfin-ac97",
},
.probe = asoc_bfin_ac97_probe,
.remove = asoc_bfin_ac97_remove,
};
module_platform_driver(asoc_bfin_ac97_driver);
MODULE_AUTHOR("Roy Huang");
MODULE_DESCRIPTION("AC97 driver for ADI Blackfin");
MODULE_LICENSE("GPL");
/*
* sound/soc/blackfin/bf5xx-ac97.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.
*/
#ifndef _BF5XX_AC97_H
#define _BF5XX_AC97_H
/* Frame format in memory, only support stereo currently */
struct ac97_frame {
u16 ac97_tag; /* slot 0 */
u16 ac97_addr; /* slot 1 */
u16 ac97_data; /* slot 2 */
u16 ac97_pcm_l; /*slot 3:front left*/
u16 ac97_pcm_r; /*slot 4:front left*/
#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
u16 ac97_mdm_l1;
u16 ac97_center; /*slot 6:center*/
u16 ac97_sl; /*slot 7:surround left*/
u16 ac97_sr; /*slot 8:surround right*/
u16 ac97_lfe; /*slot 9:lfe*/
#endif
} __attribute__ ((packed));
/* Speaker location */
#define SP_FL 0x0001
#define SP_FR 0x0010
#define SP_FC 0x0002
#define SP_LFE 0x0020
#define SP_SL 0x0004
#define SP_SR 0x0040
#define SP_STEREO (SP_FL | SP_FR)
#define SP_2DOT1 (SP_FL | SP_FR | SP_LFE)
#define SP_QUAD (SP_FL | SP_FR | SP_SL | SP_SR)
#define SP_5DOT1 (SP_FL | SP_FR | SP_FC | SP_LFE | SP_SL | SP_SR)
#define TAG_VALID 0x8000
#define TAG_CMD 0x6000
#define TAG_PCM_LEFT 0x1000
#define TAG_PCM_RIGHT 0x0800
#define TAG_PCM_MDM_L1 0x0400
#define TAG_PCM_CENTER 0x0200
#define TAG_PCM_SL 0x0100
#define TAG_PCM_SR 0x0080
#define TAG_PCM_LFE 0x0040
void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, \
size_t count, unsigned int chan_mask);
void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst, \
size_t count);
#endif
/*
* File: sound/soc/blackfin/bf5xx-ad1836.c
* Author: Barry Song <Barry.Song@analog.com>
*
* Created: Aug 4 2009
* Description: Board driver for ad1836 sound chip
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
#include <asm/blackfin.h>
#include <asm/cacheflush.h>
#include <asm/irq.h>
#include <asm/dma.h>
#include <asm/portmux.h>
#include "../codecs/ad1836.h"
static struct snd_soc_card bf5xx_ad1836;
static int bf5xx_ad1836_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7};
int ret = 0;
/* set cpu DAI channel mapping */
ret = snd_soc_dai_set_channel_map(cpu_dai, ARRAY_SIZE(channel_map),
channel_map, ARRAY_SIZE(channel_map), channel_map);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xFF, 0xFF, 8, 32);
if (ret < 0)
return ret;
return 0;
}
#define BF5XX_AD1836_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \
SND_SOC_DAIFMT_CBM_CFM)
static struct snd_soc_dai_link bf5xx_ad1836_dai = {
.name = "ad1836",
.stream_name = "AD1836",
.codec_dai_name = "ad1836-hifi",
.platform_name = "bfin-i2s-pcm-audio",
.dai_fmt = BF5XX_AD1836_DAIFMT,
.init = bf5xx_ad1836_init,
};
static struct snd_soc_card bf5xx_ad1836 = {
.name = "bfin-ad1836",
.owner = THIS_MODULE,
.dai_link = &bf5xx_ad1836_dai,
.num_links = 1,
};
static int bf5xx_ad1836_driver_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = &bf5xx_ad1836;
const char **link_name;
int ret;
link_name = pdev->dev.platform_data;
if (!link_name) {
dev_err(&pdev->dev, "No platform data supplied\n");
return -EINVAL;
}
bf5xx_ad1836_dai.cpu_dai_name = link_name[0];
bf5xx_ad1836_dai.codec_name = link_name[1];
card->dev = &pdev->dev;
platform_set_drvdata(pdev, card);
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret)
dev_err(&pdev->dev, "Failed to register card\n");
return ret;
}
static struct platform_driver bf5xx_ad1836_driver = {
.driver = {
.name = "bfin-snd-ad1836",
.pm = &snd_soc_pm_ops,
},
.probe = bf5xx_ad1836_driver_probe,
};
module_platform_driver(bf5xx_ad1836_driver);
/* Module information */
MODULE_AUTHOR("Barry Song");
MODULE_DESCRIPTION("ALSA SoC AD1836 board driver");
MODULE_LICENSE("GPL");
/*
* File: sound/soc/blackfin/bf5xx-ad193x.c
* Author: Barry Song <Barry.Song@analog.com>
*
* Created: Thur June 4 2009
* Description: Board driver for ad193x sound chip
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see the file COPYING, or write
* to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
#include <asm/blackfin.h>
#include <asm/cacheflush.h>
#include <asm/irq.h>
#include <asm/dma.h>
#include <asm/portmux.h>
#include "../codecs/ad193x.h"
static struct snd_soc_card bf5xx_ad193x;
static int bf5xx_ad193x_link_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
/* set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 24576000, SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
/* set codec DAI slots, 8 channels, all channels are enabled */
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 0xFF, 8, 32);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xFF, 0xFF, 8, 32);
if (ret < 0)
return ret;
return 0;
}
#define BF5XX_AD193X_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \
SND_SOC_DAIFMT_CBM_CFM)
static struct snd_soc_dai_link bf5xx_ad193x_dai[] = {
{
.name = "ad193x",
.stream_name = "AD193X",
.cpu_dai_name = "bfin-i2s.0",
.codec_dai_name ="ad193x-hifi",
.platform_name = "bfin-i2s-pcm-audio",
.codec_name = "spi0.5",
.dai_fmt = BF5XX_AD193X_DAIFMT,
.init = bf5xx_ad193x_link_init,
},
{
.name = "ad193x",
.stream_name = "AD193X",
.cpu_dai_name = "bfin-i2s.1",
.codec_dai_name ="ad193x-hifi",
.platform_name = "bfin-i2s-pcm-audio",
.codec_name = "spi0.5",
.dai_fmt = BF5XX_AD193X_DAIFMT,
.init = bf5xx_ad193x_link_init,
},
};
static struct snd_soc_card bf5xx_ad193x = {
.name = "bfin-ad193x",
.owner = THIS_MODULE,
.dai_link = &bf5xx_ad193x_dai[CONFIG_SND_BF5XX_SPORT_NUM],
.num_links = 1,
};
static struct platform_device *bfxx_ad193x_snd_device;
static int __init bf5xx_ad193x_init(void)
{
int ret;
bfxx_ad193x_snd_device = platform_device_alloc("soc-audio", -1);
if (!bfxx_ad193x_snd_device)
return -ENOMEM;
platform_set_drvdata(bfxx_ad193x_snd_device, &bf5xx_ad193x);
ret = platform_device_add(bfxx_ad193x_snd_device);
if (ret)
platform_device_put(bfxx_ad193x_snd_device);
return ret;
}
static void __exit bf5xx_ad193x_exit(void)
{
platform_device_unregister(bfxx_ad193x_snd_device);
}
module_init(bf5xx_ad193x_init);
module_exit(bf5xx_ad193x_exit);
/* Module information */
MODULE_AUTHOR("Barry Song");
MODULE_DESCRIPTION("ALSA SoC AD193X board driver");
MODULE_LICENSE("GPL");
/*
* File: sound/soc/blackfin/bf5xx-ad1980.c
* Author: Cliff Cai <Cliff.Cai@analog.com>
*
* Created: Tue June 06 2008
* Description: Board driver for AD1980/1 audio codec
*
* Modified:
* Copyright 2008 Analog Devices Inc.
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see the file COPYING, or write
* to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* WARNING:
*
* Because Analog Devices Inc. discontinued the ad1980 sound chip since
* Sep. 2009, this ad1980 driver is not maintained, tested and supported
* by ADI now.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <asm/dma.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <linux/gpio.h>
#include <asm/portmux.h>
#include "bf5xx-ac97.h"
static struct snd_soc_card bf5xx_board;
static struct snd_soc_dai_link bf5xx_board_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 HiFi",
.cpu_dai_name = "bfin-ac97.0",
.codec_dai_name = "ad1980-hifi",
.platform_name = "bfin-ac97-pcm-audio",
.codec_name = "ad1980",
},
{
.name = "AC97",
.stream_name = "AC97 HiFi",
.cpu_dai_name = "bfin-ac97.1",
.codec_dai_name = "ad1980-hifi",
.platform_name = "bfin-ac97-pcm-audio",
.codec_name = "ad1980",
},
};
static struct snd_soc_card bf5xx_board = {
.name = "bfin-ad1980",
.owner = THIS_MODULE,
.dai_link = &bf5xx_board_dai[CONFIG_SND_BF5XX_SPORT_NUM],
.num_links = 1,
};
static struct platform_device *bf5xx_board_snd_device;
static int __init bf5xx_board_init(void)
{
int ret;
bf5xx_board_snd_device = platform_device_alloc("soc-audio", -1);
if (!bf5xx_board_snd_device)
return -ENOMEM;
platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board);
ret = platform_device_add(bf5xx_board_snd_device);
if (ret)
platform_device_put(bf5xx_board_snd_device);
return ret;
}
static void __exit bf5xx_board_exit(void)
{
platform_device_unregister(bf5xx_board_snd_device);
}
module_init(bf5xx_board_init);
module_exit(bf5xx_board_exit);
/* Module information */
MODULE_AUTHOR("Cliff Cai");
MODULE_DESCRIPTION("ALSA SoC AD1980/1 BF5xx board (Obsolete)");
MODULE_LICENSE("GPL");
/*
* File: sound/soc/blackfin/bf5xx-ad73311.c
* Author: Cliff Cai <Cliff.Cai@analog.com>
*
* Created: Thur Sep 25 2008
* Description: Board driver for ad73311 sound chip
*
* Modified:
* Copyright 2008 Analog Devices Inc.
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see the file COPYING, or write
* to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
#include <asm/blackfin.h>
#include <asm/cacheflush.h>
#include <asm/irq.h>
#include <asm/dma.h>
#include <asm/portmux.h>
#include "../codecs/ad73311.h"
#include "bf5xx-sport.h"
#if CONFIG_SND_BF5XX_SPORT_NUM == 0
#define bfin_write_SPORT_TCR1 bfin_write_SPORT0_TCR1
#define bfin_read_SPORT_TCR1 bfin_read_SPORT0_TCR1
#define bfin_write_SPORT_TCR2 bfin_write_SPORT0_TCR2
#define bfin_write_SPORT_TX16 bfin_write_SPORT0_TX16
#define bfin_read_SPORT_STAT bfin_read_SPORT0_STAT
#else
#define bfin_write_SPORT_TCR1 bfin_write_SPORT1_TCR1
#define bfin_read_SPORT_TCR1 bfin_read_SPORT1_TCR1
#define bfin_write_SPORT_TCR2 bfin_write_SPORT1_TCR2
#define bfin_write_SPORT_TX16 bfin_write_SPORT1_TX16
#define bfin_read_SPORT_STAT bfin_read_SPORT1_STAT
#endif
#define GPIO_SE CONFIG_SND_BFIN_AD73311_SE
static struct snd_soc_card bf5xx_ad73311;
static int snd_ad73311_startup(void)
{
pr_debug("%s enter\n", __func__);
/* Pull up SE pin on AD73311L */
gpio_set_value(GPIO_SE, 1);
return 0;
}
static int snd_ad73311_configure(void)
{
unsigned short ctrl_regs[6];
unsigned short status = 0;
int count = 0;
/* DMCLK = MCLK = 16.384 MHz
* SCLK = DMCLK/8 = 2.048 MHz
* Sample Rate = DMCLK/2048 = 8 KHz
*/
ctrl_regs[0] = AD_CONTROL | AD_WRITE | CTRL_REG_B | REGB_MCDIV(0) | \
REGB_SCDIV(0) | REGB_DIRATE(0);
ctrl_regs[1] = AD_CONTROL | AD_WRITE | CTRL_REG_C | REGC_PUDEV | \
REGC_PUADC | REGC_PUDAC | REGC_PUREF | REGC_REFUSE ;
ctrl_regs[2] = AD_CONTROL | AD_WRITE | CTRL_REG_D | REGD_OGS(2) | \
REGD_IGS(2);
ctrl_regs[3] = AD_CONTROL | AD_WRITE | CTRL_REG_E | REGE_DA(0x1f);
ctrl_regs[4] = AD_CONTROL | AD_WRITE | CTRL_REG_F | REGF_SEEN ;
ctrl_regs[5] = AD_CONTROL | AD_WRITE | CTRL_REG_A | REGA_MODE_DATA;
local_irq_disable();
snd_ad73311_startup();
udelay(1);
bfin_write_SPORT_TCR1(TFSR);
bfin_write_SPORT_TCR2(0xF);
SSYNC();
/* SPORT Tx Register is a 8 x 16 FIFO, all the data can be put to
* FIFO before enable SPORT to transfer the data
*/
for (count = 0; count < 6; count++)
bfin_write_SPORT_TX16(ctrl_regs[count]);
SSYNC();
bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() | TSPEN);
SSYNC();
/* When TUVF is set, the data is already send out */
while (!(status & TUVF) && ++count < 10000) {
udelay(1);
status = bfin_read_SPORT_STAT();
SSYNC();
}
bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() & ~TSPEN);
SSYNC();
local_irq_enable();
if (count >= 10000) {
printk(KERN_ERR "ad73311: failed to configure codec\n");
return -1;
}
return 0;
}
static int bf5xx_probe(struct snd_soc_card *card)
{
int err;
if (gpio_request(GPIO_SE, "AD73311_SE")) {
printk(KERN_ERR "%s: Failed ro request GPIO_%d\n", __func__, GPIO_SE);
return -EBUSY;
}
gpio_direction_output(GPIO_SE, 0);
err = snd_ad73311_configure();
if (err < 0)
return -EFAULT;
return 0;
}
#define BF5XX_AD7311_DAI_FMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | \
SND_SOC_DAIFMT_CBM_CFM)
static struct snd_soc_dai_link bf5xx_ad73311_dai[] = {
{
.name = "ad73311",
.stream_name = "AD73311",
.cpu_dai_name = "bfin-i2s.0",
.codec_dai_name = "ad73311-hifi",
.platform_name = "bfin-i2s-pcm-audio",
.codec_name = "ad73311",
.dai_fmt = BF5XX_AD7311_DAI_FMT,
},
{
.name = "ad73311",
.stream_name = "AD73311",
.cpu_dai_name = "bfin-i2s.1",
.codec_dai_name = "ad73311-hifi",
.platform_name = "bfin-i2s-pcm-audio",
.codec_name = "ad73311",
.dai_fmt = BF5XX_AD7311_DAI_FMT,
},
};
static struct snd_soc_card bf5xx_ad73311 = {
.name = "bfin-ad73311",
.owner = THIS_MODULE,
.probe = bf5xx_probe,
.dai_link = &bf5xx_ad73311_dai[CONFIG_SND_BF5XX_SPORT_NUM],
.num_links = 1,
};
static struct platform_device *bf5xx_ad73311_snd_device;
static int __init bf5xx_ad73311_init(void)
{
int ret;
pr_debug("%s enter\n", __func__);
bf5xx_ad73311_snd_device = platform_device_alloc("soc-audio", -1);
if (!bf5xx_ad73311_snd_device)
return -ENOMEM;
platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311);
ret = platform_device_add(bf5xx_ad73311_snd_device);
if (ret)
platform_device_put(bf5xx_ad73311_snd_device);
return ret;
}
static void __exit bf5xx_ad73311_exit(void)
{
pr_debug("%s enter\n", __func__);
platform_device_unregister(bf5xx_ad73311_snd_device);
}
module_init(bf5xx_ad73311_init);
module_exit(bf5xx_ad73311_exit);
/* Module information */
MODULE_AUTHOR("Cliff Cai");
MODULE_DESCRIPTION("ALSA SoC AD73311 Blackfin");
MODULE_LICENSE("GPL");
/*
* File: sound/soc/blackfin/bf5xx-i2s-pcm.c
* Author: Cliff Cai <Cliff.Cai@analog.com>
*
* Created: Tue June 06 2008
* Description: DMA driver for i2s codec
*
* Modified:
* Copyright 2008 Analog Devices Inc.
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see the file COPYING, or write
* to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/gfp.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <asm/dma.h>
#include "bf5xx-sport.h"
#include "bf5xx-i2s-pcm.h"
static void bf5xx_dma_irq(void *data)
{
struct snd_pcm_substream *pcm = data;
snd_pcm_period_elapsed(pcm);
}
static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_BLOCK_TRANSFER,
.period_bytes_min = 32,
.period_bytes_max = 0x10000,
.periods_min = 1,
.periods_max = PAGE_SIZE/32,
.buffer_bytes_max = 0x20000, /* 128 kbytes */
.fifo_size = 16,
};
static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
unsigned int buffer_size = params_buffer_bytes(params);
struct bf5xx_i2s_pcm_data *dma_data;
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
if (dma_data->tdm_mode)
buffer_size = buffer_size / params_channels(params) * 8;
return snd_pcm_lib_malloc_pages(substream, buffer_size);
}
static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
{
snd_pcm_lib_free_pages(substream);
return 0;
}
static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
struct sport_device *sport = runtime->private_data;
int period_bytes = frames_to_bytes(runtime, runtime->period_size);
struct bf5xx_i2s_pcm_data *dma_data;
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
if (dma_data->tdm_mode)
period_bytes = period_bytes / runtime->channels * 8;
pr_debug("%s enter\n", __func__);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
sport_config_tx_dma(sport, runtime->dma_area,
runtime->periods, period_bytes);
} else {
sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
sport_config_rx_dma(sport, runtime->dma_area,
runtime->periods, period_bytes);
}
return 0;
}
static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct sport_device *sport = runtime->private_data;
int ret = 0;
pr_debug("%s enter\n", __func__);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
sport_tx_start(sport);
else
sport_rx_start(sport);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
sport_tx_stop(sport);
else
sport_rx_stop(sport);
break;
default:
ret = -EINVAL;
}
return ret;
}
static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
struct sport_device *sport = runtime->private_data;
unsigned int diff;
snd_pcm_uframes_t frames;
struct bf5xx_i2s_pcm_data *dma_data;
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
pr_debug("%s enter\n", __func__);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
diff = sport_curr_offset_tx(sport);
} else {
diff = sport_curr_offset_rx(sport);
}
/*
* TX at least can report one frame beyond the end of the
* buffer if we hit the wraparound case - clamp to within the
* buffer as the ALSA APIs require.
*/
if (diff == snd_pcm_lib_buffer_bytes(substream))
diff = 0;
frames = bytes_to_frames(substream->runtime, diff);
if (dma_data->tdm_mode)
frames = frames * runtime->channels / 8;
return frames;
}
static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_dma_buffer *buf = &substream->dma_buffer;
struct bf5xx_i2s_pcm_data *dma_data;
int ret;
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
pr_debug("%s enter\n", __func__);
snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
if (dma_data->tdm_mode)
runtime->hw.buffer_bytes_max /= 4;
else
runtime->hw.info |= SNDRV_PCM_INFO_MMAP;
ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0)
goto out;
if (sport_handle != NULL) {
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
sport_handle->tx_buf = buf->area;
else
sport_handle->rx_buf = buf->area;
runtime->private_data = sport_handle;
} else {
pr_err("sport_handle is NULL\n");
return -1;
}
return 0;
out:
return ret;
}
static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
struct snd_pcm_runtime *runtime = substream->runtime;
size_t size = vma->vm_end - vma->vm_start;
vma->vm_start = (unsigned long)runtime->dma_area;
vma->vm_end = vma->vm_start + size;
vma->vm_flags |= VM_SHARED;
return 0 ;
}
static int bf5xx_pcm_copy(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
void *buf, unsigned long count)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int sample_size = runtime->sample_bits / 8;
struct bf5xx_i2s_pcm_data *dma_data;
unsigned int i;
void *src, *dst;
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
if (dma_data->tdm_mode) {
pos = bytes_to_frames(runtime, pos);
count = bytes_to_frames(runtime, count);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
src = buf;
dst = runtime->dma_area;
dst += pos * sample_size * 8;
while (count--) {
for (i = 0; i < runtime->channels; i++) {
memcpy(dst + dma_data->map[i] *
sample_size, src, sample_size);
src += sample_size;
}
dst += 8 * sample_size;
}
} else {
src = runtime->dma_area;
src += pos * sample_size * 8;
dst = buf;
while (count--) {
for (i = 0; i < runtime->channels; i++) {
memcpy(dst, src + dma_data->map[i] *
sample_size, sample_size);
dst += sample_size;
}
src += 8 * sample_size;
}
}
} else {
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
src = buf;
dst = runtime->dma_area;
dst += pos;
} else {
src = runtime->dma_area;
src += pos;
dst = buf;
}
memcpy(dst, src, count);
}
return 0;
}
static int bf5xx_pcm_copy_user(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
void __user *buf, unsigned long count)
{
return bf5xx_pcm_copy(substream, channel, pos, (void *)buf, count);
}
static int bf5xx_pcm_silence(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
unsigned long count)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int sample_size = runtime->sample_bits / 8;
void *buf = runtime->dma_area;
struct bf5xx_i2s_pcm_data *dma_data;
unsigned int offset, samples;
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
if (dma_data->tdm_mode) {
offset = bytes_to_frames(runtime, pos) * 8 * sample_size;
samples = bytes_to_frames(runtime, count) * 8;
} else {
offset = pos;
samples = bytes_to_samples(runtime, count);
}
snd_pcm_format_set_silence(runtime->format, buf + offset, samples);
return 0;
}
static const struct snd_pcm_ops bf5xx_pcm_i2s_ops = {
.open = bf5xx_pcm_open,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = bf5xx_pcm_hw_params,
.hw_free = bf5xx_pcm_hw_free,
.prepare = bf5xx_pcm_prepare,
.trigger = bf5xx_pcm_trigger,
.pointer = bf5xx_pcm_pointer,
.mmap = bf5xx_pcm_mmap,
.copy_user = bf5xx_pcm_copy_user,
.copy_kernel = bf5xx_pcm_copy,
.fill_silence = bf5xx_pcm_silence,
};
static int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
int ret;
pr_debug("%s enter\n", __func__);
ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
if (ret)
return ret;
return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
SNDRV_DMA_TYPE_DEV, card->dev, size, size);
}
static struct snd_soc_component_driver bf5xx_i2s_soc_component = {
.ops = &bf5xx_pcm_i2s_ops,
.pcm_new = bf5xx_pcm_i2s_new,
};
static int bfin_i2s_soc_platform_probe(struct platform_device *pdev)
{
return devm_snd_soc_register_component(&pdev->dev,
&bf5xx_i2s_soc_component, NULL, 0);
}
static struct platform_driver bfin_i2s_pcm_driver = {
.driver = {
.name = "bfin-i2s-pcm-audio",
},
.probe = bfin_i2s_soc_platform_probe,
};
module_platform_driver(bfin_i2s_pcm_driver);
MODULE_AUTHOR("Cliff Cai");
MODULE_DESCRIPTION("ADI Blackfin I2S PCM DMA module");
MODULE_LICENSE("GPL");
/*
* 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 _BF5XX_TDM_PCM_H
#define _BF5XX_TDM_PCM_H
#define BFIN_TDM_DAI_MAX_SLOTS 8
struct bf5xx_i2s_pcm_data {
unsigned int map[BFIN_TDM_DAI_MAX_SLOTS];
bool tdm_mode;
};
#endif
/*
* File: sound/soc/blackfin/bf5xx-i2s.c
* Author: Cliff Cai <Cliff.Cai@analog.com>
*
* Created: Tue June 06 2008
* Description: Blackfin I2S CPU DAI driver
*
* Modified:
* Copyright 2008 Analog Devices Inc.
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see the file COPYING, or write
* to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include <asm/irq.h>
#include <asm/portmux.h>
#include <linux/mutex.h>
#include <linux/gpio.h>
#include "bf5xx-sport.h"
#include "bf5xx-i2s-pcm.h"
struct bf5xx_i2s_port {
u16 tcr1;
u16 rcr1;
u16 tcr2;
u16 rcr2;
int configured;
unsigned int slots;
unsigned int tx_mask;
unsigned int rx_mask;
struct bf5xx_i2s_pcm_data tx_dma_data;
struct bf5xx_i2s_pcm_data rx_dma_data;
};
static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
int ret = 0;
/* interface format:support I2S,slave mode */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
bf5xx_i2s->tcr1 |= TFSR | TCKFE;
bf5xx_i2s->rcr1 |= RFSR | RCKFE;
bf5xx_i2s->tcr2 |= TSFSE;
bf5xx_i2s->rcr2 |= RSFSE;
break;
case SND_SOC_DAIFMT_DSP_A:
bf5xx_i2s->tcr1 |= TFSR;
bf5xx_i2s->rcr1 |= RFSR;
break;
case SND_SOC_DAIFMT_LEFT_J:
ret = -EINVAL;
break;
default:
dev_err(cpu_dai->dev, "%s: Unknown DAI format type\n",
__func__);
ret = -EINVAL;
break;
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
break;
case SND_SOC_DAIFMT_CBS_CFS:
case SND_SOC_DAIFMT_CBM_CFS:
case SND_SOC_DAIFMT_CBS_CFM:
ret = -EINVAL;
break;
default:
dev_err(cpu_dai->dev, "%s: Unknown DAI master type\n",
__func__);
ret = -EINVAL;
break;
}
return ret;
}
static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
int ret = 0;
bf5xx_i2s->tcr2 &= ~0x1f;
bf5xx_i2s->rcr2 &= ~0x1f;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
bf5xx_i2s->tcr2 |= 7;
bf5xx_i2s->rcr2 |= 7;
sport_handle->wdsize = 1;
break;
case SNDRV_PCM_FORMAT_S16_LE:
bf5xx_i2s->tcr2 |= 15;
bf5xx_i2s->rcr2 |= 15;
sport_handle->wdsize = 2;
break;
case SNDRV_PCM_FORMAT_S24_LE:
bf5xx_i2s->tcr2 |= 23;
bf5xx_i2s->rcr2 |= 23;
sport_handle->wdsize = 3;
break;
case SNDRV_PCM_FORMAT_S32_LE:
bf5xx_i2s->tcr2 |= 31;
bf5xx_i2s->rcr2 |= 31;
sport_handle->wdsize = 4;
break;
}
if (!bf5xx_i2s->configured) {
/*
* TX and RX are not independent,they are enabled at the
* same time, even if only one side is running. So, we
* need to configure both of them at the time when the first
* stream is opened.
*
* CPU DAI:slave mode.
*/
bf5xx_i2s->configured = 1;
ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
bf5xx_i2s->rcr2, 0, 0);
if (ret) {
dev_err(dai->dev, "SPORT is busy!\n");
return -EBUSY;
}
ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
bf5xx_i2s->tcr2, 0, 0);
if (ret) {
dev_err(dai->dev, "SPORT is busy!\n");
return -EBUSY;
}
}
return 0;
}
static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
dev_dbg(dai->dev, "%s enter\n", __func__);
/* No active stream, SPORT is allowed to be configured again. */
if (!dai->active)
bf5xx_i2s->configured = 0;
}
static int bf5xx_i2s_set_channel_map(struct snd_soc_dai *dai,
unsigned int tx_num, unsigned int *tx_slot,
unsigned int rx_num, unsigned int *rx_slot)
{
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
unsigned int tx_mapped = 0, rx_mapped = 0;
unsigned int slot;
int i;
if ((tx_num > BFIN_TDM_DAI_MAX_SLOTS) ||
(rx_num > BFIN_TDM_DAI_MAX_SLOTS))
return -EINVAL;
for (i = 0; i < tx_num; i++) {
slot = tx_slot[i];
if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
(!(tx_mapped & (1 << slot)))) {
bf5xx_i2s->tx_dma_data.map[i] = slot;
tx_mapped |= 1 << slot;
} else
return -EINVAL;
}
for (i = 0; i < rx_num; i++) {
slot = rx_slot[i];
if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
(!(rx_mapped & (1 << slot)))) {
bf5xx_i2s->rx_dma_data.map[i] = slot;
rx_mapped |= 1 << slot;
} else
return -EINVAL;
}
return 0;
}
static int bf5xx_i2s_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
unsigned int rx_mask, int slots, int width)
{
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
if (slots % 8 != 0 || slots > 8)
return -EINVAL;
if (width != 32)
return -EINVAL;
bf5xx_i2s->slots = slots;
bf5xx_i2s->tx_mask = tx_mask;
bf5xx_i2s->rx_mask = rx_mask;
bf5xx_i2s->tx_dma_data.tdm_mode = slots != 0;
bf5xx_i2s->rx_dma_data.tdm_mode = slots != 0;
return sport_set_multichannel(sport_handle, slots, tx_mask, rx_mask, 0);
}
#ifdef CONFIG_PM
static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
{
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
dev_dbg(dai->dev, "%s : sport %d\n", __func__, dai->id);
if (dai->capture_active)
sport_rx_stop(sport_handle);
if (dai->playback_active)
sport_tx_stop(sport_handle);
return 0;
}
static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
{
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
int ret;
dev_dbg(dai->dev, "%s : sport %d\n", __func__, dai->id);
ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
bf5xx_i2s->rcr2, 0, 0);
if (ret) {
dev_err(dai->dev, "SPORT is busy!\n");
return -EBUSY;
}
ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
bf5xx_i2s->tcr2, 0, 0);
if (ret) {
dev_err(dai->dev, "SPORT is busy!\n");
return -EBUSY;
}
return sport_set_multichannel(sport_handle, bf5xx_i2s->slots,
bf5xx_i2s->tx_mask, bf5xx_i2s->rx_mask, 0);
}
#else
#define bf5xx_i2s_suspend NULL
#define bf5xx_i2s_resume NULL
#endif
static int bf5xx_i2s_dai_probe(struct snd_soc_dai *dai)
{
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
unsigned int i;
for (i = 0; i < BFIN_TDM_DAI_MAX_SLOTS; i++) {
bf5xx_i2s->tx_dma_data.map[i] = i;
bf5xx_i2s->rx_dma_data.map[i] = i;
}
dai->playback_dma_data = &bf5xx_i2s->tx_dma_data;
dai->capture_dma_data = &bf5xx_i2s->rx_dma_data;
return 0;
}
#define BF5XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
SNDRV_PCM_RATE_96000)
#define BF5XX_I2S_FORMATS \
(SNDRV_PCM_FMTBIT_S8 | \
SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
.shutdown = bf5xx_i2s_shutdown,
.hw_params = bf5xx_i2s_hw_params,
.set_fmt = bf5xx_i2s_set_dai_fmt,
.set_tdm_slot = bf5xx_i2s_set_tdm_slot,
.set_channel_map = bf5xx_i2s_set_channel_map,
};
static struct snd_soc_dai_driver bf5xx_i2s_dai = {
.probe = bf5xx_i2s_dai_probe,
.suspend = bf5xx_i2s_suspend,
.resume = bf5xx_i2s_resume,
.playback = {
.channels_min = 2,
.channels_max = 8,
.rates = BF5XX_I2S_RATES,
.formats = BF5XX_I2S_FORMATS,},
.capture = {
.channels_min = 2,
.channels_max = 8,
.rates = BF5XX_I2S_RATES,
.formats = BF5XX_I2S_FORMATS,},
.ops = &bf5xx_i2s_dai_ops,
};
static const struct snd_soc_component_driver bf5xx_i2s_component = {
.name = "bf5xx-i2s",
};
static int bf5xx_i2s_probe(struct platform_device *pdev)
{
struct sport_device *sport_handle;
int ret;
/* configure SPORT for I2S */
sport_handle = sport_init(pdev, 4, 8 * sizeof(u32),
sizeof(struct bf5xx_i2s_port));
if (!sport_handle)
return -ENODEV;
/* register with the ASoC layers */
ret = snd_soc_register_component(&pdev->dev, &bf5xx_i2s_component,
&bf5xx_i2s_dai, 1);
if (ret) {
dev_err(&pdev->dev, "Failed to register DAI: %d\n", ret);
sport_done(sport_handle);
return ret;
}
return 0;
}
static int bf5xx_i2s_remove(struct platform_device *pdev)
{
struct sport_device *sport_handle = platform_get_drvdata(pdev);
dev_dbg(&pdev->dev, "%s enter\n", __func__);
snd_soc_unregister_component(&pdev->dev);
sport_done(sport_handle);
return 0;
}
static struct platform_driver bfin_i2s_driver = {
.probe = bf5xx_i2s_probe,
.remove = bf5xx_i2s_remove,
.driver = {
.name = "bfin-i2s",
},
};
module_platform_driver(bfin_i2s_driver);
/* Module information */
MODULE_AUTHOR("Cliff Cai");
MODULE_DESCRIPTION("I2S driver for ADI Blackfin");
MODULE_LICENSE("GPL");
/*
* File: bf5xx_sport.c
* Based on:
* Author: Roy Huang <roy.huang@analog.com>
*
* Created: Tue Sep 21 10:52:42 CEST 2004
* Description:
* Blackfin SPORT Driver
*
* Copyright 2004-2007 Analog Devices Inc.
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see the file COPYING, or write
* to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/gpio.h>
#include <linux/bug.h>
#include <linux/module.h>
#include <asm/portmux.h>
#include <asm/dma.h>
#include <asm/blackfin.h>
#include <asm/cacheflush.h>
#include "bf5xx-sport.h"
/* delay between frame sync pulse and first data bit in multichannel mode */
#define FRAME_DELAY (1<<12)
/* note: multichannel is in units of 8 channels,
* tdm_count is # channels NOT / 8 ! */
int sport_set_multichannel(struct sport_device *sport,
int tdm_count, u32 tx_mask, u32 rx_mask, int packed)
{
pr_debug("%s tdm_count=%d tx_mask:0x%08x rx_mask:0x%08x packed=%d\n",
__func__, tdm_count, tx_mask, rx_mask, packed);
if ((sport->regs->tcr1 & TSPEN) || (sport->regs->rcr1 & RSPEN))
return -EBUSY;
if (tdm_count & 0x7)
return -EINVAL;
if (tdm_count > 32)
return -EINVAL; /* Only support less than 32 channels now */
if (tdm_count) {
sport->regs->mcmc1 = ((tdm_count>>3)-1) << 12;
sport->regs->mcmc2 = FRAME_DELAY | MCMEN | \
(packed ? (MCDTXPE|MCDRXPE) : 0);
sport->regs->mtcs0 = tx_mask;
sport->regs->mrcs0 = rx_mask;
sport->regs->mtcs1 = 0;
sport->regs->mrcs1 = 0;
sport->regs->mtcs2 = 0;
sport->regs->mrcs2 = 0;
sport->regs->mtcs3 = 0;
sport->regs->mrcs3 = 0;
} else {
sport->regs->mcmc1 = 0;
sport->regs->mcmc2 = 0;
sport->regs->mtcs0 = 0;
sport->regs->mrcs0 = 0;
}
sport->regs->mtcs1 = 0; sport->regs->mtcs2 = 0; sport->regs->mtcs3 = 0;
sport->regs->mrcs1 = 0; sport->regs->mrcs2 = 0; sport->regs->mrcs3 = 0;
SSYNC();
return 0;
}
EXPORT_SYMBOL(sport_set_multichannel);
int sport_config_rx(struct sport_device *sport, unsigned int rcr1,
unsigned int rcr2, unsigned int clkdiv, unsigned int fsdiv)
{
if ((sport->regs->tcr1 & TSPEN) || (sport->regs->rcr1 & RSPEN))
return -EBUSY;
sport->regs->rcr1 = rcr1;
sport->regs->rcr2 = rcr2;
sport->regs->rclkdiv = clkdiv;
sport->regs->rfsdiv = fsdiv;
SSYNC();
return 0;
}
EXPORT_SYMBOL(sport_config_rx);
int sport_config_tx(struct sport_device *sport, unsigned int tcr1,
unsigned int tcr2, unsigned int clkdiv, unsigned int fsdiv)
{
if ((sport->regs->tcr1 & TSPEN) || (sport->regs->rcr1 & RSPEN))
return -EBUSY;
sport->regs->tcr1 = tcr1;
sport->regs->tcr2 = tcr2;
sport->regs->tclkdiv = clkdiv;
sport->regs->tfsdiv = fsdiv;
SSYNC();
return 0;
}
EXPORT_SYMBOL(sport_config_tx);
static void setup_desc(struct dmasg *desc, void *buf, int fragcount,
size_t fragsize, unsigned int cfg,
unsigned int x_count, unsigned int ycount, size_t wdsize)
{
int i;
for (i = 0; i < fragcount; ++i) {
desc[i].next_desc_addr = &(desc[i + 1]);
desc[i].start_addr = (unsigned long)buf + i*fragsize;
desc[i].cfg = cfg;
desc[i].x_count = x_count;
desc[i].x_modify = wdsize;
desc[i].y_count = ycount;
desc[i].y_modify = wdsize;
}
/* make circular */
desc[fragcount-1].next_desc_addr = desc;
pr_debug("setup desc: desc0=%p, next0=%p, desc1=%p,"
"next1=%p\nx_count=%x,y_count=%x,addr=0x%lx,cfs=0x%x\n",
desc, desc[0].next_desc_addr,
desc+1, desc[1].next_desc_addr,
desc[0].x_count, desc[0].y_count,
desc[0].start_addr, desc[0].cfg);
}
static int sport_start(struct sport_device *sport)
{
enable_dma(sport->dma_rx_chan);
enable_dma(sport->dma_tx_chan);
sport->regs->rcr1 |= RSPEN;
sport->regs->tcr1 |= TSPEN;
SSYNC();
return 0;
}
static int sport_stop(struct sport_device *sport)
{
sport->regs->tcr1 &= ~TSPEN;
sport->regs->rcr1 &= ~RSPEN;
SSYNC();
disable_dma(sport->dma_rx_chan);
disable_dma(sport->dma_tx_chan);
return 0;
}
static inline int sport_hook_rx_dummy(struct sport_device *sport)
{
struct dmasg *desc, temp_desc;
unsigned long flags;
if (WARN_ON(!sport->dummy_rx_desc) ||
WARN_ON(sport->curr_rx_desc == sport->dummy_rx_desc))
return -EINVAL;
/* Maybe the dummy buffer descriptor ring is damaged */
sport->dummy_rx_desc->next_desc_addr = sport->dummy_rx_desc + 1;
local_irq_save(flags);
desc = get_dma_next_desc_ptr(sport->dma_rx_chan);
/* Copy the descriptor which will be damaged to backup */
temp_desc = *desc;
desc->x_count = sport->dummy_count / 2;
desc->y_count = 0;
desc->next_desc_addr = sport->dummy_rx_desc;
local_irq_restore(flags);
/* Waiting for dummy buffer descriptor is already hooked*/
while ((get_dma_curr_desc_ptr(sport->dma_rx_chan) -
sizeof(struct dmasg)) != sport->dummy_rx_desc)
continue;
sport->curr_rx_desc = sport->dummy_rx_desc;
/* Restore the damaged descriptor */
*desc = temp_desc;
return 0;
}
static inline int sport_rx_dma_start(struct sport_device *sport, int dummy)
{
if (dummy) {
sport->dummy_rx_desc->next_desc_addr = sport->dummy_rx_desc;
sport->curr_rx_desc = sport->dummy_rx_desc;
} else
sport->curr_rx_desc = sport->dma_rx_desc;
set_dma_next_desc_addr(sport->dma_rx_chan, sport->curr_rx_desc);
set_dma_x_count(sport->dma_rx_chan, 0);
set_dma_x_modify(sport->dma_rx_chan, 0);
set_dma_config(sport->dma_rx_chan, (DMAFLOW_LARGE | NDSIZE_9 | \
WDSIZE_32 | WNR));
set_dma_curr_addr(sport->dma_rx_chan, sport->curr_rx_desc->start_addr);
SSYNC();
return 0;
}
static inline int sport_tx_dma_start(struct sport_device *sport, int dummy)
{
if (dummy) {
sport->dummy_tx_desc->next_desc_addr = sport->dummy_tx_desc;
sport->curr_tx_desc = sport->dummy_tx_desc;
} else
sport->curr_tx_desc = sport->dma_tx_desc;
set_dma_next_desc_addr(sport->dma_tx_chan, sport->curr_tx_desc);
set_dma_x_count(sport->dma_tx_chan, 0);
set_dma_x_modify(sport->dma_tx_chan, 0);
set_dma_config(sport->dma_tx_chan,
(DMAFLOW_LARGE | NDSIZE_9 | WDSIZE_32));
set_dma_curr_addr(sport->dma_tx_chan, sport->curr_tx_desc->start_addr);
SSYNC();
return 0;
}
int sport_rx_start(struct sport_device *sport)
{
unsigned long flags;
pr_debug("%s enter\n", __func__);
if (sport->rx_run)
return -EBUSY;
if (sport->tx_run) {
/* tx is running, rx is not running */
if (WARN_ON(!sport->dma_rx_desc) ||
WARN_ON(sport->curr_rx_desc != sport->dummy_rx_desc))
return -EINVAL;
local_irq_save(flags);
while ((get_dma_curr_desc_ptr(sport->dma_rx_chan) -
sizeof(struct dmasg)) != sport->dummy_rx_desc)
continue;
sport->dummy_rx_desc->next_desc_addr = sport->dma_rx_desc;
local_irq_restore(flags);
sport->curr_rx_desc = sport->dma_rx_desc;
} else {
sport_tx_dma_start(sport, 1);
sport_rx_dma_start(sport, 0);
sport_start(sport);
}
sport->rx_run = 1;
return 0;
}
EXPORT_SYMBOL(sport_rx_start);
int sport_rx_stop(struct sport_device *sport)
{
pr_debug("%s enter\n", __func__);
if (!sport->rx_run)
return 0;
if (sport->tx_run) {
/* TX dma is still running, hook the dummy buffer */
sport_hook_rx_dummy(sport);
} else {
/* Both rx and tx dma will be stopped */
sport_stop(sport);
sport->curr_rx_desc = NULL;
sport->curr_tx_desc = NULL;
}
sport->rx_run = 0;
return 0;
}
EXPORT_SYMBOL(sport_rx_stop);
static inline int sport_hook_tx_dummy(struct sport_device *sport)
{
struct dmasg *desc, temp_desc;
unsigned long flags;
if (WARN_ON(!sport->dummy_tx_desc) ||
WARN_ON(sport->curr_tx_desc == sport->dummy_tx_desc))
return -EINVAL;
sport->dummy_tx_desc->next_desc_addr = sport->dummy_tx_desc + 1;
/* Shorten the time on last normal descriptor */
local_irq_save(flags);
desc = get_dma_next_desc_ptr(sport->dma_tx_chan);
/* Store the descriptor which will be damaged */
temp_desc = *desc;
desc->x_count = sport->dummy_count / 2;
desc->y_count = 0;
desc->next_desc_addr = sport->dummy_tx_desc;
local_irq_restore(flags);
/* Waiting for dummy buffer descriptor is already hooked*/
while ((get_dma_curr_desc_ptr(sport->dma_tx_chan) - \
sizeof(struct dmasg)) != sport->dummy_tx_desc)
continue;
sport->curr_tx_desc = sport->dummy_tx_desc;
/* Restore the damaged descriptor */
*desc = temp_desc;
return 0;
}
int sport_tx_start(struct sport_device *sport)
{
unsigned long flags;
pr_debug("%s: tx_run:%d, rx_run:%d\n", __func__,
sport->tx_run, sport->rx_run);
if (sport->tx_run)
return -EBUSY;
if (sport->rx_run) {
if (WARN_ON(!sport->dma_tx_desc) ||
WARN_ON(sport->curr_tx_desc != sport->dummy_tx_desc))
return -EINVAL;
/* Hook the normal buffer descriptor */
local_irq_save(flags);
while ((get_dma_curr_desc_ptr(sport->dma_tx_chan) -
sizeof(struct dmasg)) != sport->dummy_tx_desc)
continue;
sport->dummy_tx_desc->next_desc_addr = sport->dma_tx_desc;
local_irq_restore(flags);
sport->curr_tx_desc = sport->dma_tx_desc;
} else {
sport_tx_dma_start(sport, 0);
/* Let rx dma run the dummy buffer */
sport_rx_dma_start(sport, 1);
sport_start(sport);
}
sport->tx_run = 1;
return 0;
}
EXPORT_SYMBOL(sport_tx_start);
int sport_tx_stop(struct sport_device *sport)
{
if (!sport->tx_run)
return 0;
if (sport->rx_run) {
/* RX is still running, hook the dummy buffer */
sport_hook_tx_dummy(sport);
} else {
/* Both rx and tx dma stopped */
sport_stop(sport);
sport->curr_rx_desc = NULL;
sport->curr_tx_desc = NULL;
}
sport->tx_run = 0;
return 0;
}
EXPORT_SYMBOL(sport_tx_stop);
static inline int compute_wdsize(size_t wdsize)
{
switch (wdsize) {
case 1:
return WDSIZE_8;
case 2:
return WDSIZE_16;
case 4:
default:
return WDSIZE_32;
}
}
int sport_config_rx_dma(struct sport_device *sport, void *buf,
int fragcount, size_t fragsize)
{
unsigned int x_count;
unsigned int y_count;
unsigned int cfg;
dma_addr_t addr;
pr_debug("%s buf:%p, frag:%d, fragsize:0x%lx\n", __func__, \
buf, fragcount, fragsize);
x_count = fragsize / sport->wdsize;
y_count = 0;
/* for fragments larger than 64k words we use 2d dma,
* denote fragecount as two numbers' mutliply and both of them
* are less than 64k.*/
if (x_count >= 0x10000) {
int i, count = x_count;
for (i = 16; i > 0; i--) {
x_count = 1 << i;
if ((count & (x_count - 1)) == 0) {
y_count = count >> i;
if (y_count < 0x10000)
break;
}
}
if (i == 0)
return -EINVAL;
}
pr_debug("%s(x_count:0x%x, y_count:0x%x)\n", __func__,
x_count, y_count);
if (sport->dma_rx_desc)
dma_free_coherent(NULL, sport->rx_desc_bytes,
sport->dma_rx_desc, 0);
/* Allocate a new descritor ring as current one. */
sport->dma_rx_desc = dma_alloc_coherent(NULL, \
fragcount * sizeof(struct dmasg), &addr, 0);
sport->rx_desc_bytes = fragcount * sizeof(struct dmasg);
if (!sport->dma_rx_desc) {
pr_err("Failed to allocate memory for rx desc\n");
return -ENOMEM;
}
sport->rx_buf = buf;
sport->rx_fragsize = fragsize;
sport->rx_frags = fragcount;
cfg = 0x7000 | DI_EN | compute_wdsize(sport->wdsize) | WNR | \
(DESC_ELEMENT_COUNT << 8); /* large descriptor mode */
if (y_count != 0)
cfg |= DMA2D;
setup_desc(sport->dma_rx_desc, buf, fragcount, fragsize,
cfg|DMAEN, x_count, y_count, sport->wdsize);
return 0;
}
EXPORT_SYMBOL(sport_config_rx_dma);
int sport_config_tx_dma(struct sport_device *sport, void *buf, \
int fragcount, size_t fragsize)
{
unsigned int x_count;
unsigned int y_count;
unsigned int cfg;
dma_addr_t addr;
pr_debug("%s buf:%p, fragcount:%d, fragsize:0x%lx\n",
__func__, buf, fragcount, fragsize);
x_count = fragsize/sport->wdsize;
y_count = 0;
/* for fragments larger than 64k words we use 2d dma,
* denote fragecount as two numbers' mutliply and both of them
* are less than 64k.*/
if (x_count >= 0x10000) {
int i, count = x_count;
for (i = 16; i > 0; i--) {
x_count = 1 << i;
if ((count & (x_count - 1)) == 0) {
y_count = count >> i;
if (y_count < 0x10000)
break;
}
}
if (i == 0)
return -EINVAL;
}
pr_debug("%s x_count:0x%x, y_count:0x%x\n", __func__,
x_count, y_count);
if (sport->dma_tx_desc) {
dma_free_coherent(NULL, sport->tx_desc_bytes, \
sport->dma_tx_desc, 0);
}
sport->dma_tx_desc = dma_alloc_coherent(NULL, \
fragcount * sizeof(struct dmasg), &addr, 0);
sport->tx_desc_bytes = fragcount * sizeof(struct dmasg);
if (!sport->dma_tx_desc) {
pr_err("Failed to allocate memory for tx desc\n");
return -ENOMEM;
}
sport->tx_buf = buf;
sport->tx_fragsize = fragsize;
sport->tx_frags = fragcount;
cfg = 0x7000 | DI_EN | compute_wdsize(sport->wdsize) | \
(DESC_ELEMENT_COUNT << 8); /* large descriptor mode */
if (y_count != 0)
cfg |= DMA2D;
setup_desc(sport->dma_tx_desc, buf, fragcount, fragsize,
cfg|DMAEN, x_count, y_count, sport->wdsize);
return 0;
}
EXPORT_SYMBOL(sport_config_tx_dma);
/* setup dummy dma descriptor ring, which don't generate interrupts,
* the x_modify is set to 0 */
static int sport_config_rx_dummy(struct sport_device *sport)
{
struct dmasg *desc;
unsigned config;
pr_debug("%s entered\n", __func__);
if (L1_DATA_A_LENGTH)
desc = l1_data_sram_zalloc(2 * sizeof(*desc));
else {
dma_addr_t addr;
desc = dma_alloc_coherent(NULL, 2 * sizeof(*desc), &addr, 0);
memset(desc, 0, 2 * sizeof(*desc));
}
if (desc == NULL) {
pr_err("Failed to allocate memory for dummy rx desc\n");
return -ENOMEM;
}
sport->dummy_rx_desc = desc;
desc->start_addr = (unsigned long)sport->dummy_buf;
config = DMAFLOW_LARGE | NDSIZE_9 | compute_wdsize(sport->wdsize)
| WNR | DMAEN;
desc->cfg = config;
desc->x_count = sport->dummy_count/sport->wdsize;
desc->x_modify = sport->wdsize;
desc->y_count = 0;
desc->y_modify = 0;
memcpy(desc+1, desc, sizeof(*desc));
desc->next_desc_addr = desc + 1;
desc[1].next_desc_addr = desc;
return 0;
}
static int sport_config_tx_dummy(struct sport_device *sport)
{
struct dmasg *desc;
unsigned int config;
pr_debug("%s entered\n", __func__);
if (L1_DATA_A_LENGTH)
desc = l1_data_sram_zalloc(2 * sizeof(*desc));
else {
dma_addr_t addr;
desc = dma_alloc_coherent(NULL, 2 * sizeof(*desc), &addr, 0);
memset(desc, 0, 2 * sizeof(*desc));
}
if (!desc) {
pr_err("Failed to allocate memory for dummy tx desc\n");
return -ENOMEM;
}
sport->dummy_tx_desc = desc;
desc->start_addr = (unsigned long)sport->dummy_buf + \
sport->dummy_count;
config = DMAFLOW_LARGE | NDSIZE_9 |
compute_wdsize(sport->wdsize) | DMAEN;
desc->cfg = config;
desc->x_count = sport->dummy_count/sport->wdsize;
desc->x_modify = sport->wdsize;
desc->y_count = 0;
desc->y_modify = 0;
memcpy(desc+1, desc, sizeof(*desc));
desc->next_desc_addr = desc + 1;
desc[1].next_desc_addr = desc;
return 0;
}
unsigned long sport_curr_offset_rx(struct sport_device *sport)
{
unsigned long curr = get_dma_curr_addr(sport->dma_rx_chan);
return (unsigned char *)curr - sport->rx_buf;
}
EXPORT_SYMBOL(sport_curr_offset_rx);
unsigned long sport_curr_offset_tx(struct sport_device *sport)
{
unsigned long curr = get_dma_curr_addr(sport->dma_tx_chan);
return (unsigned char *)curr - sport->tx_buf;
}
EXPORT_SYMBOL(sport_curr_offset_tx);
void sport_incfrag(struct sport_device *sport, int *frag, int tx)
{
++(*frag);
if (tx == 1 && *frag == sport->tx_frags)
*frag = 0;
if (tx == 0 && *frag == sport->rx_frags)
*frag = 0;
}
EXPORT_SYMBOL(sport_incfrag);
void sport_decfrag(struct sport_device *sport, int *frag, int tx)
{
--(*frag);
if (tx == 1 && *frag == 0)
*frag = sport->tx_frags;
if (tx == 0 && *frag == 0)
*frag = sport->rx_frags;
}
EXPORT_SYMBOL(sport_decfrag);
static int sport_check_status(struct sport_device *sport,
unsigned int *sport_stat,
unsigned int *rx_stat,
unsigned int *tx_stat)
{
int status = 0;
if (sport_stat) {
SSYNC();
status = sport->regs->stat;
if (status & (TOVF|TUVF|ROVF|RUVF))
sport->regs->stat = (status & (TOVF|TUVF|ROVF|RUVF));
SSYNC();
*sport_stat = status;
}
if (rx_stat) {
SSYNC();
status = get_dma_curr_irqstat(sport->dma_rx_chan);
if (status & (DMA_DONE|DMA_ERR))
clear_dma_irqstat(sport->dma_rx_chan);
SSYNC();
*rx_stat = status;
}
if (tx_stat) {
SSYNC();
status = get_dma_curr_irqstat(sport->dma_tx_chan);
if (status & (DMA_DONE|DMA_ERR))
clear_dma_irqstat(sport->dma_tx_chan);
SSYNC();
*tx_stat = status;
}
return 0;
}
int sport_dump_stat(struct sport_device *sport, char *buf, size_t len)
{
int ret;
ret = snprintf(buf, len,
"sts: 0x%04x\n"
"rx dma %d sts: 0x%04x tx dma %d sts: 0x%04x\n",
sport->regs->stat,
sport->dma_rx_chan,
get_dma_curr_irqstat(sport->dma_rx_chan),
sport->dma_tx_chan,
get_dma_curr_irqstat(sport->dma_tx_chan));
buf += ret;
len -= ret;
ret += snprintf(buf, len,
"curr_rx_desc:0x%p, curr_tx_desc:0x%p\n"
"dma_rx_desc:0x%p, dma_tx_desc:0x%p\n"
"dummy_rx_desc:0x%p, dummy_tx_desc:0x%p\n",
sport->curr_rx_desc, sport->curr_tx_desc,
sport->dma_rx_desc, sport->dma_tx_desc,
sport->dummy_rx_desc, sport->dummy_tx_desc);
return ret;
}
static irqreturn_t rx_handler(int irq, void *dev_id)
{
unsigned int rx_stat;
struct sport_device *sport = dev_id;
pr_debug("%s enter\n", __func__);
sport_check_status(sport, NULL, &rx_stat, NULL);
if (!(rx_stat & DMA_DONE))
pr_err("rx dma is already stopped\n");
if (sport->rx_callback) {
sport->rx_callback(sport->rx_data);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
static irqreturn_t tx_handler(int irq, void *dev_id)
{
unsigned int tx_stat;
struct sport_device *sport = dev_id;
pr_debug("%s enter\n", __func__);
sport_check_status(sport, NULL, NULL, &tx_stat);
if (!(tx_stat & DMA_DONE)) {
pr_err("tx dma is already stopped\n");
return IRQ_HANDLED;
}
if (sport->tx_callback) {
sport->tx_callback(sport->tx_data);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
static irqreturn_t err_handler(int irq, void *dev_id)
{
unsigned int status = 0;
struct sport_device *sport = dev_id;
pr_debug("%s\n", __func__);
if (sport_check_status(sport, &status, NULL, NULL)) {
pr_err("error checking status ??");
return IRQ_NONE;
}
if (status & (TOVF|TUVF|ROVF|RUVF)) {
pr_info("sport status error:%s%s%s%s\n",
status & TOVF ? " TOVF" : "",
status & TUVF ? " TUVF" : "",
status & ROVF ? " ROVF" : "",
status & RUVF ? " RUVF" : "");
if (status & TOVF || status & TUVF) {
disable_dma(sport->dma_tx_chan);
if (sport->tx_run)
sport_tx_dma_start(sport, 0);
else
sport_tx_dma_start(sport, 1);
enable_dma(sport->dma_tx_chan);
} else {
disable_dma(sport->dma_rx_chan);
if (sport->rx_run)
sport_rx_dma_start(sport, 0);
else
sport_rx_dma_start(sport, 1);
enable_dma(sport->dma_rx_chan);
}
}
status = sport->regs->stat;
if (status & (TOVF|TUVF|ROVF|RUVF))
sport->regs->stat = (status & (TOVF|TUVF|ROVF|RUVF));
SSYNC();
if (sport->err_callback)
sport->err_callback(sport->err_data);
return IRQ_HANDLED;
}
int sport_set_rx_callback(struct sport_device *sport,
void (*rx_callback)(void *), void *rx_data)
{
if (WARN_ON(!rx_callback))
return -EINVAL;
sport->rx_callback = rx_callback;
sport->rx_data = rx_data;
return 0;
}
EXPORT_SYMBOL(sport_set_rx_callback);
int sport_set_tx_callback(struct sport_device *sport,
void (*tx_callback)(void *), void *tx_data)
{
if (WARN_ON(!tx_callback))
return -EINVAL;
sport->tx_callback = tx_callback;
sport->tx_data = tx_data;
return 0;
}
EXPORT_SYMBOL(sport_set_tx_callback);
int sport_set_err_callback(struct sport_device *sport,
void (*err_callback)(void *), void *err_data)
{
if (WARN_ON(!err_callback))
return -EINVAL;
sport->err_callback = err_callback;
sport->err_data = err_data;
return 0;
}
EXPORT_SYMBOL(sport_set_err_callback);
static int sport_config_pdev(struct platform_device *pdev, struct sport_param *param)
{
/* Extract settings from platform data */
struct device *dev = &pdev->dev;
struct bfin_snd_platform_data *pdata = dev->platform_data;
struct resource *res;
param->num = pdev->id;
if (!pdata) {
dev_err(dev, "no platform_data\n");
return -ENODEV;
}
param->pin_req = pdata->pin_req;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "no MEM resource\n");
return -ENODEV;
}
param->regs = (struct sport_register *)res->start;
/* first RX, then TX */
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!res) {
dev_err(dev, "no rx DMA resource\n");
return -ENODEV;
}
param->dma_rx_chan = res->start;
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!res) {
dev_err(dev, "no tx DMA resource\n");
return -ENODEV;
}
param->dma_tx_chan = res->start;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(dev, "no irq resource\n");
return -ENODEV;
}
param->err_irq = res->start;
return 0;
}
struct sport_device *sport_init(struct platform_device *pdev,
unsigned int wdsize, unsigned int dummy_count, size_t priv_size)
{
struct device *dev = &pdev->dev;
struct sport_param param;
struct sport_device *sport;
int ret;
dev_dbg(dev, "%s enter\n", __func__);
param.wdsize = wdsize;
param.dummy_count = dummy_count;
if (WARN_ON(param.wdsize == 0 || param.dummy_count == 0))
return NULL;
ret = sport_config_pdev(pdev, &param);
if (ret)
return NULL;
if (peripheral_request_list(param.pin_req, "soc-audio")) {
dev_err(dev, "requesting Peripherals failed\n");
return NULL;
}
sport = kzalloc(sizeof(*sport), GFP_KERNEL);
if (!sport) {
dev_err(dev, "failed to allocate for sport device\n");
goto __init_err0;
}
sport->num = param.num;
sport->dma_rx_chan = param.dma_rx_chan;
sport->dma_tx_chan = param.dma_tx_chan;
sport->err_irq = param.err_irq;
sport->regs = param.regs;
sport->pin_req = param.pin_req;
if (request_dma(sport->dma_rx_chan, "SPORT RX Data") == -EBUSY) {
dev_err(dev, "failed to request RX dma %d\n", sport->dma_rx_chan);
goto __init_err1;
}
if (set_dma_callback(sport->dma_rx_chan, rx_handler, sport) != 0) {
dev_err(dev, "failed to request RX irq %d\n", sport->dma_rx_chan);
goto __init_err2;
}
if (request_dma(sport->dma_tx_chan, "SPORT TX Data") == -EBUSY) {
dev_err(dev, "failed to request TX dma %d\n", sport->dma_tx_chan);
goto __init_err2;
}
if (set_dma_callback(sport->dma_tx_chan, tx_handler, sport) != 0) {
dev_err(dev, "failed to request TX irq %d\n", sport->dma_tx_chan);
goto __init_err3;
}
if (request_irq(sport->err_irq, err_handler, IRQF_SHARED, "SPORT err",
sport) < 0) {
dev_err(dev, "failed to request err irq %d\n", sport->err_irq);
goto __init_err3;
}
dev_info(dev, "dma rx:%d tx:%d, err irq:%d, regs:%p\n",
sport->dma_rx_chan, sport->dma_tx_chan,
sport->err_irq, sport->regs);
sport->wdsize = param.wdsize;
sport->dummy_count = param.dummy_count;
sport->private_data = kzalloc(priv_size, GFP_KERNEL);
if (!sport->private_data) {
dev_err(dev, "could not alloc priv data %zu bytes\n", priv_size);
goto __init_err4;
}
if (L1_DATA_A_LENGTH)
sport->dummy_buf = l1_data_sram_zalloc(param.dummy_count * 2);
else
sport->dummy_buf = kzalloc(param.dummy_count * 2, GFP_KERNEL);
if (sport->dummy_buf == NULL) {
dev_err(dev, "failed to allocate dummy buffer\n");
goto __error1;
}
ret = sport_config_rx_dummy(sport);
if (ret) {
dev_err(dev, "failed to config rx dummy ring\n");
goto __error2;
}
ret = sport_config_tx_dummy(sport);
if (ret) {
dev_err(dev, "failed to config tx dummy ring\n");
goto __error3;
}
platform_set_drvdata(pdev, sport);
return sport;
__error3:
if (L1_DATA_A_LENGTH)
l1_data_sram_free(sport->dummy_rx_desc);
else
dma_free_coherent(NULL, 2*sizeof(struct dmasg),
sport->dummy_rx_desc, 0);
__error2:
if (L1_DATA_A_LENGTH)
l1_data_sram_free(sport->dummy_buf);
else
kfree(sport->dummy_buf);
__error1:
kfree(sport->private_data);
__init_err4:
free_irq(sport->err_irq, sport);
__init_err3:
free_dma(sport->dma_tx_chan);
__init_err2:
free_dma(sport->dma_rx_chan);
__init_err1:
kfree(sport);
__init_err0:
peripheral_free_list(param.pin_req);
return NULL;
}
EXPORT_SYMBOL(sport_init);
void sport_done(struct sport_device *sport)
{
if (sport == NULL)
return;
sport_stop(sport);
if (sport->dma_rx_desc)
dma_free_coherent(NULL, sport->rx_desc_bytes,
sport->dma_rx_desc, 0);
if (sport->dma_tx_desc)
dma_free_coherent(NULL, sport->tx_desc_bytes,
sport->dma_tx_desc, 0);
#if L1_DATA_A_LENGTH != 0
l1_data_sram_free(sport->dummy_rx_desc);
l1_data_sram_free(sport->dummy_tx_desc);
l1_data_sram_free(sport->dummy_buf);
#else
dma_free_coherent(NULL, 2*sizeof(struct dmasg),
sport->dummy_rx_desc, 0);
dma_free_coherent(NULL, 2*sizeof(struct dmasg),
sport->dummy_tx_desc, 0);
kfree(sport->dummy_buf);
#endif
free_dma(sport->dma_rx_chan);
free_dma(sport->dma_tx_chan);
free_irq(sport->err_irq, sport);
kfree(sport->private_data);
peripheral_free_list(sport->pin_req);
kfree(sport);
}
EXPORT_SYMBOL(sport_done);
/*
* It is only used to send several bytes when dma is not enabled
* sport controller is configured but not enabled.
* Multichannel cannot works with pio mode */
/* Used by ac97 to write and read codec register */
int sport_send_and_recv(struct sport_device *sport, u8 *out_data, \
u8 *in_data, int len)
{
unsigned short dma_config;
unsigned short status;
unsigned long flags;
unsigned long wait = 0;
pr_debug("%s enter, out_data:%p, in_data:%p len:%d\n", \
__func__, out_data, in_data, len);
pr_debug("tcr1:0x%04x, tcr2:0x%04x, tclkdiv:0x%04x, tfsdiv:0x%04x\n"
"mcmc1:0x%04x, mcmc2:0x%04x\n",
sport->regs->tcr1, sport->regs->tcr2,
sport->regs->tclkdiv, sport->regs->tfsdiv,
sport->regs->mcmc1, sport->regs->mcmc2);
flush_dcache_range((unsigned)out_data, (unsigned)(out_data + len));
/* Enable tx dma */
dma_config = (RESTART | WDSIZE_16 | DI_EN);
set_dma_start_addr(sport->dma_tx_chan, (unsigned long)out_data);
set_dma_x_count(sport->dma_tx_chan, len/2);
set_dma_x_modify(sport->dma_tx_chan, 2);
set_dma_config(sport->dma_tx_chan, dma_config);
enable_dma(sport->dma_tx_chan);
if (in_data != NULL) {
invalidate_dcache_range((unsigned)in_data, \
(unsigned)(in_data + len));
/* Enable rx dma */
dma_config = (RESTART | WDSIZE_16 | WNR | DI_EN);
set_dma_start_addr(sport->dma_rx_chan, (unsigned long)in_data);
set_dma_x_count(sport->dma_rx_chan, len/2);
set_dma_x_modify(sport->dma_rx_chan, 2);
set_dma_config(sport->dma_rx_chan, dma_config);
enable_dma(sport->dma_rx_chan);
}
local_irq_save(flags);
sport->regs->tcr1 |= TSPEN;
sport->regs->rcr1 |= RSPEN;
SSYNC();
status = get_dma_curr_irqstat(sport->dma_tx_chan);
while (status & DMA_RUN) {
udelay(1);
status = get_dma_curr_irqstat(sport->dma_tx_chan);
pr_debug("DMA status:0x%04x\n", status);
if (wait++ > 100)
goto __over;
}
status = sport->regs->stat;
wait = 0;
while (!(status & TXHRE)) {
pr_debug("sport status:0x%04x\n", status);
udelay(1);
status = *(unsigned short *)&sport->regs->stat;
if (wait++ > 1000)
goto __over;
}
/* Wait for the last byte sent out */
udelay(20);
pr_debug("sport status:0x%04x\n", status);
__over:
sport->regs->tcr1 &= ~TSPEN;
sport->regs->rcr1 &= ~RSPEN;
SSYNC();
disable_dma(sport->dma_tx_chan);
/* Clear the status */
clear_dma_irqstat(sport->dma_tx_chan);
if (in_data != NULL) {
disable_dma(sport->dma_rx_chan);
clear_dma_irqstat(sport->dma_rx_chan);
}
SSYNC();
local_irq_restore(flags);
return 0;
}
EXPORT_SYMBOL(sport_send_and_recv);
MODULE_AUTHOR("Roy Huang");
MODULE_DESCRIPTION("SPORT driver for ADI Blackfin");
MODULE_LICENSE("GPL");
/*
* File: bf5xx_sport.h
* Based on:
* Author: Roy Huang <roy.huang@analog.com>
*
* Created:
* Description:
*
* Copyright 2004-2007 Analog Devices Inc.
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see the file COPYING, or write
* to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __BF5XX_SPORT_H__
#define __BF5XX_SPORT_H__
#include <linux/types.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <asm/dma.h>
#include <asm/bfin_sport.h>
#define DESC_ELEMENT_COUNT 9
struct sport_device {
int num;
int dma_rx_chan;
int dma_tx_chan;
int err_irq;
const unsigned short *pin_req;
struct sport_register *regs;
unsigned char *rx_buf;
unsigned char *tx_buf;
unsigned int rx_fragsize;
unsigned int tx_fragsize;
unsigned int rx_frags;
unsigned int tx_frags;
unsigned int wdsize;
/* for dummy dma transfer */
void *dummy_buf;
unsigned int dummy_count;
/* DMA descriptor ring head of current audio stream*/
struct dmasg *dma_rx_desc;
struct dmasg *dma_tx_desc;
unsigned int rx_desc_bytes;
unsigned int tx_desc_bytes;
unsigned int rx_run:1; /* rx is running */
unsigned int tx_run:1; /* tx is running */
struct dmasg *dummy_rx_desc;
struct dmasg *dummy_tx_desc;
struct dmasg *curr_rx_desc;
struct dmasg *curr_tx_desc;
int rx_curr_frag;
int tx_curr_frag;
unsigned int rcr1;
unsigned int rcr2;
int rx_tdm_count;
unsigned int tcr1;
unsigned int tcr2;
int tx_tdm_count;
void (*rx_callback)(void *data);
void *rx_data;
void (*tx_callback)(void *data);
void *tx_data;
void (*err_callback)(void *data);
void *err_data;
unsigned char *tx_dma_buf;
unsigned char *rx_dma_buf;
#ifdef CONFIG_SND_BF5XX_MMAP_SUPPORT
dma_addr_t tx_dma_phy;
dma_addr_t rx_dma_phy;
int tx_pos;/*pcm sample count*/
int rx_pos;
unsigned int tx_buffer_size;
unsigned int rx_buffer_size;
int tx_delay_pos;
int once;
#endif
void *private_data;
};
struct sport_param {
int num;
int dma_rx_chan;
int dma_tx_chan;
int err_irq;
const unsigned short *pin_req;
struct sport_register *regs;
unsigned int wdsize;
unsigned int dummy_count;
void *private_data;
};
struct sport_device *sport_init(struct platform_device *pdev,
unsigned int wdsize, unsigned int dummy_count, size_t priv_size);
void sport_done(struct sport_device *sport);
/* first use these ...*/
/* note: multichannel is in units of 8 channels, tdm_count is number of channels
* NOT / 8 ! all channels are enabled by default */
int sport_set_multichannel(struct sport_device *sport, int tdm_count,
u32 tx_mask, u32 rx_mask, int packed);
int sport_config_rx(struct sport_device *sport,
unsigned int rcr1, unsigned int rcr2,
unsigned int clkdiv, unsigned int fsdiv);
int sport_config_tx(struct sport_device *sport,
unsigned int tcr1, unsigned int tcr2,
unsigned int clkdiv, unsigned int fsdiv);
/* ... then these: */
/* buffer size (in bytes) == fragcount * fragsize_bytes */
/* this is not a very general api, it sets the dma to 2d autobuffer mode */
int sport_config_rx_dma(struct sport_device *sport, void *buf,
int fragcount, size_t fragsize_bytes);
int sport_config_tx_dma(struct sport_device *sport, void *buf,
int fragcount, size_t fragsize_bytes);
int sport_tx_start(struct sport_device *sport);
int sport_tx_stop(struct sport_device *sport);
int sport_rx_start(struct sport_device *sport);
int sport_rx_stop(struct sport_device *sport);
/* for use in interrupt handler */
unsigned long sport_curr_offset_rx(struct sport_device *sport);
unsigned long sport_curr_offset_tx(struct sport_device *sport);
void sport_incfrag(struct sport_device *sport, int *frag, int tx);
void sport_decfrag(struct sport_device *sport, int *frag, int tx);
int sport_set_rx_callback(struct sport_device *sport,
void (*rx_callback)(void *), void *rx_data);
int sport_set_tx_callback(struct sport_device *sport,
void (*tx_callback)(void *), void *tx_data);
int sport_set_err_callback(struct sport_device *sport,
void (*err_callback)(void *), void *err_data);
int sport_send_and_recv(struct sport_device *sport, u8 *out_data, \
u8 *in_data, int len);
#endif /* BF53X_SPORT_H */
/*
* File: sound/soc/blackfin/bf5xx-ssm2602.c
* Author: Cliff Cai <Cliff.Cai@analog.com>
*
* Created: Tue June 06 2008
* Description: board driver for SSM2602 sound chip
*
* Modified:
* Copyright 2008 Analog Devices Inc.
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see the file COPYING, or write
* to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
#include <asm/dma.h>
#include <asm/portmux.h>
#include <linux/gpio.h>
#include "../codecs/ssm2602.h"
#include "bf5xx-sport.h"
static struct snd_soc_card bf5xx_ssm2602;
static int bf5xx_ssm2602_dai_init(struct snd_soc_pcm_runtime *rtd)
{
/*
* If you are using a crystal source which frequency is not 12MHz
* then modify the below case statement with frequency of the crystal.
*
* If you are using the SPORT to generate clocking then this is
* where to do it.
*/
return snd_soc_dai_set_sysclk(rtd->codec_dai, SSM2602_SYSCLK, 12000000,
SND_SOC_CLOCK_IN);
}
/* CODEC is master for BCLK and LRC in this configuration. */
#define BF5XX_SSM2602_DAIFMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \
SND_SOC_DAIFMT_CBM_CFM)
static struct snd_soc_dai_link bf5xx_ssm2602_dai[] = {
{
.name = "ssm2602",
.stream_name = "SSM2602",
.cpu_dai_name = "bfin-i2s.0",
.codec_dai_name = "ssm2602-hifi",
.platform_name = "bfin-i2s-pcm-audio",
.codec_name = "ssm2602.0-001b",
.init = bf5xx_ssm2602_dai_init,
.dai_fmt = BF5XX_SSM2602_DAIFMT,
},
{
.name = "ssm2602",
.stream_name = "SSM2602",
.cpu_dai_name = "bfin-i2s.1",
.codec_dai_name = "ssm2602-hifi",
.platform_name = "bfin-i2s-pcm-audio",
.codec_name = "ssm2602.0-001b",
.init = bf5xx_ssm2602_dai_init,
.dai_fmt = BF5XX_SSM2602_DAIFMT,
},
};
static struct snd_soc_card bf5xx_ssm2602 = {
.name = "bfin-ssm2602",
.owner = THIS_MODULE,
.dai_link = &bf5xx_ssm2602_dai[CONFIG_SND_BF5XX_SPORT_NUM],
.num_links = 1,
};
static struct platform_device *bf5xx_ssm2602_snd_device;
static int __init bf5xx_ssm2602_init(void)
{
int ret;
pr_debug("%s enter\n", __func__);
bf5xx_ssm2602_snd_device = platform_device_alloc("soc-audio", -1);
if (!bf5xx_ssm2602_snd_device)
return -ENOMEM;
platform_set_drvdata(bf5xx_ssm2602_snd_device, &bf5xx_ssm2602);
ret = platform_device_add(bf5xx_ssm2602_snd_device);
if (ret)
platform_device_put(bf5xx_ssm2602_snd_device);
return ret;
}
static void __exit bf5xx_ssm2602_exit(void)
{
pr_debug("%s enter\n", __func__);
platform_device_unregister(bf5xx_ssm2602_snd_device);
}
module_init(bf5xx_ssm2602_init);
module_exit(bf5xx_ssm2602_exit);
/* Module information */
MODULE_AUTHOR("Cliff Cai");
MODULE_DESCRIPTION("ALSA SoC SSM2602 BF527-EZKIT");
MODULE_LICENSE("GPL");
/*
* bf6xx-i2s.c - Analog Devices BF6XX i2s interface driver
*
* Copyright (c) 2012 Analog Devices Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/device.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dai.h>
#include "bf6xx-sport.h"
struct sport_params param;
static int bfin_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
struct sport_device *sport = snd_soc_dai_get_drvdata(cpu_dai);
struct device *dev = &sport->pdev->dev;
int ret = 0;
param.spctl &= ~(SPORT_CTL_OPMODE | SPORT_CTL_CKRE | SPORT_CTL_FSR
| SPORT_CTL_LFS | SPORT_CTL_LAFS);
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
param.spctl |= SPORT_CTL_OPMODE | SPORT_CTL_CKRE
| SPORT_CTL_LFS;
break;
case SND_SOC_DAIFMT_DSP_A:
param.spctl |= SPORT_CTL_FSR;
break;
case SND_SOC_DAIFMT_LEFT_J:
param.spctl |= SPORT_CTL_OPMODE | SPORT_CTL_LFS
| SPORT_CTL_LAFS;
break;
default:
dev_err(dev, "%s: Unknown DAI format type\n", __func__);
ret = -EINVAL;
break;
}
param.spctl &= ~(SPORT_CTL_ICLK | SPORT_CTL_IFS);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
break;
case SND_SOC_DAIFMT_CBS_CFS:
case SND_SOC_DAIFMT_CBM_CFS:
case SND_SOC_DAIFMT_CBS_CFM:
ret = -EINVAL;
break;
default:
dev_err(dev, "%s: Unknown DAI master type\n", __func__);
ret = -EINVAL;
break;
}
return ret;
}
static int bfin_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
struct device *dev = &sport->pdev->dev;
int ret = 0;
param.spctl &= ~SPORT_CTL_SLEN;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
param.spctl |= 0x70;
sport->wdsize = 1;
break;
case SNDRV_PCM_FORMAT_S16_LE:
param.spctl |= 0xf0;
sport->wdsize = 2;
break;
case SNDRV_PCM_FORMAT_S24_LE:
param.spctl |= 0x170;
sport->wdsize = 3;
break;
case SNDRV_PCM_FORMAT_S32_LE:
param.spctl |= 0x1f0;
sport->wdsize = 4;
break;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
ret = sport_set_tx_params(sport, &param);
if (ret) {
dev_err(dev, "SPORT tx is busy!\n");
return ret;
}
} else {
ret = sport_set_rx_params(sport, &param);
if (ret) {
dev_err(dev, "SPORT rx is busy!\n");
return ret;
}
}
return 0;
}
#ifdef CONFIG_PM
static int bfin_i2s_suspend(struct snd_soc_dai *dai)
{
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
if (dai->capture_active)
sport_rx_stop(sport);
if (dai->playback_active)
sport_tx_stop(sport);
return 0;
}
static int bfin_i2s_resume(struct snd_soc_dai *dai)
{
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
struct device *dev = &sport->pdev->dev;
int ret;
ret = sport_set_tx_params(sport, &param);
if (ret) {
dev_err(dev, "SPORT tx is busy!\n");
return ret;
}
ret = sport_set_rx_params(sport, &param);
if (ret) {
dev_err(dev, "SPORT rx is busy!\n");
return ret;
}
return 0;
}
#else
#define bfin_i2s_suspend NULL
#define bfin_i2s_resume NULL
#endif
#define BFIN_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
SNDRV_PCM_RATE_96000)
#define BFIN_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dai_ops bfin_i2s_dai_ops = {
.hw_params = bfin_i2s_hw_params,
.set_fmt = bfin_i2s_set_dai_fmt,
};
static struct snd_soc_dai_driver bfin_i2s_dai = {
.suspend = bfin_i2s_suspend,
.resume = bfin_i2s_resume,
.playback = {
.channels_min = 1,
.channels_max = 2,
.rates = BFIN_I2S_RATES,
.formats = BFIN_I2S_FORMATS,
},
.capture = {
.channels_min = 1,
.channels_max = 2,
.rates = BFIN_I2S_RATES,
.formats = BFIN_I2S_FORMATS,
},
.ops = &bfin_i2s_dai_ops,
};
static const struct snd_soc_component_driver bfin_i2s_component = {
.name = "bfin-i2s",
};
static int bfin_i2s_probe(struct platform_device *pdev)
{
struct sport_device *sport;
struct device *dev = &pdev->dev;
int ret;
sport = sport_create(pdev);
if (!sport)
return -ENODEV;
/* register with the ASoC layers */
ret = snd_soc_register_component(dev, &bfin_i2s_component,
&bfin_i2s_dai, 1);
if (ret) {
dev_err(dev, "Failed to register DAI: %d\n", ret);
sport_delete(sport);
return ret;
}
platform_set_drvdata(pdev, sport);
return 0;
}
static int bfin_i2s_remove(struct platform_device *pdev)
{
struct sport_device *sport = platform_get_drvdata(pdev);
snd_soc_unregister_component(&pdev->dev);
sport_delete(sport);
return 0;
}
static struct platform_driver bfin_i2s_driver = {
.probe = bfin_i2s_probe,
.remove = bfin_i2s_remove,
.driver = {
.name = "bfin-i2s",
},
};
module_platform_driver(bfin_i2s_driver);
MODULE_DESCRIPTION("Analog Devices BF6XX i2s interface driver");
MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
MODULE_LICENSE("GPL v2");
/*
* bf6xx_sport.c Analog Devices BF6XX SPORT driver
*
* Copyright (c) 2012 Analog Devices Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <asm/blackfin.h>
#include <asm/dma.h>
#include <asm/portmux.h>
#include "bf6xx-sport.h"
int sport_set_tx_params(struct sport_device *sport,
struct sport_params *params)
{
if (sport->tx_regs->spctl & SPORT_CTL_SPENPRI)
return -EBUSY;
sport->tx_regs->spctl = params->spctl | SPORT_CTL_SPTRAN;
sport->tx_regs->div = params->div;
SSYNC();
return 0;
}
EXPORT_SYMBOL(sport_set_tx_params);
int sport_set_rx_params(struct sport_device *sport,
struct sport_params *params)
{
if (sport->rx_regs->spctl & SPORT_CTL_SPENPRI)
return -EBUSY;
sport->rx_regs->spctl = params->spctl & ~SPORT_CTL_SPTRAN;
sport->rx_regs->div = params->div;
SSYNC();
return 0;
}
EXPORT_SYMBOL(sport_set_rx_params);
static int compute_wdsize(size_t wdsize)
{
switch (wdsize) {
case 1:
return WDSIZE_8 | PSIZE_8;
case 2:
return WDSIZE_16 | PSIZE_16;
default:
return WDSIZE_32 | PSIZE_32;
}
}
void sport_tx_start(struct sport_device *sport)
{
set_dma_next_desc_addr(sport->tx_dma_chan, sport->tx_desc);
set_dma_config(sport->tx_dma_chan, DMAFLOW_LIST | DI_EN
| compute_wdsize(sport->wdsize) | NDSIZE_6);
enable_dma(sport->tx_dma_chan);
sport->tx_regs->spctl |= SPORT_CTL_SPENPRI;
SSYNC();
}
EXPORT_SYMBOL(sport_tx_start);
void sport_rx_start(struct sport_device *sport)
{
set_dma_next_desc_addr(sport->rx_dma_chan, sport->rx_desc);
set_dma_config(sport->rx_dma_chan, DMAFLOW_LIST | DI_EN | WNR
| compute_wdsize(sport->wdsize) | NDSIZE_6);
enable_dma(sport->rx_dma_chan);
sport->rx_regs->spctl |= SPORT_CTL_SPENPRI;
SSYNC();
}
EXPORT_SYMBOL(sport_rx_start);
void sport_tx_stop(struct sport_device *sport)
{
sport->tx_regs->spctl &= ~SPORT_CTL_SPENPRI;
SSYNC();
disable_dma(sport->tx_dma_chan);
}
EXPORT_SYMBOL(sport_tx_stop);
void sport_rx_stop(struct sport_device *sport)
{
sport->rx_regs->spctl &= ~SPORT_CTL_SPENPRI;
SSYNC();
disable_dma(sport->rx_dma_chan);
}
EXPORT_SYMBOL(sport_rx_stop);
void sport_set_tx_callback(struct sport_device *sport,
void (*tx_callback)(void *), void *tx_data)
{
sport->tx_callback = tx_callback;
sport->tx_data = tx_data;
}
EXPORT_SYMBOL(sport_set_tx_callback);
void sport_set_rx_callback(struct sport_device *sport,
void (*rx_callback)(void *), void *rx_data)
{
sport->rx_callback = rx_callback;
sport->rx_data = rx_data;
}
EXPORT_SYMBOL(sport_set_rx_callback);
static void setup_desc(struct dmasg *desc, void *buf, int fragcount,
size_t fragsize, unsigned int cfg,
unsigned int count, size_t wdsize)
{
int i;
for (i = 0; i < fragcount; ++i) {
desc[i].next_desc_addr = &(desc[i + 1]);
desc[i].start_addr = (unsigned long)buf + i * fragsize;
desc[i].cfg = cfg;
desc[i].x_count = count;
desc[i].x_modify = wdsize;
desc[i].y_count = 0;
desc[i].y_modify = 0;
}
/* make circular */
desc[fragcount - 1].next_desc_addr = desc;
}
int sport_config_tx_dma(struct sport_device *sport, void *buf,
int fragcount, size_t fragsize)
{
unsigned int count;
unsigned int cfg;
dma_addr_t addr;
count = fragsize / sport->wdsize;
if (sport->tx_desc)
dma_free_coherent(NULL, sport->tx_desc_size,
sport->tx_desc, 0);
sport->tx_desc = dma_alloc_coherent(NULL,
fragcount * sizeof(struct dmasg), &addr, 0);
sport->tx_desc_size = fragcount * sizeof(struct dmasg);
if (!sport->tx_desc)
return -ENOMEM;
sport->tx_buf = buf;
sport->tx_fragsize = fragsize;
sport->tx_frags = fragcount;
cfg = DMAFLOW_LIST | DI_EN | compute_wdsize(sport->wdsize) | NDSIZE_6;
setup_desc(sport->tx_desc, buf, fragcount, fragsize,
cfg | DMAEN, count, sport->wdsize);
return 0;
}
EXPORT_SYMBOL(sport_config_tx_dma);
int sport_config_rx_dma(struct sport_device *sport, void *buf,
int fragcount, size_t fragsize)
{
unsigned int count;
unsigned int cfg;
dma_addr_t addr;
count = fragsize / sport->wdsize;
if (sport->rx_desc)
dma_free_coherent(NULL, sport->rx_desc_size,
sport->rx_desc, 0);
sport->rx_desc = dma_alloc_coherent(NULL,
fragcount * sizeof(struct dmasg), &addr, 0);
sport->rx_desc_size = fragcount * sizeof(struct dmasg);
if (!sport->rx_desc)
return -ENOMEM;
sport->rx_buf = buf;
sport->rx_fragsize = fragsize;
sport->rx_frags = fragcount;
cfg = DMAFLOW_LIST | DI_EN | compute_wdsize(sport->wdsize)
| WNR | NDSIZE_6;
setup_desc(sport->rx_desc, buf, fragcount, fragsize,
cfg | DMAEN, count, sport->wdsize);
return 0;
}
EXPORT_SYMBOL(sport_config_rx_dma);
unsigned long sport_curr_offset_tx(struct sport_device *sport)
{
unsigned long curr = get_dma_curr_addr(sport->tx_dma_chan);
return (unsigned char *)curr - sport->tx_buf;
}
EXPORT_SYMBOL(sport_curr_offset_tx);
unsigned long sport_curr_offset_rx(struct sport_device *sport)
{
unsigned long curr = get_dma_curr_addr(sport->rx_dma_chan);
return (unsigned char *)curr - sport->rx_buf;
}
EXPORT_SYMBOL(sport_curr_offset_rx);
static irqreturn_t sport_tx_irq(int irq, void *dev_id)
{
struct sport_device *sport = dev_id;
static unsigned long status;
status = get_dma_curr_irqstat(sport->tx_dma_chan);
if (status & (DMA_DONE | DMA_ERR)) {
clear_dma_irqstat(sport->tx_dma_chan);
SSYNC();
}
if (sport->tx_callback)
sport->tx_callback(sport->tx_data);
return IRQ_HANDLED;
}
static irqreturn_t sport_rx_irq(int irq, void *dev_id)
{
struct sport_device *sport = dev_id;
unsigned long status;
status = get_dma_curr_irqstat(sport->rx_dma_chan);
if (status & (DMA_DONE | DMA_ERR)) {
clear_dma_irqstat(sport->rx_dma_chan);
SSYNC();
}
if (sport->rx_callback)
sport->rx_callback(sport->rx_data);
return IRQ_HANDLED;
}
static irqreturn_t sport_err_irq(int irq, void *dev_id)
{
struct sport_device *sport = dev_id;
struct device *dev = &sport->pdev->dev;
if (sport->tx_regs->spctl & SPORT_CTL_DERRPRI)
dev_err(dev, "sport error: TUVF\n");
if (sport->rx_regs->spctl & SPORT_CTL_DERRPRI)
dev_err(dev, "sport error: ROVF\n");
return IRQ_HANDLED;
}
static int sport_get_resource(struct sport_device *sport)
{
struct platform_device *pdev = sport->pdev;
struct device *dev = &pdev->dev;
struct bfin_snd_platform_data *pdata = dev->platform_data;
struct resource *res;
if (!pdata) {
dev_err(dev, "No platform data\n");
return -ENODEV;
}
sport->pin_req = pdata->pin_req;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "No tx MEM resource\n");
return -ENODEV;
}
sport->tx_regs = (struct sport_register *)res->start;
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res) {
dev_err(dev, "No rx MEM resource\n");
return -ENODEV;
}
sport->rx_regs = (struct sport_register *)res->start;
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!res) {
dev_err(dev, "No tx DMA resource\n");
return -ENODEV;
}
sport->tx_dma_chan = res->start;
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!res) {
dev_err(dev, "No rx DMA resource\n");
return -ENODEV;
}
sport->rx_dma_chan = res->start;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(dev, "No tx error irq resource\n");
return -ENODEV;
}
sport->tx_err_irq = res->start;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
if (!res) {
dev_err(dev, "No rx error irq resource\n");
return -ENODEV;
}
sport->rx_err_irq = res->start;
return 0;
}
static int sport_request_resource(struct sport_device *sport)
{
struct device *dev = &sport->pdev->dev;
int ret;
ret = peripheral_request_list(sport->pin_req, "soc-audio");
if (ret) {
dev_err(dev, "Unable to request sport pin\n");
return ret;
}
ret = request_dma(sport->tx_dma_chan, "SPORT TX Data");
if (ret) {
dev_err(dev, "Unable to allocate DMA channel for sport tx\n");
goto err_tx_dma;
}
set_dma_callback(sport->tx_dma_chan, sport_tx_irq, sport);
ret = request_dma(sport->rx_dma_chan, "SPORT RX Data");
if (ret) {
dev_err(dev, "Unable to allocate DMA channel for sport rx\n");
goto err_rx_dma;
}
set_dma_callback(sport->rx_dma_chan, sport_rx_irq, sport);
ret = request_irq(sport->tx_err_irq, sport_err_irq,
0, "SPORT TX ERROR", sport);
if (ret) {
dev_err(dev, "Unable to allocate tx error IRQ for sport\n");
goto err_tx_irq;
}
ret = request_irq(sport->rx_err_irq, sport_err_irq,
0, "SPORT RX ERROR", sport);
if (ret) {
dev_err(dev, "Unable to allocate rx error IRQ for sport\n");
goto err_rx_irq;
}
return 0;
err_rx_irq:
free_irq(sport->tx_err_irq, sport);
err_tx_irq:
free_dma(sport->rx_dma_chan);
err_rx_dma:
free_dma(sport->tx_dma_chan);
err_tx_dma:
peripheral_free_list(sport->pin_req);
return ret;
}
static void sport_free_resource(struct sport_device *sport)
{
free_irq(sport->rx_err_irq, sport);
free_irq(sport->tx_err_irq, sport);
free_dma(sport->rx_dma_chan);
free_dma(sport->tx_dma_chan);
peripheral_free_list(sport->pin_req);
}
struct sport_device *sport_create(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct sport_device *sport;
int ret;
sport = kzalloc(sizeof(*sport), GFP_KERNEL);
if (!sport)
return NULL;
sport->pdev = pdev;
ret = sport_get_resource(sport);
if (ret)
goto free_data;
ret = sport_request_resource(sport);
if (ret)
goto free_data;
dev_dbg(dev, "SPORT create success\n");
return sport;
free_data:
kfree(sport);
return NULL;
}
EXPORT_SYMBOL(sport_create);
void sport_delete(struct sport_device *sport)
{
if (sport->tx_desc)
dma_free_coherent(NULL, sport->tx_desc_size,
sport->tx_desc, 0);
if (sport->rx_desc)
dma_free_coherent(NULL, sport->rx_desc_size,
sport->rx_desc, 0);
sport_free_resource(sport);
kfree(sport);
}
EXPORT_SYMBOL(sport_delete);
MODULE_DESCRIPTION("Analog Devices BF6XX SPORT driver");
MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
MODULE_LICENSE("GPL v2");
/*
* bf6xx_sport - Analog Devices BF6XX SPORT driver
*
* Copyright (c) 2012 Analog Devices Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _BF6XX_SPORT_H_
#define _BF6XX_SPORT_H_
#include <linux/platform_device.h>
#include <asm/bfin_sport3.h>
struct sport_device {
struct platform_device *pdev;
const unsigned short *pin_req;
struct sport_register *tx_regs;
struct sport_register *rx_regs;
int tx_dma_chan;
int rx_dma_chan;
int tx_err_irq;
int rx_err_irq;
void (*tx_callback)(void *data);
void *tx_data;
void (*rx_callback)(void *data);
void *rx_data;
struct dmasg *tx_desc;
struct dmasg *rx_desc;
unsigned int tx_desc_size;
unsigned int rx_desc_size;
unsigned char *tx_buf;
unsigned char *rx_buf;
unsigned int tx_fragsize;
unsigned int rx_fragsize;
unsigned int tx_frags;
unsigned int rx_frags;
unsigned int wdsize;
};
struct sport_params {
u32 spctl;
u32 div;
};
struct sport_device *sport_create(struct platform_device *pdev);
void sport_delete(struct sport_device *sport);
int sport_set_tx_params(struct sport_device *sport,
struct sport_params *params);
int sport_set_rx_params(struct sport_device *sport,
struct sport_params *params);
void sport_tx_start(struct sport_device *sport);
void sport_rx_start(struct sport_device *sport);
void sport_tx_stop(struct sport_device *sport);
void sport_rx_stop(struct sport_device *sport);
void sport_set_tx_callback(struct sport_device *sport,
void (*tx_callback)(void *), void *tx_data);
void sport_set_rx_callback(struct sport_device *sport,
void (*rx_callback)(void *), void *rx_data);
int sport_config_tx_dma(struct sport_device *sport, void *buf,
int fragcount, size_t fragsize);
int sport_config_rx_dma(struct sport_device *sport, void *buf,
int fragcount, size_t fragsize);
unsigned long sport_curr_offset_tx(struct sport_device *sport);
unsigned long sport_curr_offset_rx(struct sport_device *sport);
#endif
/*
* Machine driver for EVAL-ADAU1373 on Analog Devices bfin
* evaluation boards.
*
* Copyright 2011 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*
* Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
#include <linux/device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
#include "../codecs/adau1373.h"
static const struct snd_soc_dapm_widget bfin_eval_adau1373_dapm_widgets[] = {
SND_SOC_DAPM_LINE("Line In1", NULL),
SND_SOC_DAPM_LINE("Line In2", NULL),
SND_SOC_DAPM_LINE("Line In3", NULL),
SND_SOC_DAPM_LINE("Line In4", NULL),
SND_SOC_DAPM_LINE("Line Out1", NULL),
SND_SOC_DAPM_LINE("Line Out2", NULL),
SND_SOC_DAPM_LINE("Stereo Out", NULL),
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_HP("Earpiece", NULL),
SND_SOC_DAPM_SPK("Speaker", NULL),
};
static const struct snd_soc_dapm_route bfin_eval_adau1373_dapm_routes[] = {
{ "AIN1L", NULL, "Line In1" },
{ "AIN1R", NULL, "Line In1" },
{ "AIN2L", NULL, "Line In2" },
{ "AIN2R", NULL, "Line In2" },
{ "AIN3L", NULL, "Line In3" },
{ "AIN3R", NULL, "Line In3" },
{ "AIN4L", NULL, "Line In4" },
{ "AIN4R", NULL, "Line In4" },
/* MICBIAS can be connected via a jumper to the line-in jack, since w
don't know which one is going to be used, just power both. */
{ "Line In1", NULL, "MICBIAS1" },
{ "Line In2", NULL, "MICBIAS1" },
{ "Line In3", NULL, "MICBIAS1" },
{ "Line In4", NULL, "MICBIAS1" },
{ "Line In1", NULL, "MICBIAS2" },
{ "Line In2", NULL, "MICBIAS2" },
{ "Line In3", NULL, "MICBIAS2" },
{ "Line In4", NULL, "MICBIAS2" },
{ "Line Out1", NULL, "LOUT1L" },
{ "Line Out1", NULL, "LOUT1R" },
{ "Line Out2", NULL, "LOUT2L" },
{ "Line Out2", NULL, "LOUT2R" },
{ "Headphone", NULL, "HPL" },
{ "Headphone", NULL, "HPR" },
{ "Earpiece", NULL, "EP" },
{ "Speaker", NULL, "SPKL" },
{ "Stereo Out", NULL, "SPKR" },
};
static int bfin_eval_adau1373_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
int pll_rate;
switch (params_rate(params)) {
case 48000:
case 8000:
case 12000:
case 16000:
case 24000:
case 32000:
pll_rate = 48000 * 1024;
break;
case 44100:
case 7350:
case 11025:
case 14700:
case 22050:
case 29400:
pll_rate = 44100 * 1024;
break;
default:
return -EINVAL;
}
ret = snd_soc_dai_set_pll(codec_dai, ADAU1373_PLL1,
ADAU1373_PLL_SRC_MCLK1, 12288000, pll_rate);
if (ret)
return ret;
ret = snd_soc_dai_set_sysclk(codec_dai, ADAU1373_CLK_SRC_PLL1, pll_rate,
SND_SOC_CLOCK_IN);
return ret;
}
static int bfin_eval_adau1373_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *codec_dai = rtd->codec_dai;
unsigned int pll_rate = 48000 * 1024;
int ret;
ret = snd_soc_dai_set_pll(codec_dai, ADAU1373_PLL1,
ADAU1373_PLL_SRC_MCLK1, 12288000, pll_rate);
if (ret)
return ret;
ret = snd_soc_dai_set_sysclk(codec_dai, ADAU1373_CLK_SRC_PLL1, pll_rate,
SND_SOC_CLOCK_IN);
return ret;
}
static const struct snd_soc_ops bfin_eval_adau1373_ops = {
.hw_params = bfin_eval_adau1373_hw_params,
};
static struct snd_soc_dai_link bfin_eval_adau1373_dai = {
.name = "adau1373",
.stream_name = "adau1373",
.cpu_dai_name = "bfin-i2s.0",
.codec_dai_name = "adau1373-aif1",
.platform_name = "bfin-i2s-pcm-audio",
.codec_name = "adau1373.0-001a",
.ops = &bfin_eval_adau1373_ops,
.init = bfin_eval_adau1373_codec_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM,
};
static struct snd_soc_card bfin_eval_adau1373 = {
.name = "bfin-eval-adau1373",
.owner = THIS_MODULE,
.dai_link = &bfin_eval_adau1373_dai,
.num_links = 1,
.dapm_widgets = bfin_eval_adau1373_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1373_dapm_widgets),
.dapm_routes = bfin_eval_adau1373_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1373_dapm_routes),
};
static int bfin_eval_adau1373_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = &bfin_eval_adau1373;
card->dev = &pdev->dev;
return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adau1373);
}
static struct platform_driver bfin_eval_adau1373_driver = {
.driver = {
.name = "bfin-eval-adau1373",
.pm = &snd_soc_pm_ops,
},
.probe = bfin_eval_adau1373_probe,
};
module_platform_driver(bfin_eval_adau1373_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("ALSA SoC bfin adau1373 driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:bfin-eval-adau1373");
/*
* Machine driver for EVAL-ADAU1701MINIZ on Analog Devices bfin
* evaluation boards.
*
* Copyright 2011 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*
* Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
#include <linux/device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
#include "../codecs/adau1701.h"
static const struct snd_soc_dapm_widget bfin_eval_adau1701_dapm_widgets[] = {
SND_SOC_DAPM_SPK("Speaker", NULL),
SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_LINE("Line In", NULL),
};
static const struct snd_soc_dapm_route bfin_eval_adau1701_dapm_routes[] = {
{ "Speaker", NULL, "OUT0" },
{ "Speaker", NULL, "OUT1" },
{ "Line Out", NULL, "OUT2" },
{ "Line Out", NULL, "OUT3" },
{ "IN0", NULL, "Line In" },
{ "IN1", NULL, "Line In" },
};
static int bfin_eval_adau1701_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
ret = snd_soc_dai_set_sysclk(codec_dai, ADAU1701_CLK_SRC_OSC, 12288000,
SND_SOC_CLOCK_IN);
return ret;
}
static struct snd_soc_ops bfin_eval_adau1701_ops = {
.hw_params = bfin_eval_adau1701_hw_params,
};
#define BFIN_EVAL_ADAU1701_DAI_FMT (SND_SOC_DAIFMT_I2S | \
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM)
static struct snd_soc_dai_link bfin_eval_adau1701_dai[] = {
{
.name = "adau1701",
.stream_name = "adau1701",
.cpu_dai_name = "bfin-i2s.0",
.codec_dai_name = "adau1701",
.platform_name = "bfin-i2s-pcm-audio",
.codec_name = "adau1701.0-0034",
.ops = &bfin_eval_adau1701_ops,
.dai_fmt = BFIN_EVAL_ADAU1701_DAI_FMT,
},
{
.name = "adau1701",
.stream_name = "adau1701",
.cpu_dai_name = "bfin-i2s.1",
.codec_dai_name = "adau1701",
.platform_name = "bfin-i2s-pcm-audio",
.codec_name = "adau1701.0-0034",
.ops = &bfin_eval_adau1701_ops,
.dai_fmt = BFIN_EVAL_ADAU1701_DAI_FMT,
},
};
static struct snd_soc_card bfin_eval_adau1701 = {
.name = "bfin-eval-adau1701",
.owner = THIS_MODULE,
.dai_link = &bfin_eval_adau1701_dai[CONFIG_SND_BF5XX_SPORT_NUM],
.num_links = 1,
.dapm_widgets = bfin_eval_adau1701_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1701_dapm_widgets),
.dapm_routes = bfin_eval_adau1701_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1701_dapm_routes),
};
static int bfin_eval_adau1701_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = &bfin_eval_adau1701;
card->dev = &pdev->dev;
return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adau1701);
}
static struct platform_driver bfin_eval_adau1701_driver = {
.driver = {
.name = "bfin-eval-adau1701",
.pm = &snd_soc_pm_ops,
},
.probe = bfin_eval_adau1701_probe,
};
module_platform_driver(bfin_eval_adau1701_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("ALSA SoC bfin ADAU1701 driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:bfin-eval-adau1701");
/*
* Machine driver for EVAL-ADAU1x61MINIZ on Analog Devices bfin
* evaluation boards.
*
* Copyright 2011-2014 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*
* Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
#include "../codecs/adau17x1.h"
static const struct snd_soc_dapm_widget bfin_eval_adau1x61_dapm_widgets[] = {
SND_SOC_DAPM_LINE("In 1", NULL),
SND_SOC_DAPM_LINE("In 2", NULL),
SND_SOC_DAPM_LINE("In 3-4", NULL),
SND_SOC_DAPM_LINE("Diff Out L", NULL),
SND_SOC_DAPM_LINE("Diff Out R", NULL),
SND_SOC_DAPM_LINE("Stereo Out", NULL),
SND_SOC_DAPM_HP("Capless HP Out", NULL),
};
static const struct snd_soc_dapm_route bfin_eval_adau1x61_dapm_routes[] = {
{ "LAUX", NULL, "In 3-4" },
{ "RAUX", NULL, "In 3-4" },
{ "LINP", NULL, "In 1" },
{ "LINN", NULL, "In 1"},
{ "RINP", NULL, "In 2" },
{ "RINN", NULL, "In 2" },
{ "In 1", NULL, "MICBIAS" },
{ "In 2", NULL, "MICBIAS" },
{ "Capless HP Out", NULL, "LHP" },
{ "Capless HP Out", NULL, "RHP" },
{ "Diff Out L", NULL, "LOUT" },
{ "Diff Out R", NULL, "ROUT" },
{ "Stereo Out", NULL, "LOUT" },
{ "Stereo Out", NULL, "ROUT" },
};
static int bfin_eval_adau1x61_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int pll_rate;
int ret;
switch (params_rate(params)) {
case 48000:
case 8000:
case 12000:
case 16000:
case 24000:
case 32000:
case 96000:
pll_rate = 48000 * 1024;
break;
case 44100:
case 7350:
case 11025:
case 14700:
case 22050:
case 29400:
case 88200:
pll_rate = 44100 * 1024;
break;
default:
return -EINVAL;
}
ret = snd_soc_dai_set_pll(codec_dai, ADAU17X1_PLL,
ADAU17X1_PLL_SRC_MCLK, 12288000, pll_rate);
if (ret)
return ret;
ret = snd_soc_dai_set_sysclk(codec_dai, ADAU17X1_CLK_SRC_PLL, pll_rate,
SND_SOC_CLOCK_IN);
return ret;
}
static const struct snd_soc_ops bfin_eval_adau1x61_ops = {
.hw_params = bfin_eval_adau1x61_hw_params,
};
static struct snd_soc_dai_link bfin_eval_adau1x61_dai = {
.name = "adau1x61",
.stream_name = "adau1x61",
.cpu_dai_name = "bfin-i2s.0",
.codec_dai_name = "adau-hifi",
.platform_name = "bfin-i2s-pcm-audio",
.codec_name = "adau1761.0-0038",
.ops = &bfin_eval_adau1x61_ops,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM,
};
static struct snd_soc_card bfin_eval_adau1x61 = {
.name = "bfin-eval-adau1x61",
.owner = THIS_MODULE,
.driver_name = "eval-adau1x61",
.dai_link = &bfin_eval_adau1x61_dai,
.num_links = 1,
.dapm_widgets = bfin_eval_adau1x61_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1x61_dapm_widgets),
.dapm_routes = bfin_eval_adau1x61_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1x61_dapm_routes),
.fully_routed = true,
};
static int bfin_eval_adau1x61_probe(struct platform_device *pdev)
{
bfin_eval_adau1x61.dev = &pdev->dev;
return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adau1x61);
}
static struct platform_driver bfin_eval_adau1x61_driver = {
.driver = {
.name = "bfin-eval-adau1x61",
.pm = &snd_soc_pm_ops,
},
.probe = bfin_eval_adau1x61_probe,
};
module_platform_driver(bfin_eval_adau1x61_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("ALSA SoC bfin adau1x61 driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:bfin-eval-adau1x61");
/*
* Machine driver for EVAL-ADAU1x81 on Analog Devices bfin
* evaluation boards.
*
* Copyright 2011-2014 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*
* Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
#include "../codecs/adau17x1.h"
static const struct snd_soc_dapm_widget bfin_eval_adau1x81_dapm_widgets[] = {
SND_SOC_DAPM_LINE("Stereo In", NULL),
SND_SOC_DAPM_LINE("Beep", NULL),
SND_SOC_DAPM_SPK("Speaker", NULL),
SND_SOC_DAPM_HP("Headphone", NULL),
};
static const struct snd_soc_dapm_route bfin_eval_adau1x81_dapm_routes[] = {
{ "BEEP", NULL, "Beep" },
{ "LMIC", NULL, "Stereo In" },
{ "LMIC", NULL, "Stereo In" },
{ "Headphone", NULL, "AOUTL" },
{ "Headphone", NULL, "AOUTR" },
{ "Speaker", NULL, "SP" },
};
static int bfin_eval_adau1x81_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int pll_rate;
int ret;
switch (params_rate(params)) {
case 48000:
case 8000:
case 12000:
case 16000:
case 24000:
case 32000:
case 96000:
pll_rate = 48000 * 1024;
break;
case 44100:
case 7350:
case 11025:
case 14700:
case 22050:
case 29400:
case 88200:
pll_rate = 44100 * 1024;
break;
default:
return -EINVAL;
}
ret = snd_soc_dai_set_pll(codec_dai, ADAU17X1_PLL,
ADAU17X1_PLL_SRC_MCLK, 12288000, pll_rate);
if (ret)
return ret;
ret = snd_soc_dai_set_sysclk(codec_dai, ADAU17X1_CLK_SRC_PLL, pll_rate,
SND_SOC_CLOCK_IN);
return ret;
}
static const struct snd_soc_ops bfin_eval_adau1x81_ops = {
.hw_params = bfin_eval_adau1x81_hw_params,
};
static struct snd_soc_dai_link bfin_eval_adau1x81_dai = {
.name = "adau1x81",
.stream_name = "adau1x81",
.cpu_dai_name = "bfin-i2s.0",
.codec_dai_name = "adau-hifi",
.platform_name = "bfin-i2s-pcm-audio",
.codec_name = "adau1781.0-0038",
.ops = &bfin_eval_adau1x81_ops,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM,
};
static struct snd_soc_card bfin_eval_adau1x81 = {
.name = "bfin-eval-adau1x81",
.driver_name = "eval-adau1x81",
.dai_link = &bfin_eval_adau1x81_dai,
.num_links = 1,
.dapm_widgets = bfin_eval_adau1x81_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1x81_dapm_widgets),
.dapm_routes = bfin_eval_adau1x81_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1x81_dapm_routes),
.fully_routed = true,
};
static int bfin_eval_adau1x81_probe(struct platform_device *pdev)
{
bfin_eval_adau1x81.dev = &pdev->dev;
return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adau1x81);
}
static struct platform_driver bfin_eval_adau1x81_driver = {
.driver = {
.name = "bfin-eval-adau1x81",
.pm = &snd_soc_pm_ops,
},
.probe = bfin_eval_adau1x81_probe,
};
module_platform_driver(bfin_eval_adau1x81_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("ALSA SoC bfin adau1x81 driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:bfin-eval-adau1x81");
/*
* Machine driver for EVAL-ADAV801 and EVAL-ADAV803 on Analog Devices bfin
* evaluation boards.
*
* Copyright 2011 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*
* Licensed under the GPL-2 or later.
*/
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include "../codecs/adav80x.h"
static const struct snd_soc_dapm_widget bfin_eval_adav80x_dapm_widgets[] = {
SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_LINE("Line In", NULL),
};
static const struct snd_soc_dapm_route bfin_eval_adav80x_dapm_routes[] = {
{ "Line Out", NULL, "VOUTL" },
{ "Line Out", NULL, "VOUTR" },
{ "VINL", NULL, "Line In" },
{ "VINR", NULL, "Line In" },
};
static int bfin_eval_adav80x_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
ret = snd_soc_dai_set_pll(codec_dai, ADAV80X_PLL1, ADAV80X_PLL_SRC_XTAL,
27000000, params_rate(params) * 256);
if (ret)
return ret;
ret = snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_PLL1,
params_rate(params) * 256, SND_SOC_CLOCK_IN);
return ret;
}
static int bfin_eval_adav80x_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *codec_dai = rtd->codec_dai;
snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK1, 0,
SND_SOC_CLOCK_OUT);
snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK2, 0,
SND_SOC_CLOCK_OUT);
snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK3, 0,
SND_SOC_CLOCK_OUT);
snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_XTAL, 2700000, 0);
return 0;
}
static const struct snd_soc_ops bfin_eval_adav80x_ops = {
.hw_params = bfin_eval_adav80x_hw_params,
};
static struct snd_soc_dai_link bfin_eval_adav80x_dais[] = {
{
.name = "adav80x",
.stream_name = "ADAV80x HiFi",
.cpu_dai_name = "bfin-i2s.0",
.codec_dai_name = "adav80x-hifi",
.platform_name = "bfin-i2s-pcm-audio",
.init = bfin_eval_adav80x_codec_init,
.ops = &bfin_eval_adav80x_ops,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM,
},
};
static struct snd_soc_card bfin_eval_adav80x = {
.name = "bfin-eval-adav80x",
.owner = THIS_MODULE,
.dai_link = bfin_eval_adav80x_dais,
.num_links = ARRAY_SIZE(bfin_eval_adav80x_dais),
.dapm_widgets = bfin_eval_adav80x_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(bfin_eval_adav80x_dapm_widgets),
.dapm_routes = bfin_eval_adav80x_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(bfin_eval_adav80x_dapm_routes),
};
enum bfin_eval_adav80x_type {
BFIN_EVAL_ADAV801,
BFIN_EVAL_ADAV803,
};
static int bfin_eval_adav80x_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = &bfin_eval_adav80x;
const char *codec_name;
switch (platform_get_device_id(pdev)->driver_data) {
case BFIN_EVAL_ADAV801:
codec_name = "spi0.1";
break;
case BFIN_EVAL_ADAV803:
codec_name = "adav803.0-0034";
break;
default:
return -EINVAL;
}
bfin_eval_adav80x_dais[0].codec_name = codec_name;
card->dev = &pdev->dev;
return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adav80x);
}
static const struct platform_device_id bfin_eval_adav80x_ids[] = {
{ "bfin-eval-adav801", BFIN_EVAL_ADAV801 },
{ "bfin-eval-adav803", BFIN_EVAL_ADAV803 },
{ },
};
MODULE_DEVICE_TABLE(platform, bfin_eval_adav80x_ids);
static struct platform_driver bfin_eval_adav80x_driver = {
.driver = {
.name = "bfin-eval-adav80x",
.pm = &snd_soc_pm_ops,
},
.probe = bfin_eval_adav80x_probe,
.id_table = bfin_eval_adav80x_ids,
};
module_platform_driver(bfin_eval_adav80x_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("ALSA SoC bfin adav80x driver");
MODULE_LICENSE("GPL");
......@@ -47,6 +47,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ALC5623 if I2C
select SND_SOC_ALC5632 if I2C
select SND_SOC_BT_SCO
select SND_SOC_BD28623
select SND_SOC_CQ0093VC
select SND_SOC_CS35L32 if I2C
select SND_SOC_CS35L33 if I2C
......@@ -418,6 +419,13 @@ config SND_SOC_ALC5623
config SND_SOC_ALC5632
tristate
config SND_SOC_BD28623
tristate "ROHM BD28623 CODEC"
help
Enable support for ROHM BD28623MUV Class D speaker amplifier.
This codec does not have any control buses such as I2C, it
detect format of I2S automatically.
config SND_SOC_BT_SCO
tristate "Dummy BT SCO codec driver"
......
......@@ -37,6 +37,7 @@ snd-soc-ak4671-objs := ak4671.o
snd-soc-ak5386-objs := ak5386.o
snd-soc-ak5558-objs := ak5558.o
snd-soc-arizona-objs := arizona.o
snd-soc-bd28623-objs := bd28623.o
snd-soc-bt-sco-objs := bt-sco.o
snd-soc-cq93vc-objs := cq93vc.o
snd-soc-cs35l32-objs := cs35l32.o
......@@ -286,6 +287,7 @@ obj-$(CONFIG_SND_SOC_AK5558) += snd-soc-ak5558.o
obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o
obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o
obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o
obj-$(CONFIG_SND_SOC_BD28623) += snd-soc-bd28623.o
obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o
obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o
......
......@@ -84,13 +84,14 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
int val;
switch (event) {
case SND_SOC_DAPM_POST_PMU:
val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3);
val = snd_soc_component_read32(component,
ARIZONA_INTERRUPT_RAW_STATUS_3);
if (val & ARIZONA_SPK_OVERHEAT_STS) {
dev_crit(arizona->dev,
"Speaker not enabled due to temperature\n");
......@@ -169,10 +170,10 @@ static const struct snd_soc_dapm_widget arizona_spkr =
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD);
int arizona_init_spk(struct snd_soc_codec *codec)
int arizona_init_spk(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
int ret;
......@@ -238,10 +239,10 @@ static const struct snd_soc_dapm_route arizona_mono_routes[] = {
{ "OUT6R", NULL, "OUT6L" },
};
int arizona_init_mono(struct snd_soc_codec *codec)
int arizona_init_mono(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
int i;
......@@ -255,11 +256,9 @@ int arizona_init_mono(struct snd_soc_codec *codec)
}
EXPORT_SYMBOL_GPL(arizona_init_mono);
int arizona_init_gpio(struct snd_soc_codec *codec)
int arizona_init_gpio(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
int i;
......@@ -643,7 +642,6 @@ const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
};
EXPORT_SYMBOL_GPL(arizona_rate_val);
const struct soc_enum arizona_isrc_fsh[] = {
SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1,
ARIZONA_ISRC1_FSH_SHIFT, 0xf,
......@@ -882,9 +880,9 @@ const struct snd_kcontrol_new arizona_voice_trigger_switch[] = {
};
EXPORT_SYMBOL_GPL(arizona_voice_trigger_switch);
static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
static void arizona_in_set_vu(struct snd_soc_component *component, int ena)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
unsigned int val;
int i;
......@@ -894,15 +892,15 @@ static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
val = 0;
for (i = 0; i < priv->num_inputs; i++)
snd_soc_update_bits(codec,
snd_soc_component_update_bits(component,
ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
ARIZONA_IN_VU, val);
}
bool arizona_input_analog(struct snd_soc_codec *codec, int shift)
bool arizona_input_analog(struct snd_soc_component *component, int shift)
{
unsigned int reg = ARIZONA_IN1L_CONTROL + ((shift / 2) * 8);
unsigned int val = snd_soc_read(codec, reg);
unsigned int val = snd_soc_component_read32(component, reg);
return !(val & ARIZONA_IN1_MODE_MASK);
}
......@@ -911,8 +909,8 @@ EXPORT_SYMBOL_GPL(arizona_input_analog);
int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
unsigned int reg;
if (w->shift % 2)
......@@ -925,25 +923,26 @@ int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
priv->in_pending++;
break;
case SND_SOC_DAPM_POST_PMU:
snd_soc_update_bits(codec, reg, ARIZONA_IN1L_MUTE, 0);
snd_soc_component_update_bits(component, reg,
ARIZONA_IN1L_MUTE, 0);
/* If this is the last input pending then allow VU */
priv->in_pending--;
if (priv->in_pending == 0) {
msleep(1);
arizona_in_set_vu(codec, 1);
arizona_in_set_vu(component, 1);
}
break;
case SND_SOC_DAPM_PRE_PMD:
snd_soc_update_bits(codec, reg,
snd_soc_component_update_bits(component, reg,
ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
break;
case SND_SOC_DAPM_POST_PMD:
/* Disable volume updates if no inputs are enabled */
reg = snd_soc_read(codec, ARIZONA_INPUT_ENABLES);
reg = snd_soc_component_read32(component, ARIZONA_INPUT_ENABLES);
if (reg == 0)
arizona_in_set_vu(codec, 0);
arizona_in_set_vu(component, 0);
break;
default:
break;
......@@ -957,8 +956,8 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
switch (event) {
......@@ -1001,7 +1000,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
case ARIZONA_OUT4R_ENA_SHIFT:
priv->out_up_pending--;
if (!priv->out_up_pending && priv->out_up_delay) {
dev_dbg(codec->dev, "Power up delay: %d\n",
dev_dbg(component->dev, "Power up delay: %d\n",
priv->out_up_delay);
msleep(priv->out_up_delay);
priv->out_up_delay = 0;
......@@ -1054,7 +1053,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
case ARIZONA_OUT4R_ENA_SHIFT:
priv->out_down_pending--;
if (!priv->out_down_pending && priv->out_down_delay) {
dev_dbg(codec->dev, "Power down delay: %d\n",
dev_dbg(component->dev, "Power down delay: %d\n",
priv->out_down_delay);
msleep(priv->out_down_delay);
priv->out_down_delay = 0;
......@@ -1072,12 +1071,11 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
}
EXPORT_SYMBOL_GPL(arizona_out_ev);
int arizona_hp_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
int arizona_hp_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
unsigned int mask = 1 << w->shift;
unsigned int val;
......@@ -1111,15 +1109,15 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,
}
EXPORT_SYMBOL_GPL(arizona_hp_ev);
static int arizona_dvfs_enable(struct snd_soc_codec *codec)
static int arizona_dvfs_enable(struct snd_soc_component *component)
{
const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
const struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
int ret;
ret = regulator_set_voltage(arizona->dcvdd, 1800000, 1800000);
if (ret) {
dev_err(codec->dev, "Failed to boost DCVDD: %d\n", ret);
dev_err(component->dev, "Failed to boost DCVDD: %d\n", ret);
return ret;
}
......@@ -1128,7 +1126,7 @@ static int arizona_dvfs_enable(struct snd_soc_codec *codec)
ARIZONA_SUBSYS_MAX_FREQ,
ARIZONA_SUBSYS_MAX_FREQ);
if (ret) {
dev_err(codec->dev, "Failed to enable subsys max: %d\n", ret);
dev_err(component->dev, "Failed to enable subsys max: %d\n", ret);
regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
return ret;
}
......@@ -1136,9 +1134,9 @@ static int arizona_dvfs_enable(struct snd_soc_codec *codec)
return 0;
}
static int arizona_dvfs_disable(struct snd_soc_codec *codec)
static int arizona_dvfs_disable(struct snd_soc_component *component)
{
const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
const struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
int ret;
......@@ -1146,28 +1144,28 @@ static int arizona_dvfs_disable(struct snd_soc_codec *codec)
ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
ARIZONA_SUBSYS_MAX_FREQ, 0);
if (ret) {
dev_err(codec->dev, "Failed to disable subsys max: %d\n", ret);
dev_err(component->dev, "Failed to disable subsys max: %d\n", ret);
return ret;
}
ret = regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
if (ret) {
dev_err(codec->dev, "Failed to unboost DCVDD: %d\n", ret);
dev_err(component->dev, "Failed to unboost DCVDD: %d\n", ret);
return ret;
}
return 0;
}
int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags)
int arizona_dvfs_up(struct snd_soc_component *component, unsigned int flags)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
int ret = 0;
mutex_lock(&priv->dvfs_lock);
if (!priv->dvfs_cached && !priv->dvfs_reqs) {
ret = arizona_dvfs_enable(codec);
ret = arizona_dvfs_enable(component);
if (ret)
goto err;
}
......@@ -1179,9 +1177,9 @@ int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags)
}
EXPORT_SYMBOL_GPL(arizona_dvfs_up);
int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags)
int arizona_dvfs_down(struct snd_soc_component *component, unsigned int flags)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
unsigned int old_reqs;
int ret = 0;
......@@ -1191,7 +1189,7 @@ int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags)
priv->dvfs_reqs &= ~flags;
if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs)
ret = arizona_dvfs_disable(codec);
ret = arizona_dvfs_disable(component);
mutex_unlock(&priv->dvfs_lock);
return ret;
......@@ -1201,8 +1199,8 @@ EXPORT_SYMBOL_GPL(arizona_dvfs_down);
int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
int ret = 0;
mutex_lock(&priv->dvfs_lock);
......@@ -1210,7 +1208,7 @@ int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_POST_PMU:
if (priv->dvfs_reqs)
ret = arizona_dvfs_enable(codec);
ret = arizona_dvfs_enable(component);
priv->dvfs_cached = false;
break;
......@@ -1222,7 +1220,7 @@ int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
priv->dvfs_cached = true;
if (priv->dvfs_reqs)
ret = arizona_dvfs_disable(codec);
ret = arizona_dvfs_disable(component);
break;
default:
break;
......@@ -1243,7 +1241,7 @@ int arizona_anc_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
unsigned int val;
switch (event) {
......@@ -1257,7 +1255,7 @@ int arizona_anc_ev(struct snd_soc_dapm_widget *w,
return 0;
}
snd_soc_write(codec, ARIZONA_CLOCK_CONTROL, val);
snd_soc_component_write(component, ARIZONA_CLOCK_CONTROL, val);
return 0;
}
......@@ -1277,10 +1275,10 @@ static unsigned int arizona_opclk_ref_44k1_rates[] = {
45158400,
};
static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
unsigned int freq)
static int arizona_set_opclk(struct snd_soc_component *component,
unsigned int clk, unsigned int freq)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
unsigned int reg;
unsigned int *rates;
int ref, div, refclk;
......@@ -1304,13 +1302,13 @@ static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
rates = arizona_opclk_ref_48k_rates;
for (ref = 0; ref < ARRAY_SIZE(arizona_opclk_ref_48k_rates) &&
rates[ref] <= refclk; ref++) {
rates[ref] <= refclk; ref++) {
div = 1;
while (rates[ref] / div >= freq && div < 32) {
if (rates[ref] / div == freq) {
dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
dev_dbg(component->dev, "Configured %dHz OPCLK\n",
freq);
snd_soc_update_bits(codec, reg,
snd_soc_component_update_bits(component, reg,
ARIZONA_OPCLK_DIV_MASK |
ARIZONA_OPCLK_SEL_MASK,
(div <<
......@@ -1322,22 +1320,22 @@ static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
}
}
dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
dev_err(component->dev, "Unable to generate %dHz OPCLK\n", freq);
return -EINVAL;
}
int arizona_clk_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
unsigned int val;
int clk_idx;
int ret;
ret = regmap_read(arizona->regmap, w->reg, &val);
if (ret) {
dev_err(codec->dev, "Failed to check clock source: %d\n", ret);
dev_err(component->dev, "Failed to check clock source: %d\n", ret);
return ret;
}
......@@ -1366,10 +1364,10 @@ int arizona_clk_ev(struct snd_soc_dapm_widget *w,
}
EXPORT_SYMBOL_GPL(arizona_clk_ev);
int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
int arizona_set_sysclk(struct snd_soc_component *component, int clk_id,
int source, unsigned int freq, int dir)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
char *name;
unsigned int reg;
......@@ -1391,7 +1389,7 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
break;
case ARIZONA_CLK_OPCLK:
case ARIZONA_CLK_ASYNC_OPCLK:
return arizona_set_opclk(codec, clk_id, freq);
return arizona_set_opclk(component, clk_id, freq);
default:
return -EINVAL;
}
......@@ -1445,8 +1443,8 @@ EXPORT_SYMBOL_GPL(arizona_set_sysclk);
static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_codec *codec = dai->codec;
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = dai->component;
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
int lrclk, bclk, mode, base;
......@@ -1620,8 +1618,8 @@ static const struct snd_pcm_hw_constraint_list arizona_constraint = {
static int arizona_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = dai->component;
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
unsigned int base_rate;
......@@ -1651,10 +1649,10 @@ static int arizona_startup(struct snd_pcm_substream *substream,
&dai_priv->constraint);
}
static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
static void arizona_wm5102_set_dac_comp(struct snd_soc_component *component,
unsigned int rate)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
struct reg_sequence dac_comp[] = {
{ 0x80, 0x3 },
......@@ -1680,8 +1678,8 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = dai->component;
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
int base = dai->driver->base;
int i, sr_val, ret;
......@@ -1704,9 +1702,9 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
case WM5102:
case WM8997:
if (arizona_sr_vals[sr_val] >= 88200)
ret = arizona_dvfs_up(codec, ARIZONA_DVFS_SR1_RQ);
ret = arizona_dvfs_up(component, ARIZONA_DVFS_SR1_RQ);
else
ret = arizona_dvfs_down(codec, ARIZONA_DVFS_SR1_RQ);
ret = arizona_dvfs_down(component, ARIZONA_DVFS_SR1_RQ);
if (ret) {
arizona_aif_err(dai, "Failed to change DVFS %d\n", ret);
......@@ -1721,26 +1719,31 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
case ARIZONA_CLK_SYSCLK:
switch (priv->arizona->type) {
case WM5102:
arizona_wm5102_set_dac_comp(codec,
arizona_wm5102_set_dac_comp(component,
params_rate(params));
break;
default:
break;
}
snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
snd_soc_component_update_bits(component, ARIZONA_SAMPLE_RATE_1,
ARIZONA_SAMPLE_RATE_1_MASK,
sr_val);
if (base)
snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
ARIZONA_AIF1_RATE_MASK, 0);
snd_soc_component_update_bits(component,
base + ARIZONA_AIF_RATE_CTRL,
ARIZONA_AIF1_RATE_MASK, 0);
break;
case ARIZONA_CLK_ASYNCCLK:
snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
ARIZONA_ASYNC_SAMPLE_RATE_1_MASK, sr_val);
snd_soc_component_update_bits(component,
ARIZONA_ASYNC_SAMPLE_RATE_1,
ARIZONA_ASYNC_SAMPLE_RATE_1_MASK,
sr_val);
if (base)
snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
ARIZONA_AIF1_RATE_MASK,
8 << ARIZONA_AIF1_RATE_SHIFT);
snd_soc_component_update_bits(component,
base + ARIZONA_AIF_RATE_CTRL,
ARIZONA_AIF1_RATE_MASK,
8 << ARIZONA_AIF1_RATE_SHIFT);
break;
default:
arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
......@@ -1750,20 +1753,20 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
return 0;
}
static bool arizona_aif_cfg_changed(struct snd_soc_codec *codec,
static bool arizona_aif_cfg_changed(struct snd_soc_component *component,
int base, int bclk, int lrclk, int frame)
{
int val;
val = snd_soc_read(codec, base + ARIZONA_AIF_BCLK_CTRL);
val = snd_soc_component_read32(component, base + ARIZONA_AIF_BCLK_CTRL);
if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
return true;
val = snd_soc_read(codec, base + ARIZONA_AIF_TX_BCLK_RATE);
val = snd_soc_component_read32(component, base + ARIZONA_AIF_TX_BCLK_RATE);
if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
return true;
val = snd_soc_read(codec, base + ARIZONA_AIF_FRAME_CTRL_1);
val = snd_soc_component_read32(component, base + ARIZONA_AIF_FRAME_CTRL_1);
if (frame != (val & (ARIZONA_AIF1TX_WL_MASK |
ARIZONA_AIF1TX_SLOT_LEN_MASK)))
return true;
......@@ -1775,8 +1778,8 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = dai->component;
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
int base = dai->driver->base;
const int *rates;
......@@ -1813,7 +1816,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
}
/* Force multiple of 2 channels for I2S mode */
val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
val = snd_soc_component_read32(component, base + ARIZONA_AIF_FORMAT);
val &= ARIZONA_AIF1_FMT_MASK;
if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) {
arizona_aif_dbg(dai, "Forcing stereo mode\n");
......@@ -1841,19 +1844,20 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width;
reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame);
reconfig = arizona_aif_cfg_changed(component, base, bclk, lrclk, frame);
if (reconfig) {
/* Save AIF TX/RX state */
aif_tx_state = snd_soc_read(codec,
aif_tx_state = snd_soc_component_read32(component,
base + ARIZONA_AIF_TX_ENABLES);
aif_rx_state = snd_soc_read(codec,
aif_rx_state = snd_soc_component_read32(component,
base + ARIZONA_AIF_RX_ENABLES);
/* Disable AIF TX/RX before reconfiguring it */
regmap_update_bits_async(arizona->regmap,
base + ARIZONA_AIF_TX_ENABLES, 0xff, 0x0);
base + ARIZONA_AIF_TX_ENABLES,
0xff, 0x0);
regmap_update_bits(arizona->regmap,
base + ARIZONA_AIF_RX_ENABLES, 0xff, 0x0);
base + ARIZONA_AIF_RX_ENABLES, 0xff, 0x0);
}
ret = arizona_hw_params_rate(substream, params, dai);
......@@ -1908,9 +1912,9 @@ static const char *arizona_dai_clk_str(int clk_id)
static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = dai->codec;
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = dai->component;
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
struct snd_soc_dapm_route routes[2];
......@@ -1926,12 +1930,12 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
return 0;
if (dai->active) {
dev_err(codec->dev, "Can't change clock on active DAI %d\n",
dev_err(component->dev, "Can't change clock on active DAI %d\n",
dai->id);
return -EBUSY;
}
dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
dev_dbg(component->dev, "Setting AIF%d to %s\n", dai->id + 1,
arizona_dai_clk_str(clk_id));
memset(&routes, 0, sizeof(routes));
......@@ -1953,7 +1957,7 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
{
struct snd_soc_codec *codec = dai->codec;
struct snd_soc_component *component = dai->component;
int base = dai->driver->base;
unsigned int reg;
......@@ -1962,16 +1966,17 @@ static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
else
reg = 0;
return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
ARIZONA_AIF1_TRI, reg);
return snd_soc_component_update_bits(component,
base + ARIZONA_AIF_RATE_CTRL,
ARIZONA_AIF1_TRI, reg);
}
static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
unsigned int base,
int channels, unsigned int mask)
{
struct snd_soc_codec *codec = dai->codec;
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = dai->component;
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
int slot, i;
......@@ -1992,8 +1997,8 @@ static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
unsigned int rx_mask, int slots, int slot_width)
{
struct snd_soc_codec *codec = dai->codec;
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = dai->component;
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
int base = dai->driver->base;
int rx_max_chan = dai->driver->playback.channels_max;
......@@ -2321,7 +2326,6 @@ static int arizona_calc_fll(struct arizona_fll *fll,
arizona_fll_dbg(fll, "GAIN=0x%x(%d)\n", cfg->gain, 1 << cfg->gain);
return 0;
}
static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
......@@ -2567,9 +2571,8 @@ int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
fll->ref_src = source;
fll->ref_freq = Fref;
if (fll->fout && Fref > 0) {
if (fll->fout && Fref > 0)
ret = arizona_enable_fll(fll);
}
return ret;
}
......@@ -2645,7 +2648,7 @@ EXPORT_SYMBOL_GPL(arizona_init_fll);
/**
* arizona_set_output_mode - Set the mode of the specified output
*
* @codec: Device to configure
* @component: Device to configure
* @output: Output number
* @diff: True to set the output to differential mode
*
......@@ -2658,7 +2661,8 @@ EXPORT_SYMBOL_GPL(arizona_init_fll);
* Most systems have a single static configuration and should use
* platform data instead.
*/
int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
int arizona_set_output_mode(struct snd_soc_component *component, int output,
bool diff)
{
unsigned int reg, val;
......@@ -2672,7 +2676,8 @@ int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
else
val = 0;
return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
return snd_soc_component_update_bits(component, reg,
ARIZONA_OUT1_MONO, val);
}
EXPORT_SYMBOL_GPL(arizona_set_output_mode);
......@@ -2721,8 +2726,8 @@ static bool arizona_eq_filter_unstable(bool mode, __be16 _a, __be16 _b)
int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
struct soc_bytes *params = (void *)kcontrol->private_value;
unsigned int val;
__be16 *data;
......@@ -2765,8 +2770,8 @@ EXPORT_SYMBOL_GPL(arizona_eq_coeff_put);
int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
__be16 *data = (__be16 *)ucontrol->value.bytes.data;
s16 val = be16_to_cpu(*data);
......
......@@ -273,7 +273,7 @@ int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
int arizona_clk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
int event);
int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source,
int arizona_set_sysclk(struct snd_soc_component *component, int clk_id, int source,
unsigned int freq, int dir);
extern const struct snd_soc_dai_ops arizona_dai_ops;
......@@ -297,8 +297,8 @@ struct arizona_fll {
char clock_ok_name[ARIZONA_FLL_NAME_LEN];
};
int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags);
int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags);
int arizona_dvfs_up(struct snd_soc_component *component, unsigned int flags);
int arizona_dvfs_down(struct snd_soc_component *component, unsigned int flags);
int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
void arizona_init_dvfs(struct arizona_priv *priv);
......@@ -310,9 +310,9 @@ int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
int arizona_set_fll(struct arizona_fll *fll, int source,
unsigned int Fref, unsigned int Fout);
int arizona_init_spk(struct snd_soc_codec *codec);
int arizona_init_gpio(struct snd_soc_codec *codec);
int arizona_init_mono(struct snd_soc_codec *codec);
int arizona_init_spk(struct snd_soc_component *component);
int arizona_init_gpio(struct snd_soc_component *component);
int arizona_init_mono(struct snd_soc_component *component);
int arizona_init_common(struct arizona *arizona);
int arizona_init_vol_limit(struct arizona *arizona);
......@@ -322,20 +322,20 @@ int arizona_free_spk_irqs(struct arizona *arizona);
int arizona_init_dai(struct arizona_priv *priv, int dai);
int arizona_set_output_mode(struct snd_soc_codec *codec, int output,
int arizona_set_output_mode(struct snd_soc_component *component, int output,
bool diff);
bool arizona_input_analog(struct snd_soc_codec *codec, int shift);
bool arizona_input_analog(struct snd_soc_component *component, int shift);
const char *arizona_sample_rate_val_to_name(unsigned int rate_val);
static inline int arizona_register_notifier(struct snd_soc_codec *codec,
static inline int arizona_register_notifier(struct snd_soc_component *component,
struct notifier_block *nb,
int (*notify)
(struct notifier_block *nb,
unsigned long action, void *data))
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
nb->notifier_call = notify;
......@@ -343,10 +343,10 @@ static inline int arizona_register_notifier(struct snd_soc_codec *codec,
return blocking_notifier_chain_register(&arizona->notifier, nb);
}
static inline int arizona_unregister_notifier(struct snd_soc_codec *codec,
static inline int arizona_unregister_notifier(struct snd_soc_component *component,
struct notifier_block *nb)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
return blocking_notifier_chain_unregister(&arizona->notifier, nb);
......
// SPDX-License-Identifier: GPL-2.0
//
// ROHM BD28623MUV class D speaker amplifier codec driver.
//
// Copyright (c) 2018 Socionext Inc.
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#define BD28623_NUM_SUPPLIES 3
static const char *const bd28623_supply_names[BD28623_NUM_SUPPLIES] = {
"VCCA",
"VCCP1",
"VCCP2",
};
struct bd28623_priv {
struct device *dev;
struct regulator_bulk_data supplies[BD28623_NUM_SUPPLIES];
struct gpio_desc *reset_gpio;
struct gpio_desc *mute_gpio;
int switch_spk;
};
static const struct snd_soc_dapm_widget bd28623_widgets[] = {
SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_OUTPUT("OUT1P"),
SND_SOC_DAPM_OUTPUT("OUT1N"),
SND_SOC_DAPM_OUTPUT("OUT2P"),
SND_SOC_DAPM_OUTPUT("OUT2N"),
};
static const struct snd_soc_dapm_route bd28623_routes[] = {
{ "OUT1P", NULL, "DAC" },
{ "OUT1N", NULL, "DAC" },
{ "OUT2P", NULL, "DAC" },
{ "OUT2N", NULL, "DAC" },
};
static int bd28623_power_on(struct bd28623_priv *bd)
{
int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(bd->supplies), bd->supplies);
if (ret) {
dev_err(bd->dev, "Failed to enable supplies: %d\n", ret);
return ret;
}
gpiod_set_value_cansleep(bd->reset_gpio, 0);
usleep_range(300000, 400000);
return 0;
}
static void bd28623_power_off(struct bd28623_priv *bd)
{
gpiod_set_value_cansleep(bd->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(bd->supplies), bd->supplies);
}
static int bd28623_get_switch_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component =
snd_soc_kcontrol_component(kcontrol);
struct bd28623_priv *bd = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = bd->switch_spk;
return 0;
}
static int bd28623_set_switch_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component =
snd_soc_kcontrol_component(kcontrol);
struct bd28623_priv *bd = snd_soc_component_get_drvdata(component);
if (bd->switch_spk == ucontrol->value.integer.value[0])
return 0;
bd->switch_spk = ucontrol->value.integer.value[0];
gpiod_set_value_cansleep(bd->mute_gpio, bd->switch_spk ? 0 : 1);
return 0;
}
static const struct snd_kcontrol_new bd28623_controls[] = {
SOC_SINGLE_BOOL_EXT("Speaker Switch", 0,
bd28623_get_switch_spk, bd28623_set_switch_spk),
};
static int bd28623_codec_probe(struct snd_soc_component *component)
{
struct bd28623_priv *bd = snd_soc_component_get_drvdata(component);
int ret;
bd->switch_spk = 1;
ret = bd28623_power_on(bd);
if (ret)
return ret;
gpiod_set_value_cansleep(bd->mute_gpio, bd->switch_spk ? 0 : 1);
return 0;
}
static void bd28623_codec_remove(struct snd_soc_component *component)
{
struct bd28623_priv *bd = snd_soc_component_get_drvdata(component);
bd28623_power_off(bd);
}
static int bd28623_codec_suspend(struct snd_soc_component *component)
{
struct bd28623_priv *bd = snd_soc_component_get_drvdata(component);
bd28623_power_off(bd);
return 0;
}
static int bd28623_codec_resume(struct snd_soc_component *component)
{
struct bd28623_priv *bd = snd_soc_component_get_drvdata(component);
int ret;
ret = bd28623_power_on(bd);
if (ret)
return ret;
gpiod_set_value_cansleep(bd->mute_gpio, bd->switch_spk ? 0 : 1);
return 0;
}
static const struct snd_soc_component_driver soc_codec_bd = {
.probe = bd28623_codec_probe,
.remove = bd28623_codec_remove,
.suspend = bd28623_codec_suspend,
.resume = bd28623_codec_resume,
.dapm_widgets = bd28623_widgets,
.num_dapm_widgets = ARRAY_SIZE(bd28623_widgets),
.dapm_routes = bd28623_routes,
.num_dapm_routes = ARRAY_SIZE(bd28623_routes),
.controls = bd28623_controls,
.num_controls = ARRAY_SIZE(bd28623_controls),
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static struct snd_soc_dai_driver soc_dai_bd = {
.name = "bd28623-speaker",
.playback = {
.stream_name = "Playback",
.formats = SNDRV_PCM_FMTBIT_S32_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_32000,
.channels_min = 2,
.channels_max = 2,
},
};
static int bd28623_probe(struct platform_device *pdev)
{
struct bd28623_priv *bd;
struct device *dev = &pdev->dev;
int i, ret;
bd = devm_kzalloc(&pdev->dev, sizeof(struct bd28623_priv), GFP_KERNEL);
if (!bd)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(bd->supplies); i++)
bd->supplies[i].supply = bd28623_supply_names[i];
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(bd->supplies),
bd->supplies);
if (ret) {
dev_err(dev, "Failed to get supplies: %d\n", ret);
return ret;
}
bd->reset_gpio = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(bd->reset_gpio)) {
dev_err(dev, "Failed to request reset_gpio: %ld\n",
PTR_ERR(bd->reset_gpio));
return PTR_ERR(bd->reset_gpio);
}
bd->mute_gpio = devm_gpiod_get_optional(dev, "mute",
GPIOD_OUT_HIGH);
if (IS_ERR(bd->mute_gpio)) {
dev_err(dev, "Failed to request mute_gpio: %ld\n",
PTR_ERR(bd->mute_gpio));
return PTR_ERR(bd->mute_gpio);
}
platform_set_drvdata(pdev, bd);
bd->dev = dev;
return devm_snd_soc_register_component(dev, &soc_codec_bd,
&soc_dai_bd, 1);
}
static const struct of_device_id bd28623_of_match[] = {
{ .compatible = "rohm,bd28623", },
{}
};
MODULE_DEVICE_TABLE(of, bd28623_of_match);
static struct platform_driver bd28623_codec_driver = {
.driver = {
.name = "bd28623",
.of_match_table = of_match_ptr(bd28623_of_match),
},
.probe = bd28623_probe,
};
module_platform_driver(bd28623_codec_driver);
MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
MODULE_DESCRIPTION("ROHM BD28623 speaker amplifier driver");
MODULE_LICENSE("GPL v2");
......@@ -62,25 +62,26 @@ static struct snd_soc_dai_driver bt_sco_dai[] = {
}
};
static const struct snd_soc_codec_driver soc_codec_dev_bt_sco = {
.component_driver = {
.dapm_widgets = bt_sco_widgets,
.num_dapm_widgets = ARRAY_SIZE(bt_sco_widgets),
.dapm_routes = bt_sco_routes,
.num_dapm_routes = ARRAY_SIZE(bt_sco_routes),
},
static const struct snd_soc_component_driver soc_component_dev_bt_sco = {
.dapm_widgets = bt_sco_widgets,
.num_dapm_widgets = ARRAY_SIZE(bt_sco_widgets),
.dapm_routes = bt_sco_routes,
.num_dapm_routes = ARRAY_SIZE(bt_sco_routes),
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static int bt_sco_probe(struct platform_device *pdev)
{
return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_bt_sco,
return devm_snd_soc_register_component(&pdev->dev,
&soc_component_dev_bt_sco,
bt_sco_dai, ARRAY_SIZE(bt_sco_dai));
}
static int bt_sco_remove(struct platform_device *pdev)
{
snd_soc_unregister_codec(&pdev->dev);
return 0;
}
......
......@@ -62,14 +62,14 @@ static const struct wm_adsp_region *cs47l24_dsp_regions[] = {
static int cs47l24_adsp_power_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
unsigned int v;
int ret;
ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &v);
if (ret != 0) {
dev_err(codec->dev, "Failed to read SYSCLK state: %d\n", ret);
dev_err(component->dev, "Failed to read SYSCLK state: %d\n", ret);
return ret;
}
......@@ -196,14 +196,13 @@ SOC_SINGLE("HPOUT1 SC Protect Switch", ARIZONA_HP1_SHORT_CIRCUIT_CTRL,
SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),
SOC_SINGLE("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L,
ARIZONA_OUT4L_MUTE_SHIFT, 1, 1),
ARIZONA_OUT4L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L,
ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_SINGLE_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L,
ARIZONA_OUT4L_VOL_SHIFT,
0xbf, 0, digital_tlv),
ARIZONA_OUT4L_VOL_SHIFT, 0xbf, 0, digital_tlv),
SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
......@@ -494,8 +493,7 @@ SND_SOC_DAPM_PGA("ISRC3DEC4", ARIZONA_ISRC_3_CTRL_3,
ARIZONA_ISRC3_DEC3_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
&cs47l24_aec_loopback_mux),
ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0, &cs47l24_aec_loopback_mux),
SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
......@@ -931,10 +929,10 @@ static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = {
{ "DSP3 Voice Trigger", "Switch", "DSP3" },
};
static int cs47l24_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
unsigned int Fref, unsigned int Fout)
static int cs47l24_set_fll(struct snd_soc_component *component, int fll_id,
int source, unsigned int Fref, unsigned int Fout)
{
struct cs47l24_priv *cs47l24 = snd_soc_codec_get_drvdata(codec);
struct cs47l24_priv *cs47l24 = snd_soc_component_get_drvdata(component);
switch (fll_id) {
case CS47L24_FLL1:
......@@ -1118,34 +1116,34 @@ static irqreturn_t cs47l24_adsp2_irq(int irq, void *data)
return IRQ_HANDLED;
}
static int cs47l24_codec_probe(struct snd_soc_codec *codec)
static int cs47l24_component_probe(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct cs47l24_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->core.arizona;
int ret;
arizona->dapm = dapm;
snd_soc_codec_init_regmap(codec, arizona->regmap);
snd_soc_component_init_regmap(component, arizona->regmap);
ret = arizona_init_spk(codec);
ret = arizona_init_spk(component);
if (ret < 0)
return ret;
arizona_init_gpio(codec);
arizona_init_mono(codec);
arizona_init_gpio(component);
arizona_init_mono(component);
ret = wm_adsp2_codec_probe(&priv->core.adsp[1], codec);
ret = wm_adsp2_component_probe(&priv->core.adsp[1], component);
if (ret)
goto err_adsp2_codec_probe;
ret = wm_adsp2_codec_probe(&priv->core.adsp[2], codec);
ret = wm_adsp2_component_probe(&priv->core.adsp[2], component);
if (ret)
goto err_adsp2_codec_probe;
ret = snd_soc_add_codec_controls(codec,
&arizona_adsp2_rate_controls[1], 2);
ret = snd_soc_add_component_controls(component,
&arizona_adsp2_rate_controls[1],
2);
if (ret)
goto err_adsp2_codec_probe;
......@@ -1154,22 +1152,20 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec)
return 0;
err_adsp2_codec_probe:
wm_adsp2_codec_remove(&priv->core.adsp[1], codec);
wm_adsp2_codec_remove(&priv->core.adsp[2], codec);
wm_adsp2_component_remove(&priv->core.adsp[1], component);
wm_adsp2_component_remove(&priv->core.adsp[2], component);
return ret;
}
static int cs47l24_codec_remove(struct snd_soc_codec *codec)
static void cs47l24_component_remove(struct snd_soc_component *component)
{
struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec);
struct cs47l24_priv *priv = snd_soc_component_get_drvdata(component);
wm_adsp2_codec_remove(&priv->core.adsp[1], codec);
wm_adsp2_codec_remove(&priv->core.adsp[2], codec);
wm_adsp2_component_remove(&priv->core.adsp[1], component);
wm_adsp2_component_remove(&priv->core.adsp[2], component);
priv->core.arizona->dapm = NULL;
return 0;
}
#define CS47L24_DIG_VU 0x0200
......@@ -1190,25 +1186,22 @@ static struct snd_compr_ops cs47l24_compr_ops = {
.copy = wm_adsp_compr_copy,
};
static const struct snd_soc_codec_driver soc_codec_dev_cs47l24 = {
.probe = cs47l24_codec_probe,
.remove = cs47l24_codec_remove,
.idle_bias_off = true,
.set_sysclk = arizona_set_sysclk,
.set_pll = cs47l24_set_fll,
.component_driver = {
.name = DRV_NAME,
.compr_ops = &cs47l24_compr_ops,
.controls = cs47l24_snd_controls,
.num_controls = ARRAY_SIZE(cs47l24_snd_controls),
.dapm_widgets = cs47l24_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(cs47l24_dapm_widgets),
.dapm_routes = cs47l24_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(cs47l24_dapm_routes),
},
static const struct snd_soc_component_driver soc_component_dev_cs47l24 = {
.probe = cs47l24_component_probe,
.remove = cs47l24_component_remove,
.set_sysclk = arizona_set_sysclk,
.set_pll = cs47l24_set_fll,
.name = DRV_NAME,
.compr_ops = &cs47l24_compr_ops,
.controls = cs47l24_snd_controls,
.num_controls = ARRAY_SIZE(cs47l24_snd_controls),
.dapm_widgets = cs47l24_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(cs47l24_dapm_widgets),
.dapm_routes = cs47l24_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(cs47l24_dapm_routes),
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static int cs47l24_probe(struct platform_device *pdev)
......@@ -1220,7 +1213,7 @@ static int cs47l24_probe(struct platform_device *pdev)
BUILD_BUG_ON(ARRAY_SIZE(cs47l24_dai) > ARIZONA_MAX_DAI);
cs47l24 = devm_kzalloc(&pdev->dev, sizeof(struct cs47l24_priv),
GFP_KERNEL);
GFP_KERNEL);
if (!cs47l24)
return -ENOMEM;
......@@ -1299,10 +1292,12 @@ static int cs47l24_probe(struct platform_device *pdev)
if (ret < 0)
goto err_dsp_irq;
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24,
cs47l24_dai, ARRAY_SIZE(cs47l24_dai));
ret = devm_snd_soc_register_component(&pdev->dev,
&soc_component_dev_cs47l24,
cs47l24_dai,
ARRAY_SIZE(cs47l24_dai));
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
dev_err(&pdev->dev, "Failed to register component: %d\n", ret);
goto err_spk_irqs;
}
......@@ -1321,7 +1316,6 @@ static int cs47l24_remove(struct platform_device *pdev)
struct cs47l24_priv *cs47l24 = platform_get_drvdata(pdev);
struct arizona *arizona = cs47l24->core.arizona;
snd_soc_unregister_codec(&pdev->dev);
pm_runtime_disable(&pdev->dev);
wm_adsp2_remove(&cs47l24->core.adsp[1]);
......
......@@ -583,8 +583,8 @@ static const struct reg_default wm5102_sysclk_revb_patch[] = {
static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
struct regmap *regmap = arizona->regmap;
const struct reg_default *patch = NULL;
int i, patch_size;
......@@ -620,10 +620,10 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
}
static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
unsigned int v = 0;
int ret;
......@@ -631,7 +631,7 @@ static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_PRE_PMU:
ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &v);
if (ret != 0) {
dev_err(codec->dev,
dev_err(component->dev,
"Failed to read SYSCLK state: %d\n", ret);
return -EIO;
}
......@@ -639,9 +639,9 @@ static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT;
if (v >= 3) {
ret = arizona_dvfs_up(codec, ARIZONA_DVFS_ADSP1_RQ);
ret = arizona_dvfs_up(component, ARIZONA_DVFS_ADSP1_RQ);
if (ret) {
dev_err(codec->dev,
dev_err(component->dev,
"Failed to raise DVFS: %d\n", ret);
return ret;
}
......@@ -649,9 +649,9 @@ static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
break;
case SND_SOC_DAPM_POST_PMD:
ret = arizona_dvfs_down(codec, ARIZONA_DVFS_ADSP1_RQ);
ret = arizona_dvfs_down(component, ARIZONA_DVFS_ADSP1_RQ);
if (ret)
dev_warn(codec->dev,
dev_warn(component->dev,
"Failed to lower DVFS: %d\n", ret);
break;
......@@ -665,8 +665,8 @@ static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
mutex_lock(&arizona->dac_comp_lock);
put_unaligned_be16(arizona->dac_comp_coeff,
......@@ -679,8 +679,8 @@ static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
mutex_lock(&arizona->dac_comp_lock);
memcpy(&arizona->dac_comp_coeff, ucontrol->value.bytes.data,
......@@ -694,8 +694,8 @@ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol,
static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
mutex_lock(&arizona->dac_comp_lock);
ucontrol->value.integer.value[0] = arizona->dac_comp_enabled;
......@@ -707,8 +707,8 @@ static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol,
static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
mutex_lock(&arizona->dac_comp_lock);
arizona->dac_comp_enabled = ucontrol->value.integer.value[0];
......@@ -717,7 +717,7 @@ static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol,
return 0;
}
static const char *wm5102_osr_text[] = {
static const char * const wm5102_osr_text[] = {
"Low power", "Normal", "High performance",
};
......@@ -1062,7 +1062,7 @@ ARIZONA_MIXER_ENUMS(DSP1R, ARIZONA_DSP1RMIX_INPUT_1_SOURCE);
ARIZONA_DSP_AUX_ENUMS(DSP1, ARIZONA_DSP1AUX1MIX_INPUT_1_SOURCE);
static const char *wm5102_aec_loopback_texts[] = {
static const char * const wm5102_aec_loopback_texts[] = {
"HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "EPOUT",
"SPKOUTL", "SPKOUTR", "SPKDAT1L", "SPKDAT1R",
};
......@@ -1317,8 +1317,7 @@ SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0,
ARIZONA_DSP_WIDGETS(DSP1, "DSP1"),
SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
&wm5102_aec_loopback_mux),
ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0, &wm5102_aec_loopback_mux),
SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
......@@ -1736,10 +1735,10 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
{ "DRC1 Signal Activity", NULL, "DRC1R" },
};
static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
unsigned int Fref, unsigned int Fout)
static int wm5102_set_fll(struct snd_soc_component *component, int fll_id,
int source, unsigned int Fref, unsigned int Fout)
{
struct wm5102_priv *wm5102 = snd_soc_codec_get_drvdata(codec);
struct wm5102_priv *wm5102 = snd_soc_component_get_drvdata(component);
switch (fll_id) {
case WM5102_FLL1:
......@@ -1933,30 +1932,29 @@ static irqreturn_t wm5102_adsp2_irq(int irq, void *data)
return IRQ_HANDLED;
}
static int wm5102_codec_probe(struct snd_soc_codec *codec)
static int wm5102_component_probe(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct wm5102_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->core.arizona;
int ret;
snd_soc_codec_init_regmap(codec, arizona->regmap);
snd_soc_component_init_regmap(component, arizona->regmap);
ret = wm_adsp2_codec_probe(&priv->core.adsp[0], codec);
ret = wm_adsp2_component_probe(&priv->core.adsp[0], component);
if (ret)
return ret;
ret = snd_soc_add_codec_controls(codec,
arizona_adsp2_rate_controls, 1);
ret = snd_soc_add_component_controls(component,
arizona_adsp2_rate_controls, 1);
if (ret)
goto err_adsp2_codec_probe;
ret = arizona_init_spk(codec);
ret = arizona_init_spk(component);
if (ret < 0)
return ret;
arizona_init_gpio(codec);
arizona_init_gpio(component);
snd_soc_component_disable_pin(component, "HAPTICS");
......@@ -1965,20 +1963,18 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
return 0;
err_adsp2_codec_probe:
wm_adsp2_codec_remove(&priv->core.adsp[0], codec);
wm_adsp2_component_remove(&priv->core.adsp[0], component);
return ret;
}
static int wm5102_codec_remove(struct snd_soc_codec *codec)
static void wm5102_component_remove(struct snd_soc_component *component)
{
struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
struct wm5102_priv *priv = snd_soc_component_get_drvdata(component);
wm_adsp2_codec_remove(&priv->core.adsp[0], codec);
wm_adsp2_component_remove(&priv->core.adsp[0], component);
priv->core.arizona->dapm = NULL;
return 0;
}
#define WM5102_DIG_VU 0x0200
......@@ -2005,25 +2001,22 @@ static struct snd_compr_ops wm5102_compr_ops = {
.copy = wm_adsp_compr_copy,
};
static const struct snd_soc_codec_driver soc_codec_dev_wm5102 = {
.probe = wm5102_codec_probe,
.remove = wm5102_codec_remove,
.idle_bias_off = true,
.set_sysclk = arizona_set_sysclk,
.set_pll = wm5102_set_fll,
.component_driver = {
.name = DRV_NAME,
.compr_ops = &wm5102_compr_ops,
.controls = wm5102_snd_controls,
.num_controls = ARRAY_SIZE(wm5102_snd_controls),
.dapm_widgets = wm5102_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm5102_dapm_widgets),
.dapm_routes = wm5102_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(wm5102_dapm_routes),
},
static const struct snd_soc_component_driver soc_component_dev_wm5102 = {
.probe = wm5102_component_probe,
.remove = wm5102_component_remove,
.set_sysclk = arizona_set_sysclk,
.set_pll = wm5102_set_fll,
.name = DRV_NAME,
.compr_ops = &wm5102_compr_ops,
.controls = wm5102_snd_controls,
.num_controls = ARRAY_SIZE(wm5102_snd_controls),
.dapm_widgets = wm5102_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm5102_dapm_widgets),
.dapm_routes = wm5102_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(wm5102_dapm_routes),
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static int wm5102_probe(struct platform_device *pdev)
......@@ -2110,10 +2103,12 @@ static int wm5102_probe(struct platform_device *pdev)
if (ret < 0)
goto err_dsp_irq;
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5102,
wm5102_dai, ARRAY_SIZE(wm5102_dai));
ret = devm_snd_soc_register_component(&pdev->dev,
&soc_component_dev_wm5102,
wm5102_dai,
ARRAY_SIZE(wm5102_dai));
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
dev_err(&pdev->dev, "Failed to register component: %d\n", ret);
goto err_spk_irqs;
}
......@@ -2132,7 +2127,6 @@ static int wm5102_remove(struct platform_device *pdev)
struct wm5102_priv *wm5102 = platform_get_drvdata(pdev);
struct arizona *arizona = wm5102->core.arizona;
snd_soc_unregister_codec(&pdev->dev);
pm_runtime_disable(&pdev->dev);
wm_adsp2_remove(&wm5102->core.adsp[0]);
......
......@@ -161,8 +161,8 @@ static const struct reg_default wm5110_sysclk_reve_patch[] = {
static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
struct regmap *regmap = arizona->regmap;
const struct reg_default *patch = NULL;
int i, patch_size;
......@@ -198,14 +198,14 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
static int wm5110_adsp_power_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
unsigned int v;
int ret;
ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &v);
if (ret != 0) {
dev_err(codec->dev, "Failed to read SYSCLK state: %d\n", ret);
dev_err(component->dev, "Failed to read SYSCLK state: %d\n", ret);
return ret;
}
......@@ -288,10 +288,10 @@ static const struct reg_sequence wm5110_dre_right_enable[] = {
static int wm5110_hp_pre_enable(struct snd_soc_dapm_widget *w)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
unsigned int val = snd_soc_read(codec, ARIZONA_DRE_ENABLE);
unsigned int val = snd_soc_component_read32(component, ARIZONA_DRE_ENABLE);
const struct reg_sequence *wseq;
int nregs;
......@@ -325,26 +325,32 @@ static int wm5110_hp_pre_enable(struct snd_soc_dapm_widget *w)
static int wm5110_hp_pre_disable(struct snd_soc_dapm_widget *w)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
unsigned int val = snd_soc_read(codec, ARIZONA_DRE_ENABLE);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
unsigned int val = snd_soc_component_read32(component, ARIZONA_DRE_ENABLE);
switch (w->shift) {
case ARIZONA_OUT1L_ENA_SHIFT:
if (!(val & ARIZONA_DRE1L_ENA_MASK)) {
snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS,
ARIZONA_WS_TRG1, ARIZONA_WS_TRG1);
snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS,
ARIZONA_WS_TRG1, 0);
snd_soc_component_update_bits(component,
ARIZONA_SPARE_TRIGGERS,
ARIZONA_WS_TRG1,
ARIZONA_WS_TRG1);
snd_soc_component_update_bits(component,
ARIZONA_SPARE_TRIGGERS,
ARIZONA_WS_TRG1, 0);
priv->out_down_delay += 27;
}
break;
case ARIZONA_OUT1R_ENA_SHIFT:
if (!(val & ARIZONA_DRE1R_ENA_MASK)) {
snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS,
ARIZONA_WS_TRG2, ARIZONA_WS_TRG2);
snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS,
ARIZONA_WS_TRG2, 0);
snd_soc_component_update_bits(component,
ARIZONA_SPARE_TRIGGERS,
ARIZONA_WS_TRG2,
ARIZONA_WS_TRG2);
snd_soc_component_update_bits(component,
ARIZONA_SPARE_TRIGGERS,
ARIZONA_WS_TRG2, 0);
priv->out_down_delay += 27;
}
break;
......@@ -358,8 +364,8 @@ static int wm5110_hp_pre_disable(struct snd_soc_dapm_widget *w)
static int wm5110_hp_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
switch (priv->arizona->rev) {
case 0 ... 3:
......@@ -397,9 +403,9 @@ static int wm5110_clear_pga_volume(struct arizona *arizona, int output)
static int wm5110_put_dre(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int ena, dre;
......@@ -458,8 +464,8 @@ static int wm5110_put_dre(struct snd_kcontrol *kcontrol,
static int wm5110_in_pga_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
int ret;
/*
......@@ -478,8 +484,8 @@ static int wm5110_in_pga_get(struct snd_kcontrol *kcontrol,
static int wm5110_in_pga_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
int ret;
/*
......@@ -498,9 +504,9 @@ static int wm5110_in_pga_put(struct snd_kcontrol *kcontrol,
static int wm5110_in_analog_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct wm5110_priv *wm5110 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct wm5110_priv *wm5110 = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
unsigned int reg, mask;
struct reg_sequence analog_seq[] = {
......@@ -519,9 +525,9 @@ static int wm5110_in_analog_ev(struct snd_soc_dapm_widget *w,
wm5110->in_post_pending++;
return 0;
case SND_SOC_DAPM_PRE_PMU:
wm5110->in_pga_cache[w->shift] = snd_soc_read(codec, reg);
wm5110->in_pga_cache[w->shift] = snd_soc_component_read32(component, reg);
snd_soc_update_bits(codec, reg, mask,
snd_soc_component_update_bits(component, reg, mask,
0x40 << ARIZONA_IN1L_PGA_VOL_SHIFT);
wm5110->in_pre_pending--;
......@@ -538,8 +544,8 @@ static int wm5110_in_analog_ev(struct snd_soc_dapm_widget *w,
break;
case SND_SOC_DAPM_POST_PMU:
snd_soc_update_bits(codec, reg, mask,
wm5110->in_pga_cache[w->shift]);
snd_soc_component_update_bits(component, reg, mask,
wm5110->in_pga_cache[w->shift]);
wm5110->in_post_pending--;
if (wm5110->in_post_pending == 0)
......@@ -557,13 +563,13 @@ static int wm5110_in_analog_ev(struct snd_soc_dapm_widget *w,
static int wm5110_in_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
switch (arizona->rev) {
case 0 ... 4:
if (arizona_input_analog(codec, w->shift))
if (arizona_input_analog(component, w->shift))
wm5110_in_analog_ev(w, kcontrol, event);
break;
......@@ -863,14 +869,14 @@ SOC_DOUBLE("SPKDAT2 Switch", ARIZONA_PDM_SPK2_CTRL_1, ARIZONA_SPK2L_MUTE_SHIFT,
ARIZONA_SPK2R_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_EXT("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE,
ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0,
snd_soc_get_volsw, wm5110_put_dre),
ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0,
snd_soc_get_volsw, wm5110_put_dre),
SOC_DOUBLE_EXT("HPOUT2 DRE Switch", ARIZONA_DRE_ENABLE,
ARIZONA_DRE2L_ENA_SHIFT, ARIZONA_DRE2R_ENA_SHIFT, 1, 0,
snd_soc_get_volsw, wm5110_put_dre),
ARIZONA_DRE2L_ENA_SHIFT, ARIZONA_DRE2R_ENA_SHIFT, 1, 0,
snd_soc_get_volsw, wm5110_put_dre),
SOC_DOUBLE_EXT("HPOUT3 DRE Switch", ARIZONA_DRE_ENABLE,
ARIZONA_DRE3L_ENA_SHIFT, ARIZONA_DRE3R_ENA_SHIFT, 1, 0,
snd_soc_get_volsw, wm5110_put_dre),
ARIZONA_DRE3L_ENA_SHIFT, ARIZONA_DRE3R_ENA_SHIFT, 1, 0,
snd_soc_get_volsw, wm5110_put_dre),
SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
......@@ -1036,7 +1042,7 @@ ARIZONA_MUX_ENUMS(ISRC3DEC2, ARIZONA_ISRC3DEC2MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC3DEC3, ARIZONA_ISRC3DEC3MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC3DEC4, ARIZONA_ISRC3DEC4MIX_INPUT_1_SOURCE);
static const char *wm5110_aec_loopback_texts[] = {
static const char * const wm5110_aec_loopback_texts[] = {
"HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "HPOUT3L", "HPOUT3R",
"SPKOUTL", "SPKOUTR", "SPKDAT1L", "SPKDAT1R", "SPKDAT2L", "SPKDAT2R",
};
......@@ -1274,18 +1280,17 @@ SND_SOC_DAPM_PGA("ISRC3DEC4", ARIZONA_ISRC_3_CTRL_3,
ARIZONA_ISRC3_DEC3_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
&wm5110_aec_loopback_mux),
ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0, &wm5110_aec_loopback_mux),
SND_SOC_DAPM_SUPPLY("RXANC NG External Clock", SND_SOC_NOPM,
ARIZONA_EXT_NG_SEL_SET_SHIFT, 0, arizona_anc_ev,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
ARIZONA_EXT_NG_SEL_SET_SHIFT, 0, arizona_anc_ev,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_PGA("RXANCL NG External", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("RXANCR NG External", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("RXANC NG Clock", SND_SOC_NOPM,
ARIZONA_CLK_NG_ENA_SET_SHIFT, 0, arizona_anc_ev,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
ARIZONA_CLK_NG_ENA_SET_SHIFT, 0, arizona_anc_ev,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_PGA("RXANCL NG Internal", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("RXANCR NG Internal", SND_SOC_NOPM, 0, 0, NULL, 0),
......@@ -2034,10 +2039,10 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
{ "DSP3 Voice Trigger", "Switch", "DSP3" },
};
static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
unsigned int Fref, unsigned int Fout)
static int wm5110_set_fll(struct snd_soc_component *component, int fll_id,
int source, unsigned int Fref, unsigned int Fout)
{
struct wm5110_priv *wm5110 = snd_soc_codec_get_drvdata(codec);
struct wm5110_priv *wm5110 = snd_soc_component_get_drvdata(component);
switch (fll_id) {
case WM5110_FLL1:
......@@ -2278,33 +2283,32 @@ static irqreturn_t wm5110_adsp2_irq(int irq, void *data)
return IRQ_HANDLED;
}
static int wm5110_codec_probe(struct snd_soc_codec *codec)
static int wm5110_component_probe(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct wm5110_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->core.arizona;
int i, ret;
arizona->dapm = dapm;
snd_soc_codec_init_regmap(codec, arizona->regmap);
snd_soc_component_init_regmap(component, arizona->regmap);
ret = arizona_init_spk(codec);
ret = arizona_init_spk(component);
if (ret < 0)
return ret;
arizona_init_gpio(codec);
arizona_init_mono(codec);
arizona_init_gpio(component);
arizona_init_mono(component);
for (i = 0; i < WM5110_NUM_ADSP; ++i) {
ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec);
ret = wm_adsp2_component_probe(&priv->core.adsp[i], component);
if (ret)
goto err_adsp2_codec_probe;
}
ret = snd_soc_add_codec_controls(codec,
arizona_adsp2_rate_controls,
WM5110_NUM_ADSP);
ret = snd_soc_add_component_controls(component,
arizona_adsp2_rate_controls,
WM5110_NUM_ADSP);
if (ret)
goto err_adsp2_codec_probe;
......@@ -2314,22 +2318,20 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
err_adsp2_codec_probe:
for (--i; i >= 0; --i)
wm_adsp2_codec_remove(&priv->core.adsp[i], codec);
wm_adsp2_component_remove(&priv->core.adsp[i], component);
return ret;
}
static int wm5110_codec_remove(struct snd_soc_codec *codec)
static void wm5110_component_remove(struct snd_soc_component *component)
{
struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
struct wm5110_priv *priv = snd_soc_component_get_drvdata(component);
int i;
for (i = 0; i < WM5110_NUM_ADSP; ++i)
wm_adsp2_codec_remove(&priv->core.adsp[i], codec);
wm_adsp2_component_remove(&priv->core.adsp[i], component);
priv->core.arizona->dapm = NULL;
return 0;
}
#define WM5110_DIG_VU 0x0200
......@@ -2359,25 +2361,22 @@ static struct snd_compr_ops wm5110_compr_ops = {
.copy = wm_adsp_compr_copy,
};
static const struct snd_soc_codec_driver soc_codec_dev_wm5110 = {
.probe = wm5110_codec_probe,
.remove = wm5110_codec_remove,
.idle_bias_off = true,
.set_sysclk = arizona_set_sysclk,
.set_pll = wm5110_set_fll,
.component_driver = {
.name = DRV_NAME,
.compr_ops = &wm5110_compr_ops,
.controls = wm5110_snd_controls,
.num_controls = ARRAY_SIZE(wm5110_snd_controls),
.dapm_widgets = wm5110_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm5110_dapm_widgets),
.dapm_routes = wm5110_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(wm5110_dapm_routes),
},
static const struct snd_soc_component_driver soc_component_dev_wm5110 = {
.probe = wm5110_component_probe,
.remove = wm5110_component_remove,
.set_sysclk = arizona_set_sysclk,
.set_pll = wm5110_set_fll,
.name = DRV_NAME,
.compr_ops = &wm5110_compr_ops,
.controls = wm5110_snd_controls,
.num_controls = ARRAY_SIZE(wm5110_snd_controls),
.dapm_widgets = wm5110_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm5110_dapm_widgets),
.dapm_routes = wm5110_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(wm5110_dapm_routes),
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static int wm5110_probe(struct platform_device *pdev)
......@@ -2465,10 +2464,12 @@ static int wm5110_probe(struct platform_device *pdev)
if (ret < 0)
goto err_dsp_irq;
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110,
wm5110_dai, ARRAY_SIZE(wm5110_dai));
ret = devm_snd_soc_register_component(&pdev->dev,
&soc_component_dev_wm5110,
wm5110_dai,
ARRAY_SIZE(wm5110_dai));
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
dev_err(&pdev->dev, "Failed to register component: %d\n", ret);
goto err_spk_irqs;
}
......@@ -2488,7 +2489,6 @@ static int wm5110_remove(struct platform_device *pdev)
struct arizona *arizona = wm5110->core.arizona;
int i;
snd_soc_unregister_codec(&pdev->dev);
pm_runtime_disable(&pdev->dev);
for (i = 0; i < WM5110_NUM_ADSP; i++)
......
......@@ -84,8 +84,8 @@ static const struct reg_default wm8997_sysclk_reva_patch[] = {
static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
struct regmap *regmap = arizona->regmap;
const struct reg_default *patch = NULL;
int i, patch_size;
......@@ -118,7 +118,7 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,
return arizona_dvfs_sysclk_ev(w, kcontrol, event);
}
static const char *wm8997_osr_text[] = {
static const char * const wm8997_osr_text[] = {
"Low power", "Normal", "High performance",
};
......@@ -609,8 +609,7 @@ SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0,
ARIZONA_SLIMRX8_ENA_SHIFT, 0),
SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
&wm8997_aec_loopback_mux),
ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0, &wm8997_aec_loopback_mux),
SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
......@@ -927,10 +926,10 @@ static const struct snd_soc_dapm_route wm8997_dapm_routes[] = {
{ "MICSUPP", NULL, "SYSCLK" },
};
static int wm8997_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
unsigned int Fref, unsigned int Fout)
static int wm8997_set_fll(struct snd_soc_component *component, int fll_id,
int source, unsigned int Fref, unsigned int Fout)
{
struct wm8997_priv *wm8997 = snd_soc_codec_get_drvdata(codec);
struct wm8997_priv *wm8997 = snd_soc_component_get_drvdata(component);
switch (fll_id) {
case WM8997_FLL1:
......@@ -1057,17 +1056,16 @@ static struct snd_soc_dai_driver wm8997_dai[] = {
},
};
static int wm8997_codec_probe(struct snd_soc_codec *codec)
static int wm8997_component_probe(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct wm8997_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->core.arizona;
int ret;
snd_soc_codec_init_regmap(codec, arizona->regmap);
snd_soc_component_init_regmap(component, arizona->regmap);
ret = arizona_init_spk(codec);
ret = arizona_init_spk(component);
if (ret < 0)
return ret;
......@@ -1078,13 +1076,11 @@ static int wm8997_codec_probe(struct snd_soc_codec *codec)
return 0;
}
static int wm8997_codec_remove(struct snd_soc_codec *codec)
static void wm8997_component_remove(struct snd_soc_component *component)
{
struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec);
struct wm8997_priv *priv = snd_soc_component_get_drvdata(component);
priv->core.arizona->dapm = NULL;
return 0;
}
#define WM8997_DIG_VU 0x0200
......@@ -1098,23 +1094,20 @@ static unsigned int wm8997_digital_vu[] = {
ARIZONA_DAC_DIGITAL_VOLUME_5R,
};
static const struct snd_soc_codec_driver soc_codec_dev_wm8997 = {
.probe = wm8997_codec_probe,
.remove = wm8997_codec_remove,
.idle_bias_off = true,
.set_sysclk = arizona_set_sysclk,
.set_pll = wm8997_set_fll,
.component_driver = {
.controls = wm8997_snd_controls,
.num_controls = ARRAY_SIZE(wm8997_snd_controls),
.dapm_widgets = wm8997_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm8997_dapm_widgets),
.dapm_routes = wm8997_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(wm8997_dapm_routes),
},
static const struct snd_soc_component_driver soc_component_dev_wm8997 = {
.probe = wm8997_component_probe,
.remove = wm8997_component_remove,
.set_sysclk = arizona_set_sysclk,
.set_pll = wm8997_set_fll,
.controls = wm8997_snd_controls,
.num_controls = ARRAY_SIZE(wm8997_snd_controls),
.dapm_widgets = wm8997_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm8997_dapm_widgets),
.dapm_routes = wm8997_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(wm8997_dapm_routes),
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static int wm8997_probe(struct platform_device *pdev)
......@@ -1178,10 +1171,12 @@ static int wm8997_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8997,
wm8997_dai, ARRAY_SIZE(wm8997_dai));
ret = devm_snd_soc_register_component(&pdev->dev,
&soc_component_dev_wm8997,
wm8997_dai,
ARRAY_SIZE(wm8997_dai));
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
dev_err(&pdev->dev, "Failed to register component: %d\n", ret);
goto err_spk_irqs;
}
......@@ -1196,7 +1191,6 @@ static int wm8997_remove(struct platform_device *pdev)
struct wm8997_priv *wm8997 = platform_get_drvdata(pdev);
struct arizona *arizona = wm8997->core.arizona;
snd_soc_unregister_codec(&pdev->dev);
pm_runtime_disable(&pdev->dev);
arizona_free_spk_irqs(arizona);
......
......@@ -41,12 +41,12 @@ static int wm8998_asrc_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
unsigned int val;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
val = snd_soc_read(codec, ARIZONA_ASRC_RATE1);
val = snd_soc_component_read32(component, ARIZONA_ASRC_RATE1);
val &= ARIZONA_ASRC_RATE1_MASK;
val >>= ARIZONA_ASRC_RATE1_SHIFT;
......@@ -54,23 +54,23 @@ static int wm8998_asrc_ev(struct snd_soc_dapm_widget *w,
case 0:
case 1:
case 2:
val = snd_soc_read(codec,
val = snd_soc_component_read32(component,
ARIZONA_SAMPLE_RATE_1 + val);
if (val >= 0x11) {
dev_warn(codec->dev,
dev_warn(component->dev,
"Unsupported ASRC rate1 (%s)\n",
arizona_sample_rate_val_to_name(val));
return -EINVAL;
}
break;
default:
dev_err(codec->dev,
dev_err(component->dev,
"Illegal ASRC rate1 selector (0x%x)\n",
val);
return -EINVAL;
}
val = snd_soc_read(codec, ARIZONA_ASRC_RATE2);
val = snd_soc_component_read32(component, ARIZONA_ASRC_RATE2);
val &= ARIZONA_ASRC_RATE2_MASK;
val >>= ARIZONA_ASRC_RATE2_SHIFT;
......@@ -78,17 +78,17 @@ static int wm8998_asrc_ev(struct snd_soc_dapm_widget *w,
case 8:
case 9:
val -= 0x8;
val = snd_soc_read(codec,
val = snd_soc_component_read32(component,
ARIZONA_ASYNC_SAMPLE_RATE_1 + val);
if (val >= 0x11) {
dev_warn(codec->dev,
dev_warn(component->dev,
"Unsupported ASRC rate2 (%s)\n",
arizona_sample_rate_val_to_name(val));
return -EINVAL;
}
break;
default:
dev_err(codec->dev,
dev_err(component->dev,
"Illegal ASRC rate2 selector (0x%x)\n",
val);
return -EINVAL;
......@@ -104,9 +104,9 @@ static int wm8998_asrc_ev(struct snd_soc_dapm_widget *w,
static int wm8998_inmux_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct wm8998_priv *wm8998 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct wm8998_priv *wm8998 = snd_soc_component_get_drvdata(component);
struct arizona *arizona = wm8998->core.arizona;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int mode_reg, mode_index;
......@@ -137,11 +137,13 @@ static int wm8998_inmux_put(struct snd_kcontrol *kcontrol,
if (inmode & ARIZONA_INMODE_SE)
src_val |= 1 << ARIZONA_IN1L_SRC_SE_SHIFT;
snd_soc_update_bits(codec, mode_reg, ARIZONA_IN1_MODE_MASK, mode_val);
snd_soc_component_update_bits(component, mode_reg,
ARIZONA_IN1_MODE_MASK, mode_val);
snd_soc_update_bits(codec, e->reg,
ARIZONA_IN1L_SRC_MASK | ARIZONA_IN1L_SRC_SE_MASK,
src_val);
snd_soc_component_update_bits(component, e->reg,
ARIZONA_IN1L_SRC_MASK |
ARIZONA_IN1L_SRC_SE_MASK,
src_val);
return snd_soc_dapm_mux_update_power(dapm, kcontrol,
ucontrol->value.enumerated.item[0],
......@@ -322,7 +324,7 @@ SOC_DOUBLE_R("HPOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
SOC_DOUBLE_R("LINEOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_2L,
ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_MUTE_SHIFT, 1, 1),
SOC_SINGLE("EPOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_3L,
ARIZONA_OUT3L_MUTE_SHIFT, 1, 1),
ARIZONA_OUT3L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L,
ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("SPKDAT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_5L,
......@@ -335,7 +337,7 @@ SOC_DOUBLE_R_TLV("LINEOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_2L,
ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_SINGLE_TLV("EPOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_3L,
ARIZONA_OUT3L_VOL_SHIFT, 0xbf, 0, digital_tlv),
ARIZONA_OUT3L_VOL_SHIFT, 0xbf, 0, digital_tlv),
SOC_DOUBLE_R_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L,
ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_VOL_SHIFT,
0xbf, 0, digital_tlv),
......@@ -615,12 +617,12 @@ SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3,
ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_MUX("AEC1 Loopback", ARIZONA_DAC_AEC_CONTROL_1,
ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
&wm8998_aec_loopback_mux[0]),
ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
&wm8998_aec_loopback_mux[0]),
SND_SOC_DAPM_MUX("AEC2 Loopback", ARIZONA_DAC_AEC_CONTROL_2,
ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
&wm8998_aec_loopback_mux[1]),
ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
&wm8998_aec_loopback_mux[1]),
SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
......@@ -739,9 +741,9 @@ SND_SOC_DAPM_PGA_E("OUT5R", ARIZONA_OUTPUT_ENABLES_1,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA("SPD1TX1", ARIZONA_SPD1_TX_CONTROL,
ARIZONA_SPD1_VAL1_SHIFT, 0, NULL, 0),
ARIZONA_SPD1_VAL1_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("SPD1TX2", ARIZONA_SPD1_TX_CONTROL,
ARIZONA_SPD1_VAL2_SHIFT, 0, NULL, 0),
ARIZONA_SPD1_VAL2_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_OUT_DRV("SPD1", ARIZONA_SPD1_TX_CONTROL,
ARIZONA_SPD1_ENA_SHIFT, 0, NULL, 0),
......@@ -1249,10 +1251,10 @@ static struct snd_soc_dai_driver wm8998_dai[] = {
},
};
static int wm8998_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
unsigned int Fref, unsigned int Fout)
static int wm8998_set_fll(struct snd_soc_component *component, int fll_id,
int source, unsigned int Fref, unsigned int Fout)
{
struct wm8998_priv *wm8998 = snd_soc_codec_get_drvdata(codec);
struct wm8998_priv *wm8998 = snd_soc_component_get_drvdata(component);
switch (fll_id) {
case WM8998_FLL1:
......@@ -1270,35 +1272,32 @@ static int wm8998_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
}
}
static int wm8998_codec_probe(struct snd_soc_codec *codec)
static int wm8998_component_probe(struct snd_soc_component *component)
{
struct wm8998_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
struct wm8998_priv *priv = snd_soc_component_get_drvdata(component);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct arizona *arizona = priv->core.arizona;
int ret;
arizona->dapm = dapm;
snd_soc_codec_init_regmap(codec, arizona->regmap);
snd_soc_component_init_regmap(component, arizona->regmap);
ret = arizona_init_spk(codec);
ret = arizona_init_spk(component);
if (ret < 0)
return ret;
arizona_init_gpio(codec);
arizona_init_gpio(component);
snd_soc_component_disable_pin(component, "HAPTICS");
return 0;
}
static int wm8998_codec_remove(struct snd_soc_codec *codec)
static void wm8998_component_remove(struct snd_soc_component *component)
{
struct wm8998_priv *priv = snd_soc_codec_get_drvdata(codec);
struct wm8998_priv *priv = snd_soc_component_get_drvdata(component);
priv->core.arizona->dapm = NULL;
return 0;
}
#define WM8998_DIG_VU 0x0200
......@@ -1315,23 +1314,20 @@ static unsigned int wm8998_digital_vu[] = {
ARIZONA_DAC_DIGITAL_VOLUME_5R,
};
static const struct snd_soc_codec_driver soc_codec_dev_wm8998 = {
.probe = wm8998_codec_probe,
.remove = wm8998_codec_remove,
.idle_bias_off = true,
.set_sysclk = arizona_set_sysclk,
.set_pll = wm8998_set_fll,
.component_driver = {
.controls = wm8998_snd_controls,
.num_controls = ARRAY_SIZE(wm8998_snd_controls),
.dapm_widgets = wm8998_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm8998_dapm_widgets),
.dapm_routes = wm8998_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(wm8998_dapm_routes),
},
static const struct snd_soc_component_driver soc_component_dev_wm8998 = {
.probe = wm8998_component_probe,
.remove = wm8998_component_remove,
.set_sysclk = arizona_set_sysclk,
.set_pll = wm8998_set_fll,
.controls = wm8998_snd_controls,
.num_controls = ARRAY_SIZE(wm8998_snd_controls),
.dapm_widgets = wm8998_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm8998_dapm_widgets),
.dapm_routes = wm8998_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(wm8998_dapm_routes),
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static int wm8998_probe(struct platform_device *pdev)
......@@ -1384,10 +1380,12 @@ static int wm8998_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8998,
wm8998_dai, ARRAY_SIZE(wm8998_dai));
ret = devm_snd_soc_register_component(&pdev->dev,
&soc_component_dev_wm8998,
wm8998_dai,
ARRAY_SIZE(wm8998_dai));
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
dev_err(&pdev->dev, "Failed to register component: %d\n", ret);
goto err_spk_irqs;
}
......@@ -1404,7 +1402,6 @@ static int wm8998_remove(struct platform_device *pdev)
struct wm8998_priv *wm8998 = platform_get_drvdata(pdev);
struct arizona *arizona = wm8998->core.arizona;
snd_soc_unregister_codec(&pdev->dev);
pm_runtime_disable(&pdev->dev);
arizona_free_spk_irqs(arizona);
......
......@@ -605,13 +605,13 @@ static const struct {
};
static void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
struct snd_soc_codec *codec)
struct snd_soc_component *component)
{
struct dentry *root = NULL;
char *root_name;
int i;
if (!codec->component.debugfs_root) {
if (!component->debugfs_root) {
adsp_err(dsp, "No codec debugfs root\n");
goto err;
}
......@@ -621,7 +621,7 @@ static void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
goto err;
snprintf(root_name, PAGE_SIZE, "dsp%d", dsp->num);
root = debugfs_create_dir(root_name, codec->component.debugfs_root);
root = debugfs_create_dir(root_name, component->debugfs_root);
kfree(root_name);
if (!root)
......@@ -662,7 +662,7 @@ static void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp)
}
#else
static inline void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
struct snd_soc_codec *codec)
struct snd_soc_component *component)
{
}
......@@ -688,9 +688,9 @@ static inline void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
ucontrol->value.enumerated.item[0] = dsp[e->shift_l].fw;
......@@ -700,9 +700,9 @@ static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
int ret = 0;
if (ucontrol->value.enumerated.item[0] == dsp[e->shift_l].fw)
......@@ -1215,7 +1215,7 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
break;
}
ret = snd_soc_add_codec_controls(dsp->codec, kcontrol, 1);
ret = snd_soc_add_component_controls(dsp->component, kcontrol, 1);
if (ret < 0)
goto err_kcontrol;
......@@ -2398,14 +2398,14 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
struct wm_adsp *dsp = &dsps[w->shift];
struct wm_coeff_ctl *ctl;
int ret;
unsigned int val;
dsp->codec = codec;
dsp->component = component;
mutex_lock(&dsp->pwr_lock);
......@@ -2635,8 +2635,8 @@ static void wm_adsp2_set_dspclk(struct wm_adsp *dsp, unsigned int freq)
int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = dsp->preloaded;
......@@ -2647,9 +2647,9 @@ EXPORT_SYMBOL_GPL(wm_adsp2_preloader_get);
int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
char preload[32];
......@@ -2685,8 +2685,8 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event,
unsigned int freq)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
struct wm_adsp *dsp = &dsps[w->shift];
struct wm_coeff_ctl *ctl;
......@@ -2728,8 +2728,8 @@ EXPORT_SYMBOL_GPL(wm_adsp2_early_event);
int wm_adsp2_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
struct wm_adsp *dsp = &dsps[w->shift];
int ret;
......@@ -2843,31 +2843,31 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
}
EXPORT_SYMBOL_GPL(wm_adsp2_event);
int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec)
int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
char preload[32];
snprintf(preload, ARRAY_SIZE(preload), "DSP%d Preload", dsp->num);
snd_soc_dapm_disable_pin(dapm, preload);
wm_adsp2_init_debugfs(dsp, codec);
wm_adsp2_init_debugfs(dsp, component);
dsp->codec = codec;
dsp->component = component;
return snd_soc_add_codec_controls(codec,
return snd_soc_add_component_controls(component,
&wm_adsp_fw_controls[dsp->num - 1],
1);
}
EXPORT_SYMBOL_GPL(wm_adsp2_codec_probe);
EXPORT_SYMBOL_GPL(wm_adsp2_component_probe);
int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec)
int wm_adsp2_component_remove(struct wm_adsp *dsp, struct snd_soc_component *component)
{
wm_adsp2_cleanup_debugfs(dsp);
return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp2_codec_remove);
EXPORT_SYMBOL_GPL(wm_adsp2_component_remove);
int wm_adsp2_init(struct wm_adsp *dsp)
{
......
......@@ -62,7 +62,7 @@ struct wm_adsp {
int type;
struct device *dev;
struct regmap *regmap;
struct snd_soc_codec *codec;
struct snd_soc_component *component;
int base;
int sysclk_reg;
......@@ -126,8 +126,8 @@ extern const struct snd_kcontrol_new wm_adsp_fw_controls[];
int wm_adsp1_init(struct wm_adsp *dsp);
int wm_adsp2_init(struct wm_adsp *dsp);
void wm_adsp2_remove(struct wm_adsp *dsp);
int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec);
int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec);
int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component);
int wm_adsp2_component_remove(struct wm_adsp *dsp, struct snd_soc_component *component);
int wm_adsp1_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
......
......@@ -31,7 +31,7 @@
#define TM2_DAI_AIF2 1
struct tm2_machine_priv {
struct snd_soc_codec *codec;
struct snd_soc_component *component;
unsigned int sysclk_rate;
struct gpio_desc *gpio_mic_bias;
};
......@@ -39,33 +39,33 @@ struct tm2_machine_priv {
static int tm2_start_sysclk(struct snd_soc_card *card)
{
struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
struct snd_soc_codec *codec = priv->codec;
struct snd_soc_component *component = priv->component;
int ret;
ret = snd_soc_codec_set_pll(codec, WM5110_FLL1_REFCLK,
ret = snd_soc_component_set_pll(component, WM5110_FLL1_REFCLK,
ARIZONA_FLL_SRC_MCLK1,
MCLK_RATE,
priv->sysclk_rate);
if (ret < 0) {
dev_err(codec->dev, "Failed to set FLL1 source: %d\n", ret);
dev_err(component->dev, "Failed to set FLL1 source: %d\n", ret);
return ret;
}
ret = snd_soc_codec_set_pll(codec, WM5110_FLL1,
ret = snd_soc_component_set_pll(component, WM5110_FLL1,
ARIZONA_FLL_SRC_MCLK1,
MCLK_RATE,
priv->sysclk_rate);
if (ret < 0) {
dev_err(codec->dev, "Failed to start FLL1: %d\n", ret);
dev_err(component->dev, "Failed to start FLL1: %d\n", ret);
return ret;
}
ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_SYSCLK,
ARIZONA_CLK_SRC_FLL1,
priv->sysclk_rate,
SND_SOC_CLOCK_IN);
if (ret < 0) {
dev_err(codec->dev, "Failed to set SYSCLK source: %d\n", ret);
dev_err(component->dev, "Failed to set SYSCLK source: %d\n", ret);
return ret;
}
......@@ -75,19 +75,19 @@ static int tm2_start_sysclk(struct snd_soc_card *card)
static int tm2_stop_sysclk(struct snd_soc_card *card)
{
struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
struct snd_soc_codec *codec = priv->codec;
struct snd_soc_component *component = priv->component;
int ret;
ret = snd_soc_codec_set_pll(codec, WM5110_FLL1, 0, 0, 0);
ret = snd_soc_component_set_pll(component, WM5110_FLL1, 0, 0, 0);
if (ret < 0) {
dev_err(codec->dev, "Failed to stop FLL1: %d\n", ret);
dev_err(component->dev, "Failed to stop FLL1: %d\n", ret);
return ret;
}
ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_SYSCLK,
ARIZONA_CLK_SRC_FLL1, 0, 0);
if (ret < 0) {
dev_err(codec->dev, "Failed to stop SYSCLK: %d\n", ret);
dev_err(component->dev, "Failed to stop SYSCLK: %d\n", ret);
return ret;
}
......@@ -98,7 +98,7 @@ static int tm2_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_component *component = rtd->codec_dai->component;
struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(rtd->card);
switch (params_rate(params)) {
......@@ -123,7 +123,7 @@ static int tm2_aif1_hw_params(struct snd_pcm_substream *substream,
priv->sysclk_rate = 135475200U;
break;
default:
dev_err(codec->dev, "Not supported sample rate: %d\n",
dev_err(component->dev, "Not supported sample rate: %d\n",
params_rate(params));
return -EINVAL;
}
......@@ -139,7 +139,7 @@ static int tm2_aif2_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_component *component = rtd->codec_dai->component;
unsigned int asyncclk_rate;
int ret;
......@@ -155,35 +155,35 @@ static int tm2_aif2_hw_params(struct snd_pcm_substream *substream,
asyncclk_rate = 45158400U;
break;
default:
dev_err(codec->dev, "Not supported sample rate: %d\n",
dev_err(component->dev, "Not supported sample rate: %d\n",
params_rate(params));
return -EINVAL;
}
ret = snd_soc_codec_set_pll(codec, WM5110_FLL2_REFCLK,
ret = snd_soc_component_set_pll(component, WM5110_FLL2_REFCLK,
ARIZONA_FLL_SRC_MCLK1,
MCLK_RATE,
asyncclk_rate);
if (ret < 0) {
dev_err(codec->dev, "Failed to set FLL2 source: %d\n", ret);
dev_err(component->dev, "Failed to set FLL2 source: %d\n", ret);
return ret;
}
ret = snd_soc_codec_set_pll(codec, WM5110_FLL2,
ret = snd_soc_component_set_pll(component, WM5110_FLL2,
ARIZONA_FLL_SRC_MCLK1,
MCLK_RATE,
asyncclk_rate);
if (ret < 0) {
dev_err(codec->dev, "Failed to start FLL2: %d\n", ret);
dev_err(component->dev, "Failed to start FLL2: %d\n", ret);
return ret;
}
ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK,
ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_ASYNCCLK,
ARIZONA_CLK_SRC_FLL2,
asyncclk_rate,
SND_SOC_CLOCK_IN);
if (ret < 0) {
dev_err(codec->dev, "Failed to set ASYNCCLK source: %d\n", ret);
dev_err(component->dev, "Failed to set ASYNCCLK source: %d\n", ret);
return ret;
}
......@@ -193,14 +193,14 @@ static int tm2_aif2_hw_params(struct snd_pcm_substream *substream,
static int tm2_aif2_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_component *component = rtd->codec_dai->component;
int ret;
/* disable FLL2 */
ret = snd_soc_codec_set_pll(codec, WM5110_FLL2, ARIZONA_FLL_SRC_MCLK1,
ret = snd_soc_component_set_pll(component, WM5110_FLL2, ARIZONA_FLL_SRC_MCLK1,
0, 0);
if (ret < 0)
dev_err(codec->dev, "Failed to stop FLL2: %d\n", ret);
dev_err(component->dev, "Failed to stop FLL2: %d\n", ret);
return ret;
}
......@@ -322,7 +322,7 @@ static int tm2_late_probe(struct snd_soc_card *card)
rtd = snd_soc_get_pcm_runtime(card, card->dai_link[TM2_DAI_AIF1].name);
aif1_dai = rtd->codec_dai;
priv->codec = rtd->codec;
priv->component = rtd->codec_dai->component;
ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0);
if (ret < 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment