diff options
Diffstat (limited to 'sound/soc/codecs/wm9081.c')
-rw-r--r-- | sound/soc/codecs/wm9081.c | 208 |
1 files changed, 59 insertions, 149 deletions
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 76b37ff6c264..ecc7c37180c7 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c | |||
@@ -156,7 +156,8 @@ static struct { | |||
156 | }; | 156 | }; |
157 | 157 | ||
158 | struct wm9081_priv { | 158 | struct wm9081_priv { |
159 | struct snd_soc_codec codec; | 159 | enum snd_soc_control_type control_type; |
160 | void *control_data; | ||
160 | u16 reg_cache[WM9081_MAX_REGISTER + 1]; | 161 | u16 reg_cache[WM9081_MAX_REGISTER + 1]; |
161 | int sysclk_source; | 162 | int sysclk_source; |
162 | int mclk_rate; | 163 | int mclk_rate; |
@@ -1212,8 +1213,8 @@ static struct snd_soc_dai_ops wm9081_dai_ops = { | |||
1212 | /* We report two channels because the CODEC processes a stereo signal, even | 1213 | /* We report two channels because the CODEC processes a stereo signal, even |
1213 | * though it is only capable of handling a mono output. | 1214 | * though it is only capable of handling a mono output. |
1214 | */ | 1215 | */ |
1215 | struct snd_soc_dai wm9081_dai = { | 1216 | static struct snd_soc_dai_driver wm9081_dai = { |
1216 | .name = "WM9081", | 1217 | .name = "wm9081-hifi", |
1217 | .playback = { | 1218 | .playback = { |
1218 | .stream_name = "HiFi Playback", | 1219 | .stream_name = "HiFi Playback", |
1219 | .channels_min = 1, | 1220 | .channels_min = 1, |
@@ -1223,34 +1224,42 @@ struct snd_soc_dai wm9081_dai = { | |||
1223 | }, | 1224 | }, |
1224 | .ops = &wm9081_dai_ops, | 1225 | .ops = &wm9081_dai_ops, |
1225 | }; | 1226 | }; |
1226 | EXPORT_SYMBOL_GPL(wm9081_dai); | ||
1227 | 1227 | ||
1228 | 1228 | static int wm9081_probe(struct snd_soc_codec *codec) | |
1229 | static struct snd_soc_codec *wm9081_codec; | ||
1230 | |||
1231 | static int wm9081_probe(struct platform_device *pdev) | ||
1232 | { | 1229 | { |
1233 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1230 | struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec); |
1234 | struct snd_soc_codec *codec; | 1231 | int ret; |
1235 | struct wm9081_priv *wm9081; | 1232 | u16 reg; |
1236 | int ret = 0; | ||
1237 | 1233 | ||
1238 | if (wm9081_codec == NULL) { | 1234 | codec->control_data = wm9081->control_data; |
1239 | dev_err(&pdev->dev, "Codec device not registered\n"); | 1235 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm9081->control_type); |
1240 | return -ENODEV; | 1236 | if (ret != 0) { |
1237 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
1238 | return ret; | ||
1241 | } | 1239 | } |
1242 | 1240 | ||
1243 | socdev->card->codec = wm9081_codec; | 1241 | reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET); |
1244 | codec = wm9081_codec; | 1242 | if (reg != 0x9081) { |
1245 | wm9081 = snd_soc_codec_get_drvdata(codec); | 1243 | dev_err(codec->dev, "Device is not a WM9081: ID=0x%x\n", reg); |
1244 | ret = -EINVAL; | ||
1245 | return ret; | ||
1246 | } | ||
1246 | 1247 | ||
1247 | /* register pcms */ | 1248 | ret = wm9081_reset(codec); |
1248 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
1249 | if (ret < 0) { | 1249 | if (ret < 0) { |
1250 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | 1250 | dev_err(codec->dev, "Failed to issue reset\n"); |
1251 | goto pcm_err; | 1251 | return ret; |
1252 | } | 1252 | } |
1253 | 1253 | ||
1254 | wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1255 | |||
1256 | /* Enable zero cross by default */ | ||
1257 | reg = snd_soc_read(codec, WM9081_ANALOGUE_LINEOUT); | ||
1258 | snd_soc_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC); | ||
1259 | reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_PGA); | ||
1260 | snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_PGA, | ||
1261 | reg | WM9081_SPKPGAZC); | ||
1262 | |||
1254 | snd_soc_add_controls(codec, wm9081_snd_controls, | 1263 | snd_soc_add_controls(codec, wm9081_snd_controls, |
1255 | ARRAY_SIZE(wm9081_snd_controls)); | 1264 | ARRAY_SIZE(wm9081_snd_controls)); |
1256 | if (!wm9081->retune) { | 1265 | if (!wm9081->retune) { |
@@ -1265,40 +1274,28 @@ static int wm9081_probe(struct platform_device *pdev) | |||
1265 | snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); | 1274 | snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); |
1266 | 1275 | ||
1267 | return ret; | 1276 | return ret; |
1268 | |||
1269 | pcm_err: | ||
1270 | return ret; | ||
1271 | } | 1277 | } |
1272 | 1278 | ||
1273 | static int wm9081_remove(struct platform_device *pdev) | 1279 | static int wm9081_remove(struct snd_soc_codec *codec) |
1274 | { | 1280 | { |
1275 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1281 | wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1276 | |||
1277 | snd_soc_free_pcms(socdev); | ||
1278 | snd_soc_dapm_free(socdev); | ||
1279 | |||
1280 | return 0; | 1282 | return 0; |
1281 | } | 1283 | } |
1282 | 1284 | ||
1283 | #ifdef CONFIG_PM | 1285 | #ifdef CONFIG_PM |
1284 | static int wm9081_suspend(struct platform_device *pdev, pm_message_t state) | 1286 | static int wm9081_suspend(struct snd_soc_codec *codec, pm_message_t state) |
1285 | { | 1287 | { |
1286 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1287 | struct snd_soc_codec *codec = socdev->card->codec; | ||
1288 | |||
1289 | wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1288 | wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1290 | 1289 | ||
1291 | return 0; | 1290 | return 0; |
1292 | } | 1291 | } |
1293 | 1292 | ||
1294 | static int wm9081_resume(struct platform_device *pdev) | 1293 | static int wm9081_resume(struct snd_soc_codec *codec) |
1295 | { | 1294 | { |
1296 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1297 | struct snd_soc_codec *codec = socdev->card->codec; | ||
1298 | u16 *reg_cache = codec->reg_cache; | 1295 | u16 *reg_cache = codec->reg_cache; |
1299 | int i; | 1296 | int i; |
1300 | 1297 | ||
1301 | for (i = 0; i < codec->reg_cache_size; i++) { | 1298 | for (i = 0; i < codec->driver->reg_cache_size; i++) { |
1302 | if (i == WM9081_SOFTWARE_RESET) | 1299 | if (i == WM9081_SOFTWARE_RESET) |
1303 | continue; | 1300 | continue; |
1304 | 1301 | ||
@@ -1314,133 +1311,43 @@ static int wm9081_resume(struct platform_device *pdev) | |||
1314 | #define wm9081_resume NULL | 1311 | #define wm9081_resume NULL |
1315 | #endif | 1312 | #endif |
1316 | 1313 | ||
1317 | struct snd_soc_codec_device soc_codec_dev_wm9081 = { | 1314 | static struct snd_soc_codec_driver soc_codec_dev_wm9081 = { |
1318 | .probe = wm9081_probe, | 1315 | .probe = wm9081_probe, |
1319 | .remove = wm9081_remove, | 1316 | .remove = wm9081_remove, |
1320 | .suspend = wm9081_suspend, | 1317 | .suspend = wm9081_suspend, |
1321 | .resume = wm9081_resume, | 1318 | .resume = wm9081_resume, |
1319 | .set_bias_level = wm9081_set_bias_level, | ||
1320 | .reg_cache_size = ARRAY_SIZE(wm9081_reg_defaults), | ||
1321 | .reg_word_size = sizeof(u16), | ||
1322 | .reg_cache_default = wm9081_reg_defaults, | ||
1323 | .volatile_register = wm9081_volatile_register, | ||
1322 | }; | 1324 | }; |
1323 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm9081); | ||
1324 | |||
1325 | static int wm9081_register(struct wm9081_priv *wm9081, | ||
1326 | enum snd_soc_control_type control) | ||
1327 | { | ||
1328 | struct snd_soc_codec *codec = &wm9081->codec; | ||
1329 | int ret; | ||
1330 | u16 reg; | ||
1331 | |||
1332 | if (wm9081_codec) { | ||
1333 | dev_err(codec->dev, "Another WM9081 is registered\n"); | ||
1334 | ret = -EINVAL; | ||
1335 | goto err; | ||
1336 | } | ||
1337 | |||
1338 | mutex_init(&codec->mutex); | ||
1339 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1340 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1341 | |||
1342 | snd_soc_codec_set_drvdata(codec, wm9081); | ||
1343 | codec->name = "WM9081"; | ||
1344 | codec->owner = THIS_MODULE; | ||
1345 | codec->dai = &wm9081_dai; | ||
1346 | codec->num_dai = 1; | ||
1347 | codec->reg_cache_size = ARRAY_SIZE(wm9081->reg_cache); | ||
1348 | codec->reg_cache = &wm9081->reg_cache; | ||
1349 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
1350 | codec->set_bias_level = wm9081_set_bias_level; | ||
1351 | codec->volatile_register = wm9081_volatile_register; | ||
1352 | |||
1353 | memcpy(codec->reg_cache, wm9081_reg_defaults, | ||
1354 | sizeof(wm9081_reg_defaults)); | ||
1355 | |||
1356 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, control); | ||
1357 | if (ret != 0) { | ||
1358 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
1359 | goto err; | ||
1360 | } | ||
1361 | |||
1362 | reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET); | ||
1363 | if (reg != 0x9081) { | ||
1364 | dev_err(codec->dev, "Device is not a WM9081: ID=0x%x\n", reg); | ||
1365 | ret = -EINVAL; | ||
1366 | goto err; | ||
1367 | } | ||
1368 | |||
1369 | ret = wm9081_reset(codec); | ||
1370 | if (ret < 0) { | ||
1371 | dev_err(codec->dev, "Failed to issue reset\n"); | ||
1372 | goto err; | ||
1373 | } | ||
1374 | |||
1375 | wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1376 | |||
1377 | /* Enable zero cross by default */ | ||
1378 | reg = snd_soc_read(codec, WM9081_ANALOGUE_LINEOUT); | ||
1379 | snd_soc_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC); | ||
1380 | reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_PGA); | ||
1381 | snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_PGA, | ||
1382 | reg | WM9081_SPKPGAZC); | ||
1383 | |||
1384 | wm9081_dai.dev = codec->dev; | ||
1385 | |||
1386 | wm9081_codec = codec; | ||
1387 | |||
1388 | ret = snd_soc_register_codec(codec); | ||
1389 | if (ret != 0) { | ||
1390 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
1391 | goto err; | ||
1392 | } | ||
1393 | |||
1394 | ret = snd_soc_register_dai(&wm9081_dai); | ||
1395 | if (ret != 0) { | ||
1396 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
1397 | goto err_codec; | ||
1398 | } | ||
1399 | |||
1400 | return 0; | ||
1401 | |||
1402 | err_codec: | ||
1403 | snd_soc_unregister_codec(codec); | ||
1404 | err: | ||
1405 | kfree(wm9081); | ||
1406 | return ret; | ||
1407 | } | ||
1408 | |||
1409 | static void wm9081_unregister(struct wm9081_priv *wm9081) | ||
1410 | { | ||
1411 | wm9081_set_bias_level(&wm9081->codec, SND_SOC_BIAS_OFF); | ||
1412 | snd_soc_unregister_dai(&wm9081_dai); | ||
1413 | snd_soc_unregister_codec(&wm9081->codec); | ||
1414 | kfree(wm9081); | ||
1415 | wm9081_codec = NULL; | ||
1416 | } | ||
1417 | 1325 | ||
1326 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1418 | static __devinit int wm9081_i2c_probe(struct i2c_client *i2c, | 1327 | static __devinit int wm9081_i2c_probe(struct i2c_client *i2c, |
1419 | const struct i2c_device_id *id) | 1328 | const struct i2c_device_id *id) |
1420 | { | 1329 | { |
1421 | struct wm9081_priv *wm9081; | 1330 | struct wm9081_priv *wm9081; |
1422 | struct snd_soc_codec *codec; | 1331 | int ret; |
1423 | 1332 | ||
1424 | wm9081 = kzalloc(sizeof(struct wm9081_priv), GFP_KERNEL); | 1333 | wm9081 = kzalloc(sizeof(struct wm9081_priv), GFP_KERNEL); |
1425 | if (wm9081 == NULL) | 1334 | if (wm9081 == NULL) |
1426 | return -ENOMEM; | 1335 | return -ENOMEM; |
1427 | 1336 | ||
1428 | codec = &wm9081->codec; | ||
1429 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1430 | wm9081->retune = i2c->dev.platform_data; | ||
1431 | |||
1432 | i2c_set_clientdata(i2c, wm9081); | 1337 | i2c_set_clientdata(i2c, wm9081); |
1433 | codec->control_data = i2c; | 1338 | wm9081->control_data = i2c; |
1434 | |||
1435 | codec->dev = &i2c->dev; | ||
1436 | 1339 | ||
1437 | return wm9081_register(wm9081, SND_SOC_I2C); | 1340 | ret = snd_soc_register_codec(&i2c->dev, |
1341 | &soc_codec_dev_wm9081, &wm9081_dai, 1); | ||
1342 | if (ret < 0) | ||
1343 | kfree(wm9081); | ||
1344 | return ret; | ||
1438 | } | 1345 | } |
1439 | 1346 | ||
1440 | static __devexit int wm9081_i2c_remove(struct i2c_client *client) | 1347 | static __devexit int wm9081_i2c_remove(struct i2c_client *client) |
1441 | { | 1348 | { |
1442 | struct wm9081_priv *wm9081 = i2c_get_clientdata(client); | 1349 | snd_soc_unregister_codec(&client->dev); |
1443 | wm9081_unregister(wm9081); | 1350 | kfree(i2c_get_clientdata(client)); |
1444 | return 0; | 1351 | return 0; |
1445 | } | 1352 | } |
1446 | 1353 | ||
@@ -1452,31 +1359,34 @@ MODULE_DEVICE_TABLE(i2c, wm9081_i2c_id); | |||
1452 | 1359 | ||
1453 | static struct i2c_driver wm9081_i2c_driver = { | 1360 | static struct i2c_driver wm9081_i2c_driver = { |
1454 | .driver = { | 1361 | .driver = { |
1455 | .name = "wm9081", | 1362 | .name = "wm9081-codec", |
1456 | .owner = THIS_MODULE, | 1363 | .owner = THIS_MODULE, |
1457 | }, | 1364 | }, |
1458 | .probe = wm9081_i2c_probe, | 1365 | .probe = wm9081_i2c_probe, |
1459 | .remove = __devexit_p(wm9081_i2c_remove), | 1366 | .remove = __devexit_p(wm9081_i2c_remove), |
1460 | .id_table = wm9081_i2c_id, | 1367 | .id_table = wm9081_i2c_id, |
1461 | }; | 1368 | }; |
1369 | #endif | ||
1462 | 1370 | ||
1463 | static int __init wm9081_modinit(void) | 1371 | static int __init wm9081_modinit(void) |
1464 | { | 1372 | { |
1465 | int ret; | 1373 | int ret = 0; |
1466 | 1374 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | |
1467 | ret = i2c_add_driver(&wm9081_i2c_driver); | 1375 | ret = i2c_add_driver(&wm9081_i2c_driver); |
1468 | if (ret != 0) { | 1376 | if (ret != 0) { |
1469 | printk(KERN_ERR "Failed to register WM9081 I2C driver: %d\n", | 1377 | printk(KERN_ERR "Failed to register WM9081 I2C driver: %d\n", |
1470 | ret); | 1378 | ret); |
1471 | } | 1379 | } |
1472 | 1380 | #endif | |
1473 | return ret; | 1381 | return ret; |
1474 | } | 1382 | } |
1475 | module_init(wm9081_modinit); | 1383 | module_init(wm9081_modinit); |
1476 | 1384 | ||
1477 | static void __exit wm9081_exit(void) | 1385 | static void __exit wm9081_exit(void) |
1478 | { | 1386 | { |
1387 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1479 | i2c_del_driver(&wm9081_i2c_driver); | 1388 | i2c_del_driver(&wm9081_i2c_driver); |
1389 | #endif | ||
1480 | } | 1390 | } |
1481 | module_exit(wm9081_exit); | 1391 | module_exit(wm9081_exit); |
1482 | 1392 | ||