ASoC: ac97: Support multi-platform AC'97

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>
This commit is contained in:
Mark Brown 2013-06-26 12:45:59 +01:00
parent b49dff8cb6
commit b047e1cce8
20 changed files with 154 additions and 72 deletions

View File

@ -340,7 +340,7 @@ struct snd_soc_jack_gpio;
typedef int (*hw_write_t)(void *,const char* ,int); 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 { enum snd_soc_control_type {
SND_SOC_I2C = 1, SND_SOC_I2C = 1,
@ -467,6 +467,8 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
struct snd_ac97_bus_ops *ops, int num); struct snd_ac97_bus_ops *ops, int num);
void snd_soc_free_ac97_codec(struct snd_soc_codec *codec); void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
/* /*
*Controls *Controls
*/ */

View File

@ -179,13 +179,12 @@ static void au1xac97c_ac97_cold_reset(struct snd_ac97 *ac97)
} }
/* AC97 controller operations */ /* AC97 controller operations */
struct snd_ac97_bus_ops soc_ac97_ops = { static struct snd_ac97_bus_ops ac97c_bus_ops = {
.read = au1xac97c_ac97_read, .read = au1xac97c_ac97_read,
.write = au1xac97c_ac97_write, .write = au1xac97c_ac97_write,
.reset = au1xac97c_ac97_cold_reset, .reset = au1xac97c_ac97_cold_reset,
.warm_reset = au1xac97c_ac97_warm_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, static int alchemy_ac97c_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
@ -272,6 +271,10 @@ static int au1xac97c_drvprobe(struct platform_device *pdev)
platform_set_drvdata(pdev, ctx); 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, ret = snd_soc_register_component(&pdev->dev, &au1xac97c_component,
&au1xac97c_dai_driver, 1); &au1xac97c_dai_driver, 1);
if (ret) if (ret)

View File

@ -201,13 +201,12 @@ static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97)
} }
/* AC97 controller operations */ /* AC97 controller operations */
struct snd_ac97_bus_ops soc_ac97_ops = { static struct snd_ac97_bus_ops psc_ac97_ops = {
.read = au1xpsc_ac97_read, .read = au1xpsc_ac97_read,
.write = au1xpsc_ac97_write, .write = au1xpsc_ac97_write,
.reset = au1xpsc_ac97_cold_reset, .reset = au1xpsc_ac97_cold_reset,
.warm_reset = au1xpsc_ac97_warm_reset, .warm_reset = au1xpsc_ac97_warm_reset,
}; };
EXPORT_SYMBOL_GPL(soc_ac97_ops);
static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_pcm_hw_params *params,
@ -417,6 +416,10 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)
platform_set_drvdata(pdev, wd); 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, ret = snd_soc_register_component(&pdev->dev, &au1xpsc_ac97_component,
&wd->dai_drv, 1); &wd->dai_drv, 1);
if (ret) if (ret)

View File

@ -198,13 +198,12 @@ static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97)
#endif #endif
} }
struct snd_ac97_bus_ops soc_ac97_ops = { static struct snd_ac97_bus_ops bf5xx_ac97_ops = {
.read = bf5xx_ac97_read, .read = bf5xx_ac97_read,
.write = bf5xx_ac97_write, .write = bf5xx_ac97_write,
.warm_reset = bf5xx_ac97_warm_reset, .warm_reset = bf5xx_ac97_warm_reset,
.reset = bf5xx_ac97_cold_reset, .reset = bf5xx_ac97_cold_reset,
}; };
EXPORT_SYMBOL_GPL(soc_ac97_ops);
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int bf5xx_ac97_suspend(struct snd_soc_dai *dai) static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
@ -336,6 +335,12 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
goto sport_config_err; 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, ret = snd_soc_register_component(&pdev->dev, &bfin_ac97_component,
&bfin_ac97_dai, 1); &bfin_ac97_dai, 1);
if (ret) { if (ret) {
@ -350,6 +355,7 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
sport_config_err: sport_config_err:
sport_done(sport_handle); sport_done(sport_handle);
sport_err: sport_err:
snd_soc_set_ac97_ops(NULL);
return ret; return ret;
} }
@ -360,6 +366,7 @@ static int asoc_bfin_ac97_remove(struct platform_device *pdev)
snd_soc_unregister_component(&pdev->dev); snd_soc_unregister_component(&pdev->dev);
sport_done(sport_handle); sport_done(sport_handle);
snd_soc_set_ac97_ops(NULL);
return 0; return 0;
} }

