diff options
-rw-r--r-- | drivers/base/regmap/internal.h | 2 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-debugfs.c | 50 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 154 | ||||
-rw-r--r-- | include/linux/regmap.h | 6 | ||||
-rw-r--r-- | sound/soc/codecs/wm2200.c | 459 |
5 files changed, 200 insertions, 471 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 80f9ab9c3aa4..ac869d28d5ba 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h | |||
@@ -120,6 +120,8 @@ int _regmap_write(struct regmap *map, unsigned int reg, | |||
120 | 120 | ||
121 | struct regmap_range_node { | 121 | struct regmap_range_node { |
122 | struct rb_node node; | 122 | struct rb_node node; |
123 | const char *name; | ||
124 | struct regmap *map; | ||
123 | 125 | ||
124 | unsigned int range_min; | 126 | unsigned int range_min; |
125 | unsigned int range_max; | 127 | unsigned int range_max; |
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index bb1ff175b962..f4b9dd01c981 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c | |||
@@ -56,15 +56,15 @@ static const struct file_operations regmap_name_fops = { | |||
56 | .llseek = default_llseek, | 56 | .llseek = default_llseek, |
57 | }; | 57 | }; |
58 | 58 | ||
59 | static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, | 59 | static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from, |
60 | size_t count, loff_t *ppos) | 60 | unsigned int to, char __user *user_buf, |
61 | size_t count, loff_t *ppos) | ||
61 | { | 62 | { |
62 | int reg_len, val_len, tot_len; | 63 | int reg_len, val_len, tot_len; |
63 | size_t buf_pos = 0; | 64 | size_t buf_pos = 0; |
64 | loff_t p = 0; | 65 | loff_t p = 0; |
65 | ssize_t ret; | 66 | ssize_t ret; |
66 | int i; | 67 | int i; |
67 | struct regmap *map = file->private_data; | ||
68 | char *buf; | 68 | char *buf; |
69 | unsigned int val; | 69 | unsigned int val; |
70 | 70 | ||
@@ -80,7 +80,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, | |||
80 | val_len = 2 * map->format.val_bytes; | 80 | val_len = 2 * map->format.val_bytes; |
81 | tot_len = reg_len + val_len + 3; /* : \n */ | 81 | tot_len = reg_len + val_len + 3; /* : \n */ |
82 | 82 | ||
83 | for (i = 0; i <= map->max_register; i += map->reg_stride) { | 83 | for (i = from; i <= to; i += map->reg_stride) { |
84 | if (!regmap_readable(map, i)) | 84 | if (!regmap_readable(map, i)) |
85 | continue; | 85 | continue; |
86 | 86 | ||
@@ -95,7 +95,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, | |||
95 | 95 | ||
96 | /* Format the register */ | 96 | /* Format the register */ |
97 | snprintf(buf + buf_pos, count - buf_pos, "%.*x: ", | 97 | snprintf(buf + buf_pos, count - buf_pos, "%.*x: ", |
98 | reg_len, i); | 98 | reg_len, i - from); |
99 | buf_pos += reg_len + 2; | 99 | buf_pos += reg_len + 2; |
100 | 100 | ||
101 | /* Format the value, write all X if we can't read */ | 101 | /* Format the value, write all X if we can't read */ |
@@ -126,6 +126,15 @@ out: | |||
126 | return ret; | 126 | return ret; |
127 | } | 127 | } |
128 | 128 | ||
129 | static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, | ||
130 | size_t count, loff_t *ppos) | ||
131 | { | ||
132 | struct regmap *map = file->private_data; | ||
133 | |||
134 | return regmap_read_debugfs(map, 0, map->max_register, user_buf, | ||
135 | count, ppos); | ||
136 | } | ||
137 | |||
129 | #undef REGMAP_ALLOW_WRITE_DEBUGFS | 138 | #undef REGMAP_ALLOW_WRITE_DEBUGFS |
130 | #ifdef REGMAP_ALLOW_WRITE_DEBUGFS | 139 | #ifdef REGMAP_ALLOW_WRITE_DEBUGFS |
131 | /* | 140 | /* |
@@ -174,6 +183,22 @@ static const struct file_operations regmap_map_fops = { | |||
174 | .llseek = default_llseek, | 183 | .llseek = default_llseek, |
175 | }; | 184 | }; |
176 | 185 | ||
186 | static ssize_t regmap_range_read_file(struct file *file, char __user *user_buf, | ||
187 | size_t count, loff_t *ppos) | ||
188 | { | ||
189 | struct regmap_range_node *range = file->private_data; | ||
190 | struct regmap *map = range->map; | ||
191 | |||
192 | return regmap_read_debugfs(map, range->range_min, range->range_max, | ||
193 | user_buf, count, ppos); | ||
194 | } | ||
195 | |||
196 | static const struct file_operations regmap_range_fops = { | ||
197 | .open = simple_open, | ||
198 | .read = regmap_range_read_file, | ||
199 | .llseek = default_llseek, | ||
200 | }; | ||
201 | |||
177 | static ssize_t regmap_access_read_file(struct file *file, | 202 | static ssize_t regmap_access_read_file(struct file *file, |
178 | char __user *user_buf, size_t count, | 203 | char __user *user_buf, size_t count, |
179 | loff_t *ppos) | 204 | loff_t *ppos) |
@@ -244,6 +269,9 @@ static const struct file_operations regmap_access_fops = { | |||
244 | 269 | ||
245 | void regmap_debugfs_init(struct regmap *map, const char *name) | 270 | void regmap_debugfs_init(struct regmap *map, const char *name) |
246 | { | 271 | { |
272 | struct rb_node *next; | ||
273 | struct regmap_range_node *range_node; | ||
274 | |||
247 | if (name) { | 275 | if (name) { |
248 | map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s", | 276 | map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s", |
249 | dev_name(map->dev), name); | 277 | dev_name(map->dev), name); |
@@ -276,6 +304,18 @@ void regmap_debugfs_init(struct regmap *map, const char *name) | |||
276 | debugfs_create_bool("cache_bypass", 0400, map->debugfs, | 304 | debugfs_create_bool("cache_bypass", 0400, map->debugfs, |
277 | &map->cache_bypass); | 305 | &map->cache_bypass); |
278 | } | 306 | } |
307 | |||
308 | next = rb_first(&map->range_tree); | ||
309 | while (next) { | ||
310 | range_node = rb_entry(next, struct regmap_range_node, node); | ||
311 | |||
312 | if (range_node->name) | ||
313 | debugfs_create_file(range_node->name, 0400, | ||
314 | map->debugfs, range_node, | ||
315 | ®map_range_fops); | ||
316 | |||
317 | next = rb_next(&range_node->node); | ||
318 | } | ||
279 | } | 319 | } |
280 | 320 | ||
281 | void regmap_debugfs_exit(struct regmap *map) | 321 | void regmap_debugfs_exit(struct regmap *map) |
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 52069d29ff12..96253cd949e9 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
@@ -519,20 +519,38 @@ struct regmap *regmap_init(struct device *dev, | |||
519 | } | 519 | } |
520 | 520 | ||
521 | map->range_tree = RB_ROOT; | 521 | map->range_tree = RB_ROOT; |
522 | for (i = 0; i < config->n_ranges; i++) { | 522 | for (i = 0; i < config->num_ranges; i++) { |
523 | const struct regmap_range_cfg *range_cfg = &config->ranges[i]; | 523 | const struct regmap_range_cfg *range_cfg = &config->ranges[i]; |
524 | struct regmap_range_node *new; | 524 | struct regmap_range_node *new; |
525 | 525 | ||
526 | /* Sanity check */ | 526 | /* Sanity check */ |
527 | if (range_cfg->range_max < range_cfg->range_min || | 527 | if (range_cfg->range_max < range_cfg->range_min) { |
528 | range_cfg->range_max > map->max_register || | 528 | dev_err(map->dev, "Invalid range %d: %d < %d\n", i, |
529 | range_cfg->selector_reg > map->max_register || | 529 | range_cfg->range_max, range_cfg->range_min); |
530 | range_cfg->window_len == 0) | ||
531 | goto err_range; | 530 | goto err_range; |
531 | } | ||
532 | |||
533 | if (range_cfg->range_max > map->max_register) { | ||
534 | dev_err(map->dev, "Invalid range %d: %d > %d\n", i, | ||
535 | range_cfg->range_max, map->max_register); | ||
536 | goto err_range; | ||
537 | } | ||
538 | |||
539 | if (range_cfg->selector_reg > map->max_register) { | ||
540 | dev_err(map->dev, | ||
541 | "Invalid range %d: selector out of map\n", i); | ||
542 | goto err_range; | ||
543 | } | ||
544 | |||
545 | if (range_cfg->window_len == 0) { | ||
546 | dev_err(map->dev, "Invalid range %d: window_len 0\n", | ||
547 | i); | ||
548 | goto err_range; | ||
549 | } | ||
532 | 550 | ||
533 | /* Make sure, that this register range has no selector | 551 | /* Make sure, that this register range has no selector |
534 | or data window within its boundary */ | 552 | or data window within its boundary */ |
535 | for (j = 0; j < config->n_ranges; j++) { | 553 | for (j = 0; j < config->num_ranges; j++) { |
536 | unsigned sel_reg = config->ranges[j].selector_reg; | 554 | unsigned sel_reg = config->ranges[j].selector_reg; |
537 | unsigned win_min = config->ranges[j].window_start; | 555 | unsigned win_min = config->ranges[j].window_start; |
538 | unsigned win_max = win_min + | 556 | unsigned win_max = win_min + |
@@ -540,11 +558,17 @@ struct regmap *regmap_init(struct device *dev, | |||
540 | 558 | ||
541 | if (range_cfg->range_min <= sel_reg && | 559 | if (range_cfg->range_min <= sel_reg && |
542 | sel_reg <= range_cfg->range_max) { | 560 | sel_reg <= range_cfg->range_max) { |
561 | dev_err(map->dev, | ||
562 | "Range %d: selector for %d in window\n", | ||
563 | i, j); | ||
543 | goto err_range; | 564 | goto err_range; |
544 | } | 565 | } |
545 | 566 | ||
546 | if (!(win_max < range_cfg->range_min || | 567 | if (!(win_max < range_cfg->range_min || |
547 | win_min > range_cfg->range_max)) { | 568 | win_min > range_cfg->range_max)) { |
569 | dev_err(map->dev, | ||
570 | "Range %d: window for %d in window\n", | ||
571 | i, j); | ||
548 | goto err_range; | 572 | goto err_range; |
549 | } | 573 | } |
550 | } | 574 | } |
@@ -555,6 +579,8 @@ struct regmap *regmap_init(struct device *dev, | |||
555 | goto err_range; | 579 | goto err_range; |
556 | } | 580 | } |
557 | 581 | ||
582 | new->map = map; | ||
583 | new->name = range_cfg->name; | ||
558 | new->range_min = range_cfg->range_min; | 584 | new->range_min = range_cfg->range_min; |
559 | new->range_max = range_cfg->range_max; | 585 | new->range_max = range_cfg->range_max; |
560 | new->selector_reg = range_cfg->selector_reg; | 586 | new->selector_reg = range_cfg->selector_reg; |
@@ -564,6 +590,7 @@ struct regmap *regmap_init(struct device *dev, | |||
564 | new->window_len = range_cfg->window_len; | 590 | new->window_len = range_cfg->window_len; |
565 | 591 | ||
566 | if (_regmap_range_add(map, new) == false) { | 592 | if (_regmap_range_add(map, new) == false) { |
593 | dev_err(map->dev, "Failed to add range %d\n", i); | ||
567 | kfree(new); | 594 | kfree(new); |
568 | goto err_range; | 595 | goto err_range; |
569 | } | 596 | } |
@@ -579,7 +606,7 @@ struct regmap *regmap_init(struct device *dev, | |||
579 | } | 606 | } |
580 | 607 | ||
581 | ret = regcache_init(map, config); | 608 | ret = regcache_init(map, config); |
582 | if (ret < 0) | 609 | if (ret != 0) |
583 | goto err_range; | 610 | goto err_range; |
584 | 611 | ||
585 | regmap_debugfs_init(map, config->name); | 612 | regmap_debugfs_init(map, config->name); |
@@ -738,59 +765,57 @@ struct regmap *dev_get_regmap(struct device *dev, const char *name) | |||
738 | EXPORT_SYMBOL_GPL(dev_get_regmap); | 765 | EXPORT_SYMBOL_GPL(dev_get_regmap); |
739 | 766 | ||
740 | static int _regmap_select_page(struct regmap *map, unsigned int *reg, | 767 | static int _regmap_select_page(struct regmap *map, unsigned int *reg, |
768 | struct regmap_range_node *range, | ||
741 | unsigned int val_num) | 769 | unsigned int val_num) |
742 | { | 770 | { |
743 | struct regmap_range_node *range; | ||
744 | void *orig_work_buf; | 771 | void *orig_work_buf; |
745 | unsigned int win_offset; | 772 | unsigned int win_offset; |
746 | unsigned int win_page; | 773 | unsigned int win_page; |
747 | bool page_chg; | 774 | bool page_chg; |
748 | int ret; | 775 | int ret; |
749 | 776 | ||
750 | range = _regmap_range_lookup(map, *reg); | 777 | win_offset = (*reg - range->range_min) % range->window_len; |
751 | if (range) { | 778 | win_page = (*reg - range->range_min) / range->window_len; |
752 | win_offset = (*reg - range->range_min) % range->window_len; | ||
753 | win_page = (*reg - range->range_min) / range->window_len; | ||
754 | |||
755 | if (val_num > 1) { | ||
756 | /* Bulk write shouldn't cross range boundary */ | ||
757 | if (*reg + val_num - 1 > range->range_max) | ||
758 | return -EINVAL; | ||
759 | 779 | ||
760 | /* ... or single page boundary */ | 780 | if (val_num > 1) { |
761 | if (val_num > range->window_len - win_offset) | 781 | /* Bulk write shouldn't cross range boundary */ |
762 | return -EINVAL; | 782 | if (*reg + val_num - 1 > range->range_max) |
763 | } | 783 | return -EINVAL; |
764 | 784 | ||
765 | /* It is possible to have selector register inside data window. | 785 | /* ... or single page boundary */ |
766 | In that case, selector register is located on every page and | 786 | if (val_num > range->window_len - win_offset) |
767 | it needs no page switching, when accessed alone. */ | 787 | return -EINVAL; |
768 | if (val_num > 1 || | 788 | } |
769 | range->window_start + win_offset != range->selector_reg) { | ||
770 | /* Use separate work_buf during page switching */ | ||
771 | orig_work_buf = map->work_buf; | ||
772 | map->work_buf = map->selector_work_buf; | ||
773 | 789 | ||
774 | ret = _regmap_update_bits(map, range->selector_reg, | 790 | /* It is possible to have selector register inside data window. |
775 | range->selector_mask, | 791 | In that case, selector register is located on every page and |
776 | win_page << range->selector_shift, | 792 | it needs no page switching, when accessed alone. */ |
777 | &page_chg); | 793 | if (val_num > 1 || |
794 | range->window_start + win_offset != range->selector_reg) { | ||
795 | /* Use separate work_buf during page switching */ | ||
796 | orig_work_buf = map->work_buf; | ||
797 | map->work_buf = map->selector_work_buf; | ||
778 | 798 | ||
779 | map->work_buf = orig_work_buf; | 799 | ret = _regmap_update_bits(map, range->selector_reg, |
800 | range->selector_mask, | ||
801 | win_page << range->selector_shift, | ||
802 | &page_chg); | ||
780 | 803 | ||
781 | if (ret < 0) | 804 | map->work_buf = orig_work_buf; |
782 | return ret; | ||
783 | } | ||
784 | 805 | ||
785 | *reg = range->window_start + win_offset; | 806 | if (ret != 0) |
807 | return ret; | ||
786 | } | 808 | } |
787 | 809 | ||
810 | *reg = range->window_start + win_offset; | ||
811 | |||
788 | return 0; | 812 | return 0; |
789 | } | 813 | } |
790 | 814 | ||
791 | static int _regmap_raw_write(struct regmap *map, unsigned int reg, | 815 | static int _regmap_raw_write(struct regmap *map, unsigned int reg, |
792 | const void *val, size_t val_len) | 816 | const void *val, size_t val_len) |
793 | { | 817 | { |
818 | struct regmap_range_node *range; | ||
794 | u8 *u8 = map->work_buf; | 819 | u8 *u8 = map->work_buf; |
795 | void *buf; | 820 | void *buf; |
796 | int ret = -ENOTSUPP; | 821 | int ret = -ENOTSUPP; |
@@ -825,9 +850,35 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, | |||
825 | } | 850 | } |
826 | } | 851 | } |
827 | 852 | ||
828 | ret = _regmap_select_page(map, ®, val_len / map->format.val_bytes); | 853 | range = _regmap_range_lookup(map, reg); |
829 | if (ret < 0) | 854 | if (range) { |
830 | return ret; | 855 | int val_num = val_len / map->format.val_bytes; |
856 | int win_offset = (reg - range->range_min) % range->window_len; | ||
857 | int win_residue = range->window_len - win_offset; | ||
858 | |||
859 | /* If the write goes beyond the end of the window split it */ | ||
860 | while (val_num > win_residue) { | ||
861 | dev_dbg(map->dev, "Writing window %d/%d\n", | ||
862 | win_residue, val_len / map->format.val_bytes); | ||
863 | ret = _regmap_raw_write(map, reg, val, win_residue * | ||
864 | map->format.val_bytes); | ||
865 | if (ret != 0) | ||
866 | return ret; | ||
867 | |||
868 | reg += win_residue; | ||
869 | val_num -= win_residue; | ||
870 | val += win_residue * map->format.val_bytes; | ||
871 | val_len -= win_residue * map->format.val_bytes; | ||
872 | |||
873 | win_offset = (reg - range->range_min) % | ||
874 | range->window_len; | ||
875 | win_residue = range->window_len - win_offset; | ||
876 | } | ||
877 | |||
878 | ret = _regmap_select_page(map, ®, range, val_num); | ||
879 | if (ret != 0) | ||
880 | return ret; | ||
881 | } | ||
831 | 882 | ||
832 | map->format.format_reg(map->work_buf, reg, map->reg_shift); | 883 | map->format.format_reg(map->work_buf, reg, map->reg_shift); |
833 | 884 | ||
@@ -876,6 +927,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, | |||
876 | int _regmap_write(struct regmap *map, unsigned int reg, | 927 | int _regmap_write(struct regmap *map, unsigned int reg, |
877 | unsigned int val) | 928 | unsigned int val) |
878 | { | 929 | { |
930 | struct regmap_range_node *range; | ||
879 | int ret; | 931 | int ret; |
880 | BUG_ON(!map->format.format_write && !map->format.format_val); | 932 | BUG_ON(!map->format.format_write && !map->format.format_val); |
881 | 933 | ||
@@ -897,9 +949,12 @@ int _regmap_write(struct regmap *map, unsigned int reg, | |||
897 | trace_regmap_reg_write(map->dev, reg, val); | 949 | trace_regmap_reg_write(map->dev, reg, val); |
898 | 950 | ||
899 | if (map->format.format_write) { | 951 | if (map->format.format_write) { |
900 | ret = _regmap_select_page(map, ®, 1); | 952 | range = _regmap_range_lookup(map, reg); |
901 | if (ret < 0) | 953 | if (range) { |
902 | return ret; | 954 | ret = _regmap_select_page(map, ®, range, 1); |
955 | if (ret != 0) | ||
956 | return ret; | ||
957 | } | ||
903 | 958 | ||
904 | map->format.format_write(map, reg, val); | 959 | map->format.format_write(map, reg, val); |
905 | 960 | ||
@@ -1055,12 +1110,17 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write); | |||
1055 | static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, | 1110 | static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, |
1056 | unsigned int val_len) | 1111 | unsigned int val_len) |
1057 | { | 1112 | { |
1113 | struct regmap_range_node *range; | ||
1058 | u8 *u8 = map->work_buf; | 1114 | u8 *u8 = map->work_buf; |
1059 | int ret; | 1115 | int ret; |
1060 | 1116 | ||
1061 | ret = _regmap_select_page(map, ®, val_len / map->format.val_bytes); | 1117 | range = _regmap_range_lookup(map, reg); |
1062 | if (ret < 0) | 1118 | if (range) { |
1063 | return ret; | 1119 | ret = _regmap_select_page(map, ®, range, |
1120 | val_len / map->format.val_bytes); | ||
1121 | if (ret != 0) | ||
1122 | return ret; | ||
1123 | } | ||
1064 | 1124 | ||
1065 | map->format.format_reg(map->work_buf, reg, map->reg_shift); | 1125 | map->format.format_reg(map->work_buf, reg, map->reg_shift); |
1066 | 1126 | ||
diff --git a/include/linux/regmap.h b/include/linux/regmap.h index e3bcc3f4dcb8..9f228d7f7ac4 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h | |||
@@ -133,7 +133,7 @@ struct regmap_config { | |||
133 | enum regmap_endian val_format_endian; | 133 | enum regmap_endian val_format_endian; |
134 | 134 | ||
135 | const struct regmap_range_cfg *ranges; | 135 | const struct regmap_range_cfg *ranges; |
136 | unsigned int n_ranges; | 136 | unsigned int num_ranges; |
137 | }; | 137 | }; |
138 | 138 | ||
139 | /** | 139 | /** |
@@ -142,6 +142,8 @@ struct regmap_config { | |||
142 | * 1. page selector register update; | 142 | * 1. page selector register update; |
143 | * 2. access through data window registers. | 143 | * 2. access through data window registers. |
144 | * | 144 | * |
145 | * @name: Descriptive name for diagnostics | ||
146 | * | ||
145 | * @range_min: Address of the lowest register address in virtual range. | 147 | * @range_min: Address of the lowest register address in virtual range. |
146 | * @range_max: Address of the highest register in virtual range. | 148 | * @range_max: Address of the highest register in virtual range. |
147 | * | 149 | * |
@@ -153,6 +155,8 @@ struct regmap_config { | |||
153 | * @window_len: Number of registers in data window. | 155 | * @window_len: Number of registers in data window. |
154 | */ | 156 | */ |
155 | struct regmap_range_cfg { | 157 | struct regmap_range_cfg { |
158 | const char *name; | ||
159 | |||
156 | /* Registers of virtual address range */ | 160 | /* Registers of virtual address range */ |
157 | unsigned int range_min; | 161 | unsigned int range_min; |
158 | unsigned int range_max; | 162 | unsigned int range_max; |
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 06d4e612a164..ff45b02a9dff 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c | |||
@@ -34,6 +34,7 @@ | |||
34 | 34 | ||
35 | #include "wm2200.h" | 35 | #include "wm2200.h" |
36 | #include "wmfw.h" | 36 | #include "wmfw.h" |
37 | #include "wm_adsp.h" | ||
37 | 38 | ||
38 | #define WM2200_DSP_CONTROL_1 0x00 | 39 | #define WM2200_DSP_CONTROL_1 0x00 |
39 | #define WM2200_DSP_CONTROL_2 0x02 | 40 | #define WM2200_DSP_CONTROL_2 0x02 |
@@ -83,6 +84,7 @@ struct wm2200_fll { | |||
83 | 84 | ||
84 | /* codec private data */ | 85 | /* codec private data */ |
85 | struct wm2200_priv { | 86 | struct wm2200_priv { |
87 | struct wm_adsp dsp[2]; | ||
86 | struct regmap *regmap; | 88 | struct regmap *regmap; |
87 | struct device *dev; | 89 | struct device *dev; |
88 | struct snd_soc_codec *codec; | 90 | struct snd_soc_codec *codec; |
@@ -109,48 +111,42 @@ struct wm2200_priv { | |||
109 | #define WM2200_DSP2_ZM_BASE (WM2200_DSP_RANGE_BASE + (5 * WM2200_DSP_SPACING)) | 111 | #define WM2200_DSP2_ZM_BASE (WM2200_DSP_RANGE_BASE + (5 * WM2200_DSP_SPACING)) |
110 | 112 | ||
111 | static const struct regmap_range_cfg wm2200_ranges[] = { | 113 | static const struct regmap_range_cfg wm2200_ranges[] = { |
112 | /* DSP1 DM */ | 114 | { .name = "DSP1DM", .range_min = WM2200_DSP1_DM_BASE, |
113 | { .range_min = WM2200_DSP1_DM_BASE, | ||
114 | .range_max = WM2200_DSP1_DM_BASE + 12287, | 115 | .range_max = WM2200_DSP1_DM_BASE + 12287, |
115 | .selector_reg = WM2200_DSP1_CONTROL_3, | 116 | .selector_reg = WM2200_DSP1_CONTROL_3, |
116 | .selector_mask = WM2200_DSP1_PAGE_BASE_DM_0_MASK, | 117 | .selector_mask = WM2200_DSP1_PAGE_BASE_DM_0_MASK, |
117 | .selector_shift = WM2200_DSP1_PAGE_BASE_DM_0_SHIFT, | 118 | .selector_shift = WM2200_DSP1_PAGE_BASE_DM_0_SHIFT, |
118 | .window_start = WM2200_DSP1_DM_0, .window_len = 2048, }, | 119 | .window_start = WM2200_DSP1_DM_0, .window_len = 2048, }, |
119 | 120 | ||
120 | /* DSP1 PM */ | 121 | { .name = "DSP1PM", .range_min = WM2200_DSP1_PM_BASE, |
121 | { .range_min = WM2200_DSP1_PM_BASE, | ||
122 | .range_max = WM2200_DSP1_PM_BASE + 12287, | 122 | .range_max = WM2200_DSP1_PM_BASE + 12287, |
123 | .selector_reg = WM2200_DSP1_CONTROL_2, | 123 | .selector_reg = WM2200_DSP1_CONTROL_2, |
124 | .selector_mask = WM2200_DSP1_PAGE_BASE_PM_0_MASK, | 124 | .selector_mask = WM2200_DSP1_PAGE_BASE_PM_0_MASK, |
125 | .selector_shift = WM2200_DSP1_PAGE_BASE_PM_0_SHIFT, | 125 | .selector_shift = WM2200_DSP1_PAGE_BASE_PM_0_SHIFT, |
126 | .window_start = WM2200_DSP1_PM_0, .window_len = 768, }, | 126 | .window_start = WM2200_DSP1_PM_0, .window_len = 768, }, |
127 | 127 | ||
128 | /* DSP1 ZM */ | 128 | { .name = "DSP1ZM", .range_min = WM2200_DSP1_ZM_BASE, |
129 | { .range_min = WM2200_DSP1_ZM_BASE, | ||
130 | .range_max = WM2200_DSP1_ZM_BASE + 2047, | 129 | .range_max = WM2200_DSP1_ZM_BASE + 2047, |
131 | .selector_reg = WM2200_DSP1_CONTROL_4, | 130 | .selector_reg = WM2200_DSP1_CONTROL_4, |
132 | .selector_mask = WM2200_DSP1_PAGE_BASE_ZM_0_MASK, | 131 | .selector_mask = WM2200_DSP1_PAGE_BASE_ZM_0_MASK, |
133 | .selector_shift = WM2200_DSP1_PAGE_BASE_ZM_0_SHIFT, | 132 | .selector_shift = WM2200_DSP1_PAGE_BASE_ZM_0_SHIFT, |
134 | .window_start = WM2200_DSP1_ZM_0, .window_len = 1024, }, | 133 | .window_start = WM2200_DSP1_ZM_0, .window_len = 1024, }, |
135 | 134 | ||
136 | /* DSP2 DM */ | 135 | { .name = "DSP2DM", .range_min = WM2200_DSP2_DM_BASE, |
137 | { .range_min = WM2200_DSP2_DM_BASE, | ||
138 | .range_max = WM2200_DSP2_DM_BASE + 4095, | 136 | .range_max = WM2200_DSP2_DM_BASE + 4095, |
139 | .selector_reg = WM2200_DSP2_CONTROL_3, | 137 | .selector_reg = WM2200_DSP2_CONTROL_3, |
140 | .selector_mask = WM2200_DSP2_PAGE_BASE_DM_0_MASK, | 138 | .selector_mask = WM2200_DSP2_PAGE_BASE_DM_0_MASK, |
141 | .selector_shift = WM2200_DSP2_PAGE_BASE_DM_0_SHIFT, | 139 | .selector_shift = WM2200_DSP2_PAGE_BASE_DM_0_SHIFT, |
142 | .window_start = WM2200_DSP2_DM_0, .window_len = 2048, }, | 140 | .window_start = WM2200_DSP2_DM_0, .window_len = 2048, }, |
143 | 141 | ||
144 | /* DSP2 PM */ | 142 | { .name = "DSP2PM", .range_min = WM2200_DSP2_PM_BASE, |
145 | { .range_min = WM2200_DSP2_PM_BASE, | ||
146 | .range_max = WM2200_DSP2_PM_BASE + 11287, | 143 | .range_max = WM2200_DSP2_PM_BASE + 11287, |
147 | .selector_reg = WM2200_DSP2_CONTROL_2, | 144 | .selector_reg = WM2200_DSP2_CONTROL_2, |
148 | .selector_mask = WM2200_DSP2_PAGE_BASE_PM_0_MASK, | 145 | .selector_mask = WM2200_DSP2_PAGE_BASE_PM_0_MASK, |
149 | .selector_shift = WM2200_DSP2_PAGE_BASE_PM_0_SHIFT, | 146 | .selector_shift = WM2200_DSP2_PAGE_BASE_PM_0_SHIFT, |
150 | .window_start = WM2200_DSP2_PM_0, .window_len = 768, }, | 147 | .window_start = WM2200_DSP2_PM_0, .window_len = 768, }, |
151 | 148 | ||
152 | /* DSP2 ZM */ | 149 | { .name = "DSP2ZM", .range_min = WM2200_DSP2_ZM_BASE, |
153 | { .range_min = WM2200_DSP2_ZM_BASE, | ||
154 | .range_max = WM2200_DSP2_ZM_BASE + 2047, | 150 | .range_max = WM2200_DSP2_ZM_BASE + 2047, |
155 | .selector_reg = WM2200_DSP2_CONTROL_4, | 151 | .selector_reg = WM2200_DSP2_CONTROL_4, |
156 | .selector_mask = WM2200_DSP2_PAGE_BASE_ZM_0_MASK, | 152 | .selector_mask = WM2200_DSP2_PAGE_BASE_ZM_0_MASK, |
@@ -158,6 +154,18 @@ static const struct regmap_range_cfg wm2200_ranges[] = { | |||
158 | .window_start = WM2200_DSP2_ZM_0, .window_len = 1024, }, | 154 | .window_start = WM2200_DSP2_ZM_0, .window_len = 1024, }, |
159 | }; | 155 | }; |
160 | 156 | ||
157 | static const struct wm_adsp_region wm2200_dsp1_regions[] = { | ||
158 | { .type = WMFW_ADSP1_PM, .base = WM2200_DSP1_PM_BASE }, | ||
159 | { .type = WMFW_ADSP1_DM, .base = WM2200_DSP1_DM_BASE }, | ||
160 | { .type = WMFW_ADSP1_ZM, .base = WM2200_DSP1_ZM_BASE }, | ||
161 | }; | ||
162 | |||
163 | static const struct wm_adsp_region wm2200_dsp2_regions[] = { | ||
164 | { .type = WMFW_ADSP1_PM, .base = WM2200_DSP2_PM_BASE }, | ||
165 | { .type = WMFW_ADSP1_DM, .base = WM2200_DSP2_DM_BASE }, | ||
166 | { .type = WMFW_ADSP1_ZM, .base = WM2200_DSP2_ZM_BASE }, | ||
167 | }; | ||
168 | |||
161 | static struct reg_default wm2200_reg_defaults[] = { | 169 | static struct reg_default wm2200_reg_defaults[] = { |
162 | { 0x000B, 0x0000 }, /* R11 - Tone Generator 1 */ | 170 | { 0x000B, 0x0000 }, /* R11 - Tone Generator 1 */ |
163 | { 0x0102, 0x0000 }, /* R258 - Clocking 3 */ | 171 | { 0x0102, 0x0000 }, /* R258 - Clocking 3 */ |
@@ -987,400 +995,6 @@ static int wm2200_reset(struct wm2200_priv *wm2200) | |||
987 | } | 995 | } |
988 | } | 996 | } |
989 | 997 | ||
990 | static int wm2200_dsp_load(struct snd_soc_codec *codec, int base) | ||
991 | { | ||
992 | const struct firmware *firmware; | ||
993 | struct regmap *regmap = codec->control_data; | ||
994 | unsigned int pos = 0; | ||
995 | const struct wmfw_header *header; | ||
996 | const struct wmfw_adsp1_sizes *adsp1_sizes; | ||
997 | const struct wmfw_footer *footer; | ||
998 | const struct wmfw_region *region; | ||
999 | const char *file, *region_name; | ||
1000 | char *text; | ||
1001 | unsigned int dm, pm, zm, reg; | ||
1002 | int regions = 0; | ||
1003 | int ret, offset, type; | ||
1004 | |||
1005 | switch (base) { | ||
1006 | case WM2200_DSP1_CONTROL_1: | ||
1007 | file = "wm2200-dsp1.wmfw"; | ||
1008 | dm = WM2200_DSP1_DM_BASE; | ||
1009 | pm = WM2200_DSP1_PM_BASE; | ||
1010 | zm = WM2200_DSP1_ZM_BASE; | ||
1011 | break; | ||
1012 | case WM2200_DSP2_CONTROL_1: | ||
1013 | file = "wm2200-dsp2.wmfw"; | ||
1014 | dm = WM2200_DSP2_DM_BASE; | ||
1015 | pm = WM2200_DSP2_PM_BASE; | ||
1016 | zm = WM2200_DSP2_ZM_BASE; | ||
1017 | break; | ||
1018 | default: | ||
1019 | dev_err(codec->dev, "BASE %x\n", base); | ||
1020 | BUG_ON(1); | ||
1021 | return -EINVAL; | ||
1022 | } | ||
1023 | |||
1024 | ret = request_firmware(&firmware, file, codec->dev); | ||
1025 | if (ret != 0) { | ||
1026 | dev_err(codec->dev, "Failed to request '%s'\n", file); | ||
1027 | return ret; | ||
1028 | } | ||
1029 | |||
1030 | pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); | ||
1031 | if (pos >= firmware->size) { | ||
1032 | dev_err(codec->dev, "%s: file too short, %d bytes\n", | ||
1033 | file, firmware->size); | ||
1034 | return -EINVAL; | ||
1035 | } | ||
1036 | |||
1037 | header = (void*)&firmware->data[0]; | ||
1038 | |||
1039 | if (memcmp(&header->magic[0], "WMFW", 4) != 0) { | ||
1040 | dev_err(codec->dev, "%s: invalid magic\n", file); | ||
1041 | return -EINVAL; | ||
1042 | } | ||
1043 | |||
1044 | if (header->ver != 0) { | ||
1045 | dev_err(codec->dev, "%s: unknown file format %d\n", | ||
1046 | file, header->ver); | ||
1047 | return -EINVAL; | ||
1048 | } | ||
1049 | |||
1050 | if (le32_to_cpu(header->len) != sizeof(*header) + | ||
1051 | sizeof(*adsp1_sizes) + sizeof(*footer)) { | ||
1052 | dev_err(codec->dev, "%s: unexpected header length %d\n", | ||
1053 | file, le32_to_cpu(header->len)); | ||
1054 | return -EINVAL; | ||
1055 | } | ||
1056 | |||
1057 | if (header->core != WMFW_ADSP1) { | ||
1058 | dev_err(codec->dev, "%s: invalid core %d\n", | ||
1059 | file, header->core); | ||
1060 | return -EINVAL; | ||
1061 | } | ||
1062 | |||
1063 | adsp1_sizes = (void *)&(header[1]); | ||
1064 | footer = (void *)&(adsp1_sizes[1]); | ||
1065 | |||
1066 | dev_dbg(codec->dev, "%s: %d DM, %d PM, %d ZM\n", | ||
1067 | file, le32_to_cpu(adsp1_sizes->dm), | ||
1068 | le32_to_cpu(adsp1_sizes->pm), le32_to_cpu(adsp1_sizes->zm)); | ||
1069 | |||
1070 | dev_dbg(codec->dev, "%s: timestamp %llu\n", file, | ||
1071 | le64_to_cpu(footer->timestamp)); | ||
1072 | |||
1073 | while (pos < firmware->size && | ||
1074 | pos - firmware->size > sizeof(*region)) { | ||
1075 | region = (void *)&(firmware->data[pos]); | ||
1076 | region_name = "Unknown"; | ||
1077 | reg = 0; | ||
1078 | text = NULL; | ||
1079 | offset = le32_to_cpu(region->offset) & 0xffffff; | ||
1080 | type = be32_to_cpu(region->type) & 0xff; | ||
1081 | |||
1082 | switch (type) { | ||
1083 | case WMFW_NAME_TEXT: | ||
1084 | region_name = "Firmware name"; | ||
1085 | text = kzalloc(le32_to_cpu(region->len) + 1, | ||
1086 | GFP_KERNEL); | ||
1087 | break; | ||
1088 | case WMFW_INFO_TEXT: | ||
1089 | region_name = "Information"; | ||
1090 | text = kzalloc(le32_to_cpu(region->len) + 1, | ||
1091 | GFP_KERNEL); | ||
1092 | break; | ||
1093 | case WMFW_ABSOLUTE: | ||
1094 | region_name = "Absolute"; | ||
1095 | reg = offset; | ||
1096 | break; | ||
1097 | case WMFW_ADSP1_PM: | ||
1098 | region_name = "PM"; | ||
1099 | reg = pm + (offset * 3); | ||
1100 | break; | ||
1101 | case WMFW_ADSP1_DM: | ||
1102 | region_name = "DM"; | ||
1103 | reg = dm + (offset * 2); | ||
1104 | break; | ||
1105 | case WMFW_ADSP1_ZM: | ||
1106 | region_name = "ZM"; | ||
1107 | reg = zm + (offset * 2); | ||
1108 | break; | ||
1109 | default: | ||
1110 | dev_warn(codec->dev, | ||
1111 | "%s.%d: Unknown region type %x at %d(%x)\n", | ||
1112 | file, regions, type, pos, pos); | ||
1113 | break; | ||
1114 | } | ||
1115 | |||
1116 | dev_dbg(codec->dev, "%s.%d: %d bytes at %d in %s\n", file, | ||
1117 | regions, le32_to_cpu(region->len), offset, | ||
1118 | region_name); | ||
1119 | |||
1120 | if (text) { | ||
1121 | memcpy(text, region->data, le32_to_cpu(region->len)); | ||
1122 | dev_info(codec->dev, "%s: %s\n", file, text); | ||
1123 | kfree(text); | ||
1124 | } | ||
1125 | |||
1126 | if (reg) { | ||
1127 | ret = regmap_raw_write(regmap, reg, region->data, | ||
1128 | le32_to_cpu(region->len)); | ||
1129 | if (ret != 0) { | ||
1130 | dev_err(codec->dev, | ||
1131 | "%s.%d: Failed to write %d bytes at %d in %s: %d\n", | ||
1132 | file, regions, | ||
1133 | le32_to_cpu(region->len), offset, | ||
1134 | region_name, ret); | ||
1135 | goto out; | ||
1136 | } | ||
1137 | } | ||
1138 | |||
1139 | pos += le32_to_cpu(region->len) + sizeof(*region); | ||
1140 | regions++; | ||
1141 | } | ||
1142 | |||
1143 | if (pos > firmware->size) | ||
1144 | dev_warn(codec->dev, "%s.%d: %d bytes at end of file\n", | ||
1145 | file, regions, pos - firmware->size); | ||
1146 | |||
1147 | out: | ||
1148 | release_firmware(firmware); | ||
1149 | |||
1150 | return ret; | ||
1151 | } | ||
1152 | |||
1153 | static int wm2200_setup_algs(struct snd_soc_codec *codec, int base) | ||
1154 | { | ||
1155 | struct regmap *regmap = codec->control_data; | ||
1156 | struct wmfw_adsp1_id_hdr id; | ||
1157 | struct wmfw_adsp1_alg_hdr *alg; | ||
1158 | size_t algs; | ||
1159 | int zm, dm, pm, ret, i; | ||
1160 | __be32 val; | ||
1161 | |||
1162 | switch (base) { | ||
1163 | case WM2200_DSP1_CONTROL_1: | ||
1164 | dm = WM2200_DSP1_DM_BASE; | ||
1165 | pm = WM2200_DSP1_PM_BASE; | ||
1166 | zm = WM2200_DSP1_ZM_BASE; | ||
1167 | break; | ||
1168 | case WM2200_DSP2_CONTROL_1: | ||
1169 | dm = WM2200_DSP2_DM_BASE; | ||
1170 | pm = WM2200_DSP2_PM_BASE; | ||
1171 | zm = WM2200_DSP2_ZM_BASE; | ||
1172 | break; | ||
1173 | default: | ||
1174 | dev_err(codec->dev, "BASE %x\n", base); | ||
1175 | BUG_ON(1); | ||
1176 | return -EINVAL; | ||
1177 | } | ||
1178 | |||
1179 | ret = regmap_raw_read(regmap, dm, &id, sizeof(id)); | ||
1180 | if (ret != 0) { | ||
1181 | dev_err(codec->dev, "Failed to read algorithm info: %d\n", | ||
1182 | ret); | ||
1183 | return ret; | ||
1184 | } | ||
1185 | |||
1186 | algs = be32_to_cpu(id.algs); | ||
1187 | dev_info(codec->dev, "Firmware: %x v%d.%d.%d, %d algorithms\n", | ||
1188 | be32_to_cpu(id.fw.id), | ||
1189 | (be32_to_cpu(id.fw.ver) & 0xff000) >> 16, | ||
1190 | (be32_to_cpu(id.fw.ver) & 0xff00) >> 8, | ||
1191 | be32_to_cpu(id.fw.ver) & 0xff, | ||
1192 | algs); | ||
1193 | |||
1194 | /* Read the terminator first to validate the length */ | ||
1195 | ret = regmap_raw_read(regmap, dm + | ||
1196 | (sizeof(id) + (algs * sizeof(*alg))) / 2, | ||
1197 | &val, sizeof(val)); | ||
1198 | if (ret != 0) { | ||
1199 | dev_err(codec->dev, "Failed to read algorithm list end: %d\n", | ||
1200 | ret); | ||
1201 | return ret; | ||
1202 | } | ||
1203 | |||
1204 | if (be32_to_cpu(val) != 0xbedead) | ||
1205 | dev_warn(codec->dev, "Algorithm list end %x 0x%x != 0xbeadead\n", | ||
1206 | (sizeof(id) + (algs * sizeof(*alg))) / 2, | ||
1207 | be32_to_cpu(val)); | ||
1208 | |||
1209 | alg = kzalloc(sizeof(*alg) * algs, GFP_KERNEL); | ||
1210 | if (!alg) | ||
1211 | return -ENOMEM; | ||
1212 | |||
1213 | ret = regmap_raw_read(regmap, dm + (sizeof(id) / 2), | ||
1214 | alg, algs * sizeof(*alg)); | ||
1215 | if (ret != 0) { | ||
1216 | dev_err(codec->dev, "Failed to read algorithm list: %d\n", | ||
1217 | ret); | ||
1218 | goto out; | ||
1219 | } | ||
1220 | |||
1221 | for (i = 0; i < algs; i++) { | ||
1222 | dev_info(codec->dev, "%d: ID %x v%d.%d.%d\n", | ||
1223 | i, be32_to_cpu(alg[i].alg.id), | ||
1224 | (be32_to_cpu(alg[i].alg.ver) & 0xff000) >> 16, | ||
1225 | (be32_to_cpu(alg[i].alg.ver) & 0xff00) >> 8, | ||
1226 | be32_to_cpu(alg[i].alg.ver) & 0xff); | ||
1227 | } | ||
1228 | |||
1229 | out: | ||
1230 | kfree(alg); | ||
1231 | return ret; | ||
1232 | } | ||
1233 | |||
1234 | static int wm2200_load_coeff(struct snd_soc_codec *codec, int base) | ||
1235 | { | ||
1236 | struct regmap *regmap = codec->control_data; | ||
1237 | struct wmfw_coeff_hdr *hdr; | ||
1238 | struct wmfw_coeff_item *blk; | ||
1239 | const struct firmware *firmware; | ||
1240 | const char *file, *region_name; | ||
1241 | int ret, dm, pm, zm, pos, blocks, type, offset, reg; | ||
1242 | |||
1243 | switch (base) { | ||
1244 | case WM2200_DSP1_CONTROL_1: | ||
1245 | file = "wm2200-dsp1.bin"; | ||
1246 | dm = WM2200_DSP1_DM_BASE; | ||
1247 | pm = WM2200_DSP1_PM_BASE; | ||
1248 | zm = WM2200_DSP1_ZM_BASE; | ||
1249 | break; | ||
1250 | case WM2200_DSP2_CONTROL_1: | ||
1251 | file = "wm2200-dsp2.bin"; | ||
1252 | dm = WM2200_DSP2_DM_BASE; | ||
1253 | pm = WM2200_DSP2_PM_BASE; | ||
1254 | zm = WM2200_DSP2_ZM_BASE; | ||
1255 | break; | ||
1256 | default: | ||
1257 | dev_err(codec->dev, "BASE %x\n", base); | ||
1258 | BUG_ON(1); | ||
1259 | return -EINVAL; | ||
1260 | } | ||
1261 | |||
1262 | ret = request_firmware(&firmware, file, codec->dev); | ||
1263 | if (ret != 0) { | ||
1264 | dev_err(codec->dev, "Failed to request '%s'\n", file); | ||
1265 | return ret; | ||
1266 | } | ||
1267 | |||
1268 | if (sizeof(*hdr) >= firmware->size) { | ||
1269 | dev_err(codec->dev, "%s: file too short, %d bytes\n", | ||
1270 | file, firmware->size); | ||
1271 | return -EINVAL; | ||
1272 | } | ||
1273 | |||
1274 | hdr = (void*)&firmware->data[0]; | ||
1275 | if (memcmp(hdr->magic, "WMDR", 4) != 0) { | ||
1276 | dev_err(codec->dev, "%s: invalid magic\n", file); | ||
1277 | return -EINVAL; | ||
1278 | } | ||
1279 | |||
1280 | dev_dbg(codec->dev, "%s: v%d.%d.%d\n", file, | ||
1281 | (le32_to_cpu(hdr->ver) >> 16) & 0xff, | ||
1282 | (le32_to_cpu(hdr->ver) >> 8) & 0xff, | ||
1283 | le32_to_cpu(hdr->ver) & 0xff); | ||
1284 | |||
1285 | pos = le32_to_cpu(hdr->len); | ||
1286 | |||
1287 | blocks = 0; | ||
1288 | while (pos < firmware->size && | ||
1289 | pos - firmware->size > sizeof(*blk)) { | ||
1290 | blk = (void*)(&firmware->data[pos]); | ||
1291 | |||
1292 | type = be32_to_cpu(blk->type) & 0xff; | ||
1293 | offset = le32_to_cpu(blk->offset) & 0xffffff; | ||
1294 | |||
1295 | dev_dbg(codec->dev, "%s.%d: %x v%d.%d.%d\n", | ||
1296 | file, blocks, le32_to_cpu(blk->id), | ||
1297 | (le32_to_cpu(blk->ver) >> 16) & 0xff, | ||
1298 | (le32_to_cpu(blk->ver) >> 8) & 0xff, | ||
1299 | le32_to_cpu(blk->ver) & 0xff); | ||
1300 | dev_dbg(codec->dev, "%s.%d: %d bytes at 0x%x in %x\n", | ||
1301 | file, blocks, le32_to_cpu(blk->len), offset, type); | ||
1302 | |||
1303 | reg = 0; | ||
1304 | region_name = "Unknown"; | ||
1305 | switch (type) { | ||
1306 | case WMFW_NAME_TEXT: | ||
1307 | case WMFW_INFO_TEXT: | ||
1308 | break; | ||
1309 | case WMFW_ABSOLUTE: | ||
1310 | region_name = "register"; | ||
1311 | reg = offset; | ||
1312 | break; | ||
1313 | default: | ||
1314 | dev_err(codec->dev, "Unknown region type %x\n", type); | ||
1315 | break; | ||
1316 | } | ||
1317 | |||
1318 | if (reg) { | ||
1319 | ret = regmap_raw_write(regmap, reg, blk->data, | ||
1320 | le32_to_cpu(blk->len)); | ||
1321 | if (ret != 0) { | ||
1322 | dev_err(codec->dev, | ||
1323 | "%s.%d: Failed to write to %x in %s\n", | ||
1324 | file, blocks, reg, region_name); | ||
1325 | } | ||
1326 | } | ||
1327 | |||
1328 | pos += le32_to_cpu(blk->len) + sizeof(*blk); | ||
1329 | blocks++; | ||
1330 | } | ||
1331 | |||
1332 | if (pos > firmware->size) | ||
1333 | dev_warn(codec->dev, "%s.%d: %d bytes at end of file\n", | ||
1334 | file, blocks, pos - firmware->size); | ||
1335 | |||
1336 | return 0; | ||
1337 | } | ||
1338 | |||
1339 | static int wm2200_dsp_ev(struct snd_soc_dapm_widget *w, | ||
1340 | struct snd_kcontrol *kcontrol, | ||
1341 | int event) | ||
1342 | { | ||
1343 | struct snd_soc_codec *codec = w->codec; | ||
1344 | int base = w->reg - WM2200_DSP_CONTROL_30; | ||
1345 | int ret; | ||
1346 | |||
1347 | switch (event) { | ||
1348 | case SND_SOC_DAPM_POST_PMU: | ||
1349 | ret = wm2200_dsp_load(codec, base); | ||
1350 | if (ret != 0) | ||
1351 | return ret; | ||
1352 | |||
1353 | ret = wm2200_setup_algs(codec, base); | ||
1354 | if (ret != 0) | ||
1355 | return ret; | ||
1356 | |||
1357 | ret = wm2200_load_coeff(codec, base); | ||
1358 | if (ret != 0) | ||
1359 | return ret; | ||
1360 | |||
1361 | /* Start the core running */ | ||
1362 | snd_soc_update_bits(codec, w->reg, | ||
1363 | WM2200_DSP1_CORE_ENA | WM2200_DSP1_START, | ||
1364 | WM2200_DSP1_CORE_ENA | WM2200_DSP1_START); | ||
1365 | break; | ||
1366 | |||
1367 | case SND_SOC_DAPM_PRE_PMD: | ||
1368 | /* Halt the core */ | ||
1369 | snd_soc_update_bits(codec, w->reg, | ||
1370 | WM2200_DSP1_CORE_ENA | WM2200_DSP1_START, | ||
1371 | 0); | ||
1372 | |||
1373 | snd_soc_update_bits(codec, base + WM2200_DSP_CONTROL_19, | ||
1374 | WM2200_DSP1_WDMA_BUFFER_LENGTH_MASK, 0); | ||
1375 | break; | ||
1376 | |||
1377 | default: | ||
1378 | break; | ||
1379 | } | ||
1380 | |||
1381 | return 0; | ||
1382 | } | ||
1383 | |||
1384 | static DECLARE_TLV_DB_SCALE(in_tlv, -6300, 100, 0); | 998 | static DECLARE_TLV_DB_SCALE(in_tlv, -6300, 100, 0); |
1385 | static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); | 999 | static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); |
1386 | static DECLARE_TLV_DB_SCALE(out_tlv, -6400, 100, 0); | 1000 | static DECLARE_TLV_DB_SCALE(out_tlv, -6400, 100, 0); |
@@ -1728,12 +1342,8 @@ SND_SOC_DAPM_PGA("LHPF1", WM2200_HPLPF1_1, WM2200_LHPF1_ENA_SHIFT, 0, | |||
1728 | SND_SOC_DAPM_PGA("LHPF2", WM2200_HPLPF2_1, WM2200_LHPF2_ENA_SHIFT, 0, | 1342 | SND_SOC_DAPM_PGA("LHPF2", WM2200_HPLPF2_1, WM2200_LHPF2_ENA_SHIFT, 0, |
1729 | NULL, 0), | 1343 | NULL, 0), |
1730 | 1344 | ||
1731 | SND_SOC_DAPM_PGA_E("DSP1", WM2200_DSP1_CONTROL_30, WM2200_DSP1_SYS_ENA_SHIFT, | 1345 | WM_ADSP1("DSP1", 0), |
1732 | 0, NULL, 0, wm2200_dsp_ev, | 1346 | WM_ADSP1("DSP2", 1), |
1733 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
1734 | SND_SOC_DAPM_PGA_E("DSP2", WM2200_DSP2_CONTROL_30, WM2200_DSP2_SYS_ENA_SHIFT, | ||
1735 | 0, NULL, 0, wm2200_dsp_ev, | ||
1736 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
1737 | 1347 | ||
1738 | SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0, | 1348 | SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0, |
1739 | WM2200_AUDIO_IF_1_22, WM2200_AIF1TX1_ENA_SHIFT, 0), | 1349 | WM2200_AUDIO_IF_1_22, WM2200_AIF1TX1_ENA_SHIFT, 0), |
@@ -2595,9 +2205,25 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c, | |||
2595 | ret = PTR_ERR(wm2200->regmap); | 2205 | ret = PTR_ERR(wm2200->regmap); |
2596 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", | 2206 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", |
2597 | ret); | 2207 | ret); |
2598 | goto err; | 2208 | return ret; |
2209 | } | ||
2210 | |||
2211 | for (i = 0; i < 2; i++) { | ||
2212 | wm2200->dsp[i].type = WMFW_ADSP1; | ||
2213 | wm2200->dsp[i].part = "wm2200"; | ||
2214 | wm2200->dsp[i].num = i + 1; | ||
2215 | wm2200->dsp[i].dev = &i2c->dev; | ||
2216 | wm2200->dsp[i].regmap = wm2200->regmap; | ||
2599 | } | 2217 | } |
2600 | 2218 | ||
2219 | wm2200->dsp[0].base = WM2200_DSP1_CONTROL_1; | ||
2220 | wm2200->dsp[0].mem = wm2200_dsp1_regions; | ||
2221 | wm2200->dsp[0].num_mems = ARRAY_SIZE(wm2200_dsp1_regions); | ||
2222 | |||
2223 | wm2200->dsp[1].base = WM2200_DSP2_CONTROL_1; | ||
2224 | wm2200->dsp[1].mem = wm2200_dsp2_regions; | ||
2225 | wm2200->dsp[1].num_mems = ARRAY_SIZE(wm2200_dsp2_regions); | ||
2226 | |||
2601 | if (pdata) | 2227 | if (pdata) |
2602 | wm2200->pdata = *pdata; | 2228 | wm2200->pdata = *pdata; |
2603 | 2229 | ||
@@ -2612,7 +2238,7 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c, | |||
2612 | if (ret != 0) { | 2238 | if (ret != 0) { |
2613 | dev_err(&i2c->dev, "Failed to request core supplies: %d\n", | 2239 | dev_err(&i2c->dev, "Failed to request core supplies: %d\n", |
2614 | ret); | 2240 | ret); |
2615 | goto err_regmap; | 2241 | return ret; |
2616 | } | 2242 | } |
2617 | 2243 | ||
2618 | ret = regulator_bulk_enable(ARRAY_SIZE(wm2200->core_supplies), | 2244 | ret = regulator_bulk_enable(ARRAY_SIZE(wm2200->core_supplies), |
@@ -2620,7 +2246,7 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c, | |||
2620 | if (ret != 0) { | 2246 | if (ret != 0) { |
2621 | dev_err(&i2c->dev, "Failed to enable core supplies: %d\n", | 2247 | dev_err(&i2c->dev, "Failed to enable core supplies: %d\n", |
2622 | ret); | 2248 | ret); |
2623 | goto err_core; | 2249 | return ret; |
2624 | } | 2250 | } |
2625 | 2251 | ||
2626 | if (wm2200->pdata.ldo_ena) { | 2252 | if (wm2200->pdata.ldo_ena) { |
@@ -2756,9 +2382,6 @@ err_ldo: | |||
2756 | err_enable: | 2382 | err_enable: |
2757 | regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies), | 2383 | regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies), |
2758 | wm2200->core_supplies); | 2384 | wm2200->core_supplies); |
2759 | err_core: | ||
2760 | err_regmap: | ||
2761 | err: | ||
2762 | return ret; | 2385 | return ret; |
2763 | } | 2386 | } |
2764 | 2387 | ||