Skip to content

Commit

Permalink
Merge remote-tracking branches 'asoc/topic/stac9766', 'asoc/topic/sti…
Browse files Browse the repository at this point in the history
…', 'asoc/topic/sti-codec', 'asoc/topic/sunxi' and 'asoc/topic/tegra' into asoc-next
  • Loading branch information
broonie committed Dec 12, 2016
6 parents f617134 + 7aacbc7 + 4db61af + 92591ef + 4a15b24 + 8a7a282 commit da644e2
Show file tree
Hide file tree
Showing 23 changed files with 1,816 additions and 463 deletions.
65 changes: 63 additions & 2 deletions Documentation/devicetree/bindings/sound/sun4i-codec.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
* Allwinner A10 Codec

Required properties:
- compatible: must be either "allwinner,sun4i-a10-codec" or
"allwinner,sun7i-a20-codec"
- compatible: must be one of the following compatibles:
- "allwinner,sun4i-a10-codec"
- "allwinner,sun6i-a31-codec"
- "allwinner,sun7i-a20-codec"
- "allwinner,sun8i-a23-codec"
- "allwinner,sun8i-h3-codec"
- reg: must contain the registers location and length
- interrupts: must contain the codec interrupt
- dmas: DMA channels for tx and rx dma. See the DMA client binding,
Expand All @@ -17,6 +21,43 @@ Required properties:
Optional properties:
- allwinner,pa-gpios: gpio to enable external amplifier

Required properties for the following compatibles:
- "allwinner,sun6i-a31-codec"
- "allwinner,sun8i-a23-codec"
- "allwinner,sun8i-h3-codec"
- resets: phandle to the reset control for this device
- allwinner,audio-routing: A list of the connections between audio components.
Each entry is a pair of strings, the first being the
connection's sink, the second being the connection's
source. Valid names include:

Audio pins on the SoC:
"HP"
"HPCOM"
"LINEIN"
"LINEOUT" (not on sun8i-a23)
"MIC1"
"MIC2"
"MIC3" (sun6i-a31 only)

Microphone biases from the SoC:
"HBIAS"
"MBIAS"

Board connectors:
"Headphone"
"Headset Mic"
"Line In"
"Line Out"
"Mic"
"Speaker"

Required properties for the following compatibles:
- "allwinner,sun8i-a23-codec"
- "allwinner,sun8i-h3-codec"
- allwinner,codec-analog-controls: A phandle to the codec analog controls
block in the PRCM.

