Index: firmware/export/audiohw.h
===================================================================
--- firmware/export/audiohw.h	(revision 0)
+++ firmware/export/audiohw.h	(revision 0)
@@ -0,0 +1,127 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2007 by Christian Gmeiner
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _AUDIOHW_H_
+#define _AUDIOHW_H_
+
+#include <stdbool.h>
+#include "config.h"
+
+enum {
+    SOUND_VOLUME = 0,
+    SOUND_BASS,
+    SOUND_TREBLE,
+    SOUND_BALANCE,
+    SOUND_CHANNELS,
+    SOUND_STEREO_WIDTH,
+#ifdef HAVE_OUTPUT_LINEOUT
+    SOUND_VOLUME_LINEOUT,
+#endif
+#ifdef HAVE_OUTPUT_SPDIF
+    SOUND_VOLUME_SPDIF
+#endif
+};
+
+enum Channel {
+    SOUND_CHAN_STEREO,
+    SOUND_CHAN_MONO,
+    SOUND_CHAN_CUSTOM,
+    SOUND_CHAN_MONO_LEFT,
+    SOUND_CHAN_MONO_RIGHT,
+    SOUND_CHAN_KARAOKE,
+    SOUND_CHAN_NUM_MODES,
+};
+
+/* Enumeration with supported audio output modes */
+enum OutDestination {
+    OUTPUT_HEADPHONES,
+#ifdef HAVE_OUTPUT_LINEOUT
+    OUTPUT_LINEOUT,
+#endif
+#ifdef HAVE_OUTPUT_SPDIF
+    OUTPUT_SPDIF,
+#endif
+};
+
+#ifdef HAVE_RECORDING
+/* Enumeration with supported audio recording sources */
+enum RecSource {
+#ifdef HAVE_RECORING_MIC
+    REC_SOURCE_MIC,
+#endif
+#ifdef HAVE_RECORING_LINEIN
+    REC_SOURCE_LINEIN,
+#endif
+#ifdef HAVE_RECORING_FN
+    REC_SOURCE_FM,
+#endif
+#ifdef HAVE_RECORING_SPDIF
+    REC_SOURCE_SPDIF,
+#endif
+};
+#endif
+
+struct sound_settings_info {
+    const char *unit;
+    int numdecimals;
+    int steps;
+    int minval;
+    int maxval;
+    int defaultval;
+};
+
+/* This struct is used by every driver to export its min/max values for
+ * its audio settings */
+extern const struct sound_settings_info audiohw_settings[];
+
+/* All usable functions exported by a audio codec driver. Most of
+ * the function in sound settings are only called, when in audio codecs
+ * .h file suitable defines are added.
+ */
+extern void audiohw_init(void);
+extern void audiohw_postinit(void);
+extern void audiohw_shutdown(void);
+extern void audiohw_reset(void);
+
+/* playback */
+extern void audiohw_enable_output(bool enable);
+extern void audiohw_set_output_destination(enum OutDestination destination);
+extern void audiohw_mute(bool mute);
+
+/* sound settings */
+extern void audiohw_set_volume(int l, int r);
+extern void audiohw_set_bass(int value);                /* #define AUDIOHW_HAVE_BASS */
+extern void audiohw_set_treble(int value);              /* #define AUDIOHW_HAVE_TREBLE */
+extern void audiohw_set_channel(enum Channel value);    /* #define AUDIOHW_HAVE_CHANNEL */
+extern void audiohw_set_stereo_width(int value);        /* #define AUDIOHW_HAVE_STEREO_WIDTH */
+extern void audiohw_set_prescale(int value);            /* #define AUDIOHW_HAVE_PRESCALE */
+extern void audiohw_set_frequency(int freq);
+
+/* recording */
+#ifdef HAVE_RECORDING
+extern void audiohw_enable_recording(bool enable);
+extern void audiohw_set_rec_source(enum RecSource source);
+extern void audiohw_enable_rec_monitor(bool enable);
+/* TODO: volume control */
+#endif
+
+/* special stuff */
+extern void audiohw_add_dither(bool add);               /* #define AUDIOHW_HAVE_DITHERING */
+
+#endif /* _AUDIOHW_H_ */
Index: firmware/export/config-e200.h
===================================================================
--- firmware/export/config-e200.h	(revision 13366)
+++ firmware/export/config-e200.h	(working copy)
@@ -51,6 +51,10 @@
 /* The PP5024 has a built-in AustriaMicrosystems AS3514 */
 #define HAVE_AS3514
 
+/* define what input and output we support */
+#define HAVE_RECORING_MIC
+#define HAVE_RECORING_FM
+
 /* define this if you have a real-time clock */
 #ifndef BOOTLOADER
 #define CONFIG_RTC RTC_AS3514
Index: firmware/export/as3514.h
===================================================================
--- firmware/export/as3514.h	(revision 13366)
+++ firmware/export/as3514.h	(working copy)
@@ -20,24 +20,8 @@
 #ifndef _AS3514_H
 #define _AS3514_H
 
-#include <stdbool.h>
+#include "audiohw.h"
 
-extern int tenthdb2master(int db);
-
-extern void audiohw_reset(void);
-extern int audiohw_init(void);
-extern void audiohw_enable_output(bool enable);
-extern int audiohw_set_master_vol(int vol_l, int vol_r);
-extern int audiohw_set_lineout_vol(int vol_l, int vol_r);
-extern int audiohw_mute(int mute);
-extern void audiohw_close(void);
-extern void audiohw_set_sample_rate(int sampling_control);
-
-extern void audiohw_enable_recording(bool source_mic);
-extern void audiohw_disable_recording(void);
-extern void audiohw_set_recvol(int left, int right, int type);
-extern void audiohw_set_monitor(int enable);
-
 /* Register Descriptions */
 #define LINE_OUT_R 0x00
 #define LINE_OUT_L 0x01
Index: firmware/export/sound.h
===================================================================
--- firmware/export/sound.h	(revision 13366)
+++ firmware/export/sound.h	(working copy)
@@ -36,43 +36,6 @@
 #include "as3514.h"
 #endif
 
