|
|
|
@ -16,6 +16,7 @@ |
|
|
|
|
#include <linux/mfd/88pm860x.h> |
|
|
|
|
#include <linux/slab.h> |
|
|
|
|
#include <linux/delay.h> |
|
|
|
|
#include <linux/regmap.h> |
|
|
|
|
#include <sound/core.h> |
|
|
|
|
#include <sound/pcm.h> |
|
|
|
|
#include <sound/pcm_params.h> |
|
|
|
@ -140,6 +141,7 @@ struct pm860x_priv { |
|
|
|
|
unsigned int filter; |
|
|
|
|
struct snd_soc_codec *codec; |
|
|
|
|
struct i2c_client *i2c; |
|
|
|
|
struct regmap *regmap; |
|
|
|
|
struct pm860x_chip *chip; |
|
|
|
|
struct pm860x_det det; |
|
|
|
|
|
|
|
|
@ -269,48 +271,6 @@ static struct st_gain st_table[] = { |
|
|
|
|
{ -86, 29, 0}, { -56, 30, 0}, { -28, 31, 0}, { 0, 0, 0}, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static int pm860x_volatile(unsigned int reg) |
|
|
|
|
{ |
|
|
|
|
BUG_ON(reg >= REG_CACHE_SIZE); |
|
|
|
|
|
|
|
|
|
switch (reg) { |
|
|
|
|
case PM860X_AUDIO_SUPPLIES_2: |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static unsigned int pm860x_read_reg_cache(struct snd_soc_codec *codec, |
|
|
|
|
unsigned int reg) |
|
|
|
|
{ |
|
|
|
|
unsigned char *cache = codec->reg_cache; |
|
|
|
|
|
|
|
|
|
BUG_ON(reg >= REG_CACHE_SIZE); |
|
|
|
|
|
|
|
|
|
if (pm860x_volatile(reg)) |
|
|
|
|
return cache[reg]; |
|
|
|
|
|
|
|
|
|
reg += REG_CACHE_BASE; |
|
|
|
|
|
|
|
|
|
return pm860x_reg_read(codec->control_data, reg); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int pm860x_write_reg_cache(struct snd_soc_codec *codec, |
|
|
|
|
unsigned int reg, unsigned int value) |
|
|
|
|
{ |
|
|
|
|
unsigned char *cache = codec->reg_cache; |
|
|
|
|
|
|
|
|
|
BUG_ON(reg >= REG_CACHE_SIZE); |
|
|
|
|
|
|
|
|
|
if (!pm860x_volatile(reg)) |
|
|
|
|
cache[reg] = (unsigned char)value; |
|
|
|
|
|
|
|
|
|
reg += REG_CACHE_BASE; |
|
|
|
|
|
|
|
|
|
return pm860x_reg_write(codec->control_data, reg, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol, |
|
|
|
|
struct snd_ctl_elem_value *ucontrol) |
|
|
|
|
{ |
|
|
|
@ -1169,6 +1129,7 @@ static int pm860x_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, |
|
|
|
|
static int pm860x_set_bias_level(struct snd_soc_codec *codec, |
|
|
|
|
enum snd_soc_bias_level level) |
|
|
|
|
{ |
|
|
|
|
struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec); |
|
|
|
|
int data; |
|
|
|
|
|
|
|
|
|
switch (level) { |
|
|
|
@ -1182,17 +1143,17 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec, |
|
|
|
|
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { |
|
|
|
|
/* Enable Audio PLL & Audio section */ |
|
|
|
|
data = AUDIO_PLL | AUDIO_SECTION_ON; |
|
|
|
|
pm860x_reg_write(codec->control_data, REG_MISC2, data); |
|
|
|
|
pm860x_reg_write(pm860x->i2c, REG_MISC2, data); |
|
|
|
|
udelay(300); |
|
|
|
|
data = AUDIO_PLL | AUDIO_SECTION_RESET |
|
|
|
|
| AUDIO_SECTION_ON; |
|
|
|
|
pm860x_reg_write(codec->control_data, REG_MISC2, data); |
|
|
|
|
pm860x_reg_write(pm860x->i2c, REG_MISC2, data); |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case SND_SOC_BIAS_OFF: |
|
|
|
|
data = AUDIO_PLL | AUDIO_SECTION_RESET | AUDIO_SECTION_ON; |
|
|
|
|
pm860x_set_bits(codec->control_data, REG_MISC2, data, 0); |
|
|
|
|
pm860x_set_bits(pm860x->i2c, REG_MISC2, data, 0); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
codec->dapm.bias_level = level; |
|
|
|
@ -1322,17 +1283,17 @@ int pm860x_hs_jack_detect(struct snd_soc_codec *codec, |
|
|
|
|
pm860x->det.lo_shrt = lo_shrt; |
|
|
|
|
|
|
|
|
|
if (det & SND_JACK_HEADPHONE) |
|
|
|
|
pm860x_set_bits(codec->control_data, REG_HS_DET, |
|
|
|
|
pm860x_set_bits(pm860x->i2c, REG_HS_DET, |
|
|
|
|
EN_HS_DET, EN_HS_DET); |
|
|
|
|
/* headset short detect */ |
|
|
|
|
if (hs_shrt) { |
|
|
|
|
data = CLR_SHORT_HS2 | CLR_SHORT_HS1; |
|
|
|
|
pm860x_set_bits(codec->control_data, REG_SHORTS, data, data); |
|
|
|
|
pm860x_set_bits(pm860x->i2c, REG_SHORTS, data, data); |
|
|
|
|
} |
|
|
|
|
/* Lineout short detect */ |
|
|
|
|
if (lo_shrt) { |
|
|
|
|
data = CLR_SHORT_LO2 | CLR_SHORT_LO1; |
|
|
|
|
pm860x_set_bits(codec->control_data, REG_SHORTS, data, data); |
|
|
|
|
pm860x_set_bits(pm860x->i2c, REG_SHORTS, data, data); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* sync status */ |
|
|
|
@ -1350,7 +1311,7 @@ int pm860x_mic_jack_detect(struct snd_soc_codec *codec, |
|
|
|
|
pm860x->det.mic_det = det; |
|
|
|
|
|
|
|
|
|
if (det & SND_JACK_MICROPHONE) |
|
|
|
|
pm860x_set_bits(codec->control_data, REG_MIC_DET, |
|
|
|
|
pm860x_set_bits(pm860x->i2c, REG_MIC_DET, |
|
|
|
|
MICDET_MASK, MICDET_MASK); |
|
|
|
|
|
|
|
|
|
/* sync status */ |
|
|
|
@ -1366,7 +1327,7 @@ static int pm860x_probe(struct snd_soc_codec *codec) |
|
|
|
|
|
|
|
|
|
pm860x->codec = codec; |
|
|
|
|
|
|
|
|
|
codec->control_data = pm860x->i2c; |
|
|
|
|
codec->control_data = pm860x->regmap; |
|
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) { |
|
|
|
|
ret = request_threaded_irq(pm860x->irq[i], NULL, |
|
|
|
@ -1380,14 +1341,6 @@ static int pm860x_probe(struct snd_soc_codec *codec) |
|
|
|
|
|
|
|
|
|
pm860x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
|
|
|
|
|
|
|
|
|
ret = pm860x_bulk_read(codec->control_data, REG_CACHE_BASE, |
|
|
|
|
REG_CACHE_SIZE, codec->reg_cache); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
dev_err(codec->dev, "Failed to fill register cache: %d\n", |
|
|
|
|
ret); |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
out: |
|
|
|
@ -1410,10 +1363,6 @@ static int pm860x_remove(struct snd_soc_codec *codec) |
|
|
|
|
static struct snd_soc_codec_driver soc_codec_dev_pm860x = { |
|
|
|
|
.probe = pm860x_probe, |
|
|
|
|
.remove = pm860x_remove, |
|
|
|
|
.read = pm860x_read_reg_cache, |
|
|
|
|
.write = pm860x_write_reg_cache, |
|
|
|
|
.reg_cache_size = REG_CACHE_SIZE, |
|
|
|
|
.reg_word_size = sizeof(u8), |
|
|
|
|
.set_bias_level = pm860x_set_bias_level, |
|
|
|
|
|
|
|
|
|
.controls = pm860x_snd_controls, |
|
|
|
@ -1439,6 +1388,8 @@ static int pm860x_codec_probe(struct platform_device *pdev) |
|
|
|
|
pm860x->chip = chip; |
|
|
|
|
pm860x->i2c = (chip->id == CHIP_PM8607) ? chip->client |
|
|
|
|
: chip->companion; |
|
|
|
|
pm860x->regmap = (chip->id == CHIP_PM8607) ? chip->regmap |
|
|
|
|
: chip->regmap_companion; |
|
|
|
|
platform_set_drvdata(pdev, pm860x); |
|
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) { |
|
|
|
|