Example:
codec: codec@01c22c00 {
#sound-dai-cells = <0>;
Expand All @@ -28,3 +69,23 @@ codec: codec@01c22c00 {
dmas = <&dma 0 19>, <&dma 0 19>;
dma-names = "rx", "tx";
};

codec: codec@01c22c00 {
#sound-dai-cells = <0>;
compatible = "allwinner,sun6i-a31-codec";
reg = <0x01c22c00 0x98>;
interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_APB1_CODEC>, <&ccu CLK_CODEC>;
clock-names = "apb", "codec";
resets = <&ccu RST_APB1_CODEC>;
dmas = <&dma 15>, <&dma 15>;
dma-names = "rx", "tx";
allwinner,audio-routing =
"Headphone", "HP",
"Speaker", "LINEOUT",
"LINEIN", "Line In",
"MIC1", "MBIAS",
"MIC1", "Mic",
"MIC2", "HBIAS",
"MIC2", "Headset Mic";
};
16 changes: 16 additions & 0 deletions Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
* Allwinner Codec Analog Controls

Required properties:
- compatible: must be one of the following compatibles:
- "allwinner,sun8i-a23-codec-analog"
- "allwinner,sun8i-h3-codec-analog"

Required properties if not a sub-node of the PRCM node:
- reg: must contain the registers location and length

Example:
prcm: prcm@01f01400 {
codec_analog: codec-analog {
compatible = "allwinner,sun8i-a23-codec-analog";
};
};
162 changes: 72 additions & 90 deletions sound/soc/codecs/stac9766.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
Expand All @@ -26,31 +27,56 @@
#include <sound/soc.h>
#include <sound/tlv.h>

#include "stac9766.h"

#define STAC9766_VENDOR_ID 0x83847666
#define STAC9766_VENDOR_ID_MASK 0xffffffff

/*
* STAC9766 register cache
*/
static const u16 stac9766_reg[] = {
0x6A90, 0x8000, 0x8000, 0x8000, /* 6 */
0x0000, 0x0000, 0x8008, 0x8008, /* e */
0x8808, 0x8808, 0x8808, 0x8808, /* 16 */
0x8808, 0x0000, 0x8000, 0x0000, /* 1e */
0x0000, 0x0000, 0x0000, 0x000f, /* 26 */
0x0a05, 0x0400, 0xbb80, 0x0000, /* 2e */
0x0000, 0xbb80, 0x0000, 0x0000, /* 36 */
0x0000, 0x2000, 0x0000, 0x0100, /* 3e */
0x0000, 0x0000, 0x0080, 0x0000, /* 46 */
0x0000, 0x0000, 0x0003, 0xffff, /* 4e */
0x0000, 0x0000, 0x0000, 0x0000, /* 56 */
0x4000, 0x0000, 0x0000, 0x0000, /* 5e */
0x1201, 0xFFFF, 0xFFFF, 0x0000, /* 66 */
0x0000, 0x0000, 0x0000, 0x0000, /* 6e */
0x0000, 0x0000, 0x0000, 0x0006, /* 76 */
0x0000, 0x0000, 0x0000, 0x0000, /* 7e */
#define AC97_STAC_DA_CONTROL 0x6A
#define AC97_STAC_ANALOG_SPECIAL 0x6E
#define AC97_STAC_STEREO_MIC 0x78

static const struct reg_default stac9766_reg_defaults[] = {
{ 0x02, 0x8000 },
{ 0x04, 0x8000 },
{ 0x06, 0x8000 },
{ 0x0a, 0x0000 },
{ 0x0c, 0x8008 },
{ 0x0e, 0x8008 },
{ 0x10, 0x8808 },
{ 0x12, 0x8808 },
{ 0x14, 0x8808 },
{ 0x16, 0x8808 },
{ 0x18, 0x8808 },
{ 0x1a, 0x0000 },
{ 0x1c, 0x8000 },
{ 0x20, 0x0000 },
{ 0x22, 0x0000 },
{ 0x28, 0x0a05 },
{ 0x2c, 0xbb80 },
{ 0x32, 0xbb80 },
{ 0x3a, 0x2000 },
{ 0x3e, 0x0100 },
{ 0x4c, 0x0300 },
{ 0x4e, 0xffff },
{ 0x50, 0x0000 },
{ 0x52, 0x0000 },
{ 0x54, 0x0000 },
{ 0x6a, 0x0000 },
{ 0x6e, 0x1000 },
{ 0x72, 0x0000 },
{ 0x78, 0x0000 },
};

static const struct regmap_config stac9766_regmap_config = {
.reg_bits = 16,
.reg_stride = 2,
.val_bits = 16,
.max_register = 0x78,
.cache_type = REGCACHE_RBTREE,

.volatile_reg = regmap_ac97_default_volatile,

.reg_defaults = stac9766_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(stac9766_reg_defaults),
};

static const char *stac9766_record_mux[] = {"Mic", "CD", "Video", "AUX",
Expand Down Expand Up @@ -139,90 +165,39 @@ static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = {
SOC_ENUM("Pop Bypass Mux", stac9766_popbypass_enum),
};

static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int val)
{
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
u16 *cache = codec->reg_cache;

if (reg > AC97_STAC_PAGE0) {
stac9766_ac97_write(codec, AC97_INT_PAGING, 0);
soc_ac97_ops->write(ac97, reg, val);
stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
return 0;
}
if (reg / 2 >= ARRAY_SIZE(stac9766_reg))
return -EIO;

soc_ac97_ops->write(ac97, reg, val);
cache[reg / 2] = val;
return 0;
}

static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec,
unsigned int reg)
{
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
u16 val = 0, *cache = codec->reg_cache;

if (reg > AC97_STAC_PAGE0) {
stac9766_ac97_write(codec, AC97_INT_PAGING, 0);
val = soc_ac97_ops->read(ac97, reg - AC97_STAC_PAGE0);
stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
return val;
}
if (reg / 2 >= ARRAY_SIZE(stac9766_reg))
return -EIO;

if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 ||
reg == AC97_VENDOR_ID2) {

val = soc_ac97_ops->read(ac97, reg);
return val;
}
return cache[reg / 2];
}

