Merge branch 'for-3.2' into for-3.3
[firefly-linux-kernel-4.4.55.git] / sound / soc / soc-cache.c
1 /*
2  * soc-cache.c  --  ASoC register cache helpers
3  *
4  * Copyright 2009 Wolfson Microelectronics PLC.
5  *
6  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7  *
8  *  This program is free software; you can redistribute  it and/or modify it
9  *  under  the terms of  the GNU General  Public License as published by the
10  *  Free Software Foundation;  either version 2 of the  License, or (at your
11  *  option) any later version.
12  */
13
14 #include <linux/i2c.h>
15 #include <linux/spi/spi.h>
16 #include <sound/soc.h>
17 #include <linux/bitmap.h>
18 #include <linux/rbtree.h>
19 #include <linux/export.h>
20
21 #include <trace/events/asoc.h>
22
23 static bool snd_soc_set_cache_val(void *base, unsigned int idx,
24                                   unsigned int val, unsigned int word_size)
25 {
26         switch (word_size) {
27         case 1: {
28                 u8 *cache = base;
29                 if (cache[idx] == val)
30                         return true;
31                 cache[idx] = val;
32                 break;
33         }
34         case 2: {
35                 u16 *cache = base;
36                 if (cache[idx] == val)
37                         return true;
38                 cache[idx] = val;
39                 break;
40         }
41         default:
42                 BUG();
43         }
44         return false;
45 }
46
47 static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
48                 unsigned int word_size)
49 {
50         if (!base)
51                 return -1;
52
53         switch (word_size) {
54         case 1: {
55                 const u8 *cache = base;
56                 return cache[idx];
57         }
58         case 2: {
59                 const u16 *cache = base;
60                 return cache[idx];
61         }
62         default:
63                 BUG();
64         }
65         /* unreachable */
66         return -1;
67 }
68
69 struct snd_soc_rbtree_node {
70         struct rb_node node; /* the actual rbtree node holding this block */
71         unsigned int base_reg; /* base register handled by this block */
72         unsigned int word_size; /* number of bytes needed to represent the register index */
73         void *block; /* block of adjacent registers */
74         unsigned int blklen; /* number of registers available in the block */
75 } __attribute__ ((packed));
76
77 struct snd_soc_rbtree_ctx {
78         struct rb_root root;
79         struct snd_soc_rbtree_node *cached_rbnode;
80 };
81
82 static inline void snd_soc_rbtree_get_base_top_reg(
83         struct snd_soc_rbtree_node *rbnode,
84         unsigned int *base, unsigned int *top)
85 {
86         *base = rbnode->base_reg;
87         *top = rbnode->base_reg + rbnode->blklen - 1;
88 }
89
90 static unsigned int snd_soc_rbtree_get_register(
91         struct snd_soc_rbtree_node *rbnode, unsigned int idx)
92 {
93         unsigned int val;
94
95         switch (rbnode->word_size) {
96         case 1: {
97                 u8 *p = rbnode->block;
98                 val = p[idx];
99                 return val;
100         }
101         case 2: {
102                 u16 *p = rbnode->block;
103                 val = p[idx];
104                 return val;
105         }
106         default:
107                 BUG();
108                 break;
109         }
110         return -1;
111 }
112
113 static void snd_soc_rbtree_set_register(struct snd_soc_rbtree_node *rbnode,
114                                         unsigned int idx, unsigned int val)
115 {
116         switch (rbnode->word_size) {
117         case 1: {
118                 u8 *p = rbnode->block;
119                 p[idx] = val;
120                 break;
121         }
122         case 2: {
123                 u16 *p = rbnode->block;
124                 p[idx] = val;
125                 break;
126         }
127         default:
128                 BUG();
129                 break;
130         }
131 }
132
133 static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup(
134         struct rb_root *root, unsigned int reg)
135 {
136         struct rb_node *node;
137         struct snd_soc_rbtree_node *rbnode;
138         unsigned int base_reg, top_reg;
139
140         node = root->rb_node;
141         while (node) {
142                 rbnode = container_of(node, struct snd_soc_rbtree_node, node);
143                 snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
144                 if (reg >= base_reg && reg <= top_reg)
145                         return rbnode;
146                 else if (reg > top_reg)
147                         node = node->rb_right;
148                 else if (reg < base_reg)
149                         node = node->rb_left;
150         }
151
152         return NULL;
153 }
154
155 static int snd_soc_rbtree_insert(struct rb_root *root,
156                                  struct snd_soc_rbtree_node *rbnode)
157 {
158         struct rb_node **new, *parent;
159         struct snd_soc_rbtree_node *rbnode_tmp;
160         unsigned int base_reg_tmp, top_reg_tmp;
161         unsigned int base_reg;
162
163         parent = NULL;
164         new = &root->rb_node;
165         while (*new) {
166                 rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node,
167                                           node);
168                 /* base and top registers of the current rbnode */
169                 snd_soc_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp,
170                                                 &top_reg_tmp);
171                 /* base register of the rbnode to be added */
172                 base_reg = rbnode->base_reg;
173                 parent = *new;
174                 /* if this register has already been inserted, just return */
175                 if (base_reg >= base_reg_tmp &&
176                     base_reg <= top_reg_tmp)
177                         return 0;
178                 else if (base_reg > top_reg_tmp)
179                         new = &((*new)->rb_right);
180                 else if (base_reg < base_reg_tmp)
181                         new = &((*new)->rb_left);
182         }
183
184         /* insert the node into the rbtree */
185         rb_link_node(&rbnode->node, parent, new);
186         rb_insert_color(&rbnode->node, root);
187
188         return 1;
189 }
190
191 static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
192 {
193         struct snd_soc_rbtree_ctx *rbtree_ctx;
194         struct rb_node *node;
195         struct snd_soc_rbtree_node *rbnode;
196         unsigned int regtmp;
197         unsigned int val, def;
198         int ret;
199         int i;
200
201         rbtree_ctx = codec->reg_cache;
202         for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
203                 rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
204                 for (i = 0; i < rbnode->blklen; ++i) {
205                         regtmp = rbnode->base_reg + i;
206                         val = snd_soc_rbtree_get_register(rbnode, i);
207                         def = snd_soc_get_cache_val(codec->reg_def_copy, i,
208                                                     rbnode->word_size);
209                         if (val == def)
210                                 continue;
211
212                         WARN_ON(!snd_soc_codec_writable_register(codec, regtmp));
213
214                         codec->cache_bypass = 1;
215                         ret = snd_soc_write(codec, regtmp, val);
216                         codec->cache_bypass = 0;
217                         if (ret)
218                                 return ret;
219                         dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
220                                 regtmp, val);
221                 }
222         }
223
224         return 0;
225 }
226
227 static int snd_soc_rbtree_insert_to_block(struct snd_soc_rbtree_node *rbnode,
228                                           unsigned int pos, unsigned int reg,
229                                           unsigned int value)
230 {
231         u8 *blk;
232
233         blk = krealloc(rbnode->block,
234                        (rbnode->blklen + 1) * rbnode->word_size, GFP_KERNEL);
235         if (!blk)
236                 return -ENOMEM;
237
238         /* insert the register value in the correct place in the rbnode block */
239         memmove(blk + (pos + 1) * rbnode->word_size,
240                 blk + pos * rbnode->word_size,
241                 (rbnode->blklen - pos) * rbnode->word_size);
242
243         /* update the rbnode block, its size and the base register */
244         rbnode->block = blk;
245         rbnode->blklen++;
246         if (!pos)
247                 rbnode->base_reg = reg;
248
249         snd_soc_rbtree_set_register(rbnode, pos, value);
250         return 0;
251 }
252
253 static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec,
254                                       unsigned int reg, unsigned int value)
255 {
256         struct snd_soc_rbtree_ctx *rbtree_ctx;
257         struct snd_soc_rbtree_node *rbnode, *rbnode_tmp;
258         struct rb_node *node;
259         unsigned int val;
260         unsigned int reg_tmp;
261         unsigned int base_reg, top_reg;
262         unsigned int pos;
263         int i;
264         int ret;
265
266         rbtree_ctx = codec->reg_cache;
267         /* look up the required register in the cached rbnode */
268         rbnode = rbtree_ctx->cached_rbnode;
269         if (rbnode) {
270                 snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
271                 if (reg >= base_reg && reg <= top_reg) {
272                         reg_tmp = reg - base_reg;
273                         val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
274                         if (val == value)
275                                 return 0;
276                         snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
277                         return 0;
278                 }
279         }
280         /* if we can't locate it in the cached rbnode we'll have
281          * to traverse the rbtree looking for it.
282          */
283         rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
284         if (rbnode) {
285                 reg_tmp = reg - rbnode->base_reg;
286                 val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
287                 if (val == value)
288                         return 0;
289                 snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
290                 rbtree_ctx->cached_rbnode = rbnode;
291         } else {
292                 /* bail out early, no need to create the rbnode yet */
293                 if (!value)
294                         return 0;
295                 /* look for an adjacent register to the one we are about to add */
296                 for (node = rb_first(&rbtree_ctx->root); node;
297                      node = rb_next(node)) {
298                         rbnode_tmp = rb_entry(node, struct snd_soc_rbtree_node, node);
299                         for (i = 0; i < rbnode_tmp->blklen; ++i) {
300                                 reg_tmp = rbnode_tmp->base_reg + i;
301                                 if (abs(reg_tmp - reg) != 1)
302                                         continue;
303                                 /* decide where in the block to place our register */
304                                 if (reg_tmp + 1 == reg)
305                                         pos = i + 1;
306                                 else
307                                         pos = i;
308                                 ret = snd_soc_rbtree_insert_to_block(rbnode_tmp, pos,
309                                                                      reg, value);
310                                 if (ret)
311                                         return ret;
312                                 rbtree_ctx->cached_rbnode = rbnode_tmp;
313                                 return 0;
314                         }
315                 }
316                 /* we did not manage to find a place to insert it in an existing
317                  * block so create a new rbnode with a single register in its block.
318                  * This block will get populated further if any other adjacent
319                  * registers get modified in the future.
320                  */
321                 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
322                 if (!rbnode)
323                         return -ENOMEM;
324                 rbnode->blklen = 1;
325                 rbnode->base_reg = reg;
326                 rbnode->word_size = codec->driver->reg_word_size;
327                 rbnode->block = kmalloc(rbnode->blklen * rbnode->word_size,
328                                         GFP_KERNEL);
329                 if (!rbnode->block) {
330                         kfree(rbnode);
331                         return -ENOMEM;
332                 }
333                 snd_soc_rbtree_set_register(rbnode, 0, value);
334                 snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode);
335                 rbtree_ctx->cached_rbnode = rbnode;
336         }
337
338         return 0;
339 }
340
341 static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec,
342                                      unsigned int reg, unsigned int *value)
343 {
344         struct snd_soc_rbtree_ctx *rbtree_ctx;
345         struct snd_soc_rbtree_node *rbnode;
346         unsigned int base_reg, top_reg;
347         unsigned int reg_tmp;
348
349         rbtree_ctx = codec->reg_cache;
350         /* look up the required register in the cached rbnode */
351         rbnode = rbtree_ctx->cached_rbnode;
352         if (rbnode) {
353                 snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
354                 if (reg >= base_reg && reg <= top_reg) {
355                         reg_tmp = reg - base_reg;
356                         *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
357                         return 0;
358                 }
359         }
360         /* if we can't locate it in the cached rbnode we'll have
361          * to traverse the rbtree looking for it.
362          */
363         rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
364         if (rbnode) {
365                 reg_tmp = reg - rbnode->base_reg;
366                 *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
367                 rbtree_ctx->cached_rbnode = rbnode;
368         } else {
369                 /* uninitialized registers default to 0 */
370                 *value = 0;
371         }
372
373         return 0;
374 }
375
376 static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
377 {
378         struct rb_node *next;
379         struct snd_soc_rbtree_ctx *rbtree_ctx;
380         struct snd_soc_rbtree_node *rbtree_node;
381
382         /* if we've already been called then just return */
383         rbtree_ctx = codec->reg_cache;
384         if (!rbtree_ctx)
385                 return 0;
386
387         /* free up the rbtree */
388         next = rb_first(&rbtree_ctx->root);
389         while (next) {
390                 rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node);
391                 next = rb_next(&rbtree_node->node);
392                 rb_erase(&rbtree_node->node, &rbtree_ctx->root);
393                 kfree(rbtree_node->block);
394                 kfree(rbtree_node);
395         }
396
397         /* release the resources */
398         kfree(codec->reg_cache);
399         codec->reg_cache = NULL;
400
401         return 0;
402 }
403
404 static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
405 {
406         struct snd_soc_rbtree_ctx *rbtree_ctx;
407         unsigned int word_size;
408         unsigned int val;
409         int i;
410         int ret;
411
412         codec->reg_cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL);
413         if (!codec->reg_cache)
414                 return -ENOMEM;
415
416         rbtree_ctx = codec->reg_cache;
417         rbtree_ctx->root = RB_ROOT;
418         rbtree_ctx->cached_rbnode = NULL;
419
420         if (!codec->reg_def_copy)
421                 return 0;
422
423         word_size = codec->driver->reg_word_size;
424         for (i = 0; i < codec->driver->reg_cache_size; ++i) {
425                 val = snd_soc_get_cache_val(codec->reg_def_copy, i,
426                                             word_size);
427                 if (!val)
428                         continue;
429                 ret = snd_soc_rbtree_cache_write(codec, i, val);
430                 if (ret)
431                         goto err;
432         }
433
434         return 0;
435
436 err:
437         snd_soc_cache_exit(codec);
438         return ret;
439 }
440
441 static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
442 {
443         int i;
444         int ret;
445         const struct snd_soc_codec_driver *codec_drv;
446         unsigned int val;
447
448         codec_drv = codec->driver;
449         for (i = 0; i < codec_drv->reg_cache_size; ++i) {
450                 ret = snd_soc_cache_read(codec, i, &val);
451                 if (ret)
452                         return ret;
453                 if (codec->reg_def_copy)
454                         if (snd_soc_get_cache_val(codec->reg_def_copy,
455                                                   i, codec_drv->reg_word_size) == val)
456                                 continue;
457
458                 WARN_ON(!snd_soc_codec_writable_register(codec, i));
459
460                 ret = snd_soc_write(codec, i, val);
461                 if (ret)
462                         return ret;
463                 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
464                         i, val);
465         }
466         return 0;
467 }
468
469 static int snd_soc_flat_cache_write(struct snd_soc_codec *codec,
470                                     unsigned int reg, unsigned int value)
471 {
472         snd_soc_set_cache_val(codec->reg_cache, reg, value,
473                               codec->driver->reg_word_size);
474         return 0;
475 }
476
477 static int snd_soc_flat_cache_read(struct snd_soc_codec *codec,
478                                    unsigned int reg, unsigned int *value)
479 {
480         *value = snd_soc_get_cache_val(codec->reg_cache, reg,
481                                        codec->driver->reg_word_size);
482         return 0;
483 }
484
485 static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec)
486 {
487         if (!codec->reg_cache)
488                 return 0;
489         kfree(codec->reg_cache);
490         codec->reg_cache = NULL;
491         return 0;
492 }
493
494 static int snd_soc_flat_cache_init(struct snd_soc_codec *codec)
495 {
496         if (codec->reg_def_copy)
497                 codec->reg_cache = kmemdup(codec->reg_def_copy,
498                                            codec->reg_size, GFP_KERNEL);
499         else
500                 codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL);
501         if (!codec->reg_cache)
502                 return -ENOMEM;
503
504         return 0;
505 }
506
507 /* an array of all supported compression types */
508 static const struct snd_soc_cache_ops cache_types[] = {
509         /* Flat *must* be the first entry for fallback */
510         {
511                 .id = SND_SOC_FLAT_COMPRESSION,
512                 .name = "flat",
513                 .init = snd_soc_flat_cache_init,
514                 .exit = snd_soc_flat_cache_exit,
515                 .read = snd_soc_flat_cache_read,
516                 .write = snd_soc_flat_cache_write,
517                 .sync = snd_soc_flat_cache_sync
518         },
519         {
520                 .id = SND_SOC_RBTREE_COMPRESSION,
521                 .name = "rbtree",
522                 .init = snd_soc_rbtree_cache_init,
523                 .exit = snd_soc_rbtree_cache_exit,
524                 .read = snd_soc_rbtree_cache_read,
525                 .write = snd_soc_rbtree_cache_write,
526                 .sync = snd_soc_rbtree_cache_sync
527         }
528 };
529
530 int snd_soc_cache_init(struct snd_soc_codec *codec)
531 {
532         int i;
533
534         for (i = 0; i < ARRAY_SIZE(cache_types); ++i)
535                 if (cache_types[i].id == codec->compress_type)
536                         break;
537
538         /* Fall back to flat compression */
539         if (i == ARRAY_SIZE(cache_types)) {
540                 dev_warn(codec->dev, "Could not match compress type: %d\n",
541                          codec->compress_type);
542                 i = 0;
543         }
544
545         mutex_init(&codec->cache_rw_mutex);
546         codec->cache_ops = &cache_types[i];
547
548         if (codec->cache_ops->init) {
549                 if (codec->cache_ops->name)
550                         dev_dbg(codec->dev, "Initializing %s cache for %s codec\n",
551                                 codec->cache_ops->name, codec->name);
552                 return codec->cache_ops->init(codec);
553         }
554         return -ENOSYS;
555 }
556
557 /*
558  * NOTE: keep in mind that this function might be called
559  * multiple times.
560  */
561 int snd_soc_cache_exit(struct snd_soc_codec *codec)
562 {
563         if (codec->cache_ops && codec->cache_ops->exit) {
564                 if (codec->cache_ops->name)
565                         dev_dbg(codec->dev, "Destroying %s cache for %s codec\n",
566                                 codec->cache_ops->name, codec->name);
567                 return codec->cache_ops->exit(codec);
568         }
569         return -ENOSYS;
570 }
571
572 /**
573  * snd_soc_cache_read: Fetch the value of a given register from the cache.
574  *
575  * @codec: CODEC to configure.
576  * @reg: The register index.
577  * @value: The value to be returned.
578  */
579 int snd_soc_cache_read(struct snd_soc_codec *codec,
580                        unsigned int reg, unsigned int *value)
581 {
582         int ret;
583
584         mutex_lock(&codec->cache_rw_mutex);
585
586         if (value && codec->cache_ops && codec->cache_ops->read) {
587                 ret = codec->cache_ops->read(codec, reg, value);
588                 mutex_unlock(&codec->cache_rw_mutex);
589                 return ret;
590         }
591
592         mutex_unlock(&codec->cache_rw_mutex);
593         return -ENOSYS;
594 }
595 EXPORT_SYMBOL_GPL(snd_soc_cache_read);
596
597 /**
598  * snd_soc_cache_write: Set the value of a given register in the cache.
599  *
600  * @codec: CODEC to configure.
601  * @reg: The register index.
602  * @value: The new register value.
603  */
604 int snd_soc_cache_write(struct snd_soc_codec *codec,
605                         unsigned int reg, unsigned int value)
606 {
607         int ret;
608
609         mutex_lock(&codec->cache_rw_mutex);
610
611         if (codec->cache_ops && codec->cache_ops->write) {
612                 ret = codec->cache_ops->write(codec, reg, value);
613                 mutex_unlock(&codec->cache_rw_mutex);
614                 return ret;
615         }
616
617         mutex_unlock(&codec->cache_rw_mutex);
618         return -ENOSYS;
619 }
620 EXPORT_SYMBOL_GPL(snd_soc_cache_write);
621
622 /**
623  * snd_soc_cache_sync: Sync the register cache with the hardware.
624  *
625  * @codec: CODEC to configure.
626  *
627  * Any registers that should not be synced should be marked as
628  * volatile.  In general drivers can choose not to use the provided
629  * syncing functionality if they so require.
630  */
631 int snd_soc_cache_sync(struct snd_soc_codec *codec)
632 {
633         int ret;
634         const char *name;
635
636         if (!codec->cache_sync) {
637                 return 0;
638         }
639
640         if (!codec->cache_ops || !codec->cache_ops->sync)
641                 return -ENOSYS;
642
643         if (codec->cache_ops->name)
644                 name = codec->cache_ops->name;
645         else
646                 name = "unknown";
647
648         if (codec->cache_ops->name)
649                 dev_dbg(codec->dev, "Syncing %s cache for %s codec\n",
650                         codec->cache_ops->name, codec->name);
651         trace_snd_soc_cache_sync(codec, name, "start");
652         ret = codec->cache_ops->sync(codec);
653         if (!ret)
654                 codec->cache_sync = 0;
655         trace_snd_soc_cache_sync(codec, name, "end");
656         return ret;
657 }
658 EXPORT_SYMBOL_GPL(snd_soc_cache_sync);
659
660 static int snd_soc_get_reg_access_index(struct snd_soc_codec *codec,
661                                         unsigned int reg)
662 {
663         const struct snd_soc_codec_driver *codec_drv;
664         unsigned int min, max, index;
665
666         codec_drv = codec->driver;
667         min = 0;
668         max = codec_drv->reg_access_size - 1;
669         do {
670                 index = (min + max) / 2;
671                 if (codec_drv->reg_access_default[index].reg == reg)
672                         return index;
673                 if (codec_drv->reg_access_default[index].reg < reg)
674                         min = index + 1;
675                 else
676                         max = index;
677         } while (min <= max);
678         return -1;
679 }
680
681 int snd_soc_default_volatile_register(struct snd_soc_codec *codec,
682                                       unsigned int reg)
683 {
684         int index;
685
686         if (reg >= codec->driver->reg_cache_size)
687                 return 1;
688         index = snd_soc_get_reg_access_index(codec, reg);
689         if (index < 0)
690                 return 0;
691         return codec->driver->reg_access_default[index].vol;
692 }
693 EXPORT_SYMBOL_GPL(snd_soc_default_volatile_register);
694
695 int snd_soc_default_readable_register(struct snd_soc_codec *codec,
696                                       unsigned int reg)
697 {
698         int index;
699
700         if (reg >= codec->driver->reg_cache_size)
701                 return 1;
702         index = snd_soc_get_reg_access_index(codec, reg);
703         if (index < 0)
704                 return 0;
705         return codec->driver->reg_access_default[index].read;
706 }
707 EXPORT_SYMBOL_GPL(snd_soc_default_readable_register);
708
709 int snd_soc_default_writable_register(struct snd_soc_codec *codec,
710                                       unsigned int reg)
711 {
712         int index;
713
714         if (reg >= codec->driver->reg_cache_size)
715                 return 1;
716         index = snd_soc_get_reg_access_index(codec, reg);
717         if (index < 0)
718                 return 0;
719         return codec->driver->reg_access_default[index].write;
720 }
721 EXPORT_SYMBOL_GPL(snd_soc_default_writable_register);