/*
* soc-cache.c -- ASoC register cache helpers
*
* Copyright 2009 Wolfson Microelectronics PLC.
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <sound/soc.h>
#include <linux/lzo.h>
#include <linux/bitmap.h>
#include <linux/rbtree.h>
#include <trace/events/asoc.h>
static bool snd_soc_set_cache_val(void *base, unsigned int idx,
unsigned int val, unsigned int word_size)
{
switch (word_size) {
case 1: {
u8 *cache = base;
if (cache[idx] == val)
return true;
cache[idx] = val;
break;
}
case 2: {
u16 *cache = base;
if (cache[idx] == val)
return true;
cache[idx] = val;
break;
}
default:
BUG();
}
return false;
}
static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
unsigned int word_size)
{
if (!base)
return -1;
switch (word_size) {
case 1: {
const u8 *cache = base;
return cache[idx];
}
case 2: {
const u16 *cache = base;
return cache[idx];
}
default:
BUG();
}
/* unreachable */
return -1;
}
struct snd_soc_rbtree_node {
struct rb_node node; /* the actual rbtree node holding this block */
unsigned int base_reg; /* base register handled by this block */
unsigned int word_size; /* number of bytes needed to represent the register index */
void *block; /* block of adjacent registers */
unsigned int blklen; /* number of registers available in the block */
} __attribute__ ((packed));
struct snd_soc_rbtree_ctx {
struct rb_root root;
struct snd_soc_rbtree_node *cached_rbnode;
};
static inline void snd_soc_rbtree_get_base_top_reg(
struct snd_soc_rbtree_node *rbnode,
unsigned int *base, unsigned int *top)
{
*base = rbnode->base_reg;
*top = rbnode->base_reg + rbnode->blklen - 1;
}
static unsigned int snd_soc_rbtree_get_register(
struct snd_soc_rbtree_node *rbnode, unsigned int idx)
{
unsigned int val;
switch (rbnode->word_size) {
case 1: {
u8 *p = rbnode->block;
val = p[idx];
return val;
}
case 2: {
u16 *p = rbnode->block;
val = p[idx];
return val;
}
default:
BUG();
break;
}
return -1;
}
static void snd_soc_rbtree_set_register(struct snd_soc_rbtree_node *rbnode,
unsigned int idx, unsigned int val)
{
switch (rbnode->word_size) {
case 1: {
u8 *p = rbnode->block;
p[idx] = val;
break;
}
case 2: {
u16 *p = rbnode->block;
p[idx] = val;
break;
}
default:
BUG();
break;
}
}
static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup(