Skip to content

Commit

Permalink
ASoC: ac97: Support multi-platform AC'97
Browse files Browse the repository at this point in the history
Currently we can only have a single platform built in with AC'97 support
due to the use of a global variable to provide the bus operations. Fix
this by making that variable a pointer and having the bus drivers set the
operations prior to registering.

This is not a particularly good or nice approach but it avoids blocking
multiplatform and a real fix involves fixing the fairly deep problems
with AC'97 support - we should be converting it to a real bus.

Acked-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
  • Loading branch information
Mark Brown committed Jun 27, 2013
1 parent b49dff8 commit b047e1c
Show file tree
Hide file tree
Showing 20 changed files with 154 additions and 72 deletions.
4 changes: 3 additions & 1 deletion include/sound/soc.h
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ struct snd_soc_jack_gpio;

typedef int (*hw_write_t)(void *,const char* ,int);

extern struct snd_ac97_bus_ops soc_ac97_ops;
extern struct snd_ac97_bus_ops *soc_ac97_ops;

enum snd_soc_control_type {
SND_SOC_I2C = 1,
Expand Down Expand Up @@ -467,6 +467,8 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
struct snd_ac97_bus_ops *ops, int num);
void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);

int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);

/*
*Controls
*/
Expand Down
7 changes: 5 additions & 2 deletions sound/soc/au1x/ac97c.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,13 +179,12 @@ static void au1xac97c_ac97_cold_reset(struct snd_ac97 *ac97)
}

/* AC97 controller operations */
struct snd_ac97_bus_ops soc_ac97_ops = {
static struct snd_ac97_bus_ops ac97c_bus_ops = {
.read = au1xac97c_ac97_read,
.write = au1xac97c_ac97_write,
.reset = au1xac97c_ac97_cold_reset,
.warm_reset = au1xac97c_ac97_warm_reset,
};
EXPORT_SYMBOL_GPL(soc_ac97_ops); /* globals be gone! */

static int alchemy_ac97c_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
Expand Down Expand Up @@ -272,6 +271,10 @@ static int au1xac97c_drvprobe(struct platform_device *pdev)

platform_set_drvdata(pdev, ctx);

ret = snd_soc_set_ac97_ops(&ac97c_bus_ops);
if (ret)
return ret;

ret = snd_soc_register_component(&pdev->dev, &au1xac97c_component,
&au1xac97c_dai_driver, 1);
if (ret)
Expand Down
7 changes: 5 additions & 2 deletions sound/soc/au1x/psc-ac97.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,13 +201,12 @@ static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97)
}

/* AC97 controller operations */
struct snd_ac97_bus_ops soc_ac97_ops = {
static struct snd_ac97_bus_ops psc_ac97_ops = {
.read = au1xpsc_ac97_read,
.write = au1xpsc_ac97_write,
.reset = au1xpsc_ac97_cold_reset,
.warm_reset = au1xpsc_ac97_warm_reset,
};
EXPORT_SYMBOL_GPL(soc_ac97_ops);

static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
Expand Down Expand Up @@ -417,6 +416,10 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)

platform_set_drvdata(pdev, wd);

ret = snd_soc_set_ac97_ops(&psc_ac97_ops);
if (ret)
return ret;

ret = snd_soc_register_component(&pdev->dev, &au1xpsc_ac97_component,
&wd->dai_drv, 1);
if (ret)
Expand Down
11 changes: 9 additions & 2 deletions sound/soc/blackfin/bf5xx-ac97.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,13 +198,12 @@ static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97)
#endif
}

struct snd_ac97_bus_ops soc_ac97_ops = {
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,
};
EXPORT_SYMBOL_GPL(soc_ac97_ops);

#ifdef CONFIG_PM
static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
Expand Down Expand Up @@ -336,6 +335,12 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
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) {
Expand All @@ -350,6 +355,7 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
sport_config_err:
sport_done(sport_handle);
sport_err:
snd_soc_set_ac97_ops(NULL);

return ret;
}
Expand All @@ -360,6 +366,7 @@ static int asoc_bfin_ac97_remove(struct platform_device *pdev)

snd_soc_unregister_component(&pdev->dev);
sport_done(sport_handle);
snd_soc_set_ac97_ops(NULL);

return 0;
}
Expand Down
10 changes: 8 additions & 2 deletions sound/soc/cirrus/ep93xx-ac97.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,13 +237,12 @@ static irqreturn_t ep93xx_ac97_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}