static int ac97_analog_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned short reg, vra;

vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS);
unsigned short reg;

vra |= 0x1; /* enable variable rate audio */
vra &= ~0x4; /* disable SPDIF output */

stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra);
/* enable variable rate audio, disable SPDIF output */
snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x5, 0x1);

if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
reg = AC97_PCM_FRONT_DAC_RATE;
else
reg = AC97_PCM_LR_ADC_RATE;

return stac9766_ac97_write(codec, reg, runtime->rate);
return snd_soc_write(codec, reg, runtime->rate);
}

static int ac97_digital_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned short reg, vra;

stac9766_ac97_write(codec, AC97_SPDIF, 0x2002);
unsigned short reg;

vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS);
vra |= 0x5; /* Enable VRA and SPDIF out */
snd_soc_write(codec, AC97_SPDIF, 0x2002);

stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra);
/* Enable VRA and SPDIF out */
snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x5, 0x5);

reg = AC97_PCM_FRONT_DAC_RATE;

return stac9766_ac97_write(codec, reg, runtime->rate);
return snd_soc_write(codec, reg, runtime->rate);
}

static int stac9766_set_bias_level(struct snd_soc_codec *codec,
Expand All @@ -232,11 +207,11 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_ON: /* full On */
case SND_SOC_BIAS_PREPARE: /* partial On */
case SND_SOC_BIAS_STANDBY: /* Off, with power */
stac9766_ac97_write(codec, AC97_POWERDOWN, 0x0000);
snd_soc_write(codec, AC97_POWERDOWN, 0x0000);
break;
case SND_SOC_BIAS_OFF: /* Off, without power */
/* disable everything including AC link */
stac9766_ac97_write(codec, AC97_POWERDOWN, 0xffff);
snd_soc_write(codec, AC97_POWERDOWN, 0xffff);
break;
}
return 0;
Expand Down Expand Up @@ -300,21 +275,34 @@ static struct snd_soc_dai_driver stac9766_dai[] = {
static int stac9766_codec_probe(struct snd_soc_codec *codec)
{
struct snd_ac97 *ac97;
struct regmap *regmap;
int ret;

ac97 = snd_soc_new_ac97_codec(codec, STAC9766_VENDOR_ID,
STAC9766_VENDOR_ID_MASK);
if (IS_ERR(ac97))
return PTR_ERR(ac97);

regmap = regmap_init_ac97(ac97, &stac9766_regmap_config);
if (IS_ERR(regmap)) {
ret = PTR_ERR(regmap);
goto err_free_ac97;
}

snd_soc_codec_init_regmap(codec, regmap);
snd_soc_codec_set_drvdata(codec, ac97);

return 0;
err_free_ac97:
snd_soc_free_ac97_codec(ac97);
return ret;
}

static int stac9766_codec_remove(struct snd_soc_codec *codec)
{
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);

snd_soc_codec_exit_regmap(codec);
snd_soc_free_ac97_codec(ac97);
return 0;
}
Expand All @@ -324,17 +312,11 @@ static struct snd_soc_codec_driver soc_codec_dev_stac9766 = {
.controls = stac9766_snd_ac97_controls,
.num_controls = ARRAY_SIZE(stac9766_snd_ac97_controls),
},
.write = stac9766_ac97_write,
.read = stac9766_ac97_read,
.set_bias_level = stac9766_set_bias_level,
.suspend_bias_off = true,
.probe = stac9766_codec_probe,
.remove = stac9766_codec_remove,
.resume = stac9766_codec_resume,
.reg_cache_size = ARRAY_SIZE(stac9766_reg),
.reg_word_size = sizeof(u16),
.reg_cache_step = 2,
.reg_cache_default = stac9766_reg,
};

static int stac9766_probe(struct platform_device *pdev)
Expand Down
17 changes: 0 additions & 17 deletions sound/soc/codecs/stac9766.h

This file was deleted.

Loading

0 comments on commit da644e2

Please sign in to comment.