diff options
Diffstat (limited to 'sound/soc/codecs/wm8900.c')
| -rw-r--r-- | sound/soc/codecs/wm8900.c | 262 |
1 files changed, 107 insertions, 155 deletions
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 3b326c9b5586..6767de10ded0 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c | |||
| @@ -138,6 +138,10 @@ | |||
| 138 | struct snd_soc_codec_device soc_codec_dev_wm8900; | 138 | struct snd_soc_codec_device soc_codec_dev_wm8900; |
| 139 | 139 | ||
| 140 | struct wm8900_priv { | 140 | struct wm8900_priv { |
| 141 | struct snd_soc_codec codec; | ||
| 142 | |||
| 143 | u16 reg_cache[WM8900_MAXREG]; | ||
| 144 | |||
| 141 | u32 fll_in; /* FLL input frequency */ | 145 | u32 fll_in; /* FLL input frequency */ |
| 142 | u32 fll_out; /* FLL output frequency */ | 146 | u32 fll_out; /* FLL output frequency */ |
| 143 | }; | 147 | }; |
| @@ -727,7 +731,8 @@ static int wm8900_add_widgets(struct snd_soc_codec *codec) | |||
| 727 | } | 731 | } |
| 728 | 732 | ||
| 729 | static int wm8900_hw_params(struct snd_pcm_substream *substream, | 733 | static int wm8900_hw_params(struct snd_pcm_substream *substream, |
| 730 | struct snd_pcm_hw_params *params) | 734 | struct snd_pcm_hw_params *params, |
| 735 | struct snd_soc_dai *dai) | ||
| 731 | { | 736 | { |
| 732 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 737 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 733 | struct snd_soc_device *socdev = rtd->socdev; | 738 | struct snd_soc_device *socdev = rtd->socdev; |
| @@ -1117,8 +1122,6 @@ struct snd_soc_dai wm8900_dai = { | |||
| 1117 | }, | 1122 | }, |
| 1118 | .ops = { | 1123 | .ops = { |
| 1119 | .hw_params = wm8900_hw_params, | 1124 | .hw_params = wm8900_hw_params, |
| 1120 | }, | ||
| 1121 | .dai_ops = { | ||
| 1122 | .set_clkdiv = wm8900_set_dai_clkdiv, | 1125 | .set_clkdiv = wm8900_set_dai_clkdiv, |
| 1123 | .set_pll = wm8900_set_dai_pll, | 1126 | .set_pll = wm8900_set_dai_pll, |
| 1124 | .set_fmt = wm8900_set_dai_fmt, | 1127 | .set_fmt = wm8900_set_dai_fmt, |
| @@ -1283,16 +1286,28 @@ static int wm8900_resume(struct platform_device *pdev) | |||
| 1283 | return 0; | 1286 | return 0; |
| 1284 | } | 1287 | } |
| 1285 | 1288 | ||
| 1286 | /* | 1289 | static struct snd_soc_codec *wm8900_codec; |
| 1287 | * initialise the WM8900 driver | 1290 | |
| 1288 | * register the mixer and dsp interfaces with the kernel | 1291 | static int wm8900_i2c_probe(struct i2c_client *i2c, |
| 1289 | */ | 1292 | const struct i2c_device_id *id) |
| 1290 | static int wm8900_init(struct snd_soc_device *socdev) | ||
| 1291 | { | 1293 | { |
| 1292 | struct snd_soc_codec *codec = socdev->codec; | 1294 | struct wm8900_priv *wm8900; |
| 1293 | int ret = 0; | 1295 | struct snd_soc_codec *codec; |
| 1294 | unsigned int reg; | 1296 | unsigned int reg; |
| 1295 | struct i2c_client *i2c_client = socdev->codec->control_data; | 1297 | int ret; |
| 1298 | |||
| 1299 | wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL); | ||
| 1300 | if (wm8900 == NULL) | ||
| 1301 | return -ENOMEM; | ||
| 1302 | |||
| 1303 | codec = &wm8900->codec; | ||
| 1304 | codec->private_data = wm8900; | ||
| 1305 | codec->reg_cache = &wm8900->reg_cache[0]; | ||
| 1306 | codec->reg_cache_size = WM8900_MAXREG; | ||
| 1307 | |||
| 1308 | mutex_init(&codec->mutex); | ||
| 1309 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
| 1310 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
| 1296 | 1311 | ||
| 1297 | codec->name = "WM8900"; | 1312 | codec->name = "WM8900"; |
| 1298 | codec->owner = THIS_MODULE; | 1313 | codec->owner = THIS_MODULE; |
| @@ -1300,33 +1315,28 @@ static int wm8900_init(struct snd_soc_device *socdev) | |||
| 1300 | codec->write = wm8900_write; | 1315 | codec->write = wm8900_write; |
| 1301 | codec->dai = &wm8900_dai; | 1316 | codec->dai = &wm8900_dai; |
| 1302 | codec->num_dai = 1; | 1317 | codec->num_dai = 1; |
| 1303 | codec->reg_cache_size = WM8900_MAXREG; | 1318 | codec->hw_write = (hw_write_t)i2c_master_send; |
| 1304 | codec->reg_cache = kmemdup(wm8900_reg_defaults, | 1319 | codec->control_data = i2c; |
| 1305 | sizeof(wm8900_reg_defaults), GFP_KERNEL); | 1320 | codec->set_bias_level = wm8900_set_bias_level; |
| 1306 | 1321 | codec->dev = &i2c->dev; | |
| 1307 | if (codec->reg_cache == NULL) | ||
| 1308 | return -ENOMEM; | ||
| 1309 | 1322 | ||
| 1310 | reg = wm8900_read(codec, WM8900_REG_ID); | 1323 | reg = wm8900_read(codec, WM8900_REG_ID); |
| 1311 | if (reg != 0x8900) { | 1324 | if (reg != 0x8900) { |
| 1312 | dev_err(&i2c_client->dev, "Device is not a WM8900 - ID %x\n", | 1325 | dev_err(&i2c->dev, "Device is not a WM8900 - ID %x\n", reg); |
| 1313 | reg); | 1326 | ret = -ENODEV; |
| 1314 | return -ENODEV; | 1327 | goto err; |
| 1315 | } | ||
| 1316 | |||
| 1317 | codec->private_data = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL); | ||
| 1318 | if (codec->private_data == NULL) { | ||
| 1319 | ret = -ENOMEM; | ||
| 1320 | goto priv_err; | ||
| 1321 | } | 1328 | } |
| 1322 | 1329 | ||
| 1323 | /* Read back from the chip */ | 1330 | /* Read back from the chip */ |
| 1324 | reg = wm8900_chip_read(codec, WM8900_REG_POWER1); | 1331 | reg = wm8900_chip_read(codec, WM8900_REG_POWER1); |
| 1325 | reg = (reg >> 12) & 0xf; | 1332 | reg = (reg >> 12) & 0xf; |
| 1326 | dev_info(&i2c_client->dev, "WM8900 revision %d\n", reg); | 1333 | dev_info(&i2c->dev, "WM8900 revision %d\n", reg); |
| 1327 | 1334 | ||
| 1328 | wm8900_reset(codec); | 1335 | wm8900_reset(codec); |
| 1329 | 1336 | ||
| 1337 | /* Turn the chip on */ | ||
| 1338 | wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
| 1339 | |||
| 1330 | /* Latch the volume update bits */ | 1340 | /* Latch the volume update bits */ |
| 1331 | wm8900_write(codec, WM8900_REG_LINVOL, | 1341 | wm8900_write(codec, WM8900_REG_LINVOL, |
| 1332 | wm8900_read(codec, WM8900_REG_LINVOL) | 0x100); | 1342 | wm8900_read(codec, WM8900_REG_LINVOL) | 0x100); |
| @@ -1352,160 +1362,98 @@ static int wm8900_init(struct snd_soc_device *socdev) | |||
| 1352 | /* Set the DAC and mixer output bias */ | 1362 | /* Set the DAC and mixer output bias */ |
| 1353 | wm8900_write(codec, WM8900_REG_OUTBIASCTL, 0x81); | 1363 | wm8900_write(codec, WM8900_REG_OUTBIASCTL, 0x81); |
| 1354 | 1364 | ||
| 1355 | /* Register pcms */ | 1365 | wm8900_dai.dev = &i2c->dev; |
| 1356 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
| 1357 | if (ret < 0) { | ||
| 1358 | dev_err(&i2c_client->dev, "Failed to register new PCMs\n"); | ||
| 1359 | goto pcm_err; | ||
| 1360 | } | ||
| 1361 | |||
| 1362 | /* Turn the chip on */ | ||
| 1363 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
| 1364 | wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
| 1365 | |||
| 1366 | wm8900_add_controls(codec); | ||
| 1367 | wm8900_add_widgets(codec); | ||
| 1368 | |||
| 1369 | ret = snd_soc_register_card(socdev); | ||
| 1370 | if (ret < 0) { | ||
| 1371 | dev_err(&i2c_client->dev, "Failed to register card\n"); | ||
| 1372 | goto card_err; | ||
| 1373 | } | ||
| 1374 | return ret; | ||
| 1375 | |||
| 1376 | card_err: | ||
| 1377 | snd_soc_free_pcms(socdev); | ||
| 1378 | snd_soc_dapm_free(socdev); | ||
| 1379 | pcm_err: | ||
| 1380 | kfree(codec->reg_cache); | ||
| 1381 | priv_err: | ||
| 1382 | kfree(codec->private_data); | ||
| 1383 | return ret; | ||
| 1384 | } | ||
| 1385 | 1366 | ||
| 1386 | static struct snd_soc_device *wm8900_socdev; | 1367 | wm8900_codec = codec; |
| 1387 | 1368 | ||
| 1388 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1369 | ret = snd_soc_register_codec(codec); |
| 1389 | 1370 | if (ret != 0) { | |
| 1390 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | 1371 | dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); |
| 1391 | |||
| 1392 | /* Magic definition of all other variables and things */ | ||
| 1393 | I2C_CLIENT_INSMOD; | ||
| 1394 | |||
| 1395 | static struct i2c_driver wm8900_i2c_driver; | ||
| 1396 | static struct i2c_client client_template; | ||
| 1397 | |||
| 1398 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
| 1399 | around */ | ||
| 1400 | static int wm8900_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
| 1401 | { | ||
| 1402 | struct snd_soc_device *socdev = wm8900_socdev; | ||
| 1403 | struct wm8900_setup_data *setup = socdev->codec_data; | ||
| 1404 | struct snd_soc_codec *codec = socdev->codec; | ||
| 1405 | struct i2c_client *i2c; | ||
| 1406 | int ret; | ||
| 1407 | |||
| 1408 | if (addr != setup->i2c_address) | ||
| 1409 | return -ENODEV; | ||
| 1410 | |||
| 1411 | dev_err(&adap->dev, "Probe on %x\n", addr); | ||
| 1412 | |||
| 1413 | client_template.adapter = adap; | ||
| 1414 | client_template.addr = addr; | ||
| 1415 | |||
| 1416 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
| 1417 | if (i2c == NULL) { | ||
| 1418 | kfree(codec); | ||
| 1419 | return -ENOMEM; | ||
| 1420 | } | ||
| 1421 | i2c_set_clientdata(i2c, codec); | ||
| 1422 | codec->control_data = i2c; | ||
| 1423 | |||
| 1424 | ret = i2c_attach_client(i2c); | ||
| 1425 | if (ret < 0) { | ||
| 1426 | dev_err(&adap->dev, | ||
| 1427 | "failed to attach codec at addr %x\n", addr); | ||
| 1428 | goto err; | 1372 | goto err; |
| 1429 | } | 1373 | } |
| 1430 | 1374 | ||
| 1431 | ret = wm8900_init(socdev); | 1375 | ret = snd_soc_register_dai(&wm8900_dai); |
| 1432 | if (ret < 0) { | 1376 | if (ret != 0) { |
| 1433 | dev_err(&adap->dev, "failed to initialise WM8900\n"); | 1377 | dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret); |
| 1434 | goto err; | 1378 | goto err_codec; |
| 1435 | } | 1379 | } |
| 1380 | |||
| 1436 | return ret; | 1381 | return ret; |
| 1437 | 1382 | ||
| 1383 | err_codec: | ||
| 1384 | snd_soc_unregister_codec(codec); | ||
| 1438 | err: | 1385 | err: |
| 1439 | kfree(codec); | 1386 | kfree(wm8900); |
| 1440 | kfree(i2c); | 1387 | wm8900_codec = NULL; |
| 1441 | return ret; | 1388 | return ret; |
| 1442 | } | 1389 | } |
| 1443 | 1390 | ||
| 1444 | static int wm8900_i2c_detach(struct i2c_client *client) | 1391 | static int wm8900_i2c_remove(struct i2c_client *client) |
| 1445 | { | 1392 | { |
| 1446 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 1393 | snd_soc_unregister_dai(&wm8900_dai); |
| 1447 | i2c_detach_client(client); | 1394 | snd_soc_unregister_codec(wm8900_codec); |
| 1448 | kfree(codec->reg_cache); | 1395 | |
| 1449 | kfree(client); | 1396 | wm8900_set_bias_level(wm8900_codec, SND_SOC_BIAS_OFF); |
| 1397 | |||
| 1398 | wm8900_dai.dev = NULL; | ||
| 1399 | kfree(wm8900_codec->private_data); | ||
| 1400 | wm8900_codec = NULL; | ||
| 1401 | |||
| 1450 | return 0; | 1402 | return 0; |
| 1451 | } | 1403 | } |
| 1452 | 1404 | ||
| 1453 | static int wm8900_i2c_attach(struct i2c_adapter *adap) | 1405 | static const struct i2c_device_id wm8900_i2c_id[] = { |
| 1454 | { | 1406 | { "wm8900", 0 }, |
| 1455 | return i2c_probe(adap, &addr_data, wm8900_codec_probe); | 1407 | { } |
| 1456 | } | 1408 | }; |
| 1409 | MODULE_DEVICE_TABLE(i2c, wm8900_i2c_id); | ||
| 1457 | 1410 | ||
| 1458 | /* corgi i2c codec control layer */ | ||
| 1459 | static struct i2c_driver wm8900_i2c_driver = { | 1411 | static struct i2c_driver wm8900_i2c_driver = { |
| 1460 | .driver = { | 1412 | .driver = { |
| 1461 | .name = "WM8900 I2C codec", | 1413 | .name = "WM8900", |
| 1462 | .owner = THIS_MODULE, | 1414 | .owner = THIS_MODULE, |
| 1463 | }, | 1415 | }, |
| 1464 | .attach_adapter = wm8900_i2c_attach, | 1416 | .probe = wm8900_i2c_probe, |
| 1465 | .detach_client = wm8900_i2c_detach, | 1417 | .remove = wm8900_i2c_remove, |
| 1466 | .command = NULL, | 1418 | .id_table = wm8900_i2c_id, |
| 1467 | }; | ||
| 1468 | |||
| 1469 | static struct i2c_client client_template = { | ||
| 1470 | .name = "WM8900", | ||
| 1471 | .driver = &wm8900_i2c_driver, | ||
| 1472 | }; | 1419 | }; |
| 1473 | #endif | ||
| 1474 | 1420 | ||
| 1475 | static int wm8900_probe(struct platform_device *pdev) | 1421 | static int wm8900_probe(struct platform_device *pdev) |
| 1476 | { | 1422 | { |
| 1477 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1423 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
| 1478 | struct wm8900_setup_data *setup; | ||
| 1479 | struct snd_soc_codec *codec; | 1424 | struct snd_soc_codec *codec; |
| 1480 | int ret = 0; | 1425 | int ret = 0; |
| 1481 | 1426 | ||
| 1482 | dev_info(&pdev->dev, "WM8900 Audio Codec\n"); | 1427 | if (!wm8900_codec) { |
| 1483 | 1428 | dev_err(&pdev->dev, "I2C client not yet instantiated\n"); | |
| 1484 | setup = socdev->codec_data; | 1429 | return -ENODEV; |
| 1485 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 1430 | } |
| 1486 | if (codec == NULL) | ||
| 1487 | return -ENOMEM; | ||
| 1488 | |||
| 1489 | mutex_init(&codec->mutex); | ||
| 1490 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
| 1491 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
| 1492 | 1431 | ||
| 1432 | codec = wm8900_codec; | ||
| 1493 | socdev->codec = codec; | 1433 | socdev->codec = codec; |
| 1494 | 1434 | ||
| 1495 | codec->set_bias_level = wm8900_set_bias_level; | 1435 | /* Register pcms */ |
| 1436 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
| 1437 | if (ret < 0) { | ||
| 1438 | dev_err(&pdev->dev, "Failed to register new PCMs\n"); | ||
| 1439 | goto pcm_err; | ||
| 1440 | } | ||
| 1496 | 1441 | ||
| 1497 | wm8900_socdev = socdev; | 1442 | wm8900_add_controls(codec); |
| 1498 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1443 | wm8900_add_widgets(codec); |
| 1499 | if (setup->i2c_address) { | 1444 | |
| 1500 | normal_i2c[0] = setup->i2c_address; | 1445 | ret = snd_soc_init_card(socdev); |
| 1501 | codec->hw_write = (hw_write_t)i2c_master_send; | 1446 | if (ret < 0) { |
| 1502 | ret = i2c_add_driver(&wm8900_i2c_driver); | 1447 | dev_err(&pdev->dev, "Failed to register card\n"); |
| 1503 | if (ret != 0) | 1448 | goto card_err; |
| 1504 | printk(KERN_ERR "can't add i2c driver"); | ||
| 1505 | } | 1449 | } |
| 1506 | #else | 1450 | |
| 1507 | #error Non-I2C interfaces not yet supported | 1451 | return ret; |
| 1508 | #endif | 1452 | |
| 1453 | card_err: | ||
| 1454 | snd_soc_free_pcms(socdev); | ||
| 1455 | snd_soc_dapm_free(socdev); | ||
| 1456 | pcm_err: | ||
| 1509 | return ret; | 1457 | return ret; |
| 1510 | } | 1458 | } |
| 1511 | 1459 | ||
| @@ -1513,17 +1461,9 @@ static int wm8900_probe(struct platform_device *pdev) | |||
| 1513 | static int wm8900_remove(struct platform_device *pdev) | 1461 | static int wm8900_remove(struct platform_device *pdev) |
| 1514 | { | 1462 | { |
| 1515 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1463 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
| 1516 | struct snd_soc_codec *codec = socdev->codec; | ||
| 1517 | |||
| 1518 | if (codec->control_data) | ||
| 1519 | wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
| 1520 | 1464 | ||
| 1521 | snd_soc_free_pcms(socdev); | 1465 | snd_soc_free_pcms(socdev); |
| 1522 | snd_soc_dapm_free(socdev); | 1466 | snd_soc_dapm_free(socdev); |
| 1523 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
| 1524 | i2c_del_driver(&wm8900_i2c_driver); | ||
| 1525 | #endif | ||
| 1526 | kfree(codec); | ||
| 1527 | 1467 | ||
| 1528 | return 0; | 1468 | return 0; |
| 1529 | } | 1469 | } |
| @@ -1536,6 +1476,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8900 = { | |||
| 1536 | }; | 1476 | }; |
| 1537 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900); | 1477 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900); |
| 1538 | 1478 | ||
| 1479 | static int __init wm8900_modinit(void) | ||
| 1480 | { | ||
| 1481 | return i2c_add_driver(&wm8900_i2c_driver); | ||
| 1482 | } | ||
| 1483 | module_init(wm8900_modinit); | ||
| 1484 | |||
| 1485 | static void __exit wm8900_exit(void) | ||
| 1486 | { | ||
| 1487 | i2c_del_driver(&wm8900_i2c_driver); | ||
| 1488 | } | ||
| 1489 | module_exit(wm8900_exit); | ||
| 1490 | |||
| 1539 | MODULE_DESCRIPTION("ASoC WM8900 driver"); | 1491 | MODULE_DESCRIPTION("ASoC WM8900 driver"); |
| 1540 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>"); | 1492 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>"); |
| 1541 | MODULE_LICENSE("GPL"); | 1493 | MODULE_LICENSE("GPL"); |