struct snd_ac97_bus_ops soc_ac97_ops = {
static struct snd_ac97_bus_ops ep93xx_ac97_ops = {
.read = ep93xx_ac97_read,
.write = ep93xx_ac97_write,
.reset = ep93xx_ac97_cold_reset,
.warm_reset = ep93xx_ac97_warm_reset,
};
EXPORT_SYMBOL_GPL(soc_ac97_ops);

static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
Expand Down Expand Up @@ -395,6 +394,10 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
ep93xx_ac97_info = info;
platform_set_drvdata(pdev, info);

ret = snd_soc_set_ac97_ops(&ep93xx_ac97_ops);
if (ret)
goto fail;

ret = snd_soc_register_component(&pdev->dev, &ep93xx_ac97_component,
&ep93xx_ac97_dai, 1);
if (ret)
Expand All @@ -405,6 +408,7 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
fail:
platform_set_drvdata(pdev, NULL);
ep93xx_ac97_info = NULL;
snd_soc_set_ac97_ops(NULL);
return ret;
}

Expand All @@ -420,6 +424,8 @@ static int ep93xx_ac97_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
ep93xx_ac97_info = NULL;

snd_soc_set_ac97_ops(NULL);

return 0;
}

Expand Down
7 changes: 4 additions & 3 deletions sound/soc/codecs/ac97.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ static struct snd_soc_dai_driver ac97_dai = {
static unsigned int ac97_read(struct snd_soc_codec *codec,
unsigned int reg)
{
return soc_ac97_ops.read(codec->ac97, reg);
return soc_ac97_ops->read(codec->ac97, reg);
}

static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int val)
{
soc_ac97_ops.write(codec->ac97, reg, val);
soc_ac97_ops->write(codec->ac97, reg, val);
return 0;
}

Expand All @@ -79,7 +79,8 @@ static int ac97_soc_probe(struct snd_soc_codec *codec)
int ret;

/* add codec as bus device for standard ac97 */
ret = snd_ac97_bus(codec->card->snd_card, 0, &soc_ac97_ops, NULL, &ac97_bus);
ret = snd_ac97_bus(codec->card->snd_card, 0, soc_ac97_ops, NULL,
&ac97_bus);
if (ret < 0)
return ret;

Expand Down
12 changes: 6 additions & 6 deletions sound/soc/codecs/ad1980.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec,
case AC97_EXTENDED_STATUS:
case AC97_VENDOR_ID1:
case AC97_VENDOR_ID2:
return soc_ac97_ops.read(codec->ac97, reg);
return soc_ac97_ops->read(codec->ac97, reg);
default:
reg = reg >> 1;