View File

@ -237,13 +237,12 @@ static irqreturn_t ep93xx_ac97_interrupt(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
struct snd_ac97_bus_ops soc_ac97_ops = { static struct snd_ac97_bus_ops ep93xx_ac97_ops = {
.read = ep93xx_ac97_read, .read = ep93xx_ac97_read,
.write = ep93xx_ac97_write, .write = ep93xx_ac97_write,
.reset = ep93xx_ac97_cold_reset, .reset = ep93xx_ac97_cold_reset,
.warm_reset = ep93xx_ac97_warm_reset, .warm_reset = ep93xx_ac97_warm_reset,
}; };
EXPORT_SYMBOL_GPL(soc_ac97_ops);
static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream, static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai) int cmd, struct snd_soc_dai *dai)
@ -395,6 +394,10 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
ep93xx_ac97_info = info; ep93xx_ac97_info = info;
platform_set_drvdata(pdev, 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, ret = snd_soc_register_component(&pdev->dev, &ep93xx_ac97_component,
&ep93xx_ac97_dai, 1); &ep93xx_ac97_dai, 1);
if (ret) if (ret)
@ -405,6 +408,7 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
fail: fail:
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
ep93xx_ac97_info = NULL; ep93xx_ac97_info = NULL;
snd_soc_set_ac97_ops(NULL);
return ret; return ret;
} }
@ -420,6 +424,8 @@ static int ep93xx_ac97_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
ep93xx_ac97_info = NULL; ep93xx_ac97_info = NULL;
snd_soc_set_ac97_ops(NULL);
return 0; return 0;
} }

View File

