diff options
author | Oder Chiou <oder_chiou@realtek.com> | 2014-10-06 04:30:51 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2014-10-20 07:22:20 -0400 |
commit | af48f1d08a5474184da9aaf8b77f4a2848b1875e (patch) | |
tree | 59de8e574da74fe9ee49b8f426209a4ee5d91a6b | |
parent | 40eb90a18e93fbd4fd0e6892b31241356c3c8e43 (diff) |
ASoC: rt5677: Support DSP function for VAD application
The ALC5677 has a programmable DSP, and there is a SPI that is dadicated for DSP
firmware loading. Therefore, the patch includes a SPI driver for writing the DSP
firmware. The VAD(Voice Activaty Detection) has be implemented and use the DSP to
recognize the key phase.
Signed-off-by: Oder Chiou <oder_chiou@realtek.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | sound/soc/codecs/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/codecs/rt5677-spi.c | 128 | ||||
-rw-r--r-- | sound/soc/codecs/rt5677-spi.h | 21 | ||||
-rw-r--r-- | sound/soc/codecs/rt5677.c | 288 | ||||
-rw-r--r-- | sound/soc/codecs/rt5677.h | 6 |
5 files changed, 440 insertions, 5 deletions
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 5dce451661e4..4435f9f18ce8 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -79,7 +79,7 @@ snd-soc-rt5640-objs := rt5640.o | |||
79 | snd-soc-rt5645-objs := rt5645.o | 79 | snd-soc-rt5645-objs := rt5645.o |
80 | snd-soc-rt5651-objs := rt5651.o | 80 | snd-soc-rt5651-objs := rt5651.o |
81 | snd-soc-rt5670-objs := rt5670.o | 81 | snd-soc-rt5670-objs := rt5670.o |
82 | snd-soc-rt5677-objs := rt5677.o | 82 | snd-soc-rt5677-objs := rt5677.o rt5677-spi.o |
83 | snd-soc-sgtl5000-objs := sgtl5000.o | 83 | snd-soc-sgtl5000-objs := sgtl5000.o |
84 | snd-soc-alc5623-objs := alc5623.o | 84 | snd-soc-alc5623-objs := alc5623.o |
85 | snd-soc-alc5632-objs := alc5632.o | 85 | snd-soc-alc5632-objs := alc5632.o |
diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c new file mode 100644 index 000000000000..11c38f3a9b72 --- /dev/null +++ b/sound/soc/codecs/rt5677-spi.c | |||
@@ -0,0 +1,128 @@ | |||
1 | /* | ||
2 | * rt5677-spi.c -- RT5677 ALSA SoC audio codec driver | ||
3 | * | ||
4 | * Copyright 2013 Realtek Semiconductor Corp. | ||
5 | * Author: Oder Chiou <oder_chiou@realtek.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/input.h> | ||
14 | #include <linux/spi/spi.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/irq.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/kthread.h> | ||
24 | #include <linux/uaccess.h> | ||
25 | #include <linux/miscdevice.h> | ||
26 | #include <linux/regulator/consumer.h> | ||
27 | #include <linux/pm_qos.h> | ||
28 | #include <linux/sysfs.h> | ||
29 | #include <linux/clk.h> | ||
30 | #include <linux/firmware.h> | ||
31 | |||
32 | #include "rt5677-spi.h" | ||
33 | |||
34 | static struct spi_device *g_spi; | ||
35 | |||
36 | /** | ||
37 | * rt5677_spi_write - Write data to SPI. | ||
38 | * @txbuf: Data Buffer for writing. | ||
39 | * @len: Data length. | ||
40 | * | ||
41 | * | ||
42 | * Returns true for success. | ||
43 | */ | ||
44 | int rt5677_spi_write(u8 *txbuf, size_t len) | ||
45 | { | ||
46 | int status; | ||
47 | |||
48 | status = spi_write(g_spi, txbuf, len); | ||
49 | |||
50 | if (status) | ||
51 | dev_err(&g_spi->dev, "rt5677_spi_write error %d\n", status); | ||
52 | |||
53 | return status; | ||
54 | } | ||
55 | |||
56 | /** | ||
57 | * rt5677_spi_burst_write - Write data to SPI by rt5677 dsp memory address. | ||
58 | * @addr: Start address. | ||
59 | * @txbuf: Data Buffer for writng. | ||
60 | * @len: Data length, it must be a multiple of 8. | ||
61 | * | ||
62 | * | ||
63 | * Returns true for success. | ||
64 | */ | ||
65 | int rt5677_spi_burst_write(u32 addr, const struct firmware *fw) | ||
66 | { | ||
67 | u8 spi_cmd = RT5677_SPI_CMD_BURST_WRITE; | ||
68 | u8 *write_buf; | ||
69 | unsigned int i, end, offset = 0; | ||
70 | |||
71 | write_buf = kmalloc(RT5677_SPI_BUF_LEN + 6, GFP_KERNEL); | ||
72 | |||
73 | if (write_buf == NULL) | ||
74 | return -ENOMEM; | ||
75 | |||
76 | while (offset < fw->size) { | ||
77 | if (offset + RT5677_SPI_BUF_LEN <= fw->size) | ||
78 | end = RT5677_SPI_BUF_LEN; | ||
79 | else | ||
80 | end = fw->size % RT5677_SPI_BUF_LEN; | ||
81 | |||
82 | write_buf[0] = spi_cmd; | ||
83 | write_buf[1] = ((addr + offset) & 0xff000000) >> 24; | ||
84 | write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16; | ||
85 | write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8; | ||
86 | write_buf[4] = ((addr + offset) & 0x000000ff) >> 0; | ||
87 | |||
88 | for (i = 0; i < end; i += 8) { | ||
89 | write_buf[i + 12] = fw->data[offset + i + 0]; | ||
90 | write_buf[i + 11] = fw->data[offset + i + 1]; | ||
91 | write_buf[i + 10] = fw->data[offset + i + 2]; | ||
92 | write_buf[i + 9] = fw->data[offset + i + 3]; | ||
93 | write_buf[i + 8] = fw->data[offset + i + 4]; | ||
94 | write_buf[i + 7] = fw->data[offset + i + 5]; | ||
95 | write_buf[i + 6] = fw->data[offset + i + 6]; | ||
96 | write_buf[i + 5] = fw->data[offset + i + 7]; | ||
97 | } | ||
98 | |||
99 | write_buf[end + 5] = spi_cmd; | ||
100 | |||
101 | rt5677_spi_write(write_buf, end + 6); | ||
102 | |||
103 | offset += RT5677_SPI_BUF_LEN; | ||
104 | } | ||
105 | |||
106 | kfree(write_buf); | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static int rt5677_spi_probe(struct spi_device *spi) | ||
112 | { | ||
113 | g_spi = spi; | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static struct spi_driver rt5677_spi_driver = { | ||
118 | .driver = { | ||
119 | .name = "rt5677", | ||
120 | .owner = THIS_MODULE, | ||
121 | }, | ||
122 | .probe = rt5677_spi_probe, | ||
123 | }; | ||
124 | module_spi_driver(rt5677_spi_driver); | ||
125 | |||
126 | MODULE_DESCRIPTION("ASoC RT5677 SPI driver"); | ||
127 | MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>"); | ||
128 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/rt5677-spi.h b/sound/soc/codecs/rt5677-spi.h new file mode 100644 index 000000000000..7528bfd0b596 --- /dev/null +++ b/sound/soc/codecs/rt5677-spi.h | |||
@@ -0,0 +1,21 @@ | |||
1 | /* | ||
2 | * rt5677-spi.h -- RT5677 ALSA SoC audio codec driver | ||
3 | * | ||
4 | * Copyright 2013 Realtek Semiconductor Corp. | ||
5 | * Author: Oder Chiou <oder_chiou@realtek.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef __RT5671_SPI_H__ | ||
13 | #define __RT5671_SPI_H__ | ||
14 | |||
15 | #define RT5677_SPI_BUF_LEN 240 | ||
16 | #define RT5677_SPI_CMD_BURST_WRITE 0x05 | ||
17 | |||
18 | int rt5677_spi_write(u8 *txbuf, size_t len); | ||
19 | int rt5677_spi_burst_write(u32 addr, const struct firmware *fw); | ||
20 | |||
21 | #endif /* __RT5677_SPI_H__ */ | ||
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index a454df39b7a5..e6e54fa648aa 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/spi/spi.h> | 22 | #include <linux/spi/spi.h> |
23 | #include <linux/firmware.h> | ||
23 | #include <linux/gpio.h> | 24 | #include <linux/gpio.h> |
24 | #include <sound/core.h> | 25 | #include <sound/core.h> |
25 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
@@ -31,6 +32,7 @@ | |||
31 | 32 | ||
32 | #include "rl6231.h" | 33 | #include "rl6231.h" |
33 | #include "rt5677.h" | 34 | #include "rt5677.h" |
35 | #include "rt5677-spi.h" | ||
34 | 36 | ||
35 | #define RT5677_DEVICE_ID 0x6327 | 37 | #define RT5677_DEVICE_ID 0x6327 |
36 | 38 | ||
@@ -537,6 +539,243 @@ static bool rt5677_readable_register(struct device *dev, unsigned int reg) | |||
537 | } | 539 | } |
538 | } | 540 | } |
539 | 541 | ||
542 | /** | ||
543 | * rt5677_dsp_mode_i2c_write_addr - Write value to address on DSP mode. | ||
544 | * @codec: SoC audio codec device. | ||
545 | * @addr: Address index. | ||
546 | * @value: Address data. | ||
547 | * | ||
548 | * | ||
549 | * Returns 0 for success or negative error code. | ||
550 | */ | ||
551 | static int rt5677_dsp_mode_i2c_write_addr(struct snd_soc_codec *codec, | ||
552 | unsigned int addr, unsigned int value, unsigned int opcode) | ||
553 | { | ||
554 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | ||
555 | int ret; | ||
556 | |||
557 | mutex_lock(&rt5677->dsp_cmd_lock); | ||
558 | |||
559 | ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_ADDR_MSB, addr >> 16); | ||
560 | if (ret < 0) { | ||
561 | dev_err(codec->dev, "Failed to set addr msb value: %d\n", ret); | ||
562 | goto err; | ||
563 | } | ||
564 | |||
565 | ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_ADDR_LSB, | ||
566 | addr & 0xffff); | ||
567 | if (ret < 0) { | ||
568 | dev_err(codec->dev, "Failed to set addr lsb value: %d\n", ret); | ||
569 | goto err; | ||
570 | } | ||
571 | |||
572 | ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_DATA_MSB, | ||
573 | value >> 16); | ||
574 | if (ret < 0) { | ||
575 | dev_err(codec->dev, "Failed to set data msb value: %d\n", ret); | ||
576 | goto err; | ||
577 | } | ||
578 | |||
579 | ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_DATA_LSB, | ||
580 | value & 0xffff); | ||
581 | if (ret < 0) { | ||
582 | dev_err(codec->dev, "Failed to set data lsb value: %d\n", ret); | ||
583 | goto err; | ||
584 | } | ||
585 | |||
586 | ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_OP_CODE, opcode); | ||
587 | if (ret < 0) { | ||
588 | dev_err(codec->dev, "Failed to set op code value: %d\n", ret); | ||
589 | goto err; | ||
590 | } | ||
591 | |||
592 | err: | ||
593 | mutex_unlock(&rt5677->dsp_cmd_lock); | ||
594 | |||
595 | return ret; | ||
596 | } | ||
597 | |||
598 | /** | ||
599 | * rt5677_dsp_mode_i2c_read_addr - Read value from address on DSP mode. | ||
600 | * @codec: SoC audio codec device. | ||
601 | * @addr: Address index. | ||
602 | * @value: Address data. | ||
603 | * | ||
604 | * Returns 0 for success or negative error code. | ||
605 | */ | ||
606 | static int rt5677_dsp_mode_i2c_read_addr( | ||
607 | struct snd_soc_codec *codec, unsigned int addr, unsigned int *value) | ||
608 | { | ||
609 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | ||
610 | int ret; | ||
611 | unsigned int msb, lsb; | ||
612 | |||
613 | mutex_lock(&rt5677->dsp_cmd_lock); | ||
614 | |||
615 | ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_ADDR_MSB, addr >> 16); | ||
616 | if (ret < 0) { | ||
617 | dev_err(codec->dev, "Failed to set addr msb value: %d\n", ret); | ||
618 | goto err; | ||
619 | } | ||
620 | |||
621 | ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_ADDR_LSB, | ||
622 | addr & 0xffff); | ||
623 | if (ret < 0) { | ||
624 | dev_err(codec->dev, "Failed to set addr lsb value: %d\n", ret); | ||
625 | goto err; | ||
626 | } | ||
627 | |||
628 | ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_OP_CODE , 0x0002); | ||
629 | if (ret < 0) { | ||
630 | dev_err(codec->dev, "Failed to set op code value: %d\n", ret); | ||
631 | goto err; | ||
632 | } | ||
633 | |||
634 | regmap_read(rt5677->regmap, RT5677_DSP_I2C_DATA_MSB, &msb); | ||
635 | regmap_read(rt5677->regmap, RT5677_DSP_I2C_DATA_LSB, &lsb); | ||
636 | *value = (msb << 16) | lsb; | ||
637 | |||
638 | err: | ||
639 | mutex_unlock(&rt5677->dsp_cmd_lock); | ||
640 | |||
641 | return ret; | ||
642 | } | ||
643 | |||
644 | /** | ||
645 | * rt5677_dsp_mode_i2c_write - Write register on DSP mode. | ||
646 | * @codec: SoC audio codec device. | ||
647 | * @reg: Register index. | ||
648 | * @value: Register data. | ||
649 | * | ||
650 | * | ||
651 | * Returns 0 for success or negative error code. | ||
652 | */ | ||
653 | static int rt5677_dsp_mode_i2c_write(struct snd_soc_codec *codec, | ||
654 | unsigned int reg, unsigned int value) | ||
655 | { | ||
656 | return rt5677_dsp_mode_i2c_write_addr(codec, 0x18020000 + reg * 2, | ||
657 | value, 0x0001); | ||
658 | } | ||
659 | |||
660 | /** | ||
661 | * rt5677_dsp_mode_i2c_read - Read register on DSP mode. | ||
662 | * @codec: SoC audio codec device. | ||
663 | * @reg: Register index. | ||
664 | * | ||
665 | * | ||
666 | * Returns Register value. | ||
667 | */ | ||
668 | static unsigned int rt5677_dsp_mode_i2c_read( | ||
669 | struct snd_soc_codec *codec, unsigned int reg) | ||
670 | { | ||
671 | unsigned int value = 0; | ||
672 | |||
673 | rt5677_dsp_mode_i2c_read_addr(codec, 0x18020000 + reg * 2, &value); | ||
674 | |||
675 | return value; | ||
676 | } | ||
677 | |||
678 | /** | ||
679 | * rt5677_dsp_mode_i2c_update_bits - update register on DSP mode. | ||
680 | * @codec: audio codec | ||
681 | * @reg: register index. | ||
682 | * @mask: register mask | ||
683 | * @value: new value | ||
684 | * | ||
685 | * | ||
686 | * Returns 1 for change, 0 for no change, or negative error code. | ||
687 | */ | ||
688 | static int rt5677_dsp_mode_i2c_update_bits(struct snd_soc_codec *codec, | ||
689 | unsigned int reg, unsigned int mask, unsigned int value) | ||
690 | { | ||
691 | unsigned int old, new; | ||
692 | int change, ret; | ||
693 | |||
694 | ret = rt5677_dsp_mode_i2c_read(codec, reg); | ||
695 | if (ret < 0) { | ||
696 | dev_err(codec->dev, "Failed to read reg: %d\n", ret); | ||
697 | goto err; | ||
698 | } | ||
699 | |||
700 | old = ret; | ||
701 | new = (old & ~mask) | (value & mask); | ||
702 | change = old != new; | ||
703 | if (change) { | ||
704 | ret = rt5677_dsp_mode_i2c_write(codec, reg, new); | ||
705 | if (ret < 0) { | ||
706 | dev_err(codec->dev, | ||
707 | "Failed to write reg: %d\n", ret); | ||
708 | goto err; | ||
709 | } | ||
710 | } | ||
711 | return change; | ||
712 | |||
713 | err: | ||
714 | return ret; | ||
715 | } | ||
716 | |||
717 | static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on) | ||
718 | { | ||
719 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | ||
720 | static bool activity; | ||
721 | int ret; | ||
722 | |||
723 | if (on && !activity) { | ||
724 | activity = true; | ||
725 | |||
726 | regcache_cache_only(rt5677->regmap, false); | ||
727 | regcache_cache_bypass(rt5677->regmap, true); | ||
728 | |||
729 | regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x1, 0x1); | ||
730 | regmap_update_bits(rt5677->regmap, | ||
731 | RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0f00); | ||
732 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, | ||
733 | RT5677_LDO1_SEL_MASK, 0x0); | ||
734 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, | ||
735 | RT5677_PWR_LDO1, RT5677_PWR_LDO1); | ||
736 | regmap_write(rt5677->regmap, RT5677_GLB_CLK2, 0x0080); | ||
737 | regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x07ff); | ||
738 | regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x07ff); | ||
739 | |||
740 | ret = request_firmware(&rt5677->fw1, RT5677_FIRMWARE1, | ||
741 | codec->dev); | ||
742 | if (ret == 0) { | ||
743 | rt5677_spi_burst_write(0x50000000, rt5677->fw1); | ||
744 | release_firmware(rt5677->fw1); | ||
745 | } | ||
746 | |||
747 | ret = request_firmware(&rt5677->fw2, RT5677_FIRMWARE2, | ||
748 | codec->dev); | ||
749 | if (ret == 0) { | ||
750 | rt5677_spi_burst_write(0x60000000, rt5677->fw2); | ||
751 | release_firmware(rt5677->fw2); | ||
752 | } | ||
753 | |||
754 | rt5677_dsp_mode_i2c_update_bits(codec, RT5677_PWR_DSP1, 0x1, | ||
755 | 0x0); | ||
756 | |||
757 | regcache_cache_bypass(rt5677->regmap, false); | ||
758 | regcache_cache_only(rt5677->regmap, true); | ||
759 | } else if (!on && activity) { | ||
760 | activity = false; | ||
761 | |||
762 | regcache_cache_only(rt5677->regmap, false); | ||
763 | regcache_cache_bypass(rt5677->regmap, true); | ||
764 | |||
765 | rt5677_dsp_mode_i2c_update_bits(codec, RT5677_PWR_DSP1, 0x1, | ||
766 | 0x1); | ||
767 | rt5677_dsp_mode_i2c_write(codec, RT5677_PWR_DSP1, 0x0001); | ||
768 | |||
769 | regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); | ||
770 | |||
771 | regcache_cache_bypass(rt5677->regmap, false); | ||
772 | regcache_mark_dirty(rt5677->regmap); | ||
773 | regcache_sync(rt5677->regmap); | ||
774 | } | ||
775 | |||
776 | return 0; | ||
777 | } | ||
778 | |||
540 | static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); | 779 | static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); |
541 | static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); | 780 | static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); |
542 | static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); | 781 | static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); |
@@ -556,6 +795,31 @@ static unsigned int bst_tlv[] = { | |||
556 | 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), | 795 | 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), |
557 | }; | 796 | }; |
558 | 797 | ||
798 | static int rt5677_dsp_vad_get(struct snd_kcontrol *kcontrol, | ||
799 | struct snd_ctl_elem_value *ucontrol) | ||
800 | { | ||
801 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
802 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | ||
803 | |||
804 | ucontrol->value.integer.value[0] = rt5677->dsp_vad_en; | ||
805 | |||
806 | return 0; | ||
807 | } | ||
808 | |||
809 | static int rt5677_dsp_vad_put(struct snd_kcontrol *kcontrol, | ||
810 | struct snd_ctl_elem_value *ucontrol) | ||
811 | { | ||
812 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
813 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | ||
814 | |||
815 | rt5677->dsp_vad_en = !!ucontrol->value.integer.value[0]; | ||
816 | |||
817 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) | ||
818 | rt5677_set_dsp_vad(codec, rt5677->dsp_vad_en); | ||
819 | |||
820 | return 0; | ||
821 | } | ||
822 | |||
559 | static const struct snd_kcontrol_new rt5677_snd_controls[] = { | 823 | static const struct snd_kcontrol_new rt5677_snd_controls[] = { |
560 | /* OUTPUT Control */ | 824 | /* OUTPUT Control */ |
561 | SOC_SINGLE("OUT1 Playback Switch", RT5677_LOUT1, | 825 | SOC_SINGLE("OUT1 Playback Switch", RT5677_LOUT1, |
@@ -627,6 +891,9 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = { | |||
627 | SOC_DOUBLE_TLV("Mono ADC Boost Volume", RT5677_ADC_BST_CTRL2, | 891 | SOC_DOUBLE_TLV("Mono ADC Boost Volume", RT5677_ADC_BST_CTRL2, |
628 | RT5677_MONO_ADC_L_BST_SFT, RT5677_MONO_ADC_R_BST_SFT, 3, 0, | 892 | RT5677_MONO_ADC_L_BST_SFT, RT5677_MONO_ADC_R_BST_SFT, 3, 0, |
629 | adc_bst_tlv), | 893 | adc_bst_tlv), |
894 | |||
895 | SOC_SINGLE_EXT("DSP VAD Switch", SND_SOC_NOPM, 0, 1, 0, | ||
896 | rt5677_dsp_vad_get, rt5677_dsp_vad_put), | ||
630 | }; | 897 | }; |
631 | 898 | ||
632 | /** | 899 | /** |
@@ -3181,6 +3448,8 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec, | |||
3181 | 3448 | ||
3182 | case SND_SOC_BIAS_PREPARE: | 3449 | case SND_SOC_BIAS_PREPARE: |
3183 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { | 3450 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { |
3451 | rt5677_set_dsp_vad(codec, false); | ||
3452 | |||
3184 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, | 3453 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, |
3185 | RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK, | 3454 | RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK, |
3186 | 0x0055); | 3455 | 0x0055); |
@@ -3214,6 +3483,9 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec, | |||
3214 | regmap_write(rt5677->regmap, RT5677_PWR_ANLG2, 0x0000); | 3483 | regmap_write(rt5677->regmap, RT5677_PWR_ANLG2, 0x0000); |
3215 | regmap_update_bits(rt5677->regmap, | 3484 | regmap_update_bits(rt5677->regmap, |
3216 | RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0000); | 3485 | RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0000); |
3486 | |||
3487 | if (rt5677->dsp_vad_en) | ||
3488 | rt5677_set_dsp_vad(codec, true); | ||
3217 | break; | 3489 | break; |
3218 | 3490 | ||
3219 | default: | 3491 | default: |
@@ -3407,6 +3679,8 @@ static int rt5677_probe(struct snd_soc_codec *codec) | |||
3407 | for (i = 0; i < RT5677_GPIO_NUM; i++) | 3679 | for (i = 0; i < RT5677_GPIO_NUM; i++) |
3408 | rt5677_gpio_config(rt5677, i, rt5677->pdata.gpio_config[i]); | 3680 | rt5677_gpio_config(rt5677, i, rt5677->pdata.gpio_config[i]); |
3409 | 3681 | ||
3682 | mutex_init(&rt5677->dsp_cmd_lock); | ||
3683 | |||
3410 | return 0; | 3684 | return 0; |
3411 | } | 3685 | } |
3412 | 3686 | ||
@@ -3426,8 +3700,11 @@ static int rt5677_suspend(struct snd_soc_codec *codec) | |||
3426 | { | 3700 | { |
3427 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | 3701 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); |
3428 | 3702 | ||
3429 | regcache_cache_only(rt5677->regmap, true); | 3703 | if (!rt5677->dsp_vad_en) { |
3430 | regcache_mark_dirty(rt5677->regmap); | 3704 | regcache_cache_only(rt5677->regmap, true); |
3705 | regcache_mark_dirty(rt5677->regmap); | ||
3706 | } | ||
3707 | |||
3431 | if (gpio_is_valid(rt5677->pow_ldo2)) | 3708 | if (gpio_is_valid(rt5677->pow_ldo2)) |
3432 | gpio_set_value_cansleep(rt5677->pow_ldo2, 0); | 3709 | gpio_set_value_cansleep(rt5677->pow_ldo2, 0); |
3433 | 3710 | ||
@@ -3442,8 +3719,11 @@ static int rt5677_resume(struct snd_soc_codec *codec) | |||
3442 | gpio_set_value_cansleep(rt5677->pow_ldo2, 1); | 3719 | gpio_set_value_cansleep(rt5677->pow_ldo2, 1); |
3443 | msleep(10); | 3720 | msleep(10); |
3444 | } | 3721 | } |
3445 | regcache_cache_only(rt5677->regmap, false); | 3722 | |
3446 | regcache_sync(rt5677->regmap); | 3723 | if (!rt5677->dsp_vad_en) { |
3724 | regcache_cache_only(rt5677->regmap, false); | ||
3725 | regcache_sync(rt5677->regmap); | ||
3726 | } | ||
3447 | 3727 | ||
3448 | return 0; | 3728 | return 0; |
3449 | } | 3729 | } |
diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 99fd023e3290..20efa4a4c82c 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h | |||
@@ -1507,6 +1507,9 @@ | |||
1507 | #define RT5677_GPIO5_FUNC_GPIO (0x0 << 9) | 1507 | #define RT5677_GPIO5_FUNC_GPIO (0x0 << 9) |
1508 | #define RT5677_GPIO5_FUNC_DMIC (0x1 << 9) | 1508 | #define RT5677_GPIO5_FUNC_DMIC (0x1 << 9) |
1509 | 1509 | ||
1510 | #define RT5677_FIRMWARE1 "rt5677_dsp_fw1.bin" | ||
1511 | #define RT5677_FIRMWARE2 "rt5677_dsp_fw2.bin" | ||
1512 | |||
1510 | /* System Clock Source */ | 1513 | /* System Clock Source */ |
1511 | enum { | 1514 | enum { |
1512 | RT5677_SCLK_S_MCLK, | 1515 | RT5677_SCLK_S_MCLK, |
@@ -1546,6 +1549,8 @@ struct rt5677_priv { | |||
1546 | struct snd_soc_codec *codec; | 1549 | struct snd_soc_codec *codec; |
1547 | struct rt5677_platform_data pdata; | 1550 | struct rt5677_platform_data pdata; |
1548 | struct regmap *regmap; | 1551 | struct regmap *regmap; |
1552 | const struct firmware *fw1, *fw2; | ||
1553 | struct mutex dsp_cmd_lock; | ||
1549 | 1554 | ||
1550 | int sysclk; | 1555 | int sysclk; |
1551 | int sysclk_src; | 1556 | int sysclk_src; |
@@ -1559,6 +1564,7 @@ struct rt5677_priv { | |||
1559 | #ifdef CONFIG_GPIOLIB | 1564 | #ifdef CONFIG_GPIOLIB |
1560 | struct gpio_chip gpio_chip; | 1565 | struct gpio_chip gpio_chip; |
1561 | #endif | 1566 | #endif |
1567 | bool dsp_vad_en; | ||
1562 | }; | 1568 | }; |
1563 | 1569 | ||
1564 | #endif /* __RT5677_H__ */ | 1570 | #endif /* __RT5677_H__ */ |