summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/ak4642.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/ak4642.c')
-rw-r--r--sound/soc/codecs/ak4642.c75
1 files changed, 63 insertions, 12 deletions
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 92655cc189ae..3ba4c0f11418 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -98,7 +98,7 @@
#define MGAIN0 (1 << 0) /* MIC amp gain*/
/* TIMER */
-#define ZTM(param) ((param & 0x3) << 4) /* ALC Zoro Crossing TimeOut */
+#define ZTM(param) ((param & 0x3) << 4) /* ALC Zero Crossing TimeOut */
#define WTM(param) (((param & 0x4) << 4) | ((param & 0x3) << 2))
/* ALC_CTL1 */
@@ -134,6 +134,15 @@
/* MD_CTL4 */
#define DACH (1 << 0)
+struct ak4642_drvdata {
+ const struct regmap_config *regmap_config;
+ int extended_frequencies;
+};
+
+struct ak4642_priv {
+ const struct ak4642_drvdata *drvdata;
+};
+
/*
* Playback Volume (table 39)
*
@@ -148,6 +157,8 @@ static const struct snd_kcontrol_new ak4642_snd_controls[] = {
SOC_DOUBLE_R_TLV("Digital Playback Volume", L_DVC, R_DVC,
0, 0xFF, 1, out_tlv),
+ SOC_SINGLE("ALC Capture Switch", ALC_CTL1, 5, 1, 0),
+ SOC_SINGLE("ALC Capture ZC Switch", ALC_CTL1, 4, 1, 1),
};
static const struct snd_kcontrol_new ak4642_headphone_control =
@@ -287,7 +298,9 @@ static int ak4642_dai_set_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
+ struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec);
u8 pll;
+ int extended_freq = 0;
switch (freq) {
case 11289600:
@@ -308,9 +321,25 @@ static int ak4642_dai_set_sysclk(struct snd_soc_dai *codec_dai,
case 27000000:
pll = PLL3 | PLL2 | PLL0;
break;
+ case 19200000:
+ pll = PLL3;
+ extended_freq = 1;
+ break;
+ case 13000000:
+ pll = PLL3 | PLL2 | PLL1;
+ extended_freq = 1;
+ break;
+ case 26000000:
+ pll = PLL3 | PLL2 | PLL1 | PLL0;
+ extended_freq = 1;
+ break;
default:
return -EINVAL;
}
+
+ if (extended_freq && !priv->drvdata->extended_frequencies)
+ return -EINVAL;
+
snd_soc_update_bits(codec, MD_CTL1, PLL_MASK, pll);
return 0;
@@ -505,30 +534,52 @@ static const struct regmap_config ak4648_regmap = {
.num_reg_defaults = ARRAY_SIZE(ak4648_reg),
};
+static const struct ak4642_drvdata ak4642_drvdata = {
+ .regmap_config = &ak4642_regmap,
+};
+
+static const struct ak4642_drvdata ak4643_drvdata = {
+ .regmap_config = &ak4642_regmap,
+};
+
+static const struct ak4642_drvdata ak4648_drvdata = {
+ .regmap_config = &ak4648_regmap,
+ .extended_frequencies = 1,
+};
+
static struct of_device_id ak4642_of_match[];
static int ak4642_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct device_node *np = i2c->dev.of_node;
- const struct regmap_config *regmap_config = NULL;
+ const struct ak4642_drvdata *drvdata = NULL;
struct regmap *regmap;
+ struct ak4642_priv *priv;
if (np) {
const struct of_device_id *of_id;
of_id = of_match_device(ak4642_of_match, &i2c->dev);
if (of_id)
- regmap_config = of_id->data;
+ drvdata = of_id->data;
} else {
- regmap_config = (const struct regmap_config *)id->driver_data;
+ drvdata = (const struct ak4642_drvdata *)id->driver_data;
}
- if (!regmap_config) {
+ if (!drvdata) {
dev_err(&i2c->dev, "Unknown device type\n");
return -EINVAL;
}
- regmap = devm_regmap_init_i2c(i2c, regmap_config);
+ priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->drvdata = drvdata;
+
+ i2c_set_clientdata(i2c, priv);
+
+ regmap = devm_regmap_init_i2c(i2c, drvdata->regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
@@ -543,17 +594,17 @@ static int ak4642_i2c_remove(struct i2c_client *client)
}
static struct of_device_id ak4642_of_match[] = {
- { .compatible = "asahi-kasei,ak4642", .data = &ak4642_regmap},
- { .compatible = "asahi-kasei,ak4643", .data = &ak4642_regmap},
- { .compatible = "asahi-kasei,ak4648", .data = &ak4648_regmap},
+ { .compatible = "asahi-kasei,ak4642", .data = &ak4642_drvdata},
+ { .compatible = "asahi-kasei,ak4643", .data = &ak4643_drvdata},
+ { .compatible = "asahi-kasei,ak4648", .data = &ak4648_drvdata},
{},
};
MODULE_DEVICE_TABLE(of, ak4642_of_match);
static const struct i2c_device_id ak4642_i2c_id[] = {
- { "ak4642", (kernel_ulong_t)&ak4642_regmap },
- { "ak4643", (kernel_ulong_t)&ak4642_regmap },
- { "ak4648", (kernel_ulong_t)&ak4648_regmap },
+ { "ak4642", (kernel_ulong_t)&ak4642_drvdata },
+ { "ak4643", (kernel_ulong_t)&ak4643_drvdata },
+ { "ak4648", (kernel_ulong_t)&ak4648_drvdata },
{ }
};
MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);