-extern void audiohw_postinit(void);
-
-enum {
-    SOUND_VOLUME = 0,
-    SOUND_BASS,
-    SOUND_TREBLE,
-    SOUND_BALANCE,
-    SOUND_CHANNELS,
-    SOUND_STEREO_WIDTH,
-#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-    SOUND_LOUDNESS,
-    SOUND_AVC,
-    SOUND_MDB_STRENGTH,
-    SOUND_MDB_HARMONICS,
-    SOUND_MDB_CENTER,
-    SOUND_MDB_SHAPE,
-    SOUND_MDB_ENABLE,
-    SOUND_SUPERBASS,
-#endif
-#if CONFIG_CODEC == MAS3587F || defined(HAVE_UDA1380) || defined(HAVE_TLV320)\
-    || defined(HAVE_WM8975) || defined(HAVE_WM8758) || defined(HAVE_WM8731)
-    SOUND_LEFT_GAIN,
-    SOUND_RIGHT_GAIN,
-    SOUND_MIC_GAIN,
-#endif
-};
-
-enum {
-    SOUND_CHAN_STEREO = 0,
-    SOUND_CHAN_MONO,
-    SOUND_CHAN_CUSTOM,
-    SOUND_CHAN_MONO_LEFT,
-    SOUND_CHAN_MONO_RIGHT,
-    SOUND_CHAN_KARAOKE,
-    SOUND_CHAN_NUM_MODES
-};
-
 typedef void sound_set_type(int value);
 
 const char *sound_unit(int setting);
@@ -90,23 +53,8 @@
 void sound_set_treble(int value);
 void sound_set_channels(int value);
 void sound_set_stereo_width(int value);
-#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-void sound_set_loudness(int value);
-void sound_set_avc(int value);
-void sound_set_mdb_strength(int value);
-void sound_set_mdb_harmonics(int value);
-void sound_set_mdb_center(int value);
-void sound_set_mdb_shape(int value);
-void sound_set_mdb_enable(int value);
-void sound_set_superbass(int value);
-#endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
 
 void sound_set(int setting, int value);
 int sound_val2phys(int setting, int value);
 
-#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-void sound_set_pitch(int permille);
-int sound_get_pitch(void);
 #endif
-
-#endif
Index: firmware/sound.c
===================================================================
--- firmware/sound.c	(revision 13366)
+++ firmware/sound.c	(working copy)
@@ -8,6 +8,7 @@
  * $Id$
  *
  * Copyright (C) 2005 by Linus Nielsen Feltzing
+ * Copyright (C) 2007 by Christian Gmeiner
  *
  * All files in this archive are subject to the GNU General Public License.
  * See the file COPYING in the source tree root for full license agreement.
@@ -20,325 +21,171 @@
 #include <stdio.h>
 #include "config.h"
 #include "sound.h"
-#include "logf.h"
-#ifndef SIMULATOR
-#include "i2c.h"
-#include "mas.h"
-#if CONFIG_CPU == PNX0101
-#include "pnx0101.h"
-#endif
-#include "dac.h"
 #include "system.h"
-#if CONFIG_CODEC == SWCODEC
-#include "pcm_playback.h"
-#endif
-#endif
 
 #ifndef SIMULATOR
 extern bool audio_is_initialized;
-
-#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-extern unsigned long shadow_io_control_main;
-extern unsigned shadow_codec_reg0;
-#endif
 #endif /* SIMULATOR */
 
-struct sound_settings_info {
-    const char *unit;
-    int numdecimals;
-    int steps;
-    int minval;
-    int maxval;
-    int defaultval;
-    sound_set_type *setfn;
-};
+#define VOLUME_RANGE (VOLUME_MAX - VOLUME_MIN)
+int current_volume = 0;
+int current_balance = 0;
+int current_bass = 0;
+int current_treble = 0;
 