Expand All @@ -124,7 +124,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
{
u16 *cache = codec->reg_cache;

soc_ac97_ops.write(codec->ac97, reg, val);
soc_ac97_ops->write(codec->ac97, reg, val);
reg = reg >> 1;
if (reg < ARRAY_SIZE(ad1980_reg))
cache[reg] = val;
Expand Down Expand Up @@ -154,13 +154,13 @@ static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
u16 retry_cnt = 0;

retry:
if (try_warm && soc_ac97_ops.warm_reset) {
soc_ac97_ops.warm_reset(codec->ac97);
if (try_warm && soc_ac97_ops->warm_reset) {
soc_ac97_ops->warm_reset(codec->ac97);
if (ac97_read(codec, AC97_RESET) == 0x0090)
return 1;
}

soc_ac97_ops.reset(codec->ac97);
soc_ac97_ops->reset(codec->ac97);
/* Set bit 16slot in register 74h, then every slot will has only 16
* bits. This command is sent out in 20bit mode, in which case the
* first nibble of data is eaten by the addr. (Tag is always 16 bit)*/
Expand All @@ -186,7 +186,7 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec)

printk(KERN_INFO "AD1980 SoC Audio Codec\n");

ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
if (ret < 0) {
printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
return ret;
Expand Down
22 changes: 11 additions & 11 deletions sound/soc/codecs/stac9766.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,14 +143,14 @@ static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg,

if (reg > AC97_STAC_PAGE0) {
stac9766_ac97_write(codec, AC97_INT_PAGING, 0);
soc_ac97_ops.write(codec->ac97, reg, val);
soc_ac97_ops->write(codec->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(codec->ac97, reg, val);
soc_ac97_ops->write(codec->ac97, reg, val);
cache[reg / 2] = val;
return 0;
}
Expand All @@ -162,7 +162,7 @@ static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec,

if (reg > AC97_STAC_PAGE0) {
stac9766_ac97_write(codec, AC97_INT_PAGING, 0);
val = soc_ac97_ops.read(codec->ac97, reg - AC97_STAC_PAGE0);
val = soc_ac97_ops->read(codec->ac97, reg - AC97_STAC_PAGE0);
stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
return val;
}
Expand All @@ -173,7 +173,7 @@ static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec,
reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 ||
reg == AC97_VENDOR_ID2) {

val = soc_ac97_ops.read(codec->ac97, reg);
val = soc_ac97_ops->read(codec->ac97, reg);
return val;
}
return cache[reg / 2];
Expand Down Expand Up @@ -240,15 +240,15 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec,

static int stac9766_reset(struct snd_soc_codec *codec, int try_warm)
{
if (try_warm && soc_ac97_ops.warm_reset) {
soc_ac97_ops.warm_reset(codec->ac97);
if (try_warm && soc_ac97_ops->warm_reset) {
soc_ac97_ops->warm_reset(codec->ac97);
if (stac9766_ac97_read(codec, 0) == stac9766_reg[0])
return 1;
}

soc_ac97_ops.reset(codec->ac97);
if (soc_ac97_ops.warm_reset)
soc_ac97_ops.warm_reset(codec->ac97);
soc_ac97_ops->reset(codec->ac97);
if (soc_ac97_ops->warm_reset)
soc_ac97_ops->warm_reset(codec->ac97);
if (stac9766_ac97_read(codec, 0) != stac9766_reg[0])
return -EIO;
return 0;
Expand All @@ -272,7 +272,7 @@ static int stac9766_codec_resume(struct snd_soc_codec *codec)
return -EIO;
}
codec->ac97->bus->ops->warm_reset(codec->ac97);
id = soc_ac97_ops.read(codec->ac97, AC97_VENDOR_ID2);
id = soc_ac97_ops->read(codec->ac97, AC97_VENDOR_ID2);
if (id != 0x4c13) {
stac9766_reset(codec, 0);
reset++;
Expand Down Expand Up @@ -336,7 +336,7 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec)
{
int ret = 0;

ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
if (ret < 0)
goto codec_err;

Expand Down
14 changes: 7 additions & 7 deletions sound/soc/codecs/wm9705.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg)
case AC97_RESET:
case AC97_VENDOR_ID1:
case AC97_VENDOR_ID2:
return soc_ac97_ops.read(codec->ac97, reg);
return soc_ac97_ops->read(codec->ac97, reg);
default:
reg = reg >> 1;

Expand All @@ -225,7 +225,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
{
u16 *cache = codec->reg_cache;

soc_ac97_ops.write(codec->ac97, reg, val);
soc_ac97_ops->write(codec->ac97, reg, val);
reg = reg >> 1;
if (reg < (ARRAY_SIZE(wm9705_reg)))
cache[reg] = val;
Expand Down Expand Up @@ -294,8 +294,8 @@ static struct snd_soc_dai_driver wm9705_dai[] = {

static int wm9705_reset(struct snd_soc_codec *codec)
{
if (soc_ac97_ops.reset) {
soc_ac97_ops.reset(codec->ac97);
if (soc_ac97_ops->reset) {
soc_ac97_ops->reset(codec->ac97);
if (ac97_read(codec, 0) == wm9705_reg[0])
return 0; /* Success */
}
Expand All @@ -306,7 +306,7 @@ static int wm9705_reset(struct snd_soc_codec *codec)
#ifdef CONFIG_PM
static int wm9705_soc_suspend(struct snd_soc_codec *codec)
{
soc_ac97_ops.write(codec->ac97, AC97_POWERDOWN, 0xffff);
soc_ac97_ops->write(codec->ac97, AC97_POWERDOWN, 0xffff);

return 0;
}
Expand All @@ -323,7 +323,7 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec)
}

for (i = 2; i < ARRAY_SIZE(wm9705_reg) << 1; i += 2) {
soc_ac97_ops.write(codec->ac97, i, cache[i>>1]);
soc_ac97_ops->write(codec->ac97, i, cache[i>>1]);
}

return 0;
Expand All @@ -337,7 +337,7 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec)
{
int ret = 0;

ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
if (ret < 0) {
printk(KERN_ERR "wm9705: failed to register AC97 codec\n");
return ret;
Expand Down
Loading

0 comments on commit b047e1c

Please sign in to comment.