diff options
Diffstat (limited to 'sound/soc/codecs/sgtl5000.c')
-rw-r--r-- | sound/soc/codecs/sgtl5000.c | 76 |
1 files changed, 24 insertions, 52 deletions
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 1f4093f3f3a1..0fcbe90f3ef2 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c | |||
@@ -115,6 +115,7 @@ struct sgtl5000_priv { | |||
115 | struct ldo_regulator *ldo; | 115 | struct ldo_regulator *ldo; |
116 | struct regmap *regmap; | 116 | struct regmap *regmap; |
117 | struct clk *mclk; | 117 | struct clk *mclk; |
118 | int revision; | ||
118 | }; | 119 | }; |
119 | 120 | ||
120 | /* | 121 | /* |
@@ -1285,41 +1286,45 @@ static int sgtl5000_replace_vddd_with_ldo(struct snd_soc_codec *codec) | |||
1285 | 1286 | ||
1286 | sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME; | 1287 | sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME; |
1287 | 1288 | ||
1288 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies), | ||
1289 | sgtl5000->supplies); | ||
1290 | |||
1291 | if (ret) { | ||
1292 | ldo_regulator_remove(codec); | ||
1293 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
1294 | return ret; | ||
1295 | } | ||
1296 | |||
1297 | dev_info(codec->dev, "Using internal LDO instead of VDDD\n"); | 1289 | dev_info(codec->dev, "Using internal LDO instead of VDDD\n"); |
1298 | return 0; | 1290 | return 0; |
1299 | } | 1291 | } |
1300 | 1292 | ||
1301 | static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) | 1293 | static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) |
1302 | { | 1294 | { |
1303 | int reg; | ||
1304 | int ret; | 1295 | int ret; |
1305 | int rev; | ||
1306 | int i; | 1296 | int i; |
1307 | int external_vddd = 0; | 1297 | int external_vddd = 0; |
1308 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | 1298 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); |
1299 | struct regulator *vddd; | ||
1309 | 1300 | ||
1310 | for (i = 0; i < ARRAY_SIZE(sgtl5000->supplies); i++) | 1301 | for (i = 0; i < ARRAY_SIZE(sgtl5000->supplies); i++) |
1311 | sgtl5000->supplies[i].supply = supply_names[i]; | 1302 | sgtl5000->supplies[i].supply = supply_names[i]; |
1312 | 1303 | ||
1313 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies), | 1304 | /* External VDDD only works before revision 0x11 */ |
1314 | sgtl5000->supplies); | 1305 | if (sgtl5000->revision < 0x11) { |
1315 | if (!ret) | 1306 | vddd = regulator_get_optional(codec->dev, "VDDD"); |
1316 | external_vddd = 1; | 1307 | if (IS_ERR(vddd)) { |
1317 | else { | 1308 | /* See if it's just not registered yet */ |
1309 | if (PTR_ERR(vddd) == -EPROBE_DEFER) | ||
1310 | return -EPROBE_DEFER; | ||
1311 | } else { | ||
1312 | external_vddd = 1; | ||
1313 | regulator_put(vddd); | ||
1314 | } | ||
1315 | } | ||
1316 | |||
1317 | if (!external_vddd) { | ||
1318 | ret = sgtl5000_replace_vddd_with_ldo(codec); | 1318 | ret = sgtl5000_replace_vddd_with_ldo(codec); |
1319 | if (ret) | 1319 | if (ret) |
1320 | return ret; | 1320 | return ret; |
1321 | } | 1321 | } |
1322 | 1322 | ||
1323 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies), | ||
1324 | sgtl5000->supplies); | ||
1325 | if (ret) | ||
1326 | goto err_ldo_remove; | ||
1327 | |||
1323 | ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies), | 1328 | ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies), |
1324 | sgtl5000->supplies); | 1329 | sgtl5000->supplies); |
1325 | if (ret) | 1330 | if (ret) |
@@ -1328,47 +1333,13 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) | |||
1328 | /* wait for all power rails bring up */ | 1333 | /* wait for all power rails bring up */ |
1329 | udelay(10); | 1334 | udelay(10); |
1330 | 1335 | ||
1331 | /* | ||
1332 | * workaround for revision 0x11 and later, | ||
1333 | * roll back to use internal LDO | ||
1334 | */ | ||
1335 | |||
1336 | ret = regmap_read(sgtl5000->regmap, SGTL5000_CHIP_ID, ®); | ||
1337 | if (ret) | ||
1338 | goto err_regulator_disable; | ||
1339 | |||
1340 | rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT; | ||
1341 | |||
1342 | if (external_vddd && rev >= 0x11) { | ||
1343 | /* disable all regulator first */ | ||
1344 | regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), | ||
1345 | sgtl5000->supplies); | ||
1346 | /* free VDDD regulator */ | ||
1347 | regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), | ||
1348 | sgtl5000->supplies); | ||
1349 | |||
1350 | ret = sgtl5000_replace_vddd_with_ldo(codec); | ||
1351 | if (ret) | ||
1352 | return ret; | ||
1353 | |||
1354 | ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies), | ||
1355 | sgtl5000->supplies); | ||
1356 | if (ret) | ||
1357 | goto err_regulator_free; | ||
1358 | |||
1359 | /* wait for all power rails bring up */ | ||
1360 | udelay(10); | ||
1361 | } | ||
1362 | |||
1363 | return 0; | 1336 | return 0; |
1364 | 1337 | ||
1365 | err_regulator_disable: | ||
1366 | regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), | ||
1367 | sgtl5000->supplies); | ||
1368 | err_regulator_free: | 1338 | err_regulator_free: |
1369 | regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), | 1339 | regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), |
1370 | sgtl5000->supplies); | 1340 | sgtl5000->supplies); |
1371 | if (external_vddd) | 1341 | err_ldo_remove: |
1342 | if (!external_vddd) | ||
1372 | ldo_regulator_remove(codec); | 1343 | ldo_regulator_remove(codec); |
1373 | return ret; | 1344 | return ret; |
1374 | 1345 | ||
@@ -1566,6 +1537,7 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, | |||
1566 | 1537 | ||
1567 | rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT; | 1538 | rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT; |
1568 | dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev); | 1539 | dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev); |
1540 | sgtl5000->revision = rev; | ||
1569 | 1541 | ||
1570 | i2c_set_clientdata(client, sgtl5000); | 1542 | i2c_set_clientdata(client, sgtl5000); |
1571 | 1543 | ||