-static const struct sound_settings_info sound_settings_table[] = {
-#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-    [SOUND_VOLUME]        = {"dB", 0,  1,-100,  12, -25, sound_set_volume},
-    [SOUND_BASS]          = {"dB", 0,  1, -12,  12,   6, sound_set_bass},
-    [SOUND_TREBLE]        = {"dB", 0,  1, -12,  12,   6, sound_set_treble},
-#elif defined(HAVE_UDA1380)
-    [SOUND_VOLUME]        = {"dB", 0,  1, -84,   0, -25, sound_set_volume},
-    [SOUND_BASS]          = {"dB", 0,  2,   0,  24,   0, sound_set_bass},
-    [SOUND_TREBLE]        = {"dB", 0,  2,   0,   6,   0, sound_set_treble},
-#elif defined(HAVE_TLV320)
-    [SOUND_VOLUME]        = {"dB", 0,  1, -73,   6, -20, sound_set_volume},
-#elif defined(HAVE_WM8751)
-    [SOUND_VOLUME]        = {"dB", 0,  1, -74,   6, -25, sound_set_volume},
-    [SOUND_BASS]          = {"dB", 1, 15, -60,  90,   0, sound_set_bass},
-    [SOUND_TREBLE]        = {"dB", 1, 15, -60,  90,   0, sound_set_treble},
-#elif defined(HAVE_WM8975)
-    [SOUND_VOLUME]        = {"dB", 0,  1, -74,   6, -25, sound_set_volume},
-    [SOUND_BASS]          = {"dB", 0,  1,  -6,   9,   0, sound_set_bass},
-    [SOUND_TREBLE]        = {"dB", 0,  1,  -6,   9,   0, sound_set_treble},
-#elif defined(HAVE_WM8758)
-    [SOUND_VOLUME]        = {"dB", 0,  1, -58,   6, -25, sound_set_volume},
-    [SOUND_BASS]          = {"dB", 0,  1,  -6,   9,   0, sound_set_bass},
-    [SOUND_TREBLE]        = {"dB", 0,  1,  -6,   9,   0, sound_set_treble},
-#elif defined(HAVE_WM8731) || defined(HAVE_WM8721)
-    [SOUND_VOLUME]        = {"dB", 0,  1, -74,   6, -25, sound_set_volume},
-#elif (CONFIG_CPU == PNX0101)
-    [SOUND_VOLUME]        = {"dB", 0,  1, -48,  15,   0, sound_set_volume},
-#elif defined(HAVE_AS3514)
-    [SOUND_VOLUME]        = {"dB", 0,  1, -40,   6, -25, sound_set_volume},
-#else /* MAS3507D */
-    [SOUND_VOLUME]        = {"dB", 0,  1, -78,  18, -18, sound_set_volume},
-    [SOUND_BASS]          = {"dB", 0,  1, -15,  15,   7, sound_set_bass},
-    [SOUND_TREBLE]        = {"dB", 0,  1, -15,  15,   7, sound_set_treble},
-#endif
-/* Override any other potentially existing treble/bass controllers if wanted */
-#ifdef HAVE_SW_TONE_CONTROLS
-    [SOUND_BASS]          = {"dB", 0,  1, -24,  24,   0, sound_set_bass},
-    [SOUND_TREBLE]        = {"dB", 0,  1, -24,  24,   0, sound_set_treble},
-#endif
-    [SOUND_BALANCE]       = {"%",  0,  1,-100, 100,   0, sound_set_balance},
-    [SOUND_CHANNELS]      = {"",   0,  1,   0,   5,   0, sound_set_channels},
-    [SOUND_STEREO_WIDTH]  = {"%",  0,  1,   0, 255, 100, sound_set_stereo_width},
-#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-    [SOUND_LOUDNESS]      = {"dB", 0,  1,   0,  17,   0, sound_set_loudness},
-    [SOUND_AVC]           = {"",   0,  1,  -1,   4,   0, sound_set_avc},
-    [SOUND_MDB_STRENGTH]  = {"dB", 0,  1,   0, 127,  48, sound_set_mdb_strength},
-    [SOUND_MDB_HARMONICS] = {"%",  0,  1,   0, 100,  50, sound_set_mdb_harmonics},
-    [SOUND_MDB_CENTER]    = {"Hz", 0, 10,  20, 300,  60, sound_set_mdb_center},
-    [SOUND_MDB_SHAPE]     = {"Hz", 0, 10,  50, 300,  90, sound_set_mdb_shape},
-    [SOUND_MDB_ENABLE]    = {"",   0,  1,   0,   1,   0, sound_set_mdb_enable},
-    [SOUND_SUPERBASS]     = {"",   0,  1,   0,   1,   0, sound_set_superbass},
-#endif
-#if CONFIG_CODEC == MAS3587F
-    [SOUND_LEFT_GAIN]     = {"dB", 1,  1,   0,  15,   8, NULL},
-    [SOUND_RIGHT_GAIN]    = {"dB", 1,  1,   0,  15,   8, NULL},
-    [SOUND_MIC_GAIN]      = {"dB", 1,  1,   0,  15,   2, NULL},
-#elif defined(HAVE_UDA1380)
-    [SOUND_LEFT_GAIN]     = {"dB", 1,  1,-128,  96,   0, NULL},
-    [SOUND_RIGHT_GAIN]    = {"dB", 1,  1,-128,  96,   0, NULL},
-    [SOUND_MIC_GAIN]      = {"dB", 1,  1,-128, 108,  16, NULL},
-#elif defined(HAVE_TLV320)
-    [SOUND_LEFT_GAIN]     = {"dB", 1,  1,   0,  31,  23, NULL},
-    [SOUND_RIGHT_GAIN]    = {"dB", 1,  1,   0,  31,  23, NULL},
-    [SOUND_MIC_GAIN]      = {"dB", 1,  1,   0,   1,   1, NULL},
-#elif defined(HAVE_WM8975)
-    [SOUND_LEFT_GAIN]     = {"dB", 1,  1,-128,  96,   0, NULL},
-    [SOUND_RIGHT_GAIN]    = {"dB", 1,  1,-128,  96,   0, NULL},
-    [SOUND_MIC_GAIN]      = {"dB", 1,  1,-128, 108,  16, NULL},
-#elif defined(HAVE_WM8758)
-    [SOUND_LEFT_GAIN]     = {"dB", 1,  1,-128,  96,   0, NULL},
-    [SOUND_RIGHT_GAIN]    = {"dB", 1,  1,-128,  96,   0, NULL},
-    [SOUND_MIC_GAIN]      = {"dB", 1,  1,-128, 108,  16, NULL},
-#elif defined(HAVE_WM8731)
-    [SOUND_LEFT_GAIN]     = {"dB", 1,  1,-128,  96,   0, NULL},
-    [SOUND_RIGHT_GAIN]    = {"dB", 1,  1,-128,  96,   0, NULL},
-    [SOUND_MIC_GAIN]      = {"dB", 1,  1,-128, 108,  16, NULL},
-#endif
+/* Copied from dsp.h, nasty nasty, but we don't want to include dsp.h */
+enum {
+    DSP_CALLBACK_SET_PRESCALE = 0,
+    DSP_CALLBACK_SET_BASS,
+    DSP_CALLBACK_SET_TREBLE,
+    DSP_CALLBACK_SET_CHANNEL_CONFIG,
+    DSP_CALLBACK_SET_STEREO_WIDTH
 };
 
+static int (*dsp_callback)(int, intptr_t) = NULL;
+
+/**
+ * Set function pointer to dsp callback, which is used
+ * to modify dsp setting for audio settings, which a
+ * audio codec does not support dirctly in hardware.
+ * @param func adress of function
+*/
+void sound_set_dsp_callback(int (*func)(int, intptr_t))
+{
+    dsp_callback = func;
+}
+
+/**
+ * @param setting from which getting informations
+ * @return unit of wanted audio setting
+*/
 const char *sound_unit(int setting)
 {
-    return sound_settings_table[setting].unit;
+    return audiohw_settings[setting].unit;
 }
 
+/**
+ * @param setting from which getting informations
+ * @return unit of wanted audio setting
+*/
 int sound_numdecimals(int setting)
 {
-    return sound_settings_table[setting].numdecimals;
+    return audiohw_settings[setting].numdecimals;
 }
 
+/**
+ * @param setting from which getting informations
+ * @return steps to in/decrease value of wanted audio setting
+*/
 int sound_steps(int setting)
 {
-    return sound_settings_table[setting].steps;
+    return audiohw_settings[setting].steps;
 }
 
+/**
+ * @param setting from which getting informations
+ * @return min value of wanted audio setting
+*/
 int sound_min(int setting)
 {
-    return sound_settings_table[setting].minval;
+    return audiohw_settings[setting].minval;
 }
 
+/**
+ * @param setting from which getting informations
+ * @return max value of wanted audio setting
+*/
 int sound_max(int setting)
 {
-    return sound_settings_table[setting].maxval;
+    return audiohw_settings[setting].maxval;
 }
 
+/**
+ * @param setting from which getting informations
+ * @return default value of wanted audio setting
+*/
 int sound_default(int setting)
 {
-    return sound_settings_table[setting].defaultval;
+    return audiohw_settings[setting].defaultval;
 }
 
+/**
+ * @param setting from which getting informations
+ * @return a function pointer to set values of wanted audio setting
+*/
 sound_set_type* sound_get_fn(int setting)
 {
-    if ((unsigned)setting < (sizeof(sound_settings_table)
-                             / sizeof(struct sound_settings_info)))
-        return sound_settings_table[setting].setfn;
-    else
-        return NULL;
-}
+    sound_set_type* result = NULL;
 
-#if CONFIG_CODEC == SWCODEC
-/* Copied from dsp.h, nasty nasty, but we don't want to include dsp.h */
-enum {
-    DSP_CALLBACK_SET_PRESCALE = 0,
-    DSP_CALLBACK_SET_BASS,
-    DSP_CALLBACK_SET_TREBLE,
-    DSP_CALLBACK_SET_CHANNEL_CONFIG,
-    DSP_CALLBACK_SET_STEREO_WIDTH
-};
-
-static int (*dsp_callback)(int, intptr_t) = NULL;
-
-void sound_set_dsp_callback(int (*func)(int, intptr_t))
-{
-    dsp_callback = func;
-}
+    switch (setting) {
+        case SOUND_VOLUME:
+#ifdef HAVE_OUTPUT_LINEOUT
+        case SOUND_VOLUME_LINEOUT:
 #endif
+#ifdef HAVE_OUTPUT_SPDIF
+        case SOUND_VOLUME_SPDIF:
+#endif
+            result = &sound_set_volume;
+            break;
 
-#ifndef SIMULATOR
-#if CONFIG_CODEC == MAS3507D /* volume/balance/treble/bass interdependency */
-#define VOLUME_MIN -780
-#define VOLUME_MAX  180
+        case SOUND_BASS:
+            result = &sound_set_bass;
+            break;
 
-static const unsigned int bass_table[] =
-{
-    0x9e400, /* -15dB */
-    0xa2800, /* -14dB */
-    0xa7400, /* -13dB */
-    0xac400, /* -12dB */
-    0xb1800, /* -11dB */
-    0xb7400, /* -10dB */
-    0xbd400, /* -9dB */
-    0xc3c00, /* -8dB */
-    0xca400, /* -7dB */
-    0xd1800, /* -6dB */
-    0xd8c00, /* -5dB */
-    0xe0400, /* -4dB */
-    0xe8000, /* -3dB */
-    0xefc00, /* -2dB */
-    0xf7c00, /* -1dB */
-    0,
-    0x800,   /* 1dB */
-    0x10000, /* 2dB */
-    0x17c00, /* 3dB */
-    0x1f800, /* 4dB */
-    0x27000, /* 5dB */
-    0x2e400, /* 6dB */
-    0x35800, /* 7dB */
-    0x3c000, /* 8dB */
-    0x42800, /* 9dB */
-    0x48800, /* 10dB */
-    0x4e400, /* 11dB */
-    0x53800, /* 12dB */
-    0x58800, /* 13dB */
-    0x5d400, /* 14dB */
-    0x61800  /* 15dB */
-};
+        case SOUND_TREBLE:
+            result = &sound_set_treble;
+            break;
 
-static const unsigned int treble_table[] =
-{
-    0xb2c00, /* -15dB */
-    0xbb400, /* -14dB */
-    0xc1800, /* -13dB */
-    0xc6c00, /* -12dB */
-    0xcbc00, /* -11dB */
-    0xd0400, /* -10dB */
-    0xd5000, /* -9dB */
-    0xd9800, /* -8dB */
-    0xde000, /* -7dB */
-    0xe2800, /* -6dB */
-    0xe7e00, /* -5dB */
-    0xec000, /* -4dB */
-    0xf0c00, /* -3dB */
-    0xf5c00, /* -2dB */
-    0xfac00, /* -1dB */
-    0,
-    0x5400,  /* 1dB */
-    0xac00,  /* 2dB */
-    0x10400, /* 3dB */
-    0x16000, /* 4dB */
-    0x1c000, /* 5dB */
-    0x22400, /* 6dB */
-    0x28400, /* 7dB */
-    0x2ec00, /* 8dB */
-    0x35400, /* 9dB */
-    0x3c000, /* 10dB */
-    0x42c00, /* 11dB */
-    0x49c00, /* 12dB */
-    0x51800, /* 13dB */
-    0x58400, /* 14dB */
-    0x5f800  /* 15dB */
-};
+        case SOUND_BALANCE:
+            result = &sound_set_balance;
+            break;
 
-static const unsigned int prescale_table[] =
-{
-    0x80000,  /* 0db */
-    0x8e000,  /* 1dB */
-    0x9a400,  /* 2dB */
-    0xa5800, /* 3dB */
-    0xaf400, /* 4dB */
-    0xb8000, /* 5dB */
-    0xbfc00, /* 6dB */
-    0xc6c00, /* 7dB */
-    0xcd000, /* 8dB */
-    0xd25c0, /* 9dB */
-    0xd7800, /* 10dB */
-    0xdc000, /* 11dB */
-    0xdfc00, /* 12dB */
-    0xe3400, /* 13dB */
-    0xe6800, /* 14dB */
-    0xe9400  /* 15dB */
-};
+        case SOUND_CHANNELS:
+            result = &sound_set_channels;
+            break;
 
-/* convert tenth of dB volume (-780..+180) to dac3550 register value */
-static int tenthdb2reg(int db)
-{
-    if (db < -540)                  /* 3 dB steps */
-        return (db + 780) / 30;
-    else                            /* 1.5 dB steps */
-        return (db + 660) / 15;
+        case SOUND_STEREO_WIDTH:
+            result = &sound_set_stereo_width;
+            break;
+    }
+
+    return result;
 }
-#endif
 
-#if (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 \
-    || defined HAVE_WM8975 || defined HAVE_WM8758 || defined(HAVE_WM8731) \
-    || defined(HAVE_WM8721) || defined(HAVE_TLV320) || defined(HAVE_WM8751) \
-    || defined(HAVE_AS3514)
- /* volume/balance/treble/bass interdependency main part */
-#define VOLUME_RANGE (VOLUME_MAX - VOLUME_MIN)
 
-/* all values in tenth of dB    MAS3507D    UDA1380  */
-int current_volume = 0;    /* -780..+180  -840..   0 */
-int current_balance = 0;   /* -960..+960  -840..+840 */
-int current_treble = 0;    /* -150..+150     0.. +60 */
-int current_bass = 0;      /* -150..+150     0..+240 */
-
+/**
+ *
+*/
 static void set_prescaled_volume(void)
 {
     int prescale = 0;
     int l, r;
 
-/* The WM codecs listed don't have suitable prescaler functionality, so we let
- * the prescaler stay at 0 for these unless SW tone controls are in use */
-#if defined(HAVE_SW_TONE_CONTROLS) || !(defined(HAVE_WM8975) \
-    || defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8751))
-
     prescale = MAX(current_bass, current_treble);
     if (prescale < 0)