@ -62,13 +62,13 @@ static struct snd_soc_dai_driver ac97_dai = {
static unsigned int ac97_read(struct snd_soc_codec *codec, static unsigned int ac97_read(struct snd_soc_codec *codec,
unsigned int reg) 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, static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int val) unsigned int val)
{ {
soc_ac97_ops.write(codec->ac97, reg, val); soc_ac97_ops->write(codec->ac97, reg, val);
return 0; return 0;
} }
@ -79,7 +79,8 @@ static int ac97_soc_probe(struct snd_soc_codec *codec)
int ret; int ret;
/* add codec as bus device for standard ac97 */ /* 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) if (ret < 0)
return ret; return ret;

View File

@ -108,7 +108,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec,
case AC97_EXTENDED_STATUS: case AC97_EXTENDED_STATUS:
case AC97_VENDOR_ID1: case AC97_VENDOR_ID1:
case AC97_VENDOR_ID2: case AC97_VENDOR_ID2:
return soc_ac97_ops.read(codec->ac97, reg); return soc_ac97_ops->read(codec->ac97, reg);
default: default:
reg = reg >> 1; reg = reg >> 1;
@ -124,7 +124,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
{ {
u16 *cache = codec->reg_cache; u16 *cache = codec->reg_cache;
soc_ac97_ops.write(codec->ac97, reg, val); soc_ac97_ops->write(codec->ac97, reg, val);
reg = reg >> 1; reg = reg >> 1;
if (reg < ARRAY_SIZE(ad1980_reg)) if (reg < ARRAY_SIZE(ad1980_reg))
cache[reg] = val; cache[reg] = val;
@ -154,13 +154,13 @@ static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
u16 retry_cnt = 0; u16 retry_cnt = 0;
retry: retry:
if (try_warm && soc_ac97_ops.warm_reset) { if (try_warm && soc_ac97_ops->warm_reset) {
soc_ac97_ops.warm_reset(codec->ac97); soc_ac97_ops->warm_reset(codec->ac97);
if (ac97_read(codec, AC97_RESET) == 0x0090) if (ac97_read(codec, AC97_RESET) == 0x0090)
return 1; 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 /* 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 * 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)*/ * first nibble of data is eaten by the addr. (Tag is always 16 bit)*/
@ -186,7 +186,7 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec)
printk(KERN_INFO "AD1980 SoC Audio Codec\n"); 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) { if (ret < 0) {
printk(KERN_ERR "ad1980: failed to register AC97 codec\n"); printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
return ret; return ret;

View File

@ -143,14 +143,14 @@ static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg,
if (reg > AC97_STAC_PAGE0) { if (reg > AC97_STAC_PAGE0) {
stac9766_ac97_write(codec, AC97_INT_PAGING, 0); 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); stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
return 0; return 0;
} }
if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) if (reg / 2 >= ARRAY_SIZE(stac9766_reg))
return -EIO; return -EIO;
soc_ac97_ops.write(codec->ac97, reg, val); soc_ac97_ops->write(codec->ac97, reg, val);
cache[reg / 2] = val; cache[reg / 2] = val;
return 0; return 0;
} }
@ -162,7 +162,7 @@ static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec,
if (reg > AC97_STAC_PAGE0) { if (reg > AC97_STAC_PAGE0) {
stac9766_ac97_write(codec, AC97_INT_PAGING, 0); 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); stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
return val; return val;
} }
@ -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_INT_PAGING || reg == AC97_VENDOR_ID1 ||
reg == AC97_VENDOR_ID2) { reg == AC97_VENDOR_ID2) {
val = soc_ac97_ops.read(codec->ac97, reg); val = soc_ac97_ops->read(codec->ac97, reg);
return val; return val;
} }
return cache[reg / 2]; return cache[reg / 2];
@ -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) static int stac9766_reset(struct snd_soc_codec *codec, int try_warm)
{ {
if (try_warm && soc_ac97_ops.warm_reset) { if (try_warm && soc_ac97_ops->warm_reset) {
soc_ac97_ops.warm_reset(codec->ac97); soc_ac97_ops->warm_reset(codec->ac97);
if (stac9766_ac97_read(codec, 0) == stac9766_reg[0]) if (stac9766_ac97_read(codec, 0) == stac9766_reg[0])
return 1; return 1;
} }
soc_ac97_ops.reset(codec->ac97); soc_ac97_ops->reset(codec->ac97);
if (soc_ac97_ops.warm_reset) if (soc_ac97_ops->warm_reset)
soc_ac97_ops.warm_reset(codec->ac97); soc_ac97_ops->warm_reset(codec->ac97);
if (stac9766_ac97_read(codec, 0) != stac9766_reg[0]) if (stac9766_ac97_read(codec, 0) != stac9766_reg[0])
return -EIO; return -EIO;
return 0; return 0;
@ -272,7 +272,7 @@ reset:
return -EIO; return -EIO;
} }
codec->ac97->bus->ops->warm_reset(codec->ac97); 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) { if (id != 0x4c13) {
stac9766_reset(codec, 0); stac9766_reset(codec, 0);
reset++; reset++;
@ -336,7 +336,7 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec)
{ {
int ret = 0; 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) if (ret < 0)
goto codec_err; goto codec_err;

View File

@ -209,7 +209,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg)
case AC97_RESET: case AC97_RESET:
case AC97_VENDOR_ID1: case AC97_VENDOR_ID1:
case AC97_VENDOR_ID2: case AC97_VENDOR_ID2:
return soc_ac97_ops.read(codec->ac97, reg); return soc_ac97_ops->read(codec->ac97, reg);
default: default:
reg = reg >> 1; reg = reg >> 1;
@ -225,7 +225,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
{ {
u16 *cache = codec->reg_cache; u16 *cache = codec->reg_cache;
soc_ac97_ops.write(codec->ac97, reg, val); soc_ac97_ops->write(codec->ac97, reg, val);
reg = reg >> 1; reg = reg >> 1;
if (reg < (ARRAY_SIZE(wm9705_reg))) if (reg < (ARRAY_SIZE(wm9705_reg)))
cache[reg] = val; cache[reg] = val;
@ -294,8 +294,8 @@ static struct snd_soc_dai_driver wm9705_dai[] = {
static int wm9705_reset(struct snd_soc_codec *codec) static int wm9705_reset(struct snd_soc_codec *codec)
{ {
if (soc_ac97_ops.reset) { if (soc_ac97_ops->reset) {
soc_ac97_ops.reset(codec->ac97); soc_ac97_ops->reset(codec->ac97);
if (ac97_read(codec, 0) == wm9705_reg[0]) if (ac97_read(codec, 0) == wm9705_reg[0])
return 0; /* Success */ return 0; /* Success */
} }
@ -306,7 +306,7 @@ static int wm9705_reset(struct snd_soc_codec *codec)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int wm9705_soc_suspend(struct snd_soc_codec *codec) 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; return 0;
} }
@ -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) { 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; return 0;
@ -337,7 +337,7 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec)
{ {
int ret = 0; 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) { if (ret < 0) {
printk(KERN_ERR "wm9705: failed to register AC97 codec\n"); printk(KERN_ERR "wm9705: failed to register AC97 codec\n");
return ret; return ret;

View File

@ -455,7 +455,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec,
if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 ||
reg == AC97_REC_GAIN) reg == AC97_REC_GAIN)
return soc_ac97_ops.read(codec->ac97, reg); return soc_ac97_ops->read(codec->ac97, reg);
else { else {
reg = reg >> 1; reg = reg >> 1;
@ -472,7 +472,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
u16 *cache = codec->reg_cache; u16 *cache = codec->reg_cache;
if (reg < 0x7c) if (reg < 0x7c)
soc_ac97_ops.write(codec->ac97, reg, val); soc_ac97_ops->write(codec->ac97, reg, val);
reg = reg >> 1; reg = reg >> 1;
if (reg < (ARRAY_SIZE(wm9712_reg))) if (reg < (ARRAY_SIZE(wm9712_reg)))
cache[reg] = val; cache[reg] = val;
@ -581,15 +581,15 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec,
static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) static int wm9712_reset(struct snd_soc_codec *codec, int try_warm)
{ {
if (try_warm && soc_ac97_ops.warm_reset) { if (try_warm && soc_ac97_ops->warm_reset) {
soc_ac97_ops.warm_reset(codec->ac97); soc_ac97_ops->warm_reset(codec->ac97);
if (ac97_read(codec, 0) == wm9712_reg[0]) if (ac97_read(codec, 0) == wm9712_reg[0])
return 1; return 1;
} }
soc_ac97_ops.reset(codec->ac97); soc_ac97_ops->reset(codec->ac97);
if (soc_ac97_ops.warm_reset) if (soc_ac97_ops->warm_reset)
soc_ac97_ops.warm_reset(codec->ac97); soc_ac97_ops->warm_reset(codec->ac97);
if (ac97_read(codec, 0) != wm9712_reg[0]) if (ac97_read(codec, 0) != wm9712_reg[0])
goto err; goto err;
return 0; return 0;
@ -624,7 +624,7 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec)
if (i == AC97_INT_PAGING || i == AC97_POWERDOWN || if (i == AC97_INT_PAGING || i == AC97_POWERDOWN ||
(i > 0x58 && i != 0x5c)) (i > 0x58 && i != 0x5c))
continue; continue;
soc_ac97_ops.write(codec->ac97, i, cache[i>>1]); soc_ac97_ops->write(codec->ac97, i, cache[i>>1]);
} }
} }
@ -635,7 +635,7 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec)
{ {
int ret = 0; 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) { if (ret < 0) {
printk(KERN_ERR "wm9712: failed to register AC97 codec\n"); printk(KERN_ERR "wm9712: failed to register AC97 codec\n");
return ret; return ret;

View File

@ -652,7 +652,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec,
if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 ||
reg == AC97_CD) reg == AC97_CD)
return soc_ac97_ops.read(codec->ac97, reg); return soc_ac97_ops->read(codec->ac97, reg);
else { else {
reg = reg >> 1; reg = reg >> 1;
@ -668,7 +668,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
{ {
u16 *cache = codec->reg_cache; u16 *cache = codec->reg_cache;
if (reg < 0x7c) if (reg < 0x7c)
soc_ac97_ops.write(codec->ac97, reg, val); soc_ac97_ops->write(codec->ac97, reg, val);
reg = reg >> 1; reg = reg >> 1;
if (reg < (ARRAY_SIZE(wm9713_reg))) if (reg < (ARRAY_SIZE(wm9713_reg)))
cache[reg] = val; cache[reg] = val;
@ -1095,15 +1095,15 @@ static struct snd_soc_dai_driver wm9713_dai[] = {
int wm9713_reset(struct snd_soc_codec *codec, int try_warm) int wm9713_reset(struct snd_soc_codec *codec, int try_warm)
{ {
if (try_warm && soc_ac97_ops.warm_reset) { if (try_warm && soc_ac97_ops->warm_reset) {
soc_ac97_ops.warm_reset(codec->ac97); soc_ac97_ops->warm_reset(codec->ac97);
if (ac97_read(codec, 0) == wm9713_reg[0]) if (ac97_read(codec, 0) == wm9713_reg[0])
return 1; return 1;
} }
soc_ac97_ops.reset(codec->ac97); soc_ac97_ops->reset(codec->ac97);
if (soc_ac97_ops.warm_reset) if (soc_ac97_ops->warm_reset)
soc_ac97_ops.warm_reset(codec->ac97); soc_ac97_ops->warm_reset(codec->ac97);
if (ac97_read(codec, 0) != wm9713_reg[0]) if (ac97_read(codec, 0) != wm9713_reg[0])
return -EIO; return -EIO;
return 0; return 0;
@ -1180,7 +1180,7 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec)
if (i == AC97_POWERDOWN || i == AC97_EXTENDED_MID || if (i == AC97_POWERDOWN || i == AC97_EXTENDED_MID ||
i == AC97_EXTENDED_MSTATUS || i > 0x66) i == AC97_EXTENDED_MSTATUS || i > 0x66)
continue; continue;
soc_ac97_ops.write(codec->ac97, i, cache[i>>1]); soc_ac97_ops->write(codec->ac97, i, cache[i>>1]);
} }
} }
@ -1197,7 +1197,7 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)
return -ENOMEM; return -ENOMEM;
snd_soc_codec_set_drvdata(codec, wm9713); snd_soc_codec_set_drvdata(codec, wm9713);
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) if (ret < 0)
goto codec_err; goto codec_err;

View File

@ -501,13 +501,12 @@ static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
imx_ssi_ac97_read(ac97, 0); imx_ssi_ac97_read(ac97, 0);
} }
struct snd_ac97_bus_ops soc_ac97_ops = { static struct snd_ac97_bus_ops imx_ssi_ac97_ops = {
.read = imx_ssi_ac97_read, .read = imx_ssi_ac97_read,
.write = imx_ssi_ac97_write, .write = imx_ssi_ac97_write,
.reset = imx_ssi_ac97_reset, .reset = imx_ssi_ac97_reset,
.warm_reset = imx_ssi_ac97_warm_reset .warm_reset = imx_ssi_ac97_warm_reset
}; };
EXPORT_SYMBOL_GPL(soc_ac97_ops);
static int imx_ssi_probe(struct platform_device *pdev) static int imx_ssi_probe(struct platform_device *pdev)
{ {
@ -583,6 +582,12 @@ static int imx_ssi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ssi); platform_set_drvdata(pdev, ssi);
ret = snd_soc_set_ac97_ops(&imx_ssi_ac97_ops);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
goto failed_register;
}
ret = snd_soc_register_component(&pdev->dev, &imx_component, ret = snd_soc_register_component(&pdev->dev, &imx_component,
dai, 1); dai, 1);
if (ret) { if (ret) {
@ -630,6 +635,7 @@ failed_register:
release_mem_region(res->start, resource_size(res)); release_mem_region(res->start, resource_size(res));
clk_disable_unprepare(ssi->clk); clk_disable_unprepare(ssi->clk);
failed_clk: failed_clk:
snd_soc_set_ac97_ops(NULL);
return ret; return ret;
} }
@ -649,6 +655,7 @@ static int imx_ssi_remove(struct platform_device *pdev)
release_mem_region(res->start, resource_size(res)); release_mem_region(res->start, resource_size(res));
clk_disable_unprepare(ssi->clk); clk_disable_unprepare(ssi->clk);
snd_soc_set_ac97_ops(NULL);
return 0; return 0;
} }

