Merge remote-tracking branch 'asoc/topic/jz4740' into asoc-next
This commit is contained in:
commit
18620cc586
2 changed files with 60 additions and 83 deletions
|
@ -236,6 +236,7 @@ config SND_SOC_CX20442
|
|||
tristate
|
||||
|
||||
config SND_SOC_JZ4740_CODEC
|
||||
select REGMAP_MMIO
|
||||
tristate
|
||||
|
||||
config SND_SOC_L3
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
|
@ -24,9 +25,10 @@
|
|||
#include <sound/pcm_params.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#define JZ4740_REG_CODEC_1 0x0
|
||||
#define JZ4740_REG_CODEC_2 0x1
|
||||
#define JZ4740_REG_CODEC_2 0x4
|
||||
|
||||
#define JZ4740_CODEC_1_LINE_ENABLE BIT(29)
|
||||
#define JZ4740_CODEC_1_MIC_ENABLE BIT(28)
|
||||
|
@ -67,43 +69,36 @@
|
|||
#define JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET 4
|
||||
#define JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET 0
|
||||
|
||||
static const uint32_t jz4740_codec_regs[] = {
|
||||
0x021b2302, 0x00170803,
|
||||
static const struct reg_default jz4740_codec_reg_defaults[] = {
|
||||
{ JZ4740_REG_CODEC_1, 0x021b2302 },
|
||||
{ JZ4740_REG_CODEC_2, 0x00170803 },
|
||||
};
|
||||
|
||||
struct jz4740_codec {
|
||||
void __iomem *base;
|
||||
struct resource *mem;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static unsigned int jz4740_codec_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec);
|
||||
return readl(jz4740_codec->base + (reg << 2));
|
||||
}
|
||||
static const unsigned int jz4740_mic_tlv[] = {
|
||||
TLV_DB_RANGE_HEAD(2),
|
||||
0, 2, TLV_DB_SCALE_ITEM(0, 600, 0),
|
||||
3, 3, TLV_DB_SCALE_ITEM(2000, 0, 0),
|
||||
};
|
||||
|
||||
static int jz4740_codec_write(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec);
|
||||
u32 *cache = codec->reg_cache;
|
||||
|
||||
cache[reg] = val;
|
||||
writel(val, jz4740_codec->base + (reg << 2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
static const DECLARE_TLV_DB_SCALE(jz4740_out_tlv, 0, 200, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(jz4740_in_tlv, -3450, 150, 0);
|
||||
|
||||
static const struct snd_kcontrol_new jz4740_codec_controls[] = {
|
||||
SOC_SINGLE("Master Playback Volume", JZ4740_REG_CODEC_2,
|
||||
JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET, 3, 0),
|
||||
SOC_SINGLE("Master Capture Volume", JZ4740_REG_CODEC_2,
|
||||
JZ4740_CODEC_2_INPUT_VOLUME_OFFSET, 31, 0),
|
||||
SOC_SINGLE_TLV("Master Playback Volume", JZ4740_REG_CODEC_2,
|
||||
JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET, 3, 0,
|
||||
jz4740_out_tlv),
|
||||
SOC_SINGLE_TLV("Master Capture Volume", JZ4740_REG_CODEC_2,
|
||||
JZ4740_CODEC_2_INPUT_VOLUME_OFFSET, 31, 0,
|
||||
jz4740_in_tlv),
|
||||
SOC_SINGLE("Master Playback Switch", JZ4740_REG_CODEC_1,
|
||||
JZ4740_CODEC_1_HEADPHONE_DISABLE_OFFSET, 1, 1),
|
||||
SOC_SINGLE("Mic Capture Volume", JZ4740_REG_CODEC_2,
|
||||
JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET, 3, 0),
|
||||
SOC_SINGLE_TLV("Mic Capture Volume", JZ4740_REG_CODEC_2,
|
||||
JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET, 3, 0,
|
||||
jz4740_mic_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new jz4740_codec_output_controls[] = {
|
||||
|
@ -163,8 +158,8 @@ static const struct snd_soc_dapm_route jz4740_codec_dapm_routes[] = {
|
|||
static int jz4740_codec_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(dai->codec);
|
||||
uint32_t val;
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 8000:
|
||||
|
@ -200,7 +195,7 @@ static int jz4740_codec_hw_params(struct snd_pcm_substream *substream,
|
|||
|
||||
val <<= JZ4740_CODEC_2_SAMPLE_RATE_OFFSET;
|
||||
|
||||
snd_soc_update_bits(codec, JZ4740_REG_CODEC_2,
|
||||
regmap_update_bits(jz4740_codec->regmap, JZ4740_REG_CODEC_2,
|
||||
JZ4740_CODEC_2_SAMPLE_RATE_MASK, val);
|
||||
|
||||
return 0;
|
||||
|
@ -230,25 +225,23 @@ static struct snd_soc_dai_driver jz4740_codec_dai = {
|
|||
.symmetric_rates = 1,
|
||||
};
|
||||
|
||||
static void jz4740_codec_wakeup(struct snd_soc_codec *codec)
|
||||
static void jz4740_codec_wakeup(struct regmap *regmap)
|
||||
{
|
||||
int i;
|
||||
uint32_t *cache = codec->reg_cache;
|
||||
|
||||
snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
|
||||
regmap_update_bits(regmap, JZ4740_REG_CODEC_1,
|
||||
JZ4740_CODEC_1_RESET, JZ4740_CODEC_1_RESET);
|
||||
udelay(2);
|
||||
|
||||
snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
|
||||
regmap_update_bits(regmap, JZ4740_REG_CODEC_1,
|
||||
JZ4740_CODEC_1_SUSPEND | JZ4740_CODEC_1_RESET, 0);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(jz4740_codec_regs); ++i)
|
||||
jz4740_codec_write(codec, i, cache[i]);
|
||||
regcache_sync(regmap);
|
||||
}
|
||||
|
||||
static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec);
|
||||
struct regmap *regmap = jz4740_codec->regmap;
|
||||
unsigned int mask;
|
||||
unsigned int value;
|
||||
|
||||
|
@ -261,12 +254,12 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
|
|||
JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
|
||||
value = 0;
|
||||
|
||||
snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value);
|
||||
regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value);
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
/* The only way to clear the suspend flag is to reset the codec */
|
||||
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
|
||||
jz4740_codec_wakeup(codec);
|
||||
jz4740_codec_wakeup(regmap);
|
||||
|
||||
mask = JZ4740_CODEC_1_VREF_DISABLE |
|
||||
JZ4740_CODEC_1_VREF_AMP_DISABLE |
|
||||
|
@ -275,13 +268,14 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
|
|||
JZ4740_CODEC_1_VREF_AMP_DISABLE |
|
||||
JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
|
||||
|
||||
snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value);
|
||||
regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
mask = JZ4740_CODEC_1_SUSPEND;
|
||||
value = JZ4740_CODEC_1_SUSPEND;
|
||||
|
||||
snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value);
|
||||
regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value);
|
||||
regcache_mark_dirty(regmap);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -294,7 +288,9 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
|
|||
|
||||
static int jz4740_codec_dev_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
|
||||
struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
regmap_update_bits(jz4740_codec->regmap, JZ4740_REG_CODEC_1,
|
||||
JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
|
||||
|
||||
jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
@ -331,12 +327,7 @@ static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {
|
|||
.remove = jz4740_codec_dev_remove,
|
||||
.suspend = jz4740_codec_suspend,
|
||||
.resume = jz4740_codec_resume,
|
||||
.read = jz4740_codec_read,
|
||||
.write = jz4740_codec_write,
|
||||
.set_bias_level = jz4740_codec_set_bias_level,
|
||||
.reg_cache_default = jz4740_codec_regs,
|
||||
.reg_word_size = sizeof(u32),
|
||||
.reg_cache_size = 2,
|
||||
|
||||
.controls = jz4740_codec_controls,
|
||||
.num_controls = ARRAY_SIZE(jz4740_codec_controls),
|
||||
|
@ -346,11 +337,23 @@ static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {
|
|||
.num_dapm_routes = ARRAY_SIZE(jz4740_codec_dapm_routes),
|
||||
};
|
||||
|
||||
static const struct regmap_config jz4740_codec_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.max_register = JZ4740_REG_CODEC_2,
|
||||
|
||||
.reg_defaults = jz4740_codec_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(jz4740_codec_reg_defaults),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static int __devinit jz4740_codec_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct jz4740_codec *jz4740_codec;
|
||||
struct resource *mem;
|
||||
void __iomem *base;
|
||||
|
||||
jz4740_codec = devm_kzalloc(&pdev->dev, sizeof(*jz4740_codec),
|
||||
GFP_KERNEL);
|
||||
|
@ -358,56 +361,29 @@ static int __devinit jz4740_codec_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!mem) {
|
||||
dev_err(&pdev->dev, "Failed to get mmio memory resource\n");
|
||||
ret = -ENOENT;
|
||||
goto err_out;
|
||||
}
|
||||
base = devm_request_and_ioremap(&pdev->dev, mem);
|
||||
if (!base)
|
||||
return -EBUSY;
|
||||
|
||||
mem = request_mem_region(mem->start, resource_size(mem), pdev->name);
|
||||
if (!mem) {
|
||||
dev_err(&pdev->dev, "Failed to request mmio memory region\n");
|
||||
ret = -EBUSY;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
jz4740_codec->base = ioremap(mem->start, resource_size(mem));
|
||||
if (!jz4740_codec->base) {
|
||||
dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
|
||||
ret = -EBUSY;
|
||||
goto err_release_mem_region;
|
||||
}
|
||||
jz4740_codec->mem = mem;
|
||||
jz4740_codec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
|
||||
&jz4740_codec_regmap_config);
|
||||
if (IS_ERR(jz4740_codec->regmap))
|
||||
return PTR_ERR(jz4740_codec->regmap);
|
||||
|
||||
platform_set_drvdata(pdev, jz4740_codec);
|
||||
|
||||
ret = snd_soc_register_codec(&pdev->dev,
|
||||
&soc_codec_dev_jz4740_codec, &jz4740_codec_dai, 1);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "Failed to register codec\n");
|
||||
goto err_iounmap;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_iounmap:
|
||||
iounmap(jz4740_codec->base);
|
||||
err_release_mem_region:
|
||||
release_mem_region(mem->start, resource_size(mem));
|
||||
err_out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit jz4740_codec_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct jz4740_codec *jz4740_codec = platform_get_drvdata(pdev);
|
||||
struct resource *mem = jz4740_codec->mem;
|
||||
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
|
||||
iounmap(jz4740_codec->base);
|
||||
release_mem_region(mem->start, resource_size(mem));
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in a new issue