diff options
Diffstat (limited to 'sound/soc/codecs/cs42l73.c')
-rw-r--r-- | sound/soc/codecs/cs42l73.c | 114 |
1 files changed, 77 insertions, 37 deletions
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 3b20c86cdb01..549d5d6a3fef 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
20 | #include <linux/of_gpio.h> | ||
20 | #include <linux/pm.h> | 21 | #include <linux/pm.h> |
21 | #include <linux/i2c.h> | 22 | #include <linux/i2c.h> |
22 | #include <linux/regmap.h> | 23 | #include <linux/regmap.h> |
@@ -28,6 +29,7 @@ | |||
28 | #include <sound/soc-dapm.h> | 29 | #include <sound/soc-dapm.h> |
29 | #include <sound/initval.h> | 30 | #include <sound/initval.h> |
30 | #include <sound/tlv.h> | 31 | #include <sound/tlv.h> |
32 | #include <sound/cs42l73.h> | ||
31 | #include "cs42l73.h" | 33 | #include "cs42l73.h" |
32 | 34 | ||
33 | struct sp_config { | 35 | struct sp_config { |
@@ -35,6 +37,7 @@ struct sp_config { | |||
35 | u32 srate; | 37 | u32 srate; |
36 | }; | 38 | }; |
37 | struct cs42l73_private { | 39 | struct cs42l73_private { |
40 | struct cs42l73_platform_data pdata; | ||
38 | struct sp_config config[3]; | 41 | struct sp_config config[3]; |
39 | struct regmap *regmap; | 42 | struct regmap *regmap; |
40 | u32 sysclk; | 43 | u32 sysclk; |
@@ -310,15 +313,6 @@ static const struct soc_enum ng_delay_enum = | |||
310 | SOC_ENUM_SINGLE(CS42L73_NGCAB, 0, | 313 | SOC_ENUM_SINGLE(CS42L73_NGCAB, 0, |
311 | ARRAY_SIZE(cs42l73_ng_delay_text), cs42l73_ng_delay_text); | 314 | ARRAY_SIZE(cs42l73_ng_delay_text), cs42l73_ng_delay_text); |
312 | 315 | ||
313 | static const char * const charge_pump_freq_text[] = { | ||
314 | "0", "1", "2", "3", "4", | ||
315 | "5", "6", "7", "8", "9", | ||
316 | "10", "11", "12", "13", "14", "15" }; | ||
317 | |||
318 | static const struct soc_enum charge_pump_enum = | ||
319 | SOC_ENUM_SINGLE(CS42L73_CPFCHC, 4, | ||
320 | ARRAY_SIZE(charge_pump_freq_text), charge_pump_freq_text); | ||
321 | |||
322 | static const char * const cs42l73_mono_mix_texts[] = { | 316 | static const char * const cs42l73_mono_mix_texts[] = { |
323 | "Left", "Right", "Mono Mix"}; | 317 | "Left", "Right", "Mono Mix"}; |
324 | 318 | ||
@@ -511,8 +505,6 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = { | |||
511 | SOC_SINGLE("NG Threshold", CS42L73_NGCAB, 2, 7, 0), | 505 | SOC_SINGLE("NG Threshold", CS42L73_NGCAB, 2, 7, 0), |
512 | SOC_ENUM("NG Delay", ng_delay_enum), | 506 | SOC_ENUM("NG Delay", ng_delay_enum), |
513 | 507 | ||
514 | SOC_ENUM("Charge Pump Frequency", charge_pump_enum), | ||
515 | |||
516 | SOC_DOUBLE_R_TLV("XSP-IP Volume", | 508 | SOC_DOUBLE_R_TLV("XSP-IP Volume", |
517 | CS42L73_XSPAIPAA, CS42L73_XSPBIPBA, 0, 0x3F, 1, | 509 | CS42L73_XSPAIPAA, CS42L73_XSPBIPBA, 0, 0x3F, 1, |
518 | attn_tlv), | 510 | attn_tlv), |
@@ -1055,11 +1047,11 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | |||
1055 | 1047 | ||
1056 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 1048 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
1057 | case SND_SOC_DAIFMT_CBM_CFM: | 1049 | case SND_SOC_DAIFMT_CBM_CFM: |
1058 | mmcc |= MS_MASTER; | 1050 | mmcc |= CS42L73_MS_MASTER; |
1059 | break; | 1051 | break; |
1060 | 1052 | ||
1061 | case SND_SOC_DAIFMT_CBS_CFS: | 1053 | case SND_SOC_DAIFMT_CBS_CFS: |
1062 | mmcc &= ~MS_MASTER; | 1054 | mmcc &= ~CS42L73_MS_MASTER; |
1063 | break; | 1055 | break; |
1064 | 1056 | ||
1065 | default: | 1057 | default: |
@@ -1071,11 +1063,11 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | |||
1071 | 1063 | ||
1072 | switch (format) { | 1064 | switch (format) { |
1073 | case SND_SOC_DAIFMT_I2S: | 1065 | case SND_SOC_DAIFMT_I2S: |
1074 | spc &= ~SPDIF_PCM; | 1066 | spc &= ~CS42L73_SPDIF_PCM; |
1075 | break; | 1067 | break; |
1076 | case SND_SOC_DAIFMT_DSP_A: | 1068 | case SND_SOC_DAIFMT_DSP_A: |
1077 | case SND_SOC_DAIFMT_DSP_B: | 1069 | case SND_SOC_DAIFMT_DSP_B: |
1078 | if (mmcc & MS_MASTER) { | 1070 | if (mmcc & CS42L73_MS_MASTER) { |
1079 | dev_err(codec->dev, | 1071 | dev_err(codec->dev, |
1080 | "PCM format in slave mode only\n"); | 1072 | "PCM format in slave mode only\n"); |
1081 | return -EINVAL; | 1073 | return -EINVAL; |
@@ -1085,25 +1077,25 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | |||
1085 | "PCM format is not supported on ASP port\n"); | 1077 | "PCM format is not supported on ASP port\n"); |
1086 | return -EINVAL; | 1078 | return -EINVAL; |
1087 | } | 1079 | } |
1088 | spc |= SPDIF_PCM; | 1080 | spc |= CS42L73_SPDIF_PCM; |
1089 | break; | 1081 | break; |
1090 | default: | 1082 | default: |
1091 | return -EINVAL; | 1083 | return -EINVAL; |
1092 | } | 1084 | } |
1093 | 1085 | ||
1094 | if (spc & SPDIF_PCM) { | 1086 | if (spc & CS42L73_SPDIF_PCM) { |
1095 | /* Clear PCM mode, clear PCM_BIT_ORDER bit for MSB->LSB */ | 1087 | /* Clear PCM mode, clear PCM_BIT_ORDER bit for MSB->LSB */ |
1096 | spc &= ~(PCM_MODE_MASK | PCM_BIT_ORDER); | 1088 | spc &= ~(CS42L73_PCM_MODE_MASK | CS42L73_PCM_BIT_ORDER); |
1097 | switch (format) { | 1089 | switch (format) { |
1098 | case SND_SOC_DAIFMT_DSP_B: | 1090 | case SND_SOC_DAIFMT_DSP_B: |
1099 | if (inv == SND_SOC_DAIFMT_IB_IF) | 1091 | if (inv == SND_SOC_DAIFMT_IB_IF) |
1100 | spc |= PCM_MODE0; | 1092 | spc |= CS42L73_PCM_MODE0; |
1101 | if (inv == SND_SOC_DAIFMT_IB_NF) | 1093 | if (inv == SND_SOC_DAIFMT_IB_NF) |
1102 | spc |= PCM_MODE1; | 1094 | spc |= CS42L73_PCM_MODE1; |
1103 | break; | 1095 | break; |
1104 | case SND_SOC_DAIFMT_DSP_A: | 1096 | case SND_SOC_DAIFMT_DSP_A: |
1105 | if (inv == SND_SOC_DAIFMT_IB_IF) | 1097 | if (inv == SND_SOC_DAIFMT_IB_IF) |
1106 | spc |= PCM_MODE1; | 1098 | spc |= CS42L73_PCM_MODE1; |
1107 | break; | 1099 | break; |
1108 | default: | 1100 | default: |
1109 | return -EINVAL; | 1101 | return -EINVAL; |
@@ -1163,7 +1155,7 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream, | |||
1163 | int mclk_coeff; | 1155 | int mclk_coeff; |
1164 | int srate = params_rate(params); | 1156 | int srate = params_rate(params); |
1165 | 1157 | ||
1166 | if (priv->config[id].mmcc & MS_MASTER) { | 1158 | if (priv->config[id].mmcc & CS42L73_MS_MASTER) { |
1167 | /* CS42L73 Master */ | 1159 | /* CS42L73 Master */ |
1168 | /* MCLK -> srate */ | 1160 | /* MCLK -> srate */ |
1169 | mclk_coeff = | 1161 | mclk_coeff = |
@@ -1182,13 +1174,13 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream, | |||
1182 | priv->config[id].spc &= 0xFC; | 1174 | priv->config[id].spc &= 0xFC; |
1183 | /* Use SCLK=64*Fs if internal MCLK >= 6.4MHz */ | 1175 | /* Use SCLK=64*Fs if internal MCLK >= 6.4MHz */ |
1184 | if (priv->mclk >= 6400000) | 1176 | if (priv->mclk >= 6400000) |
1185 | priv->config[id].spc |= MCK_SCLK_64FS; | 1177 | priv->config[id].spc |= CS42L73_MCK_SCLK_64FS; |
1186 | else | 1178 | else |
1187 | priv->config[id].spc |= MCK_SCLK_MCLK; | 1179 | priv->config[id].spc |= CS42L73_MCK_SCLK_MCLK; |
1188 | } else { | 1180 | } else { |
1189 | /* CS42L73 Slave */ | 1181 | /* CS42L73 Slave */ |
1190 | priv->config[id].spc &= 0xFC; | 1182 | priv->config[id].spc &= 0xFC; |
1191 | priv->config[id].spc |= MCK_SCLK_64FS; | 1183 | priv->config[id].spc |= CS42L73_MCK_SCLK_64FS; |
1192 | } | 1184 | } |
1193 | /* Update ASRCs */ | 1185 | /* Update ASRCs */ |
1194 | priv->config[id].srate = srate; | 1186 | priv->config[id].srate = srate; |
@@ -1208,8 +1200,8 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec, | |||
1208 | 1200 | ||
1209 | switch (level) { | 1201 | switch (level) { |
1210 | case SND_SOC_BIAS_ON: | 1202 | case SND_SOC_BIAS_ON: |
1211 | snd_soc_update_bits(codec, CS42L73_DMMCC, MCLKDIS, 0); | 1203 | snd_soc_update_bits(codec, CS42L73_DMMCC, CS42L73_MCLKDIS, 0); |
1212 | snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 0); | 1204 | snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 0); |
1213 | break; | 1205 | break; |
1214 | 1206 | ||
1215 | case SND_SOC_BIAS_PREPARE: | 1207 | case SND_SOC_BIAS_PREPARE: |
@@ -1220,11 +1212,11 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec, | |||
1220 | regcache_cache_only(cs42l73->regmap, false); | 1212 | regcache_cache_only(cs42l73->regmap, false); |
1221 | regcache_sync(cs42l73->regmap); | 1213 | regcache_sync(cs42l73->regmap); |
1222 | } | 1214 | } |
1223 | snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 1); | 1215 | snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 1); |
1224 | break; | 1216 | break; |
1225 | 1217 | ||
1226 | case SND_SOC_BIAS_OFF: | 1218 | case SND_SOC_BIAS_OFF: |
1227 | snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 1); | 1219 | snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 1); |
1228 | if (cs42l73->shutdwn_delay > 0) { | 1220 | if (cs42l73->shutdwn_delay > 0) { |
1229 | mdelay(cs42l73->shutdwn_delay); | 1221 | mdelay(cs42l73->shutdwn_delay); |
1230 | cs42l73->shutdwn_delay = 0; | 1222 | cs42l73->shutdwn_delay = 0; |
@@ -1233,7 +1225,7 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec, | |||
1233 | * down. | 1225 | * down. |
1234 | */ | 1226 | */ |
1235 | } | 1227 | } |
1236 | snd_soc_update_bits(codec, CS42L73_DMMCC, MCLKDIS, 1); | 1228 | snd_soc_update_bits(codec, CS42L73_DMMCC, CS42L73_MCLKDIS, 1); |
1237 | break; | 1229 | break; |
1238 | } | 1230 | } |
1239 | codec->dapm.bias_level = level; | 1231 | codec->dapm.bias_level = level; |
@@ -1367,11 +1359,16 @@ static int cs42l73_probe(struct snd_soc_codec *codec) | |||
1367 | return ret; | 1359 | return ret; |
1368 | } | 1360 | } |
1369 | 1361 | ||
1370 | regcache_cache_only(cs42l73->regmap, true); | ||
1371 | |||
1372 | cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1362 | cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1373 | 1363 | ||
1374 | cs42l73->mclksel = CS42L73_CLKID_MCLK1; /* MCLK1 as master clk */ | 1364 | /* Set Charge Pump Frequency */ |
1365 | if (cs42l73->pdata.chgfreq) | ||
1366 | snd_soc_update_bits(codec, CS42L73_CPFCHC, | ||
1367 | CS42L73_CHARGEPUMP_MASK, | ||
1368 | cs42l73->pdata.chgfreq << 4); | ||
1369 | |||
1370 | /* MCLK1 as master clk */ | ||
1371 | cs42l73->mclksel = CS42L73_CLKID_MCLK1; | ||
1375 | cs42l73->mclk = 0; | 1372 | cs42l73->mclk = 0; |
1376 | 1373 | ||
1377 | return ret; | 1374 | return ret; |
@@ -1415,9 +1412,11 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, | |||
1415 | const struct i2c_device_id *id) | 1412 | const struct i2c_device_id *id) |
1416 | { | 1413 | { |
1417 | struct cs42l73_private *cs42l73; | 1414 | struct cs42l73_private *cs42l73; |
1415 | struct cs42l73_platform_data *pdata = dev_get_platdata(&i2c_client->dev); | ||
1418 | int ret; | 1416 | int ret; |
1419 | unsigned int devid = 0; | 1417 | unsigned int devid = 0; |
1420 | unsigned int reg; | 1418 | unsigned int reg; |
1419 | u32 val32; | ||
1421 | 1420 | ||
1422 | cs42l73 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l73_private), | 1421 | cs42l73 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l73_private), |
1423 | GFP_KERNEL); | 1422 | GFP_KERNEL); |
@@ -1426,14 +1425,49 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, | |||
1426 | return -ENOMEM; | 1425 | return -ENOMEM; |
1427 | } | 1426 | } |
1428 | 1427 | ||
1429 | i2c_set_clientdata(i2c_client, cs42l73); | ||
1430 | |||
1431 | cs42l73->regmap = devm_regmap_init_i2c(i2c_client, &cs42l73_regmap); | 1428 | cs42l73->regmap = devm_regmap_init_i2c(i2c_client, &cs42l73_regmap); |
1432 | if (IS_ERR(cs42l73->regmap)) { | 1429 | if (IS_ERR(cs42l73->regmap)) { |
1433 | ret = PTR_ERR(cs42l73->regmap); | 1430 | ret = PTR_ERR(cs42l73->regmap); |
1434 | dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); | 1431 | dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); |
1435 | return ret; | 1432 | return ret; |
1436 | } | 1433 | } |
1434 | |||
1435 | if (pdata) { | ||
1436 | cs42l73->pdata = *pdata; | ||
1437 | } else { | ||
1438 | pdata = devm_kzalloc(&i2c_client->dev, | ||
1439 | sizeof(struct cs42l73_platform_data), | ||
1440 | GFP_KERNEL); | ||
1441 | if (!pdata) { | ||
1442 | dev_err(&i2c_client->dev, "could not allocate pdata\n"); | ||
1443 | return -ENOMEM; | ||
1444 | } | ||
1445 | if (i2c_client->dev.of_node) { | ||
1446 | if (of_property_read_u32(i2c_client->dev.of_node, | ||
1447 | "chgfreq", &val32) >= 0) | ||
1448 | pdata->chgfreq = val32; | ||
1449 | } | ||
1450 | pdata->reset_gpio = of_get_named_gpio(i2c_client->dev.of_node, | ||
1451 | "reset-gpio", 0); | ||
1452 | cs42l73->pdata = *pdata; | ||
1453 | } | ||
1454 | |||
1455 | i2c_set_clientdata(i2c_client, cs42l73); | ||
1456 | |||
1457 | if (cs42l73->pdata.reset_gpio) { | ||
1458 | ret = gpio_request_one(cs42l73->pdata.reset_gpio, | ||
1459 | GPIOF_OUT_INIT_HIGH, "CS42L73 /RST"); | ||
1460 | if (ret < 0) { | ||
1461 | dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n", | ||
1462 | cs42l73->pdata.reset_gpio, ret); | ||
1463 | return ret; | ||
1464 | } | ||
1465 | gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 0); | ||
1466 | gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 1); | ||
1467 | } | ||
1468 | |||
1469 | regcache_cache_bypass(cs42l73->regmap, true); | ||
1470 | |||
1437 | /* initialize codec */ | 1471 | /* initialize codec */ |
1438 | ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, ®); | 1472 | ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, ®); |
1439 | devid = (reg & 0xFF) << 12; | 1473 | devid = (reg & 0xFF) << 12; |
@@ -1444,7 +1478,6 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, | |||
1444 | ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_E, ®); | 1478 | ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_E, ®); |
1445 | devid |= (reg & 0xF0) >> 4; | 1479 | devid |= (reg & 0xF0) >> 4; |
1446 | 1480 | ||
1447 | |||
1448 | if (devid != CS42L73_DEVID) { | 1481 | if (devid != CS42L73_DEVID) { |
1449 | ret = -ENODEV; | 1482 | ret = -ENODEV; |
1450 | dev_err(&i2c_client->dev, | 1483 | dev_err(&i2c_client->dev, |
@@ -1462,7 +1495,7 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, | |||
1462 | dev_info(&i2c_client->dev, | 1495 | dev_info(&i2c_client->dev, |
1463 | "Cirrus Logic CS42L73, Revision: %02X\n", reg & 0xFF); | 1496 | "Cirrus Logic CS42L73, Revision: %02X\n", reg & 0xFF); |
1464 | 1497 | ||
1465 | regcache_cache_only(cs42l73->regmap, true); | 1498 | regcache_cache_bypass(cs42l73->regmap, false); |
1466 | 1499 | ||
1467 | ret = snd_soc_register_codec(&i2c_client->dev, | 1500 | ret = snd_soc_register_codec(&i2c_client->dev, |
1468 | &soc_codec_dev_cs42l73, cs42l73_dai, | 1501 | &soc_codec_dev_cs42l73, cs42l73_dai, |
@@ -1478,6 +1511,12 @@ static int cs42l73_i2c_remove(struct i2c_client *client) | |||
1478 | return 0; | 1511 | return 0; |
1479 | } | 1512 | } |
1480 | 1513 | ||
1514 | static const struct of_device_id cs42l73_of_match[] = { | ||
1515 | { .compatible = "cirrus,cs42l73", }, | ||
1516 | {}, | ||
1517 | }; | ||
1518 | MODULE_DEVICE_TABLE(of, cs42l73_of_match); | ||
1519 | |||
1481 | static const struct i2c_device_id cs42l73_id[] = { | 1520 | static const struct i2c_device_id cs42l73_id[] = { |
1482 | {"cs42l73", 0}, | 1521 | {"cs42l73", 0}, |
1483 | {} | 1522 | {} |
@@ -1489,6 +1528,7 @@ static struct i2c_driver cs42l73_i2c_driver = { | |||
1489 | .driver = { | 1528 | .driver = { |
1490 | .name = "cs42l73", | 1529 | .name = "cs42l73", |
1491 | .owner = THIS_MODULE, | 1530 | .owner = THIS_MODULE, |
1531 | .of_match_table = cs42l73_of_match, | ||
1492 | }, | 1532 | }, |
1493 | .id_table = cs42l73_id, | 1533 | .id_table = cs42l73_id, |
1494 | .probe = cs42l73_i2c_probe, | 1534 | .probe = cs42l73_i2c_probe, |