View File

@ -131,13 +131,12 @@ static void psc_ac97_cold_reset(struct snd_ac97 *ac97)
psc_ac97_warm_reset(ac97); psc_ac97_warm_reset(ac97);
} }
struct snd_ac97_bus_ops soc_ac97_ops = { static struct snd_ac97_bus_ops psc_ac97_ops = {
.read = psc_ac97_read, .read = psc_ac97_read,
.write = psc_ac97_write, .write = psc_ac97_write,
.reset = psc_ac97_cold_reset, .reset = psc_ac97_cold_reset,
.warm_reset = psc_ac97_warm_reset, .warm_reset = psc_ac97_warm_reset,
}; };
EXPORT_SYMBOL_GPL(soc_ac97_ops);
static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream, static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_pcm_hw_params *params,
@ -290,6 +289,12 @@ static int psc_ac97_of_probe(struct platform_device *op)
if (rc != 0) if (rc != 0)
return rc; return rc;
rc = snd_soc_set_ac97_ops(&psc_ac97_ops);
if (rc != 0) {
dev_err(&op->dev, "Failed to set AC'97 ops: %d\n", ret);
return rc;
}
rc = snd_soc_register_component(&op->dev, &psc_ac97_component, rc = snd_soc_register_component(&op->dev, &psc_ac97_component,
psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai)); psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
if (rc != 0) { if (rc != 0) {
@ -318,6 +323,7 @@ static int psc_ac97_of_remove(struct platform_device *op)
{ {
mpc5200_audio_dma_destroy(op); mpc5200_audio_dma_destroy(op);
snd_soc_unregister_component(&op->dev); snd_soc_unregister_component(&op->dev);
snd_soc_set_ac97_ops(NULL);
return 0; return 0;
} }

View File

@ -197,13 +197,12 @@ static void nuc900_ac97_cold_reset(struct snd_ac97 *ac97)
} }
/* AC97 controller operations */ /* AC97 controller operations */
struct snd_ac97_bus_ops soc_ac97_ops = { static struct snd_ac97_bus_ops nuc900_ac97_ops = {
.read = nuc900_ac97_read, .read = nuc900_ac97_read,
.write = nuc900_ac97_write, .write = nuc900_ac97_write,
.reset = nuc900_ac97_cold_reset, .reset = nuc900_ac97_cold_reset,
.warm_reset = nuc900_ac97_warm_reset, .warm_reset = nuc900_ac97_warm_reset,
} };
EXPORT_SYMBOL_GPL(soc_ac97_ops);
static int nuc900_ac97_trigger(struct snd_pcm_substream *substream, static int nuc900_ac97_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai) int cmd, struct snd_soc_dai *dai)
@ -356,6 +355,10 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev)
nuc900_ac97_data = nuc900_audio; nuc900_ac97_data = nuc900_audio;
ret = snd_soc_set_ac97_ops(&nuc900_ac97_ops);
if (ret)
goto out;
ret = snd_soc_register_component(&pdev->dev, &nuc900_ac97_component, ret = snd_soc_register_component(&pdev->dev, &nuc900_ac97_component,
&nuc900_ac97_dai, 1); &nuc900_ac97_dai, 1);
if (ret) if (ret)
@ -367,6 +370,7 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev)
return 0; return 0;
out: out:
snd_soc_set_ac97_ops(NULL);
return ret; return ret;
} }
@ -375,6 +379,7 @@ static int nuc900_ac97_drvremove(struct platform_device *pdev)
snd_soc_unregister_component(&pdev->dev); snd_soc_unregister_component(&pdev->dev);
nuc900_ac97_data = NULL; nuc900_ac97_data = NULL;
snd_soc_set_ac97_ops(NULL);
return 0; return 0;
} }

