aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/soc-cache.c232
1 files changed, 177 insertions, 55 deletions
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index 687beec56476..78c9869615df 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -595,31 +595,85 @@ static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
595} 595}
596 596
597struct snd_soc_rbtree_node { 597struct snd_soc_rbtree_node {
598 struct rb_node node; 598 struct rb_node node; /* the actual rbtree node holding this block */
599 unsigned int reg; 599 unsigned int base_reg; /* base register handled by this block */
600 unsigned int value; 600 unsigned int word_size; /* number of bytes needed to represent the register index */
601 unsigned int defval; 601 void *block; /* block of adjacent registers */
602 unsigned int blklen; /* number of registers available in the block */
602} __attribute__ ((packed)); 603} __attribute__ ((packed));
603 604
604struct snd_soc_rbtree_ctx { 605struct snd_soc_rbtree_ctx {
605 struct rb_root root; 606 struct rb_root root;
606}; 607};
607 608
609static inline void snd_soc_rbtree_get_base_top_reg(
610 struct snd_soc_rbtree_node *rbnode,
611 unsigned int *base, unsigned int *top)
612{
613 *base = rbnode->base_reg;
614 *top = rbnode->base_reg + rbnode->blklen - 1;
615}
616
617static unsigned int snd_soc_rbtree_get_register(
618 struct snd_soc_rbtree_node *rbnode, unsigned int idx)
619{
620 unsigned int val;
621
622 switch (rbnode->word_size) {
623 case 1: {
624 u8 *p = rbnode->block;
625 val = p[idx];
626 return val;
627 }
628 case 2: {
629 u16 *p = rbnode->block;
630 val = p[idx];
631 return val;
632 }
633 default:
634 BUG();
635 break;
636 }
637 return -1;
638}
639
640static void snd_soc_rbtree_set_register(struct snd_soc_rbtree_node *rbnode,
641 unsigned int idx, unsigned int val)
642{
643 switch (rbnode->word_size) {
644 case 1: {
645 u8 *p = rbnode->block;
646 p[idx] = val;
647 break;
648 }
649 case 2: {
650 u16 *p = rbnode->block;
651 p[idx] = val;
652 break;
653 }
654 default:
655 BUG();
656 break;
657 }
658}
659
608static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup( 660static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup(
609 struct rb_root *root, unsigned int reg) 661 struct rb_root *root, unsigned int reg)
610{ 662{
611 struct rb_node *node; 663 struct rb_node *node;
612 struct snd_soc_rbtree_node *rbnode; 664 struct snd_soc_rbtree_node *rbnode;
665 unsigned int base_reg, top_reg;
613 666
614 node = root->rb_node; 667 node = root->rb_node;
615 while (node) { 668 while (node) {
616 rbnode = container_of(node, struct snd_soc_rbtree_node, node); 669 rbnode = container_of(node, struct snd_soc_rbtree_node, node);
617 if (rbnode->reg < reg) 670 snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
618 node = node->rb_left; 671 if (reg >= base_reg && reg <= top_reg)
619 else if (rbnode->reg > reg)
620 node = node->rb_right;
621 else
622 return rbnode; 672 return rbnode;
673 else if (reg > top_reg)
674 node = node->rb_right;
675 else if (reg < base_reg)
676 node = node->rb_left;
623 } 677 }
624 678
625 return NULL; 679 return NULL;
@@ -630,19 +684,28 @@ static int snd_soc_rbtree_insert(struct rb_root *root,
630{ 684{
631 struct rb_node **new, *parent; 685 struct rb_node **new, *parent;
632 struct snd_soc_rbtree_node *rbnode_tmp; 686 struct snd_soc_rbtree_node *rbnode_tmp;
687 unsigned int base_reg_tmp, top_reg_tmp;
688 unsigned int base_reg;
633 689
634 parent = NULL; 690 parent = NULL;
635 new = &root->rb_node; 691 new = &root->rb_node;
636 while (*new) { 692 while (*new) {
637 rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node, 693 rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node,
638 node); 694 node);
695 /* base and top registers of the current rbnode */
696 snd_soc_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp,
697 &top_reg_tmp);
698 /* base register of the rbnode to be added */
699 base_reg = rbnode->base_reg;
639 parent = *new; 700 parent = *new;
640 if (rbnode_tmp->reg < rbnode->reg) 701 /* if this register has already been inserted, just return */
641 new = &((*new)->rb_left); 702 if (base_reg >= base_reg_tmp &&
642 else if (rbnode_tmp->reg > rbnode->reg) 703 base_reg <= top_reg_tmp)
643 new = &((*new)->rb_right);
644 else
645 return 0; 704 return 0;
705 else if (base_reg > top_reg_tmp)
706 new = &((*new)->rb_right);
707 else if (base_reg < base_reg_tmp)
708 new = &((*new)->rb_left);
646 } 709 }
647 710
648 /* insert the node into the rbtree */ 711 /* insert the node into the rbtree */
@@ -657,57 +720,120 @@ static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
657 struct snd_soc_rbtree_ctx *rbtree_ctx; 720 struct snd_soc_rbtree_ctx *rbtree_ctx;
658 struct rb_node *node; 721 struct rb_node *node;
659 struct snd_soc_rbtree_node *rbnode; 722 struct snd_soc_rbtree_node *rbnode;
723 unsigned int regtmp;
660 unsigned int val; 724 unsigned int val;
661 int ret; 725 int ret;
726 int i;
662 727
663 rbtree_ctx = codec->reg_cache; 728 rbtree_ctx = codec->reg_cache;
664 for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) { 729 for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
665 rbnode = rb_entry(node, struct snd_soc_rbtree_node, node); 730 rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
666 if (rbnode->value == rbnode->defval) 731 for (i = 0; i < rbnode->blklen; ++i) {
667 continue; 732 regtmp = rbnode->base_reg + i;
668 WARN_ON(codec->writable_register && 733 WARN_ON(codec->writable_register &&
669 codec->writable_register(codec, rbnode->reg)); 734 codec->writable_register(codec, regtmp));
670 ret = snd_soc_cache_read(codec, rbnode->reg, &val); 735 val = snd_soc_rbtree_get_register(rbnode, i);
671 if (ret) 736 codec->cache_bypass = 1;
672 return ret; 737 ret = snd_soc_write(codec, regtmp, val);
673 codec->cache_bypass = 1; 738 codec->cache_bypass = 0;
674 ret = snd_soc_write(codec, rbnode->reg, val); 739 if (ret)
675 codec->cache_bypass = 0; 740 return ret;
676 if (ret) 741 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
677 return ret; 742 regtmp, val);
678 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", 743 }
679 rbnode->reg, val);
680 } 744 }
681 745
682 return 0; 746 return 0;
683} 747}
684 748
749static int snd_soc_rbtree_insert_to_block(struct snd_soc_rbtree_node *rbnode,
750 unsigned int pos, unsigned int reg,
751 unsigned int value)
752{
753 u8 *blk;
754
755 blk = krealloc(rbnode->block,
756 (rbnode->blklen + 1) * rbnode->word_size, GFP_KERNEL);
757 if (!blk)
758 return -ENOMEM;
759
760 /* insert the register value in the correct place in the rbnode block */
761 memmove(blk + (pos + 1) * rbnode->word_size,
762 blk + pos * rbnode->word_size,
763 (rbnode->blklen - pos) * rbnode->word_size);
764
765 /* update the rbnode block, its size and the base register */
766 rbnode->block = blk;
767 rbnode->blklen++;
768 if (!pos)
769 rbnode->base_reg = reg;
770
771 snd_soc_rbtree_set_register(rbnode, pos, value);
772 return 0;
773}
774
685static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec, 775static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec,
686 unsigned int reg, unsigned int value) 776 unsigned int reg, unsigned int value)
687{ 777{
688 struct snd_soc_rbtree_ctx *rbtree_ctx; 778 struct snd_soc_rbtree_ctx *rbtree_ctx;
689 struct snd_soc_rbtree_node *rbnode; 779 struct snd_soc_rbtree_node *rbnode, *rbnode_tmp;
780 struct rb_node *node;
781 unsigned int val;
782 unsigned int reg_tmp;
783 unsigned int pos;
784 int i;
785 int ret;
690 786
691 rbtree_ctx = codec->reg_cache; 787 rbtree_ctx = codec->reg_cache;
692 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg); 788 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
693 if (rbnode) { 789 if (rbnode) {
694 if (rbnode->value == value) 790 reg_tmp = reg - rbnode->base_reg;
791 val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
792 if (val == value)
695 return 0; 793 return 0;
696 rbnode->value = value; 794 snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
697 } else { 795 } else {
698 /* bail out early, no need to create the rbnode yet */ 796 /* bail out early, no need to create the rbnode yet */
699 if (!value) 797 if (!value)
700 return 0; 798 return 0;
701 /* 799 /* look for an adjacent register to the one we are about to add */
702 * for uninitialized registers whose value is changed 800 for (node = rb_first(&rbtree_ctx->root); node;
703 * from the default zero, create an rbnode and insert 801 node = rb_next(node)) {
704 * it into the tree. 802 rbnode_tmp = rb_entry(node, struct snd_soc_rbtree_node, node);
803 for (i = 0; i < rbnode_tmp->blklen; ++i) {
804 reg_tmp = rbnode_tmp->base_reg + i;
805 if (abs(reg_tmp - reg) != 1)
806 continue;
807 /* decide where in the block to place our register */
808 if (reg_tmp + 1 == reg)
809 pos = i + 1;
810 else
811 pos = i;
812 ret = snd_soc_rbtree_insert_to_block(rbnode_tmp, pos,
813 reg, value);
814 if (ret)
815 return ret;
816 return 0;
817 }
818 }
819 /* we did not manage to find a place to insert it in an existing
820 * block so create a new rbnode with a single register in its block.
821 * This block will get populated further if any other adjacent
822 * registers get modified in the future.
705 */ 823 */
706 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL); 824 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
707 if (!rbnode) 825 if (!rbnode)
708 return -ENOMEM; 826 return -ENOMEM;
709 rbnode->reg = reg; 827 rbnode->blklen = 1;
710 rbnode->value = value; 828 rbnode->base_reg = reg;
829 rbnode->word_size = codec->driver->reg_word_size;
830 rbnode->block = kmalloc(rbnode->blklen * rbnode->word_size,
831 GFP_KERNEL);
832 if (!rbnode->block) {
833 kfree(rbnode);
834 return -ENOMEM;
835 }
836 snd_soc_rbtree_set_register(rbnode, 0, value);
711 snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode); 837 snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode);
712 } 838 }
713 839
@@ -719,11 +845,13 @@ static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec,
719{ 845{
720 struct snd_soc_rbtree_ctx *rbtree_ctx; 846 struct snd_soc_rbtree_ctx *rbtree_ctx;
721 struct snd_soc_rbtree_node *rbnode; 847 struct snd_soc_rbtree_node *rbnode;
848 unsigned int reg_tmp;
722 849
723 rbtree_ctx = codec->reg_cache; 850 rbtree_ctx = codec->reg_cache;
724 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg); 851 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
725 if (rbnode) { 852 if (rbnode) {
726 *value = rbnode->value; 853 reg_tmp = reg - rbnode->base_reg;
854 *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
727 } else { 855 } else {
728 /* uninitialized registers default to 0 */ 856 /* uninitialized registers default to 0 */
729 *value = 0; 857 *value = 0;
@@ -749,6 +877,7 @@ static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
749 rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node); 877 rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node);
750 next = rb_next(&rbtree_node->node); 878 next = rb_next(&rbtree_node->node);
751 rb_erase(&rbtree_node->node, &rbtree_ctx->root); 879 rb_erase(&rbtree_node->node, &rbtree_ctx->root);
880 kfree(rbtree_node->block);
752 kfree(rbtree_node); 881 kfree(rbtree_node);
753 } 882 }
754 883
@@ -761,10 +890,9 @@ static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
761 890
762static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec) 891static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
763{ 892{
764 struct snd_soc_rbtree_node *rbtree_node;
765 struct snd_soc_rbtree_ctx *rbtree_ctx; 893 struct snd_soc_rbtree_ctx *rbtree_ctx;
766 unsigned int val;
767 unsigned int word_size; 894 unsigned int word_size;
895 unsigned int val;
768 int i; 896 int i;
769 int ret; 897 int ret;
770 898
@@ -778,28 +906,22 @@ static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
778 if (!codec->reg_def_copy) 906 if (!codec->reg_def_copy)
779 return 0; 907 return 0;
780 908
781 /*
782 * populate the rbtree with the initialized registers. All other
783 * registers will be inserted when they are first modified.
784 */
785 word_size = codec->driver->reg_word_size; 909 word_size = codec->driver->reg_word_size;
786 for (i = 0; i < codec->driver->reg_cache_size; ++i) { 910 for (i = 0; i < codec->driver->reg_cache_size; ++i) {
787 val = snd_soc_get_cache_val(codec->reg_def_copy, i, word_size); 911 val = snd_soc_get_cache_val(codec->reg_def_copy, i,
912 word_size);
788 if (!val) 913 if (!val)
789 continue; 914 continue;
790 rbtree_node = kzalloc(sizeof *rbtree_node, GFP_KERNEL); 915 ret = snd_soc_rbtree_cache_write(codec, i, val);
791 if (!rbtree_node) { 916 if (ret)
792 ret = -ENOMEM; 917 goto err;
793 snd_soc_cache_exit(codec);
794 break;
795 }
796 rbtree_node->reg = i;
797 rbtree_node->value = val;
798 rbtree_node->defval = val;
799 snd_soc_rbtree_insert(&rbtree_ctx->root, rbtree_node);
800 } 918 }
801 919
802 return 0; 920 return 0;
921
922err:
923 snd_soc_cache_exit(codec);
924 return ret;
803} 925}
804 926
805#ifdef CONFIG_SND_SOC_CACHE_LZO 927#ifdef CONFIG_SND_SOC_CACHE_LZO