Commit 0a7e4ca1 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/ac97', 'asoc/topic/ad193x',...

Merge remote-tracking branches 'asoc/topic/ac97', 'asoc/topic/ad193x', 'asoc/topic/adau1373' and 'asoc/topic/adau17x1' into asoc-next
......@@ -3,12 +3,15 @@
# subsystems should select the appropriate symbols.
config REGMAP
default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_MMIO || REGMAP_IRQ)
default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ)
select LZO_COMPRESS
select LZO_DECOMPRESS
select IRQ_DOMAIN if REGMAP_IRQ
bool
config REGMAP_AC97
tristate
config REGMAP_I2C
tristate
depends on I2C
......
obj-$(CONFIG_REGMAP) += regmap.o regcache.o
obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o
obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o
obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o
......
/*
* Register map access API - AC'97 support
*
* Copyright 2013 Linaro Ltd. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 <http://www.gnu.org/licenses/>.
*/
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/ac97_codec.h>
bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg)
{
switch (reg) {
case AC97_RESET:
case AC97_POWERDOWN:
case AC97_INT_PAGING:
case AC97_EXTENDED_ID:
case AC97_EXTENDED_STATUS:
case AC97_EXTENDED_MID:
case AC97_EXTENDED_MSTATUS:
case AC97_GPIO_STATUS:
case AC97_MISC_AFE:
case AC97_VENDOR_ID1:
case AC97_VENDOR_ID2:
case AC97_CODEC_CLASS_REV:
case AC97_PCI_SVID:
case AC97_PCI_SID:
case AC97_FUNC_SELECT:
case AC97_FUNC_INFO:
case AC97_SENSE_INFO:
return true;
default:
return false;
}
}
EXPORT_SYMBOL_GPL(regmap_ac97_default_volatile);
static int regmap_ac97_reg_read(void *context, unsigned int reg,
unsigned int *val)
{
struct snd_ac97 *ac97 = context;
*val = ac97->bus->ops->read(ac97, reg);
return 0;
}
static int regmap_ac97_reg_write(void *context, unsigned int reg,
unsigned int val)
{
struct snd_ac97 *ac97 = context;
ac97->bus->ops->write(ac97, reg, val);
return 0;
}
static const struct regmap_bus ac97_regmap_bus = {
.reg_write = regmap_ac97_reg_write,
.reg_read = regmap_ac97_reg_read,
};
/**
* regmap_init_ac97(): Initialise AC'97 register map
*
* @ac97: Device that will be interacted with
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap.
*/
struct regmap *regmap_init_ac97(struct snd_ac97 *ac97,
const struct regmap_config *config)
{
return regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config);
}
EXPORT_SYMBOL_GPL(regmap_init_ac97);
/**
* devm_regmap_init_ac97(): Initialise AC'97 register map
*
* @ac97: Device that will be interacted with
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap. The regmap will be automatically freed by the
* device management code.
*/
struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97,
const struct regmap_config *config)
{
return devm_regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config);
}
EXPORT_SYMBOL_GPL(devm_regmap_init_ac97);
MODULE_LICENSE("GPL v2");
......@@ -27,6 +27,7 @@ struct spmi_device;
struct regmap;
struct regmap_range_cfg;
struct regmap_field;
struct snd_ac97;
/* An enum of all the supported cache types */
enum regcache_type {
......@@ -340,6 +341,8 @@ struct regmap *regmap_init_spmi_ext(struct spmi_device *dev,
struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id,
void __iomem *regs,
const struct regmap_config *config);
struct regmap *regmap_init_ac97(struct snd_ac97 *ac97,
const struct regmap_config *config);
struct regmap *devm_regmap_init(struct device *dev,
const struct regmap_bus *bus,
......@@ -356,6 +359,10 @@ struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *dev,
struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id,
void __iomem *regs,
const struct regmap_config *config);
struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97,
const struct regmap_config *config);
bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
/**
* regmap_init_mmio(): Initialise register map
......
......@@ -206,7 +206,6 @@ struct snd_soc_dai_driver {
/* DAI description */
const char *name;
unsigned int id;
int ac97_control;
unsigned int base;
/* DAI driver callbacks */
......@@ -216,6 +215,8 @@ struct snd_soc_dai_driver {
int (*resume)(struct snd_soc_dai *dai);
/* compress dai */
bool compress_dai;
/* DAI is also used for the control bus */
bool bus_control;
/* ops */
const struct snd_soc_dai_ops *ops;
......@@ -241,7 +242,6 @@ struct snd_soc_dai {
const char *name;
int id;
struct device *dev;
void *ac97_pdata; /* platform_data for the ac97 codec */
/* driver ops */
struct snd_soc_dai_driver *driver;
......
......@@ -369,8 +369,6 @@ struct snd_soc_jack_gpio;
typedef int (*hw_write_t)(void *,const char* ,int);
extern struct snd_ac97_bus_ops *soc_ac97_ops;
enum snd_soc_pcm_subclass {
SND_SOC_PCM_CLASS_PCM = 0,
SND_SOC_PCM_CLASS_BE = 1,
......@@ -499,14 +497,28 @@ int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg,
unsigned int mask, unsigned int value);
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);
#ifdef CONFIG_SND_SOC_AC97_BUS
struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec);
void snd_soc_free_ac97_codec(struct snd_ac97 *ac97);
int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
struct platform_device *pdev);
extern struct snd_ac97_bus_ops *soc_ac97_ops;
#else
static inline int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
struct platform_device *pdev)
{
return 0;
}
static inline int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops)
{
return 0;
}
#endif
/*
*Controls
*/
......@@ -778,11 +790,8 @@ struct snd_soc_codec {
struct list_head card_list;
/* runtime */
struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */
unsigned int cache_bypass:1; /* Suppress access to the cache */
unsigned int suspended:1; /* Codec is in suspend PM state */
unsigned int ac97_registered:1; /* Codec has been AC97 registered */
unsigned int ac97_created:1; /* Codec has been created by SoC */
unsigned int cache_init:1; /* codec cache has been initialized */
/* codec IO */
......@@ -1275,6 +1284,45 @@ void snd_soc_component_async_complete(struct snd_soc_component *component);
int snd_soc_component_test_bits(struct snd_soc_component *component,
unsigned int reg, unsigned int mask, unsigned int value);
#ifdef CONFIG_REGMAP
void snd_soc_component_init_regmap(struct snd_soc_component *component,
struct regmap *regmap);
void snd_soc_component_exit_regmap(struct snd_soc_component *component);
/**
* snd_soc_codec_init_regmap() - Initialize regmap instance for the CODEC
* @codec: The CODEC for which to initialize the regmap instance
* @regmap: The regmap instance that should be used by the CODEC
*
* This function allows deferred assignment of the regmap instance that is
* associated with the CODEC. Only use this if the regmap instance is not yet
* ready when the CODEC is registered. The function must also be called before
* the first IO attempt of the CODEC.
*/
static inline void snd_soc_codec_init_regmap(struct snd_soc_codec *codec,
struct regmap *regmap)
{
snd_soc_component_init_regmap(&codec->component, regmap);
}
/**
* snd_soc_codec_exit_regmap() - De-initialize regmap instance for the CODEC
* @codec: The CODEC for which to de-initialize the regmap instance
*
* Calls regmap_exit() on the regmap instance associated to the CODEC and
* removes the regmap instance from the CODEC.
*
* This function should only be used if snd_soc_codec_init_regmap() was used to
* initialize the regmap instance.
*/
static inline void snd_soc_codec_exit_regmap(struct snd_soc_codec *codec)
{
snd_soc_component_exit_regmap(&codec->component);
}
#endif
/* device driver data */
static inline void snd_soc_card_set_drvdata(struct snd_soc_card *card,
......
......@@ -5,6 +5,10 @@ ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
snd-soc-core-objs += soc-generic-dmaengine-pcm.o
endif
ifneq ($(CONFIG_SND_SOC_AC97_BUS),)
snd-soc-core-objs += soc-ac97.o
endif
obj-$(CONFIG_SND_SOC) += snd-soc-core.o
obj-$(CONFIG_SND_SOC) += codecs/
obj-$(CONFIG_SND_SOC) += generic/
......
......@@ -205,7 +205,7 @@ static int au1xac97c_dai_probe(struct snd_soc_dai *dai)
static struct snd_soc_dai_driver au1xac97c_dai_driver = {
.name = "alchemy-ac97c",
.ac97_control = 1,
.bus_control = true,
.probe = au1xac97c_dai_probe,
.playback = {
.rates = AC97_RATES,
......
......@@ -343,7 +343,7 @@ static const struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
};
static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
.ac97_control = 1,
.bus_control = true,
.probe = au1xpsc_ac97_probe,
.playback = {
.rates = AC97_RATES,
......
......@@ -260,7 +260,7 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
#endif
static struct snd_soc_dai_driver bfin_ac97_dai = {
.ac97_control = 1,
.bus_control = true,
.suspend = bf5xx_ac97_suspend,
.resume = bf5xx_ac97_resume,
.playback = {
......
......@@ -46,8 +46,6 @@
#include <linux/gpio.h>
#include <asm/portmux.h>
#include "../codecs/ad1980.h"
#include "bf5xx-ac97.h"
static struct snd_soc_card bf5xx_board;
......
......@@ -338,7 +338,7 @@ static const struct snd_soc_dai_ops ep93xx_ac97_dai_ops = {
static struct snd_soc_dai_driver ep93xx_ac97_dai = {
.name = "ep93xx-ac97",
.id = 0,
.ac97_control = 1,
.bus_control = true,
.probe = ep93xx_ac97_dai_probe,
.playback = {
.stream_name = "AC97 Playback",
......
......@@ -223,6 +223,7 @@ config SND_SOC_AD193X_I2C
select SND_SOC_AD193X
config SND_SOC_AD1980
select REGMAP_AC97
tristate
config SND_SOC_AD73311
......
......@@ -37,10 +37,11 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
return snd_ac97_set_rate(codec->ac97, reg, substream->runtime->rate);
return snd_ac97_set_rate(ac97, reg, substream->runtime->rate);
}
#define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
......@@ -53,7 +54,6 @@ static const struct snd_soc_dai_ops ac97_dai_ops = {
static struct snd_soc_dai_driver ac97_dai = {
.name = "ac97-hifi",
.ac97_control = 1,
.playback = {
.stream_name = "AC97 Playback",
.channels_min = 1,
......@@ -71,6 +71,7 @@ static struct snd_soc_dai_driver ac97_dai = {
static int ac97_soc_probe(struct snd_soc_codec *codec)
{
struct snd_ac97 *ac97;
struct snd_ac97_bus *ac97_bus;
struct snd_ac97_template ac97_template;
int ret;
......@@ -82,24 +83,31 @@ static int ac97_soc_probe(struct snd_soc_codec *codec)
return ret;
memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97);
ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97);
if (ret < 0)
return ret;
snd_soc_codec_set_drvdata(codec, ac97);
return 0;
}
#ifdef CONFIG_PM
static int ac97_soc_suspend(struct snd_soc_codec *codec)
{
snd_ac97_suspend(codec->ac97);
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
snd_ac97_suspend(ac97);
return 0;
}
static int ac97_soc_resume(struct snd_soc_codec *codec)
{
snd_ac97_resume(codec->ac97);
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
snd_ac97_resume(ac97);
return 0;
}
......
......@@ -72,11 +72,13 @@ static const struct snd_kcontrol_new ad193x_snd_controls[] = {
};
static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = {
SND_SOC_DAPM_DAC("DAC", "Playback", AD193X_DAC_CTRL0, 0, 1),
SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_PGA("DAC Output", AD193X_DAC_CTRL0, 0, 1, NULL, 0),
SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0),
SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0),
SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0),
SND_SOC_DAPM_VMID("VMID"),
SND_SOC_DAPM_OUTPUT("DAC1OUT"),
SND_SOC_DAPM_OUTPUT("DAC2OUT"),
SND_SOC_DAPM_OUTPUT("DAC3OUT"),
......@@ -87,13 +89,15 @@ static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = {
static const struct snd_soc_dapm_route audio_paths[] = {
{ "DAC", NULL, "SYSCLK" },
{ "DAC Output", NULL, "DAC" },
{ "DAC Output", NULL, "VMID" },
{ "ADC", NULL, "SYSCLK" },
{ "DAC", NULL, "ADC_PWR" },
{ "ADC", NULL, "ADC_PWR" },
{ "DAC1OUT", NULL, "DAC" },
{ "DAC2OUT", NULL, "DAC" },
{ "DAC3OUT", NULL, "DAC" },
{ "DAC4OUT", NULL, "DAC" },
{ "DAC1OUT", NULL, "DAC Output" },
{ "DAC2OUT", NULL, "DAC Output" },
{ "DAC3OUT", NULL, "DAC Output" },
{ "DAC4OUT", NULL, "DAC Output" },
{ "ADC", NULL, "ADC1IN" },
{ "ADC", NULL, "ADC2IN" },
{ "SYSCLK", NULL, "PLL_PWR" },
......
......@@ -24,34 +24,86 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include "ad1980.h"
static const struct reg_default ad1980_reg_defaults[] = {
{ 0x02, 0x8000 },
{ 0x04, 0x8000 },
{ 0x06, 0x8000 },
{ 0x0c, 0x8008 },
{ 0x0e, 0x8008 },
{ 0x10, 0x8808 },
{ 0x12, 0x8808 },
{ 0x16, 0x8808 },
{ 0x18, 0x8808 },
{ 0x1a, 0x0000 },
{ 0x1c, 0x8000 },
{ 0x20, 0x0000 },
{ 0x28, 0x03c7 },
{ 0x2c, 0xbb80 },
{ 0x2e, 0xbb80 },
{ 0x30, 0xbb80 },
{ 0x32, 0xbb80 },
{ 0x36, 0x8080 },
{ 0x38, 0x8080 },
{ 0x3a, 0x2000 },
{ 0x60, 0x0000 },
{ 0x62, 0x0000 },
{ 0x72, 0x0000 },
{ 0x74, 0x1001 },
{ 0x76, 0x0000 },
};
/*
* AD1980 register cache
*/
static const u16 ad1980_reg[] = {
0x0090, 0x8000, 0x8000, 0x8000, /* 0 - 6 */
0x0000, 0x0000, 0x8008, 0x8008, /* 8 - e */
0x8808, 0x8808, 0x0000, 0x8808, /* 10 - 16 */
0x8808, 0x0000, 0x8000, 0x0000, /* 18 - 1e */
0x0000, 0x0000, 0x0000, 0x0000, /* 20 - 26 */
0x03c7, 0x0000, 0xbb80, 0xbb80, /* 28 - 2e */
0xbb80, 0xbb80, 0x0000, 0x8080, /* 30 - 36 */
0x8080, 0x2000, 0x0000, 0x0000, /* 38 - 3e */
0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
0x8080, 0x0000, 0x0000, 0x0000, /* 60 - 66 */
0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
0x0000, 0x0000, 0x1001, 0x0000, /* 70 - 76 */
0x0000, 0x0000, 0x4144, 0x5370 /* 78 - 7e */
static bool ad1980_readable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case AC97_RESET ... AC97_MASTER_MONO:
case AC97_PHONE ... AC97_CD:
case AC97_AUX ... AC97_GENERAL_PURPOSE:
case AC97_POWERDOWN ... AC97_PCM_LR_ADC_RATE:
case AC97_SPDIF:
case AC97_CODEC_CLASS_REV:
case AC97_PCI_SVID:
case AC97_AD_CODEC_CFG:
case AC97_AD_JACK_SPDIF:
case AC97_AD_SERIAL_CFG:
case AC97_VENDOR_ID1:
case AC97_VENDOR_ID2:
return true;
default:
return false;
}
}
static bool ad1980_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case AC97_VENDOR_ID1:
case AC97_VENDOR_ID2:
return false;
default:
return ad1980_readable_reg(dev, reg);
}
}
static const struct regmap_config ad1980_regmap_config = {
.reg_bits = 16,
.reg_stride = 2,
.val_bits = 16,
.max_register = 0x7e,
.cache_type = REGCACHE_RBTREE,
.volatile_reg = regmap_ac97_default_volatile,
.readable_reg = ad1980_readable_reg,
.writeable_reg = ad1980_writeable_reg,
.reg_defaults = ad1980_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(ad1980_reg_defaults),
};
static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line",
......@@ -134,45 +186,8 @@ static const struct snd_soc_dapm_route ad1980_dapm_routes[] = {
{ "HP_OUT_R", NULL, "Playback" },
};
static unsigned int ac97_read(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
switch (reg) {
case AC97_RESET:
case AC97_INT_PAGING:
case AC97_POWERDOWN:
case AC97_EXTENDED_STATUS:
case AC97_VENDOR_ID1:
case AC97_VENDOR_ID2:
return soc_ac97_ops->read(codec->ac97, reg);
default:
reg = reg >> 1;
if (reg >= ARRAY_SIZE(ad1980_reg))
return -EINVAL;
return cache[reg];
}
}
static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int val)
{
u16 *cache = codec->reg_cache;
soc_ac97_ops->write(codec->ac97, reg, val);
reg = reg >> 1;
if (reg < ARRAY_SIZE(ad1980_reg))
cache[reg] = val;
return 0;
}
static struct snd_soc_dai_driver ad1980_dai = {
.name = "ad1980-hifi",
.ac97_control = 1,
.playback = {
.stream_name = "Playback",
.channels_min = 2,
......@@ -189,108 +204,115 @@ static struct snd_soc_dai_driver ad1980_dai = {
static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
{
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
unsigned int retry_cnt = 0;
do {
if (try_warm && soc_ac97_ops->warm_reset) {
soc_ac97_ops->warm_reset(codec->ac97);
if (ac97_read(codec, AC97_RESET) == 0x0090)
soc_ac97_ops->warm_reset(ac97);
if (snd_soc_read(codec, AC97_RESET) == 0x0090)
return 1;
}
soc_ac97_ops->reset(codec->ac97);
soc_ac97_ops->reset(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)
*/
ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900);
snd_soc_write(codec, AC97_AD_SERIAL_CFG, 0x9900);
if (ac97_read(codec, AC97_RESET) == 0x0090)
if (snd_soc_read(codec, AC97_RESET) == 0x0090)
return 0;
} while (retry_cnt++ < 10);
printk(KERN_ERR "AD1980 AC97 reset failed\n");
dev_err(codec->dev, "Failed to reset: AC97 link error\n");
return -EIO;
}
static int ad1980_soc_probe(struct snd_soc_codec *codec)
{
struct snd_ac97 *ac97;
struct regmap *regmap;
int ret;
u16 vendor_id2;
u16 ext_status;
printk(KERN_INFO "AD1980 SoC Audio Codec\n");
ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
if (ret < 0) {
printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
ac97 = snd_soc_new_ac97_codec(codec);
if (IS_ERR(ac97)) {
ret = PTR_ERR(ac97);
dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret);
return ret;
}
regmap = regmap_init_ac97(ac97, &ad1980_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);
ret = ad1980_reset(codec, 0);
if (ret < 0) {
printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n");
if (ret < 0)
goto reset_err;
}
/* Read out vendor ID to make sure it is ad1980 */
if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144) {
if (snd_soc_read(codec, AC97_VENDOR_ID1) != 0x4144) {
ret = -ENODEV;
goto reset_err;
}
vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2);
vendor_id2 = snd_soc_read(codec, AC97_VENDOR_ID2);
if (vendor_id2 != 0x5370) {
if (vendor_id2 != 0x5374) {
ret = -ENODEV;
goto reset_err;
} else {
printk(KERN_WARNING "ad1980: "
"Found AD1981 - only 2/2 IN/OUT Channels "
"supported\n");
dev_warn(codec->dev,
"Found AD1981 - only 2/2 IN/OUT Channels supported\n");
}
}
/* unmute captures and playbacks volume */
ac97_write(codec, AC97_MASTER, 0x0000);
ac97_write(codec, AC97_PCM, 0x0000);
ac97_write(codec, AC97_REC_GAIN, 0x0000);
ac97_write(codec, AC97_CENTER_LFE_MASTER, 0x0000);
ac97_write(codec, AC97_SURROUND_MASTER, 0x0000);
snd_soc_write(codec, AC97_MASTER, 0x0000);
snd_soc_write(codec, AC97_PCM, 0x0000);
snd_soc_write(codec, AC97_REC_GAIN, 0x0000);
snd_soc_write(codec, AC97_CENTER_LFE_MASTER, 0x0000);
snd_soc_write(codec, AC97_SURROUND_MASTER, 0x0000);
/*power on LFE/CENTER/Surround DACs*/
ext_status = ac97_read(codec, AC97_EXTENDED_STATUS);
ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800);
snd_soc_add_codec_controls(codec, ad1980_snd_ac97_controls,
ARRAY_SIZE(ad1980_snd_ac97_controls));
ext_status = snd_soc_read(codec, AC97_EXTENDED_STATUS);
snd_soc_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800);
return 0;
reset_err:
snd_soc_free_ac97_codec(codec);
snd_soc_codec_exit_regmap(codec);
err_free_ac97:
snd_soc_free_ac97_codec(ac97);
return ret;
}
static int ad1980_soc_remove(struct snd_soc_codec *codec)
{
snd_soc_free_ac97_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;
}
static struct snd_soc_codec_driver soc_codec_dev_ad1980 = {
.probe = ad1980_soc_probe,
.remove = ad1980_soc_remove,
.reg_cache_size = ARRAY_SIZE(ad1980_reg),
.reg_word_size = sizeof(u16),
.reg_cache_default = ad1980_reg,
.reg_cache_step = 2,
.write = ac97_write,
.read = ac97_read,
.controls = ad1980_snd_ac97_controls,
.num_controls = ARRAY_SIZE(ad1980_snd_ac97_controls),
.dapm_widgets = ad1980_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(ad1980_dapm_widgets),
.dapm_routes = ad1980_dapm_routes,
......
/*
* ad1980.h -- ad1980 Soc Audio driver
*
* 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.
*/
#ifndef _AD1980_H
#define _AD1980_H
/* Bit definition of Power-Down Control/Status Register */
#define ADC 0x0001
#define DAC 0x0002
#define ANL 0x0004
#define REF 0x0008
#define PR0 0x0100
#define PR1 0x0200
#define PR2 0x0400
#define PR3 0x0800
#define PR4 0x1000
#define PR5 0x2000
#define PR6 0x4000
#endif
......@@ -551,7 +551,7 @@ static const struct snd_kcontrol_new adau1373_drc_controls[] = {
static int adau1373_pll_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
unsigned int pll_id = w->name[3] - '1';
unsigned int val;
......@@ -823,7 +823,7 @@ static const struct snd_soc_dapm_widget adau1373_dapm_widgets[] = {
static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
struct snd_soc_codec *codec = source->codec;
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
unsigned int dai;
const char *clk;
......@@ -844,7 +844,7 @@ static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source,
static int adau1373_check_src(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
struct snd_soc_codec *codec = source->codec;
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
unsigned int dai;
......
......@@ -255,7 +255,8 @@ static const struct snd_kcontrol_new adau1761_input_mux_control =
static int adau1761_dejitter_fixup(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct adau *adau = snd_soc_codec_get_drvdata(w->codec);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct adau *adau = snd_soc_codec_get_drvdata(codec);
/* After any power changes have been made the dejitter circuit
* has to be reinitialized. */
......
......@@ -174,7 +174,7 @@ static const struct snd_kcontrol_new adau1781_mono_mixer_controls[] = {
static int adau1781_dejitter_fixup(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct adau *adau = snd_soc_codec_get_drvdata(codec);
/* After any power changes have been made the dejitter circuit
......
......@@ -61,7 +61,8 @@ static const struct snd_kcontrol_new adau17x1_controls[] = {
static int adau17x1_pll_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct adau *adau = snd_soc_codec_get_drvdata(w->codec);
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct adau *adau = snd_soc_codec_get_drvdata(codec);
int ret;
if (SND_SOC_DAPM_EVENT_ON(event)) {
......
......@@ -139,18 +139,19 @@ static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = {
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(codec->ac97, reg, val);
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(codec->ac97, reg, val);
soc_ac97_ops->write(ac97, reg, val);
cache[reg / 2] = val;
return 0;
}
......@@ -158,11 +159,12 @@ static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg,
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(codec->ac97, reg - AC97_STAC_PAGE0);
val = soc_ac97_ops->read(ac97, reg - AC97_STAC_PAGE0);
stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
return val;
}
......@@ -173,7 +175,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(ac97, reg);
return val;
}
return cache[reg / 2];
......@@ -240,15 +242,17 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec,
static int stac9766_reset(struct snd_soc_codec *codec, int try_warm)
{
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
if (try_warm && soc_ac97_ops->warm_reset) {
soc_ac97_ops->warm_reset(codec->ac97);
soc_ac97_ops->warm_reset(ac97);
if (stac9766_ac97_read(codec, 0) == stac9766_reg[0])
return 1;
}
soc_ac97_ops->reset(codec->ac97);
soc_ac97_ops->reset(ac97);
if (soc_ac97_ops->warm_reset)
soc_ac97_ops->warm_reset(codec->ac97);
soc_ac97_ops->warm_reset(ac97);
if (stac9766_ac97_read(codec, 0) != stac9766_reg[0])
return -EIO;
return 0;
......@@ -262,6 +266,7 @@ static int stac9766_codec_suspend(struct snd_soc_codec *codec)
static int stac9766_codec_resume(struct snd_soc_codec *codec)
{
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
u16 id, reset;
reset = 0;
......@@ -271,8 +276,8 @@ static int stac9766_codec_resume(struct snd_soc_codec *codec)
printk(KERN_ERR "stac9766 failed to resume");
return -EIO;
}
codec->ac97->bus->ops->warm_reset(codec->ac97);
id = soc_ac97_ops->read(codec->ac97, AC97_VENDOR_ID2);
ac97->bus->ops->warm_reset(ac97);
id = soc_ac97_ops->read(ac97, AC97_VENDOR_ID2);
if (id != 0x4c13) {
stac9766_reset(codec, 0);
reset++;
......@@ -294,7 +299,6 @@ static const struct snd_soc_dai_ops stac9766_dai_ops_digital = {
static struct snd_soc_dai_driver stac9766_dai[] = {
{
.name = "stac9766-hifi-analog",
.ac97_control = 1,
/* stream cababilities */
.playback = {
......@@ -316,7 +320,6 @@ static struct snd_soc_dai_driver stac9766_dai[] = {
},
{
.name = "stac9766-hifi-IEC958",
.ac97_control = 1,
/* stream cababilities */
.playback = {
......@@ -334,11 +337,14 @@ static struct snd_soc_dai_driver stac9766_dai[] = {
static int stac9766_codec_probe(struct snd_soc_codec *codec)
{
struct snd_ac97 *ac97;
int ret = 0;
ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
if (ret < 0)
goto codec_err;
ac97 = snd_soc_new_ac97_codec(codec);
if (IS_ERR(ac97))
return PTR_ERR(ac97);
snd_soc_codec_set_drvdata(codec, ac97);
/* do a cold reset for the controller and then try
* a warm reset followed by an optional cold reset for codec */
......@@ -357,13 +363,15 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec)
return 0;
codec_err:
snd_soc_free_ac97_codec(codec);
snd_soc_free_ac97_codec(ac97);
return ret;
}
static int stac9766_codec_remove(struct snd_soc_codec *codec)
{
snd_soc_free_ac97_codec(codec);
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
snd_soc_free_ac97_codec(ac97);
return 0;
}
......
......@@ -203,13 +203,14 @@ static const struct snd_soc_dapm_route wm9705_audio_map[] = {
/* We use a register cache to enhance read performance. */
static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg)
{
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
u16 *cache = codec->reg_cache;
switch (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(ac97, reg);
default:
reg = reg >> 1;
......@@ -223,9 +224,10 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg)
static int 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;
soc_ac97_ops->write(codec->ac97, reg, val);
soc_ac97_ops->write(ac97, reg, val);
reg = reg >> 1;
if (reg < (ARRAY_SIZE(wm9705_reg)))
cache[reg] = val;
......@@ -263,7 +265,6 @@ static const struct snd_soc_dai_ops wm9705_dai_ops = {
static struct snd_soc_dai_driver wm9705_dai[] = {
{
.name = "wm9705-hifi",
.ac97_control = 1,
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 1,
......@@ -294,36 +295,41 @@ static struct snd_soc_dai_driver wm9705_dai[] = {
static int wm9705_reset(struct snd_soc_codec *codec)
{
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
if (soc_ac97_ops->reset) {
soc_ac97_ops->reset(codec->ac97);
soc_ac97_ops->reset(ac97);
if (ac97_read(codec, 0) == wm9705_reg[0])
return 0; /* Success */
}
dev_err(codec->dev, "Failed to reset: AC97 link error\n");
return -EIO;
}
#ifdef CONFIG_PM
static int wm9705_soc_suspend(struct snd_soc_codec *codec)
{
soc_ac97_ops->write(codec->ac97, AC97_POWERDOWN, 0xffff);
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
soc_ac97_ops->write(ac97, AC97_POWERDOWN, 0xffff);
return 0;
}
static int wm9705_soc_resume(struct snd_soc_codec *codec)
{
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
int i, ret;
u16 *cache = codec->reg_cache;
ret = wm9705_reset(codec);
if (ret < 0) {
printk(KERN_ERR "could not reset AC97 codec\n");
if (ret < 0)
return ret;
}
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(ac97, i, cache[i>>1]);
}
return 0;
......@@ -335,31 +341,34 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec)
static int wm9705_soc_probe(struct snd_soc_codec *codec)
{
struct snd_ac97 *ac97;
int ret = 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");
ac97 = snd_soc_new_ac97_codec(codec);
if (IS_ERR(ac97)) {
ret = PTR_ERR(ac97);
dev_err(codec->dev, "Failed to register AC97 codec\n");
return ret;
}
snd_soc_codec_set_drvdata(codec, ac97);
ret = wm9705_reset(codec);
if (ret)
goto reset_err;
snd_soc_add_codec_controls(codec, wm9705_snd_ac97_controls,
ARRAY_SIZE(wm9705_snd_ac97_controls));
return 0;
reset_err:
snd_soc_free_ac97_codec(codec);
snd_soc_free_ac97_codec(ac97);
return ret;
}
static int wm9705_soc_remove(struct snd_soc_codec *codec)
{
snd_soc_free_ac97_codec(codec);
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
snd_soc_free_ac97_codec(ac97);
return 0;
}
......@@ -374,6 +383,9 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9705 = {
.reg_word_size = sizeof(u16),
.reg_cache_step = 2,
.reg_cache_default = wm9705_reg,
.controls = wm9705_snd_ac97_controls,
.num_controls = ARRAY_SIZE(wm9705_snd_ac97_controls),
.dapm_widgets = wm9705_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm9705_dapm_widgets),
.dapm_routes = wm9705_audio_map,
......
This diff is collapsed.
This diff is collapsed.
......@@ -1099,7 +1099,7 @@ static const struct snd_soc_component_driver fsl_ssi_component = {
};
static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
.ac97_control = 1,
.bus_control = true,
.playback = {
.stream_name = "AC97 Playback",
.channels_min = 2,
......
......@@ -382,7 +382,7 @@ static struct snd_soc_dai_driver imx_ssi_dai = {
static struct snd_soc_dai_driver imx_ac97_dai = {
.probe = imx_ssi_dai_probe,
.ac97_control = 1,
.bus_control = true,
.playback = {
.stream_name = "AC97 Playback",
.channels_min = 2,
......
......@@ -327,9 +327,6 @@ static int psc_dma_new(struct snd_soc_pcm_runtime *rtd)
goto capture_alloc_err;
}
if (rtd->codec->ac97)
rtd->codec->ac97->private_data = psc_dma;
return 0;
capture_alloc_err:
......
......@@ -237,7 +237,7 @@ static const struct snd_soc_dai_ops psc_ac97_digital_ops = {
static struct snd_soc_dai_driver psc_ac97_dai[] = {
{
.name = "mpc5200-psc-ac97.0",
.ac97_control = 1,
.bus_control = true,
.probe = psc_ac97_probe,
.playback = {
.stream_name = "AC97 Playback",
......@@ -257,7 +257,7 @@ static struct snd_soc_dai_driver psc_ac97_dai[] = {
},
{
.name = "mpc5200-psc-ac97.1",
.ac97_control = 1,
.bus_control = true,
.playback = {
.stream_name = "AC97 SPDIF",
.channels_min = 1,
......@@ -282,7 +282,6 @@ static const struct snd_soc_component_driver psc_ac97_component = {
static int psc_ac97_of_probe(struct platform_device *op)
{
int rc;
struct snd_ac97 ac97;
struct mpc52xx_psc __iomem *regs;
rc = mpc5200_audio_dma_create(op);
......@@ -304,7 +303,6 @@ static int psc_ac97_of_probe(struct platform_device *op)
psc_dma = dev_get_drvdata(&op->dev);
regs = psc_dma->psc_regs;
ac97.private_data = psc_dma;
psc_dma->imr = 0;
out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
......
......@@ -298,7 +298,7 @@ static const struct snd_soc_dai_ops nuc900_ac97_dai_ops = {
static struct snd_soc_dai_driver nuc900_ac97_dai = {
.probe = nuc900_ac97_probe,
.remove = nuc900_ac97_remove,
.ac97_control = 1,
.bus_control = true,
.playback = {
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
......
......@@ -157,7 +157,7 @@ static const struct snd_soc_dai_ops pxa_ac97_mic_dai_ops = {
static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = {
{
.name = "pxa2xx-ac97",
.ac97_control = 1,
.bus_control = true,
.playback = {
.stream_name = "AC97 Playback",
.channels_min = 2,
......@@ -174,7 +174,7 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = {
},
{
.name = "pxa2xx-ac97-aux",
.ac97_control = 1,
.bus_control = true,
.playback = {
.stream_name = "AC97 Aux Playback",
.channels_min = 1,
......@@ -191,7 +191,7 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = {
},
{
.name = "pxa2xx-ac97-mic",
.ac97_control = 1,
.bus_control = true,
.capture = {
.stream_name = "AC97 Mic Capture",
.channels_min = 1,
......
......@@ -288,7 +288,7 @@ static int s3c_ac97_mic_dai_probe(struct snd_soc_dai *dai)
static struct snd_soc_dai_driver s3c_ac97_dai[] = {
[S3C_AC97_DAI_PCM] = {
.name = "samsung-ac97",
.ac97_control = 1,
.bus_control = true,
.playback = {
.stream_name = "AC97 Playback",
.channels_min = 2,
......@@ -306,7 +306,7 @@ static struct snd_soc_dai_driver s3c_ac97_dai[] = {
},
[S3C_AC97_DAI_MIC] = {
.name = "samsung-ac97-mic",
.ac97_control = 1,
.bus_control = true,
.capture = {
.stream_name = "AC97 Mic Capture",
.channels_min = 1,
......
......@@ -272,7 +272,7 @@ static const struct snd_soc_dai_ops hac_dai_ops = {
static struct snd_soc_dai_driver sh4_hac_dai[] = {
{
.name = "hac-dai.0",
.ac97_control = 1,
.bus_control = true,
.playback = {
.rates = AC97_RATES,
.formats = AC97_FMTS,
......
/*
* soc-ac97.c -- ALSA SoC Audio Layer AC97 support
*
* Copyright 2005 Wolfson Microelectronics PLC.
* Copyright 2005 Openedhand Ltd.
* Copyright (C) 2010 Slimlogic Ltd.
* Copyright (C) 2010 Texas Instruments Inc.
*
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
* with code, comments and ideas from :-
* Richard Purdie <richard@openedhand.com>
*
* 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/ctype.h>
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/of_gpio.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/slab.h>
#include <sound/ac97_codec.h>
#include <sound/soc.h>
struct snd_ac97_reset_cfg {
struct pinctrl *pctl;
struct pinctrl_state *pstate_reset;
struct pinctrl_state *pstate_warm_reset;
struct pinctrl_state *pstate_run;
int gpio_sdata;
int gpio_sync;
int gpio_reset;
};
static struct snd_ac97_bus soc_ac97_bus = {
.ops = NULL, /* Gets initialized in snd_soc_set_ac97_ops() */
};
static void soc_ac97_device_release(struct device *dev)
{
kfree(to_ac97_t(dev));
}
/**
* snd_soc_new_ac97_codec - initailise AC97 device
* @codec: audio codec
*
* Initialises AC97 codec resources for use by ad-hoc devices only.
*/
struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec)
{
struct snd_ac97 *ac97;
int ret;
ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL);
if (ac97 == NULL)
return ERR_PTR(-ENOMEM);
ac97->bus = &soc_ac97_bus;
ac97->num = 0;
ac97->dev.bus = &ac97_bus_type;
ac97->dev.parent = codec->component.card->dev;
ac97->dev.release = soc_ac97_device_release;
dev_set_name(&ac97->dev, "%d-%d:%s",
codec->component.card->snd_card->number, 0,
codec->component.name);
ret = device_register(&ac97->dev);
if (ret) {
put_device(&ac97->dev);
return ERR_PTR(ret);
}
return ac97;
}
EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
/**
* snd_soc_free_ac97_codec - free AC97 codec device
* @codec: audio codec
*
* Frees AC97 codec device resources.
*/
void snd_soc_free_ac97_codec(struct snd_ac97 *ac97)
{
device_del(&ac97->dev);
ac97->bus = NULL;
put_device(&ac97->dev);
}
EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
static struct snd_ac97_reset_cfg snd_ac97_rst_cfg;
static void snd_soc_ac97_warm_reset(struct snd_ac97 *ac97)
{
struct pinctrl *pctl = snd_ac97_rst_cfg.pctl;
pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_warm_reset);
gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 1);
udelay(10);
gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0);
pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run);
msleep(2);
}
static void snd_soc_ac97_reset(struct snd_ac97 *ac97)
{
struct pinctrl *pctl = snd_ac97_rst_cfg.pctl;
pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_reset);
gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0);
gpio_direction_output(snd_ac97_rst_cfg.gpio_sdata, 0);
gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 0);
udelay(10);
gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 1);
pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run);
msleep(2);
}
static int snd_soc_ac97_parse_pinctl(struct device *dev,
struct snd_ac97_reset_cfg *cfg)
{
struct pinctrl *p;
struct pinctrl_state *state;
int gpio;
int ret;
p = devm_pinctrl_get(dev);
if (IS_ERR(p)) {
dev_err(dev, "Failed to get pinctrl\n");
return PTR_ERR(p);
}
cfg->pctl = p;
state = pinctrl_lookup_state(p, "ac97-reset");
if (IS_ERR(state)) {
dev_err(dev, "Can't find pinctrl state ac97-reset\n");
return PTR_ERR(state);
}
cfg->pstate_reset = state;
state = pinctrl_lookup_state(p, "ac97-warm-reset");
if (IS_ERR(state)) {
dev_err(dev, "Can't find pinctrl state ac97-warm-reset\n");
return PTR_ERR(state);
}
cfg->pstate_warm_reset = state;
state = pinctrl_lookup_state(p, "ac97-running");
if (IS_ERR(state)) {
dev_err(dev, "Can't find pinctrl state ac97-running\n");
return PTR_ERR(state);
}
cfg->pstate_run = state;
gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 0);
if (gpio < 0) {
dev_err(dev, "Can't find ac97-sync gpio\n");
return gpio;
}
ret = devm_gpio_request(dev, gpio, "AC97 link sync");
if (ret) {
dev_err(dev, "Failed requesting ac97-sync gpio\n");
return ret;
}
cfg->gpio_sync = gpio;
gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 1);
if (gpio < 0) {
dev_err(dev, "Can't find ac97-sdata gpio %d\n", gpio);
return gpio;
}
ret = devm_gpio_request(dev, gpio, "AC97 link sdata");
if (ret) {
dev_err(dev, "Failed requesting ac97-sdata gpio\n");
return ret;
}
cfg->gpio_sdata = gpio;
gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 2);
if (gpio < 0) {
dev_err(dev, "Can't find ac97-reset gpio\n");
return gpio;
}
ret = devm_gpio_request(dev, gpio, "AC97 link reset");
if (ret) {
dev_err(dev, "Failed requesting ac97-reset gpio\n");
return ret;
}
cfg->gpio_reset = gpio;
return 0;
}
struct snd_ac97_bus_ops *soc_ac97_ops;
EXPORT_SYMBOL_GPL(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;
soc_ac97_bus.ops = ops;
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops);
/**
* snd_soc_set_ac97_ops_of_reset - Set ac97 ops with generic ac97 reset functions
*
* This function sets the reset and warm_reset properties of ops and parses
* the device node of pdev to get pinctrl states and gpio numbers to use.
*/
int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct snd_ac97_reset_cfg cfg;
int ret;
ret = snd_soc_ac97_parse_pinctl(dev, &cfg);
if (ret)
return ret;
ret = snd_soc_set_ac97_ops(ops);
if (ret)
return ret;
ops->warm_reset = snd_soc_ac97_warm_reset;
ops->reset = snd_soc_ac97_reset;
snd_ac97_rst_cfg = cfg;
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_of_reset);
This diff is collapsed.
......@@ -228,7 +228,7 @@ static int tegra20_ac97_probe(struct snd_soc_dai *dai)
static struct snd_soc_dai_driver tegra20_ac97_dai = {
.name = "tegra-ac97-pcm",
.ac97_control = 1,
.bus_control = true,
.probe = tegra20_ac97_probe,
.playback = {
.stream_name = "PCM Playback",
......
......@@ -152,7 +152,7 @@ static int txx9aclc_ac97_remove(struct snd_soc_dai *dai)
}
static struct snd_soc_dai_driver txx9aclc_ac97_dai = {
.ac97_control = 1,
.bus_control = true,
.probe = txx9aclc_ac97_probe,
.remove = txx9aclc_ac97_remove,
.playback = {
......
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