+    {
         prescale = 0;  /* no need to prescale if we don't boost
                           bass or treble */
+    }
 
     /* Gain up the analog volume to compensate the prescale gain reduction,
      * but if this would push the volume over the top, reduce prescaling
      * instead (might cause clipping). */
     if (current_volume + prescale > VOLUME_MAX)
+    {
         prescale = VOLUME_MAX - current_volume;
-#endif
+    }
 
-#if defined(HAVE_SW_TONE_CONTROLS)
+#ifdef AUDIO_HAVE_PRESCALE
+    audiohw_set_prescale(prescale);
+#else
     dsp_callback(DSP_CALLBACK_SET_PRESCALE, prescale);
-#elif CONFIG_CODEC == MAS3507D
-    mas_writereg(MAS_REG_KPRESCALE, prescale_table[prescale/10]);
-#elif defined(HAVE_UDA1380) || defined(HAVE_WM8758)
-    audiohw_set_mixer_vol(tenthdb2mixer(-prescale), tenthdb2mixer(-prescale));
 #endif
 
     if (current_volume == VOLUME_MIN)
+    {
         prescale = 0;  /* Make sure the chip gets muted at VOLUME_MIN */
+    }
 
     l = r = current_volume + prescale;
 
@@ -346,519 +193,192 @@
     {
         l -= current_balance;
         if (l < VOLUME_MIN)
+        {
             l = VOLUME_MIN;
+        }
     }
     if (current_balance < 0)
     {
         r += current_balance;
         if (r < VOLUME_MIN)
+        {
             r = VOLUME_MIN;
+        }
     }
 