View File

@ -41,13 +41,12 @@ static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97)
pxa2xx_ac97_finish_reset(ac97); pxa2xx_ac97_finish_reset(ac97);
} }
struct snd_ac97_bus_ops soc_ac97_ops = { static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
.read = pxa2xx_ac97_read, .read = pxa2xx_ac97_read,
.write = pxa2xx_ac97_write, .write = pxa2xx_ac97_write,
.warm_reset = pxa2xx_ac97_warm_reset, .warm_reset = pxa2xx_ac97_warm_reset,
.reset = pxa2xx_ac97_cold_reset, .reset = pxa2xx_ac97_cold_reset,
}; };
EXPORT_SYMBOL_GPL(soc_ac97_ops);
static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = { static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = {
.name = "AC97 PCM Stereo out", .name = "AC97 PCM Stereo out",
@ -244,6 +243,10 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
return -ENXIO; return -ENXIO;
} }
ret = snd_soc_set_ac97_ops(&pxa2xx_ac97_ops);
if (ret != 0)
return ret;
/* Punt most of the init to the SoC probe; we may need the machine /* Punt most of the init to the SoC probe; we may need the machine
* driver to do interesting things with the clocking to get us up * driver to do interesting things with the clocking to get us up
* and running. * and running.
@ -255,6 +258,7 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
static int pxa2xx_ac97_dev_remove(struct platform_device *pdev) static int pxa2xx_ac97_dev_remove(struct platform_device *pdev)
{ {
snd_soc_unregister_component(&pdev->dev); snd_soc_unregister_component(&pdev->dev);
snd_soc_set_ac97_ops(NULL);
return 0; return 0;
} }

View File

@ -214,13 +214,12 @@ static irqreturn_t s3c_ac97_irq(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
struct snd_ac97_bus_ops soc_ac97_ops = { static struct snd_ac97_bus_ops s3c_ac97_ops = {
.read = s3c_ac97_read, .read = s3c_ac97_read,
.write = s3c_ac97_write, .write = s3c_ac97_write,
.warm_reset = s3c_ac97_warm_reset, .warm_reset = s3c_ac97_warm_reset,
.reset = s3c_ac97_cold_reset, .reset = s3c_ac97_cold_reset,
}; };
EXPORT_SYMBOL_GPL(soc_ac97_ops);
static int s3c_ac97_hw_params(struct snd_pcm_substream *substream, static int s3c_ac97_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_pcm_hw_params *params,
@ -452,6 +451,12 @@ static int s3c_ac97_probe(struct platform_device *pdev)
goto err4; goto err4;
} }
ret = snd_soc_set_ac97_ops(&s3c_ac97_ops);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
goto err4;
}
ret = snd_soc_register_component(&pdev->dev, &s3c_ac97_component, ret = snd_soc_register_component(&pdev->dev, &s3c_ac97_component,
s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai)); s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
if (ret) if (ret)
@ -472,7 +477,7 @@ err4:
err3: err3:
clk_disable_unprepare(s3c_ac97.ac97_clk); clk_disable_unprepare(s3c_ac97.ac97_clk);
err2: err2:
snd_soc_set_ac97_ops(NULL);
return ret; return ret;
} }
@ -488,6 +493,7 @@ static int s3c_ac97_remove(struct platform_device *pdev)
free_irq(irq_res->start, NULL); free_irq(irq_res->start, NULL);
clk_disable_unprepare(s3c_ac97.ac97_clk); clk_disable_unprepare(s3c_ac97.ac97_clk);
snd_soc_set_ac97_ops(NULL);
return 0; return 0;
} }

View File

@ -227,13 +227,12 @@ static void hac_ac97_coldrst(struct snd_ac97 *ac97)
hac_ac97_warmrst(ac97); hac_ac97_warmrst(ac97);
} }
struct snd_ac97_bus_ops soc_ac97_ops = { static struct snd_ac97_bus_ops hac_ac97_ops = {
.read = hac_ac97_read, .read = hac_ac97_read,
.write = hac_ac97_write, .write = hac_ac97_write,
.reset = hac_ac97_coldrst, .reset = hac_ac97_coldrst,
.warm_reset = hac_ac97_warmrst, .warm_reset = hac_ac97_warmrst,
}; };
EXPORT_SYMBOL_GPL(soc_ac97_ops);
static int hac_hw_params(struct snd_pcm_substream *substream, static int hac_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_pcm_hw_params *params,
@ -316,6 +315,10 @@ static const struct snd_soc_component_driver sh4_hac_component = {
static int hac_soc_platform_probe(struct platform_device *pdev) static int hac_soc_platform_probe(struct platform_device *pdev)
{ {
ret = snd_soc_set_ac97_ops(&hac_ac97_ops);
if (ret != 0)
return ret;
return snd_soc_register_component(&pdev->dev, &sh4_hac_component, return snd_soc_register_component(&pdev->dev, &sh4_hac_component,
sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai)); sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
} }
@ -323,6 +326,7 @@ static int hac_soc_platform_probe(struct platform_device *pdev)
static int hac_soc_platform_remove(struct platform_device *pdev) static int hac_soc_platform_remove(struct platform_device *pdev)
{ {
snd_soc_unregister_component(&pdev->dev); snd_soc_unregister_component(&pdev->dev);
snd_soc_set_ac97_ops(NULL);
return 0; return 0;
} }

View File

@ -2079,6 +2079,22 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
} }
EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
struct snd_ac97_bus_ops *soc_ac97_ops;
int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops)
{
if (ops == soc_ac97_ops)
return 0;
if (soc_ac97_ops && ops)
return -EBUSY;
soc_ac97_ops = ops;
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops);
/** /**
* snd_soc_free_ac97_codec - free AC97 codec device * snd_soc_free_ac97_codec - free AC97 codec device
* @codec: audio codec * @codec: audio codec

View File

@ -142,13 +142,12 @@ static void tegra20_ac97_codec_write(struct snd_ac97 *ac97_snd,
} while (!time_after(jiffies, timeout)); } while (!time_after(jiffies, timeout));
} }
struct snd_ac97_bus_ops soc_ac97_ops = { static struct snd_ac97_bus_ops tegra20_ac97_ops = {
.read = tegra20_ac97_codec_read, .read = tegra20_ac97_codec_read,
.write = tegra20_ac97_codec_write, .write = tegra20_ac97_codec_write,
.reset = tegra20_ac97_codec_reset, .reset = tegra20_ac97_codec_reset,
.warm_reset = tegra20_ac97_codec_warm_reset, .warm_reset = tegra20_ac97_codec_warm_reset,
}; };
EXPORT_SYMBOL_GPL(soc_ac97_ops);
static inline void tegra20_ac97_start_playback(struct tegra20_ac97 *ac97) static inline void tegra20_ac97_start_playback(struct tegra20_ac97 *ac97)
{ {
@ -409,6 +408,12 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
goto err_asoc_utils_fini; goto err_asoc_utils_fini;
} }
ret = snd_soc_set_ac97_ops(&tegra20_ac97_ops);
if (ret) {
dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
goto err_asoc_utils_fini;
}
ret = snd_soc_register_component(&pdev->dev, &tegra20_ac97_component, ret = snd_soc_register_component(&pdev->dev, &tegra20_ac97_component,
&tegra20_ac97_dai, 1); &tegra20_ac97_dai, 1);
if (ret) { if (ret) {
@ -436,6 +441,7 @@ err_asoc_utils_fini:
tegra_asoc_utils_fini(&ac97->util_data); tegra_asoc_utils_fini(&ac97->util_data);
err_clk_put: err_clk_put:
err: err:
snd_soc_set_ac97_ops(NULL);
return ret; return ret;
} }
@ -450,6 +456,8 @@ static int tegra20_ac97_platform_remove(struct platform_device *pdev)
clk_disable_unprepare(ac97->clk_ac97); clk_disable_unprepare(ac97->clk_ac97);
snd_soc_set_ac97_ops(NULL);
return 0; return 0;
} }

View File

@ -119,12 +119,11 @@ static void txx9aclc_ac97_cold_reset(struct snd_ac97 *ac97)
} }
/* AC97 controller operations */ /* AC97 controller operations */
struct snd_ac97_bus_ops soc_ac97_ops = { static struct snd_ac97_bus_ops txx9aclc_ac97_ops = {
.read = txx9aclc_ac97_read, .read = txx9aclc_ac97_read,
.write = txx9aclc_ac97_write, .write = txx9aclc_ac97_write,
.reset = txx9aclc_ac97_cold_reset, .reset = txx9aclc_ac97_cold_reset,
}; };
EXPORT_SYMBOL_GPL(soc_ac97_ops);
static irqreturn_t txx9aclc_ac97_irq(int irq, void *dev_id) static irqreturn_t txx9aclc_ac97_irq(int irq, void *dev_id)
{ {
@ -206,6 +205,10 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
if (err < 0) if (err < 0)
return err; return err;
err = snd_soc_set_ac97_ops(&txx9aclc_ac97_ops);
if (err < 0)
return err;
return snd_soc_register_component(&pdev->dev, &txx9aclc_ac97_component, return snd_soc_register_component(&pdev->dev, &txx9aclc_ac97_component,
&txx9aclc_ac97_dai, 1); &txx9aclc_ac97_dai, 1);
} }
@ -213,6 +216,7 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
static int txx9aclc_ac97_dev_remove(struct platform_device *pdev) static int txx9aclc_ac97_dev_remove(struct platform_device *pdev)
{ {
snd_soc_unregister_component(&pdev->dev); snd_soc_unregister_component(&pdev->dev);
snd_soc_set_ac97_ops(NULL);
return 0; return 0;
} }