diff options
Diffstat (limited to 'sound/soc/codecs/wm8753.c')
-rw-r--r-- | sound/soc/codecs/wm8753.c | 195 |
1 files changed, 146 insertions, 49 deletions
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index b114c19f530a..e27e7b62b365 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/pm.h> | 39 | #include <linux/pm.h> |
40 | #include <linux/i2c.h> | 40 | #include <linux/i2c.h> |
41 | #include <linux/of_device.h> | 41 | #include <linux/of_device.h> |
42 | #include <linux/regmap.h> | ||
42 | #include <linux/spi/spi.h> | 43 | #include <linux/spi/spi.h> |
43 | #include <linux/slab.h> | 44 | #include <linux/slab.h> |
44 | #include <sound/core.h> | 45 | #include <sound/core.h> |
@@ -65,28 +66,86 @@ static int wm8753_voice_write_dai_fmt(struct snd_soc_codec *codec, | |||
65 | * We can't read the WM8753 register space when we | 66 | * We can't read the WM8753 register space when we |
66 | * are using 2 wire for device control, so we cache them instead. | 67 | * are using 2 wire for device control, so we cache them instead. |
67 | */ | 68 | */ |
68 | static const u16 wm8753_reg[] = { | 69 | static const struct reg_default wm8753_reg_defaults[] = { |
69 | 0x0000, 0x0008, 0x0000, 0x000a, | 70 | { 0x00, 0x0000 }, |
70 | 0x000a, 0x0033, 0x0000, 0x0007, | 71 | { 0x01, 0x0008 }, |
71 | 0x00ff, 0x00ff, 0x000f, 0x000f, | 72 | { 0x02, 0x0000 }, |
72 | 0x007b, 0x0000, 0x0032, 0x0000, | 73 | { 0x03, 0x000a }, |
73 | 0x00c3, 0x00c3, 0x00c0, 0x0000, | 74 | { 0x04, 0x000a }, |
74 | 0x0000, 0x0000, 0x0000, 0x0000, | 75 | { 0x05, 0x0033 }, |
75 | 0x0000, 0x0000, 0x0000, 0x0000, | 76 | { 0x06, 0x0000 }, |
76 | 0x0000, 0x0000, 0x0000, 0x0000, | 77 | { 0x07, 0x0007 }, |
77 | 0x0055, 0x0005, 0x0050, 0x0055, | 78 | { 0x08, 0x00ff }, |
78 | 0x0050, 0x0055, 0x0050, 0x0055, | 79 | { 0x09, 0x00ff }, |
79 | 0x0079, 0x0079, 0x0079, 0x0079, | 80 | { 0x0a, 0x000f }, |
80 | 0x0079, 0x0000, 0x0000, 0x0000, | 81 | { 0x0b, 0x000f }, |
81 | 0x0000, 0x0097, 0x0097, 0x0000, | 82 | { 0x0c, 0x007b }, |
82 | 0x0004, 0x0000, 0x0083, 0x0024, | 83 | { 0x0d, 0x0000 }, |
83 | 0x01ba, 0x0000, 0x0083, 0x0024, | 84 | { 0x0e, 0x0032 }, |
84 | 0x01ba, 0x0000, 0x0000, 0x0000 | 85 | { 0x0f, 0x0000 }, |
86 | { 0x10, 0x00c3 }, | ||
87 | { 0x11, 0x00c3 }, | ||
88 | { 0x12, 0x00c0 }, | ||
89 | { 0x13, 0x0000 }, | ||
90 | { 0x14, 0x0000 }, | ||
91 | { 0x15, 0x0000 }, | ||
92 | { 0x16, 0x0000 }, | ||
93 | { 0x17, 0x0000 }, | ||
94 | { 0x18, 0x0000 }, | ||
95 | { 0x19, 0x0000 }, | ||
96 | { 0x1a, 0x0000 }, | ||
97 | { 0x1b, 0x0000 }, | ||
98 | { 0x1c, 0x0000 }, | ||
99 | { 0x1d, 0x0000 }, | ||
100 | { 0x1e, 0x0000 }, | ||
101 | { 0x1f, 0x0000 }, | ||
102 | { 0x20, 0x0055 }, | ||
103 | { 0x21, 0x0005 }, | ||
104 | { 0x22, 0x0050 }, | ||
105 | { 0x23, 0x0055 }, | ||
106 | { 0x24, 0x0050 }, | ||
107 | { 0x25, 0x0055 }, | ||
108 | { 0x26, 0x0050 }, | ||
109 | { 0x27, 0x0055 }, | ||
110 | { 0x28, 0x0079 }, | ||
111 | { 0x29, 0x0079 }, | ||
112 | { 0x2a, 0x0079 }, | ||
113 | { 0x2b, 0x0079 }, | ||
114 | { 0x2c, 0x0079 }, | ||
115 | { 0x2d, 0x0000 }, | ||
116 | { 0x2e, 0x0000 }, | ||
117 | { 0x2f, 0x0000 }, | ||
118 | { 0x30, 0x0000 }, | ||
119 | { 0x31, 0x0097 }, | ||
120 | { 0x32, 0x0097 }, | ||
121 | { 0x33, 0x0000 }, | ||
122 | { 0x34, 0x0004 }, | ||
123 | { 0x35, 0x0000 }, | ||
124 | { 0x36, 0x0083 }, | ||
125 | { 0x37, 0x0024 }, | ||
126 | { 0x38, 0x01ba }, | ||
127 | { 0x39, 0x0000 }, | ||
128 | { 0x3a, 0x0083 }, | ||
129 | { 0x3b, 0x0024 }, | ||
130 | { 0x3c, 0x01ba }, | ||
131 | { 0x3d, 0x0000 }, | ||
132 | { 0x3e, 0x0000 }, | ||
133 | { 0x3f, 0x0000 }, | ||
85 | }; | 134 | }; |
86 | 135 | ||
136 | static bool wm8753_volatile(struct device *dev, unsigned int reg) | ||
137 | { | ||
138 | return reg == WM8753_RESET; | ||
139 | } | ||
140 | |||
141 | static bool wm8753_writeable(struct device *dev, unsigned int reg) | ||
142 | { | ||
143 | return reg <= WM8753_ADCTL2; | ||
144 | } | ||
145 | |||
87 | /* codec private data */ | 146 | /* codec private data */ |
88 | struct wm8753_priv { | 147 | struct wm8753_priv { |
89 | enum snd_soc_control_type control_type; | 148 | struct regmap *regmap; |
90 | unsigned int sysclk; | 149 | unsigned int sysclk; |
91 | unsigned int pcmclk; | 150 | unsigned int pcmclk; |
92 | 151 | ||
@@ -1383,25 +1442,15 @@ static void wm8753_work(struct work_struct *work) | |||
1383 | static int wm8753_suspend(struct snd_soc_codec *codec) | 1442 | static int wm8753_suspend(struct snd_soc_codec *codec) |
1384 | { | 1443 | { |
1385 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1444 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1445 | codec->cache_sync = 1; | ||
1386 | return 0; | 1446 | return 0; |
1387 | } | 1447 | } |
1388 | 1448 | ||
1389 | static int wm8753_resume(struct snd_soc_codec *codec) | 1449 | static int wm8753_resume(struct snd_soc_codec *codec) |
1390 | { | 1450 | { |
1391 | u16 *reg_cache = codec->reg_cache; | 1451 | struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); |
1392 | int i; | ||
1393 | |||
1394 | /* Sync reg_cache with the hardware */ | ||
1395 | for (i = 1; i < ARRAY_SIZE(wm8753_reg); i++) { | ||
1396 | if (i == WM8753_RESET) | ||
1397 | continue; | ||
1398 | |||
1399 | /* No point in writing hardware default values back */ | ||
1400 | if (reg_cache[i] == wm8753_reg[i]) | ||
1401 | continue; | ||
1402 | 1452 | ||
1403 | snd_soc_write(codec, i, reg_cache[i]); | 1453 | regcache_sync(wm8753->regmap); |
1404 | } | ||
1405 | 1454 | ||
1406 | wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1455 | wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1407 | 1456 | ||
@@ -1423,7 +1472,8 @@ static int wm8753_probe(struct snd_soc_codec *codec) | |||
1423 | 1472 | ||
1424 | INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8753_work); | 1473 | INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8753_work); |
1425 | 1474 | ||
1426 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8753->control_type); | 1475 | codec->control_data = wm8753->regmap; |
1476 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); | ||
1427 | if (ret < 0) { | 1477 | if (ret < 0) { |
1428 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 1478 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
1429 | return ret; | 1479 | return ret; |
@@ -1473,9 +1523,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8753 = { | |||
1473 | .suspend = wm8753_suspend, | 1523 | .suspend = wm8753_suspend, |
1474 | .resume = wm8753_resume, | 1524 | .resume = wm8753_resume, |
1475 | .set_bias_level = wm8753_set_bias_level, | 1525 | .set_bias_level = wm8753_set_bias_level, |
1476 | .reg_cache_size = ARRAY_SIZE(wm8753_reg), | ||
1477 | .reg_word_size = sizeof(u16), | ||
1478 | .reg_cache_default = wm8753_reg, | ||
1479 | 1526 | ||
1480 | .controls = wm8753_snd_controls, | 1527 | .controls = wm8753_snd_controls, |
1481 | .num_controls = ARRAY_SIZE(wm8753_snd_controls), | 1528 | .num_controls = ARRAY_SIZE(wm8753_snd_controls), |
@@ -1491,30 +1538,62 @@ static const struct of_device_id wm8753_of_match[] = { | |||
1491 | }; | 1538 | }; |
1492 | MODULE_DEVICE_TABLE(of, wm8753_of_match); | 1539 | MODULE_DEVICE_TABLE(of, wm8753_of_match); |
1493 | 1540 | ||
1541 | static const struct regmap_config wm8753_regmap = { | ||
1542 | .reg_bits = 7, | ||
1543 | .val_bits = 9, | ||
1544 | |||
1545 | .max_register = WM8753_ADCTL2, | ||
1546 | .writeable_reg = wm8753_writeable, | ||
1547 | .volatile_reg = wm8753_volatile, | ||
1548 | |||
1549 | .cache_type = REGCACHE_RBTREE, | ||
1550 | .reg_defaults = wm8753_reg_defaults, | ||
1551 | .num_reg_defaults = ARRAY_SIZE(wm8753_reg_defaults), | ||
1552 | }; | ||
1553 | |||
1494 | #if defined(CONFIG_SPI_MASTER) | 1554 | #if defined(CONFIG_SPI_MASTER) |
1495 | static int __devinit wm8753_spi_probe(struct spi_device *spi) | 1555 | static int __devinit wm8753_spi_probe(struct spi_device *spi) |
1496 | { | 1556 | { |
1497 | struct wm8753_priv *wm8753; | 1557 | struct wm8753_priv *wm8753; |
1498 | int ret; | 1558 | int ret; |
1499 | 1559 | ||
1500 | wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); | 1560 | wm8753 = devm_kzalloc(&spi->dev, sizeof(struct wm8753_priv), |
1561 | GFP_KERNEL); | ||
1501 | if (wm8753 == NULL) | 1562 | if (wm8753 == NULL) |
1502 | return -ENOMEM; | 1563 | return -ENOMEM; |
1503 | 1564 | ||
1504 | wm8753->control_type = SND_SOC_SPI; | ||
1505 | spi_set_drvdata(spi, wm8753); | 1565 | spi_set_drvdata(spi, wm8753); |
1506 | 1566 | ||
1507 | ret = snd_soc_register_codec(&spi->dev, | 1567 | wm8753->regmap = regmap_init_spi(spi, &wm8753_regmap); |
1508 | &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai)); | 1568 | if (IS_ERR(wm8753->regmap)) { |
1509 | if (ret < 0) | 1569 | ret = PTR_ERR(wm8753->regmap); |
1510 | kfree(wm8753); | 1570 | dev_err(&spi->dev, "Failed to allocate register map: %d\n", |
1571 | ret); | ||
1572 | goto err; | ||
1573 | } | ||
1574 | |||
1575 | ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_wm8753, | ||
1576 | wm8753_dai, ARRAY_SIZE(wm8753_dai)); | ||
1577 | if (ret != 0) { | ||
1578 | dev_err(&spi->dev, "Failed to register CODEC: %d\n", ret); | ||
1579 | goto err_regmap; | ||
1580 | } | ||
1581 | |||
1582 | return 0; | ||
1583 | |||
1584 | err_regmap: | ||
1585 | regmap_exit(wm8753->regmap); | ||
1586 | err: | ||
1511 | return ret; | 1587 | return ret; |
1512 | } | 1588 | } |
1513 | 1589 | ||
1514 | static int __devexit wm8753_spi_remove(struct spi_device *spi) | 1590 | static int __devexit wm8753_spi_remove(struct spi_device *spi) |
1515 | { | 1591 | { |
1592 | struct wm8753_priv *wm8753 = spi_get_drvdata(spi); | ||
1593 | |||
1516 | snd_soc_unregister_codec(&spi->dev); | 1594 | snd_soc_unregister_codec(&spi->dev); |
1517 | kfree(spi_get_drvdata(spi)); | 1595 | regmap_exit(wm8753->regmap); |
1596 | kfree(wm8753); | ||
1518 | return 0; | 1597 | return 0; |
1519 | } | 1598 | } |
1520 | 1599 | ||
@@ -1536,24 +1615,42 @@ static __devinit int wm8753_i2c_probe(struct i2c_client *i2c, | |||
1536 | struct wm8753_priv *wm8753; | 1615 | struct wm8753_priv *wm8753; |
1537 | int ret; | 1616 | int ret; |
1538 | 1617 | ||
1539 | wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); | 1618 | wm8753 = devm_kzalloc(&i2c->dev, sizeof(struct wm8753_priv), |
1619 | GFP_KERNEL); | ||
1540 | if (wm8753 == NULL) | 1620 | if (wm8753 == NULL) |
1541 | return -ENOMEM; | 1621 | return -ENOMEM; |
1542 | 1622 | ||
1543 | i2c_set_clientdata(i2c, wm8753); | 1623 | i2c_set_clientdata(i2c, wm8753); |
1544 | wm8753->control_type = SND_SOC_I2C; | ||
1545 | 1624 | ||
1546 | ret = snd_soc_register_codec(&i2c->dev, | 1625 | wm8753->regmap = regmap_init_i2c(i2c, &wm8753_regmap); |
1547 | &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai)); | 1626 | if (IS_ERR(wm8753->regmap)) { |
1548 | if (ret < 0) | 1627 | ret = PTR_ERR(wm8753->regmap); |
1549 | kfree(wm8753); | 1628 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", |
1629 | ret); | ||
1630 | goto err; | ||
1631 | } | ||
1632 | |||
1633 | ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8753, | ||
1634 | wm8753_dai, ARRAY_SIZE(wm8753_dai)); | ||
1635 | if (ret != 0) { | ||
1636 | dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); | ||
1637 | goto err_regmap; | ||
1638 | } | ||
1639 | |||
1640 | return 0; | ||
1641 | |||
1642 | err_regmap: | ||
1643 | regmap_exit(wm8753->regmap); | ||
1644 | err: | ||
1550 | return ret; | 1645 | return ret; |
1551 | } | 1646 | } |
1552 | 1647 | ||
1553 | static __devexit int wm8753_i2c_remove(struct i2c_client *client) | 1648 | static __devexit int wm8753_i2c_remove(struct i2c_client *client) |
1554 | { | 1649 | { |
1650 | struct wm8753_priv *wm8753 = i2c_get_clientdata(client); | ||
1651 | |||
1555 | snd_soc_unregister_codec(&client->dev); | 1652 | snd_soc_unregister_codec(&client->dev); |
1556 | kfree(i2c_get_clientdata(client)); | 1653 | regmap_exit(wm8753->regmap); |
1557 | return 0; | 1654 | return 0; |
1558 | } | 1655 | } |
1559 | 1656 | ||