-#if CONFIG_CODEC == MAS3507D
-    dac_volume(tenthdb2reg(l), tenthdb2reg(r), false);
-#elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \
-   || defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8751) \
-   || defined(HAVE_AS3514)
-    audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r));
-#if defined(HAVE_WM8975) || defined(HAVE_WM8758) || defined(HAVE_WM8751)
-    audiohw_set_lineout_vol(tenthdb2master(0), tenthdb2master(0));
-#endif
-
-#elif defined(HAVE_TLV320)
-    audiohw_set_headphone_vol(tenthdb2master(l), tenthdb2master(r));
-#endif
+    audiohw_set_volume(l, r);
 }
-#endif /* (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 */
-#endif /* !SIMULATOR */
 
-#if CONFIG_CODEC != SWCODEC
-int channel_configuration = SOUND_CHAN_STEREO;
-int stereo_width = 100;
-#endif
-
-#ifndef SIMULATOR
-
-#if CONFIG_CODEC != SWCODEC
-static void set_channel_config(void)
+/**
+ * Set volume
+ * @param value to set
+*/
+void sound_set_volume(int value)
 {
-    /* default values: stereo */
-    unsigned long val_ll = 0x80000;
-    unsigned long val_lr = 0;
-    unsigned long val_rl = 0;
-    unsigned long val_rr = 0x80000;
-    
-    switch(channel_configuration)
-    {
-        /* case SOUND_CHAN_STEREO unnecessary */
-
-        case SOUND_CHAN_MONO:
-            val_ll = 0xc0000;
-            val_lr = 0xc0000;
-            val_rl = 0xc0000;
-            val_rr = 0xc0000;
-            break;
-
-        case SOUND_CHAN_CUSTOM:
-            {
-                /* fixed point variables (matching MAS internal format)
-                   integer part: upper 13 bits (inlcuding sign)
-                   fractional part: lower 19 bits */
-                long fp_width, fp_straight, fp_cross;
-                
-                fp_width = (stereo_width << 19) / 100;
-                if (stereo_width <= 100)
-                {
-                    fp_straight = - ((1<<19) + fp_width) / 2;
-                    fp_cross = fp_straight + fp_width;
-                }
-                else
-                {
-                    /* straight = - (1 + width) / (2 * width) */
-                    fp_straight = - ((((1<<19) + fp_width) / (fp_width >> 9)) << 9);
-                    fp_cross = (1<<19) + fp_straight;
-                }
-                val_ll = val_rr = fp_straight & 0xfffff;
-                val_lr = val_rl = fp_cross & 0xfffff;
-            }
-            break;
-
-        case SOUND_CHAN_MONO_LEFT:
-            val_ll = 0x80000;
-            val_lr = 0x80000;
-            val_rl = 0;
-            val_rr = 0;
-            break;
-
-        case SOUND_CHAN_MONO_RIGHT:
-            val_ll = 0;
-            val_lr = 0;
-            val_rl = 0x80000;
-            val_rr = 0x80000;
-            break;
-
-        case SOUND_CHAN_KARAOKE:
-            val_ll = 0xc0000;
-            val_lr = 0x40000;
-            val_rl = 0x40000;
-            val_rr = 0xc0000;
-            break;
+#ifndef SIMULATOR
+    if (!audio_is_initialized) {
+        return;
     }
 
-#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-    mas_writemem(MAS_BANK_D0, MAS_D0_OUT_LL, &val_ll, 1); /* LL */
-    mas_writemem(MAS_BANK_D0, MAS_D0_OUT_LR, &val_lr, 1); /* LR */
-    mas_writemem(MAS_BANK_D0, MAS_D0_OUT_RL, &val_rl, 1); /* RL */
-    mas_writemem(MAS_BANK_D0, MAS_D0_OUT_RR, &val_rr, 1); /* RR */
-#elif CONFIG_CODEC == MAS3507D
-    mas_writemem(MAS_BANK_D1, 0x7f8, &val_ll, 1); /* LL */
-    mas_writemem(MAS_BANK_D1, 0x7f9, &val_lr, 1); /* LR */
-    mas_writemem(MAS_BANK_D1, 0x7fa, &val_rl, 1); /* RL */
-    mas_writemem(MAS_BANK_D1, 0x7fb, &val_rr, 1); /* RR */
+    current_volume = value * 10;    /* tenth of dB */
+    set_prescaled_volume();
+#else
+    (void)value;
 #endif
 }
 
-#endif /* CONFIG_CODEC != SWCODEC */
-
-#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-unsigned long mdb_shape_shadow = 0;
-unsigned long loudness_shadow = 0;
-#endif
-
-void sound_set_volume(int value)
-{
-    if(!audio_is_initialized)
-        return;
-#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-    unsigned tmp = ((unsigned)(value + 115) & 0xff) << 8;
-    mas_codec_writereg(0x10, tmp);
-#elif (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 \
-   || defined HAVE_WM8975 || defined HAVE_WM8758 || defined HAVE_WM8731 \
-   || defined(HAVE_WM8721) || defined(HAVE_TLV320) || defined(HAVE_WM8751) \
-   || defined(HAVE_AS3514)
-    current_volume = value * 10;     /* tenth of dB */
-    set_prescaled_volume();                          
-#elif CONFIG_CPU == PNX0101
-    int tmp = (60 - value * 4) & 0xff;
-    CODECVOL = tmp | (tmp << 8);
-#endif
-}
-
+/**
+ * Set balance
+ * @param value to set
+*/
 void sound_set_balance(int value)
 {
-    if(!audio_is_initialized)
+#ifndef SIMULATOR
+    if (!audio_is_initialized) {
         return;
-#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-    unsigned tmp = ((unsigned)(value * 127 / 100) & 0xff) << 8;
-    mas_codec_writereg(0x11, tmp);
-#elif CONFIG_CODEC == MAS3507D || defined HAVE_UDA1380 \
-   || defined HAVE_WM8975 || defined HAVE_WM8758 || defined HAVE_WM8731 \
-   || defined(HAVE_WM8721) || defined(HAVE_TLV320) || defined(HAVE_WM8751) \
-   || defined(HAVE_AS3514)
+    }
+
     current_balance = value * VOLUME_RANGE / 100; /* tenth of dB */
     set_prescaled_volume();
-#elif CONFIG_CPU == PNX0101
-    /* TODO: implement for iFP */
+#else
     (void)value;
 #endif
 }
 
+/**
+ * Set bass
+ * @param value to set
+*/
 void sound_set_bass(int value)
 {
-    if(!audio_is_initialized)
+#ifndef SIMULATOR
+    if (!audio_is_initialized) {
         return;
-#if defined(HAVE_SW_TONE_CONTROLS)
-    current_bass = value * 10;
+    }
+
+    int current_bass = value * 10;       /* tenth of dB */
+#ifdef AUDIOHW_HAVE_BASS
+    audiohw_set_bass(value);
+#else
     dsp_callback(DSP_CALLBACK_SET_BASS, current_bass);
+#endif
     set_prescaled_volume();
-#elif (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-    unsigned tmp = ((unsigned)(value * 8) & 0xff) << 8;
-    mas_codec_writereg(0x14, tmp);
-#elif CONFIG_CODEC == MAS3507D
-    mas_writereg(MAS_REG_KBASS, bass_table[value+15]);
-    current_bass = value * 10;
-    set_prescaled_volume();
-#elif defined(HAVE_WM8751)
-    current_bass = value;
-    audiohw_set_bass(value);
-    set_prescaled_volume();
-#elif defined HAVE_WM8975 || defined HAVE_WM8758 || defined(HAVE_UDA1380) \
-    || defined HAVE_WM8731 || defined(HAVE_WM8721)
-    current_bass = value * 10;
-    audiohw_set_bass(value);
-    set_prescaled_volume();
-#elif CONFIG_CPU == PNX0101
-    /* TODO: implement for iFP */
+
+#else
     (void)value;
-#endif               
+#endif
 }
 
+/**
+ * Set treble
+ * @param value to set
+*/
 void sound_set_treble(int value)
 {
-    if(!audio_is_initialized)
+#ifndef SIMULATOR
+    if (!audio_is_initialized) {
         return;
-#if defined(HAVE_SW_TONE_CONTROLS)
-    current_treble = value * 10;
-    dsp_callback(DSP_CALLBACK_SET_TREBLE, current_treble);
-    set_prescaled_volume();
-#elif (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-    unsigned tmp = ((unsigned)(value * 8) & 0xff) << 8;
-    mas_codec_writereg(0x15, tmp);
-#elif CONFIG_CODEC == MAS3507D
-    mas_writereg(MAS_REG_KTREBLE, treble_table[value+15]);
-    current_treble = value * 10;
-    set_prescaled_volume();
-#elif defined(HAVE_WM8751)
-    audiohw_set_treble(value);
-    current_treble = value;
-    set_prescaled_volume();
-#elif defined(HAVE_WM8975) || defined(HAVE_WM8758) || defined(HAVE_UDA1380) \
-   || defined(HAVE_WM8731) || defined(HAVE_WM8721)
-    audiohw_set_treble(value);
-    current_treble = value * 10;
-    set_prescaled_volume();
-#elif CONFIG_CPU == PNX0101 
-    /* TODO: implement for iFP */
-    (void)value;
-#endif    
-}
+    }
 
-void sound_set_channels(int value)
-{
-#if CONFIG_CODEC == SWCODEC
-    dsp_callback(DSP_CALLBACK_SET_CHANNEL_CONFIG, value);
+    current_treble = value * 10;    /* tenth of dB */
+#ifdef AUDIOHW_HAVE_TREBLE
+    audiohw_set_treble(current_treble);
 #else
-    if(!audio_is_initialized)
-        return;
-    channel_configuration = value;
-    set_channel_config();
+    dsp_callback(DSP_CALLBACK_SET_TREBLE, current_treble);
 #endif
-}
+    set_prescaled_volume();
 
-void sound_set_stereo_width(int value)
-{
-#if CONFIG_CODEC == SWCODEC
-    dsp_callback(DSP_CALLBACK_SET_STEREO_WIDTH, value);
 #else
-    if(!audio_is_initialized)
-        return;
-    stereo_width = value;
-    if (channel_configuration == SOUND_CHAN_CUSTOM)
-        set_channel_config();
+    (void)value;
 #endif
 }
 
-#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-void sound_set_loudness(int value)
+/**
+ * Set channels
+ * @param value to set
+*/
+void sound_set_channels(int value)
 {
-    if(!audio_is_initialized)
+#ifndef SIMULATOR
+    if (!audio_is_initialized) {
         return;
-    loudness_shadow = (loudness_shadow & 0x04) |
-                       (MAX(MIN(value * 4, 0x44), 0) << 8);
-    mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
-}
-
-void sound_set_avc(int value)
-{
-    if(!audio_is_initialized)
-        return;
-    int tmp;
-    switch (value) {
-        case 1: /* 20ms */
-            tmp = (0x1 << 8) | (0x8 << 12);
-            break;
-        case 2: /* 2s */
-            tmp = (0x2 << 8) | (0x8 << 12);
-            break;
-        case 3: /* 4s */
-            tmp = (0x4 << 8) | (0x8 << 12);
-            break;
-        case 4: /* 8s */
-            tmp = (0x8 << 8) | (0x8 << 12);
-            break;
-        case -1: /* turn off and then turn on again to decay quickly */
-            tmp = mas_codec_readreg(MAS_REG_KAVC);
-            mas_codec_writereg(MAS_REG_KAVC, 0);
-            break;
-        default: /* off */
-            tmp = 0;
-            break;
     }
-    mas_codec_writereg(MAS_REG_KAVC, tmp);     
-}
 
-void sound_set_mdb_strength(int value)
-{
-    if(!audio_is_initialized)
-        return;
-    mas_codec_writereg(MAS_REG_KMDB_STR, (value & 0x7f) << 8); 
-}
+#ifdef AUDIOHW_HAVE_CHANNEL
+    audiohw_set_channel(value);
+#else
+    dsp_callback(DSP_CALLBACK_SET_CHANNEL_CONFIG, value);
+#endif
 
-void sound_set_mdb_harmonics(int value)
-{
-    if(!audio_is_initialized)
-        return;
-    int tmp = value * 127 / 100;
-    mas_codec_writereg(MAS_REG_KMDB_HAR, (tmp & 0x7f) << 8);
-}
-
-void sound_set_mdb_center(int value)
-{
-    if(!audio_is_initialized)
-        return;
-    mas_codec_writereg(MAS_REG_KMDB_FC, (value/10) << 8);
-}
-
-void sound_set_mdb_shape(int value)
-{
-    if(!audio_is_initialized)
-        return;
-    mdb_shape_shadow = (mdb_shape_shadow & 0x02) | ((value/10) << 8);
-    mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
-}
-
-void sound_set_mdb_enable(int value)
-{
-    if(!audio_is_initialized)
-        return;
-    mdb_shape_shadow = (mdb_shape_shadow & ~0x02) | (value?2:0);
-    mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
-}
-
-void sound_set_superbass(int value)
-{
-    if(!audio_is_initialized)
-        return;
-    loudness_shadow = (loudness_shadow & ~0x04) | (value?4:0);
-    mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
-}
-#endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
-
-#else /* SIMULATOR */
-void sound_set_volume(int value)
-{
+#else
     (void)value;
+#endif
 }
 
-void sound_set_balance(int value)
-{
-    (void)value;
-}
-
-void sound_set_bass(int value)
-{
-    (void)value;
-}
-
-void sound_set_treble(int value)
-{
-    (void)value;
-}
-
-void sound_set_channels(int value)
-{
-    (void)value;
-}
-
+/**
+ * Set stereo width
+ * @param value to set
+*/
 void sound_set_stereo_width(int value)
 {
-    (void)value;
-}
+#ifndef SIMULATOR
+    if (!audio_is_initialized) {
+        return;
+    }
 
-#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-void sound_set_loudness(int value)
-{
-    (void)value;
-}
+#ifdef AUDIO_HAVE_STEREO_WITH
+    audiohw_set_stereo_with(value);
+#else
+    dsp_callback(DSP_CALLBACK_SET_STEREO_WIDTH, value);
+#endif
 
-void sound_set_avc(int value)
-{
+#else
     (void)value;
+#endif
 }
 
-void sound_set_mdb_strength(int value)
-{
-    (void)value;
-}
-
-void sound_set_mdb_harmonics(int value)
-{
-    (void)value;
-}
-
-void sound_set_mdb_center(int value)
-{
-    (void)value;
-}
-
-void sound_set_mdb_shape(int value)
-{
-    (void)value;
-}
-
-void sound_set_mdb_enable(int value)
-{
-    (void)value;
-}
-
-void sound_set_superbass(int value)
-{
-    (void)value;
-}
-#endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
-#endif /* SIMULATOR */
-
+/**
+ * Set a specifyed audio setting
+ * @param setting defines which audio setting to change
+ * @param value to set
+*/
 void sound_set(int setting, int value)
 {
-    sound_set_type* sound_set_val = sound_get_fn(setting);
-    if (sound_set_val)
-        sound_set_val(value);
-}
-
-int sound_val2phys(int setting, int value)
-{
-#if CONFIG_CODEC == MAS3587F
-    int result = 0;
-
-    switch(setting)
-    {
-        case SOUND_LEFT_GAIN:
-        case SOUND_RIGHT_GAIN:
-            result = (value - 2) * 15;
+    switch (setting) {
+        case SOUND_VOLUME:
+#ifdef HAVE_OUTPUT_LINEOUT
+        case SOUND_VOLUME_LINEOUT:
+#endif
+#ifdef HAVE_OUTPUT_SPDIF
+        case SOUND_VOLUME_SPDIF:
+#endif
+            sound_set_volume(value);
             break;
 
-        case SOUND_MIC_GAIN:
-            result = value * 15 + 210;
+        case SOUND_BASS:
+            sound_set_bass(value);
             break;
 
-       default:
-            result = value;
+        case SOUND_TREBLE:
+            sound_set_treble(value);
             break;
-    }
-    return result;
-#elif defined(HAVE_UDA1380)
-    int result = 0;
-    
-    switch(setting)
-    {
-        case SOUND_LEFT_GAIN:
-        case SOUND_RIGHT_GAIN:
-        case SOUND_MIC_GAIN:
-            result = value * 5;         /* (1/2) * 10 */
-            break;
 
-        default:
-            result = value;
+        case SOUND_BALANCE:
+            sound_set_balance(value);
             break;
-    }
-    return result;
-#elif defined(HAVE_TLV320)
-    int result = 0;
-    
-    switch(setting)
-    {
-        case SOUND_LEFT_GAIN:
-        case SOUND_RIGHT_GAIN:
-            result = (value - 23) * 15;    /* (x - 23)/1.5 *10 */
-            break;
 
-        case SOUND_MIC_GAIN:
-            result = value * 200;          /* 0 or 20 dB */
+        case SOUND_CHANNELS:
+            sound_set_channels(value);
             break;
 
-       default:
-            result = value;
+        case SOUND_STEREO_WIDTH:
+            sound_set_stereo_width(value);
             break;
     }
-    return result;
-#else
-    (void)setting;
-    return value;
-#endif
 }
 
-#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-#ifndef SIMULATOR
-/* This function works by telling the decoder that we have another
-   crystal frequency than we actually have. It will adjust its internal
-   parameters and the result is that the audio is played at another pitch.
-
-   The pitch value is in tenths of percent.
-*/
-static int last_pitch = 1000;
-
-void sound_set_pitch(int pitch)
+int sound_val2phys(int setting, int value)
 {
-    unsigned long val;
-
-    if (pitch != last_pitch)
-    {
-        /* Calculate the new (bogus) frequency */
-        val = 18432 * 1000 / pitch;
-
-        mas_writemem(MAS_BANK_D0, MAS_D0_OFREQ_CONTROL, &val, 1);
-
-        /* We must tell the MAS that the frequency has changed.
-         * This will unfortunately cause a short silence. */
-        mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
-
-        last_pitch = pitch;
-    }
+    /* TODO */
+    return value;
 }
-
-int sound_get_pitch(void)
-{
-    return last_pitch;
-}
-#else /* SIMULATOR */
-void sound_set_pitch(int pitch)
-{
-    (void)pitch;
-}
-
-int sound_get_pitch(void)
-{
-    return 1000;
-}
-#endif /* SIMULATOR */
-#endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
Index: firmware/powermgmt.c
===================================================================
--- firmware/powermgmt.c	(revision 13366)
+++ firmware/powermgmt.c	(working copy)
@@ -1314,7 +1314,7 @@
 #if CONFIG_CODEC != SWCODEC
     mp3_shutdown();
 #else
-    audiohw_close();
+    audiohw_shutdown();
 #endif
 
     /* If HD is still active we try to wait for spindown, otherwise the
Index: firmware/drivers/audio/as3514.c
===================================================================
--- firmware/drivers/audio/as3514.c	(revision 13366)
+++ firmware/drivers/audio/as3514.c	(working copy)
@@ -27,9 +27,21 @@
 #include "i2s.h"
 #include "i2c-pp.h"
 
+const struct sound_settings_info audiohw_settings[] = {
+    [SOUND_VOLUME]        = {"dB", 0,  1, -40,   6, -25},
+    [SOUND_BASS]          = {"dB", 0,  1, -24,  24,   0},
+    [SOUND_TREBLE]        = {"dB", 0,  1, -24,  24,   0},
+    [SOUND_BALANCE]       = {"%",  0,  1,-100, 100,   0},
+    [SOUND_CHANNELS]      = {"",   0,  1,   0,   5,   0},
+    [SOUND_STEREO_WIDTH]  = {"%",  0,  1,   0, 255, 100},
+};
+
 /* Shadow registers */
 int as3514_regs[0x1E]; /* last audio register: PLLMODE 0x1d */
 
+/* store where to output music */
+enum OutDestination outputdest = OUTPUT_HEADPHONES;
+
 /*
  * little helper method to set register values.
  * With the help of as3514_regs, we minimize i2c
@@ -53,7 +65,7 @@
 }
 
 /* convert tenth of dB volume to master volume register value */
-int tenthdb2master(int db)
+static int tenthdb2volume(int db)
 {
     /* +6 to -40.43dB in 1.5dB steps == 32 levels = 5 bits */
     /* 11111 == +6dB  (0x1f) = 31) */
@@ -70,15 +82,11 @@
     }
 }
 
-void audiohw_reset(void);
-
 /*
  * Initialise the PP I2C and I2S.
  */
-int audiohw_init(void)
+void audiohw_init(void)
 {
-    unsigned int i;
-
     /* reset I2C */
     i2c_init();
 
@@ -106,114 +114,125 @@
 
     /* Set ADC off, mixer on, DAC on, line out off, line in off, mic off */
     as3514_write(AUDIOSET1, 0x20); /* Turn on DAC */
+    as3514_write(AUDIOSET2, 0x40);
     as3514_write(AUDIOSET3, 0x5); /* Set HPCM off, ZCU off*/
     as3514_write(HPH_OUT_R, 0xc0 | 0x16); /* set vol and set speaker over-current to 0 */
     as3514_write(HPH_OUT_L, 0x16); /* set default vol for headphone */
     as3514_write(PLLMODE, 0x04);
+}
 
+void audiohw_postinit(void)
+{
+    unsigned int i;
+
     /* read all reg values */
     for (i = 0; i < sizeof(as3514_regs) / sizeof(int); i++)
     {
         as3514_regs[i] = i2c_readbyte(AS3514_I2C_ADDR, i);
     }
+}
 
-    return 0;
+void audiohw_shutdown(void)
+{
+    /* mute current destination */
+    audiohw_mute(true);
+
+    /* turn off everything */
+    as3514_write(AUDIOSET1, 0x0);
 }
 
-void audiohw_postinit(void)
+void audiohw_reset(void)
 {
 }
 
-/* Silently enable / disable audio output */
+/* playback */
 void audiohw_enable_output(bool enable)
 {
     int curr;
-    curr = as3514_regs[HPH_OUT_L];
 
-    if (enable)
+    switch (outputdest)
     {
-        /* reset the I2S controller into known state */
-        i2s_reset();
+        case OUTPUT_HEADPHONES:
 
-        as3514_write(HPH_OUT_L, curr | 0x40); /* power on */
-        audiohw_mute(0);
-    } else {
-        audiohw_mute(1);
-        as3514_write(HPH_OUT_L, curr & ~(0x40)); /* power off */
-    }
-}
+            curr = as3514_regs[HPH_OUT_L];
 
-int audiohw_set_master_vol(int vol_l, int vol_r)
-{
-    vol_l &= 0x1f;
-    vol_r &= 0x1f;
+            if (enable)
+            {
+                as3514_write(HPH_OUT_L, curr | 0x40); /* power on */
+            } else {
+                as3514_write(HPH_OUT_L, curr & ~(0x40)); /* power off */
+            }
 
-    /* we are controling dac volume instead of headphone volume,
-       as the volume is bigger.
-       HDP: 1.07 dB gain
-       DAC: 6 dB gain
-    */
-    as3514_write(DAC_R, vol_r);
-    as3514_write(DAC_L, 0x40 | vol_l);
+            break;
 
-    return 0;
+        default:
+            break;
+    }
+
 }
 
-int audiohw_set_lineout_vol(int vol_l, int vol_r)
+void audiohw_set_output_destination(enum OutDestination destination)
 {
-    as3514_write(LINE_OUT_R, vol_r);
-    as3514_write(LINE_OUT_L, 0x40 | vol_l);
+    /* mute and disable old  */
+    audiohw_mute(true);
+    audiohw_enable_output(false);
 
-    return 0;
+    /* switch to new destinaton and unmute */
+    outputdest = destination;
+    audiohw_mute(false);
 }
 
-int audiohw_mute(int mute)
+void audiohw_mute(bool mute)
 {
     int curr;
-    curr = as3514_regs[HPH_OUT_L];
 
-    if (mute)
+    switch (outputdest)
     {
-        as3514_write(HPH_OUT_L, curr | 0x80);
-    } else {
-        as3514_write(HPH_OUT_L, curr & ~(0x80));
-    }
+        case OUTPUT_HEADPHONES:
 
-    return 0;
-}
+            curr = as3514_regs[HPH_OUT_L];
 
-/* Nice shutdown of WM8758 codec */
-void audiohw_close(void)
-{
-    /* mute headphones */
-    audiohw_mute(1);
+            if (mute)
+            {
+                as3514_write(HPH_OUT_L, curr | 0x80);
+            } else {
+                as3514_write(HPH_OUT_L, curr & ~(0x80));
+            }
 
-    /* turn off everything */
-    as3514_write(AUDIOSET1, 0x0);
-}
+            break;
 
-void audiohw_set_sample_rate(int sampling_control)
-{
-    (void)sampling_control;
+        default:
+            break;
+    }
 }
 
-void audiohw_enable_recording(bool source_mic)
+void audiohw_set_volume(int vol_l, int vol_r)
 {
-    (void)source_mic;
-}
+    switch (outputdest)
+    {
+        case OUTPUT_HEADPHONES:
 
-void audiohw_disable_recording(void)
-{
-}
+            /* we are controling dac volume instead of headphone volume,
+            as the volume is bigger.
+            HDP: 1.07 dB gain
+            DAC: 6 dB gain
+            */
 
-void audiohw_set_recvol(int left, int right, int type)
-{
-    (void)left;
-    (void)right;
-    (void)type;
+            // convert tenth of dB to register values
+            vol_l = tenthdb2volume(vol_l);
+            vol_r = tenthdb2volume(vol_r);
+
+            vol_l &= 0x1f;
+            vol_r &= 0x1f;
+
+            /* write data */
+            as3514_write(DAC_R, vol_r);
+            as3514_write(DAC_L, 0x40 | vol_l);
+            break;
+
+        default:
+            break;
+    }
 }
 
-void audiohw_set_monitor(int enable)
-{
-    (void)enable;
-}
+
