Introduce HiFi E.T MA9 port.

Change-Id: I79aadc958fd5222f26f91ed127f8c6fb2c465dc2
diff --git a/apps/SOURCES b/apps/SOURCES
index e8944d5..4b28f88 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -286,5 +286,7 @@
 keymaps/keymap-sansa-connect.c
 #elif CONFIG_KEYPAD == SAMSUNG_YPR0_PAD
 keymaps/keymap-ypr0.c
+#elif CONFIG_KEYPAD == MA_PAD
+keymaps/keymap-ma.c
 #endif
 
diff --git a/apps/keymaps/keymap-ma.c b/apps/keymaps/keymap-ma.c
new file mode 100644
index 0000000..e1740b6
--- /dev/null
+++ b/apps/keymaps/keymap-ma.c
@@ -0,0 +1,237 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2013 Andrew Ryabinin
+ *
+ * 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.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+/* Button Code Definitions for HiFi E.T. MA9/MA8 reference design target */
+
+#include "config.h"
+#include "action.h"
+#include "button.h"
+#include "settings.h"
+
+/*
+ * The format of the list is as follows
+ * { Action Code,   Button code,    Prereq button code }
+ * if there's no need to check the previous button's value, use BUTTON_NONE
+ * Insert LAST_ITEM_IN_LIST at the end of each mapping
+ */
+static const struct button_mapping button_context_standard[] = {
+    { ACTION_STD_PREV,       BUTTON_UP,                    BUTTON_NONE },
+    { ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT,      BUTTON_NONE },
+    { ACTION_STD_NEXT,       BUTTON_DOWN,                  BUTTON_NONE },
+    { ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT,    BUTTON_NONE },
+
+    { ACTION_STD_CONTEXT,    BUTTON_PLAY|BUTTON_REPEAT,    BUTTON_PLAY },
+    { ACTION_STD_CANCEL,     BUTTON_BACK,                  BUTTON_NONE },
+    { ACTION_STD_OK,         BUTTON_PLAY|BUTTON_REL,       BUTTON_PLAY },
+    { ACTION_STD_MENU,       BUTTON_MENU|BUTTON_REL,       BUTTON_MENU },
+
+    LAST_ITEM_IN_LIST
+}; /* button_context_standard */
+
+static const struct button_mapping button_context_wps[] = {
+    { ACTION_WPS_PLAY,      BUTTON_PLAY|BUTTON_REL,         BUTTON_PLAY },
+    { ACTION_WPS_STOP,      BUTTON_PLAY|BUTTON_REPEAT,      BUTTON_PLAY },
+    { ACTION_WPS_SKIPPREV,  BUTTON_LEFT|BUTTON_REL,         BUTTON_LEFT },
+    { ACTION_WPS_SEEKBACK,  BUTTON_LEFT|BUTTON_REPEAT,      BUTTON_NONE },
+    { ACTION_WPS_STOPSEEK,  BUTTON_LEFT|BUTTON_REL,         BUTTON_LEFT|BUTTON_REPEAT },
+    { ACTION_WPS_SKIPNEXT,  BUTTON_RIGHT|BUTTON_REL,        BUTTON_RIGHT},
+    { ACTION_WPS_SEEKFWD,   BUTTON_RIGHT|BUTTON_REPEAT,     BUTTON_NONE },
+    { ACTION_WPS_STOPSEEK,  BUTTON_RIGHT|BUTTON_REL,        BUTTON_RIGHT|BUTTON_REPEAT },
+    { ACTION_WPS_VOLUP,     BUTTON_UP,                      BUTTON_NONE },
+    { ACTION_WPS_VOLUP,     BUTTON_UP|BUTTON_REPEAT,        BUTTON_NONE },
+    { ACTION_WPS_VOLDOWN,   BUTTON_DOWN,                    BUTTON_NONE },
+    { ACTION_WPS_VOLDOWN,   BUTTON_DOWN|BUTTON_REPEAT,      BUTTON_NONE },
+
+    { ACTION_WPS_ABSETB_NEXTDIR,BUTTON_BACK|BUTTON_RIGHT,   BUTTON_BACK },
+    { ACTION_WPS_ABSETA_PREVDIR,BUTTON_BACK|BUTTON_LEFT,    BUTTON_BACK },
+    { ACTION_WPS_ABRESET,       BUTTON_BACK|BUTTON_UP,      BUTTON_BACK },
+
+    { ACTION_WPS_BROWSE,        BUTTON_BACK|BUTTON_REL,     BUTTON_BACK },
+    { ACTION_WPS_CONTEXT,       BUTTON_MENU|BUTTON_REPEAT,  BUTTON_MENU },
+    { ACTION_WPS_MENU,          BUTTON_MENU|BUTTON_REL,     BUTTON_MENU },
+    { ACTION_WPS_QUICKSCREEN,   BUTTON_BACK|BUTTON_REPEAT,  BUTTON_BACK },
+
+#ifndef HAS_BUTTON_HOLD
+    { ACTION_STD_KEYLOCK,       BUTTON_MENU|BUTTON_BACK,    BUTTON_MENU },
+#endif
+
+    LAST_ITEM_IN_LIST
+}; /* button_context_wps */
+
+/** Bookmark Screen **/
+static const struct button_mapping button_context_bmark[] = {
+    { ACTION_BMS_DELETE,       BUTTON_PLAY|BUTTON_REPEAT, BUTTON_PLAY },
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_LIST),
+}; /* button_context_settings_bmark */
+
+
+/** Keyboard **/
+static const struct button_mapping button_context_keyboard[] = {
+    { ACTION_KBD_LEFT,         BUTTON_LEFT,                    BUTTON_NONE },
+    { ACTION_KBD_LEFT,         BUTTON_LEFT|BUTTON_REPEAT,      BUTTON_NONE },
+    { ACTION_KBD_RIGHT,        BUTTON_RIGHT,                   BUTTON_NONE },
+    { ACTION_KBD_RIGHT,        BUTTON_RIGHT|BUTTON_REPEAT,     BUTTON_NONE },
+    { ACTION_KBD_UP,           BUTTON_UP,                      BUTTON_NONE },
+    { ACTION_KBD_UP,           BUTTON_UP|BUTTON_REPEAT,        BUTTON_NONE },
+    { ACTION_KBD_DOWN,         BUTTON_DOWN,                    BUTTON_NONE },
+    { ACTION_KBD_DOWN,         BUTTON_DOWN|BUTTON_REPEAT,      BUTTON_NONE },
+    { ACTION_KBD_SELECT,       BUTTON_PLAY|BUTTON_REL,         BUTTON_PLAY },
+    { ACTION_KBD_DONE,         BUTTON_PLAY|BUTTON_REPEAT,      BUTTON_PLAY },
+    { ACTION_KBD_ABORT,        BUTTON_BACK,                    BUTTON_NONE },
+
+    LAST_ITEM_IN_LIST
+}; /* button_context_keyboard */
+
+/** Pitchscreen **/
+static const struct button_mapping button_context_pitchscreen[] = {
+    { ACTION_PS_INC_SMALL,      BUTTON_UP,                  BUTTON_NONE },
+    { ACTION_PS_INC_BIG,        BUTTON_UP|BUTTON_REPEAT,    BUTTON_NONE },
+    { ACTION_PS_DEC_SMALL,      BUTTON_DOWN,                BUTTON_NONE },
+    { ACTION_PS_DEC_BIG,        BUTTON_DOWN|BUTTON_REPEAT,  BUTTON_NONE },
+    { ACTION_PS_NUDGE_LEFT,     BUTTON_LEFT,                BUTTON_NONE },
+    { ACTION_PS_NUDGE_LEFTOFF,  BUTTON_LEFT|BUTTON_REL,     BUTTON_NONE },
+    { ACTION_PS_NUDGE_RIGHT,    BUTTON_RIGHT,               BUTTON_NONE },
+    { ACTION_PS_NUDGE_RIGHTOFF, BUTTON_RIGHT|BUTTON_REL,    BUTTON_NONE },
+    { ACTION_PS_TOGGLE_MODE,    BUTTON_PLAY|BUTTON_REL,     BUTTON_NONE },
+    { ACTION_PS_RESET,          BUTTON_BACK,                BUTTON_NONE },
+    { ACTION_PS_EXIT,           BUTTON_MENU,                BUTTON_NONE },
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
+}; /* button_context_pitchscreen */
+
+/** Quickscreen **/
+static const struct button_mapping button_context_quickscreen[] = {
+    { ACTION_QS_TOP,        BUTTON_UP,                      BUTTON_NONE },
+    { ACTION_QS_TOP,        BUTTON_UP|BUTTON_REPEAT,        BUTTON_NONE },
+    { ACTION_QS_DOWN,       BUTTON_DOWN,                    BUTTON_NONE },
+    { ACTION_QS_DOWN,       BUTTON_DOWN|BUTTON_REPEAT,      BUTTON_NONE },
+    { ACTION_QS_LEFT,       BUTTON_LEFT,                    BUTTON_NONE },
+    { ACTION_QS_LEFT,       BUTTON_LEFT|BUTTON_REPEAT,      BUTTON_NONE },
+    { ACTION_QS_RIGHT,      BUTTON_RIGHT,                   BUTTON_NONE },
+    { ACTION_QS_RIGHT,      BUTTON_RIGHT|BUTTON_REPEAT,     BUTTON_NONE },
+    { ACTION_STD_CANCEL,    BUTTON_BACK|BUTTON_REL,         BUTTON_BACK },
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
+}; /* button_context_quickscreen */
+
+/** Settings - General Mappings **/
+static const struct button_mapping button_context_settings[] = {
+    { ACTION_SETTINGS_RESET,        BUTTON_PLAY,                BUTTON_NONE },
+    { ACTION_SETTINGS_INC,          BUTTON_UP,                  BUTTON_NONE },
+    { ACTION_SETTINGS_INCREPEAT,    BUTTON_UP|BUTTON_REPEAT,    BUTTON_NONE },
+    { ACTION_SETTINGS_DEC,          BUTTON_DOWN,                BUTTON_NONE },
+    { ACTION_SETTINGS_DECREPEAT,    BUTTON_DOWN|BUTTON_REPEAT,  BUTTON_NONE },
+    { ACTION_STD_PREV,              BUTTON_LEFT,                BUTTON_NONE },
+    { ACTION_STD_PREVREPEAT,        BUTTON_LEFT|BUTTON_REPEAT,  BUTTON_NONE },
+    { ACTION_STD_CANCEL,            BUTTON_BACK|BUTTON_REL,     BUTTON_BACK },
+    { ACTION_STD_NEXTREPEAT,        BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
+}; /* button_context_settings */
+
+/** Settings - Using Sliders **/
+static const struct button_mapping button_context_settings_r_is_inc[] = {
+    { ACTION_SETTINGS_INC,          BUTTON_RIGHT,               BUTTON_NONE },
+    { ACTION_SETTINGS_INCREPEAT,    BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
+    { ACTION_SETTINGS_DEC,          BUTTON_LEFT,                BUTTON_NONE },
+    { ACTION_SETTINGS_DECREPEAT,    BUTTON_LEFT|BUTTON_REPEAT,  BUTTON_NONE },
+
+    { ACTION_STD_CANCEL,            BUTTON_BACK|BUTTON_REL,    BUTTON_BACK},
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
+}; /* button_context_settings_r_is_inc */
+
+/** Tree **/
+static const struct button_mapping button_context_tree[] = {
+    { ACTION_TREE_WPS,    BUTTON_RIGHT|BUTTON_REL,       BUTTON_RIGHT },
+    { ACTION_TREE_STOP,   BUTTON_BACK|BUTTON_PLAY,       BUTTON_BACK },
+    { ACTION_TREE_HOTKEY, BUTTON_BACK|BUTTON_UP,         BUTTON_BACK },
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
+}; /* button_context_tree */
+
+static const struct button_mapping button_context_tree_scroll_lr[] = {
+    { ACTION_NONE,              BUTTON_LEFT,                BUTTON_NONE },
+    { ACTION_STD_CANCEL,        BUTTON_LEFT|BUTTON_REL,     BUTTON_LEFT },
+    { ACTION_TREE_ROOT_INIT,    BUTTON_LEFT|BUTTON_REPEAT,  BUTTON_LEFT },
+    { ACTION_TREE_PGLEFT,       BUTTON_LEFT|BUTTON_REPEAT,  BUTTON_NONE },
+    { ACTION_NONE,              BUTTON_RIGHT,               BUTTON_NONE },
+    { ACTION_TREE_PGRIGHT,      BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_CUSTOM|CONTEXT_TREE),
+}; /* button_context_tree_scroll_lr */
+
+/** Yes/No Screen **/
+static const struct button_mapping button_context_yesnoscreen[] = {
+    { ACTION_YESNO_ACCEPT,          BUTTON_PLAY,              BUTTON_NONE },
+    LAST_ITEM_IN_LIST
+}; /* button_context_settings_yesnoscreen */
+
+/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
+const struct button_mapping* get_context_mapping(int context)
+{
+    switch (context)
+    {
+        /* anything that uses button_context_standard */
+        case CONTEXT_LIST:
+        case CONTEXT_STD:
+        default:
+            return button_context_standard;
+
+        /* contexts with special mapping */
+        case CONTEXT_BOOKMARKSCREEN:
+            return button_context_bmark;
+
+        case CONTEXT_KEYBOARD:
+        case CONTEXT_MORSE_INPUT:
+            return button_context_keyboard;
+
+        case CONTEXT_PITCHSCREEN:
+            return button_context_pitchscreen;
+
+        case CONTEXT_QUICKSCREEN:
+            return button_context_quickscreen;
+
+        case CONTEXT_SETTINGS:
+        case CONTEXT_SETTINGS_TIME:
+            return button_context_settings;
+
+        case CONTEXT_SETTINGS_COLOURCHOOSER:
+        case CONTEXT_SETTINGS_EQ:
+        case CONTEXT_SETTINGS_RECTRIGGER:
+            return button_context_settings_r_is_inc;
+
+        case CONTEXT_TREE:
+        case CONTEXT_MAINMENU:
+            if (global_settings.hold_lr_for_scroll_in_list)
+                return button_context_tree_scroll_lr;
+            /* else fall through to CONTEXT_TREE|CONTEXT_CUSTOM */
+        case CONTEXT_TREE|CONTEXT_CUSTOM:
+            return button_context_tree;
+
+        case CONTEXT_WPS:
+            return button_context_wps;
+
+        case CONTEXT_YESNOSCREEN:
+            return button_context_yesnoscreen;
+    }
+}
diff --git a/bootloader/SOURCES b/bootloader/SOURCES
index 4678175..e2f23ba 100644
--- a/bootloader/SOURCES
+++ b/bootloader/SOURCES
@@ -67,7 +67,7 @@
 show_logo.c
 #elif defined(MPIO_HD200) || defined(MPIO_HD300)
 mpio_hd200_hd300.c
-#elif defined(RK27_GENERIC) || defined(HM60X) || defined(HM801)
+#elif defined(RK27_GENERIC) || defined(HM60X) || defined(HM801) || defined(MA9)
 rk27xx.c
 show_logo.c
 #elif defined(SANSA_CONNECT)
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 9c45808..5843002 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -403,6 +403,8 @@
 drivers/audio/aic3x.c
 #elif defined (HAVE_DUMMY_CODEC)
 drivers/audio/dummy_codec.c
+#elif defined (HAVE_DF1704_CODEC)
+drivers/audio/df1704.c
 #endif /* defined(HAVE_*) */
 #else /* PLATFORM_HOSTED */
 #if defined(SAMSUNG_YPR0) && defined(HAVE_AS3514)
@@ -689,6 +691,8 @@
 target/arm/imx31/gigabeat-s/lcd-gigabeat-s.c
 #elif CONFIG_LCD == LCD_GIGABEAT || CONFIG_LCD == LCD_MINI2440
 target/arm/s3c2440/lcd-s3c2440.c
+#elif CONFIG_LCD == LCD_ILI9342
+target/arm/rk27xx/ma/lcd-ma.c
 #endif
 
 /* USB Stack */
@@ -1695,6 +1699,15 @@
 target/arm/rk27xx/hm801/power-hm801.c
 #endif
 
+#if defined(MA9)
+target/arm/rk27xx/ma/button-ma.c
+target/arm/rk27xx/ma/powermgmt-ma.c
+target/arm/rk27xx/ma/power-ma.c
+drivers/pca9555.c
+target/arm/rk27xx/ma/pca9555-ma.c
+target/arm/rk27xx/ma/audio-ma.c
+#endif
+
 #if (CONFIG_PLATFORM & PLATFORM_ANDROID)
 target/hosted/kernel-unix.c
 target/hosted/filesystem-unix.c
diff --git a/firmware/drivers/audio/df1704.c b/firmware/drivers/audio/df1704.c
new file mode 100644
index 0000000..b0b9d7b
--- /dev/null
+++ b/firmware/drivers/audio/df1704.c
@@ -0,0 +1,115 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2013 Andrew Ryabinin
+ *
+ * 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.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "system.h"
+#include "df1704.h"
+#include "config.h"
+#include "audio.h"
+#include "audiohw.h"
+
+static void df1704_write_reg(const int reg, const unsigned int value)
+{
+    int i;
+
+    df1704_set_ml_dir(0);
+    df1704_set_ml(1);
+    df1704_set_md(1);
+    df1704_set_mc(1);
+
+    for (i = (1<<15); i; i >>= 1) {
+        udelay(40);
+        df1704_set_mc(0);
+
+        if ((reg|value) & i) {
+            df1704_set_md(1);
+        } else {
+            df1704_set_md(0);
+        }
+
+        udelay(40);
+        df1704_set_mc(1);
+    }
+
+    df1704_set_ml(0);
+    udelay(130);
+    df1704_set_ml(1);
+    udelay(130);
+    df1704_set_ml_dir(1);
+}
+
+static int vol_tenthdb2hw(const int tdb)
+{
+    if (tdb < DF1704_VOLUME_MIN) {
+        return 0;
+    } else if (tdb > DF1704_VOLUME_MAX) {
+        return 0xff;
+    } else {
+        return (tdb/5+0xff);
+    }
+}
+
+
+void df1704_init(void)
+{
+    df1704_write_reg(DF1704_MODE(2),
+                     DF1704_OW_24     |
+                     DF1704_IW_16_I2S |
+                     DF1704_DEM_OFF   |
+                     DF1704_MUTE_OFF);
+    df1704_write_reg(DF1704_MODE(3),
+                     DF1704_CKO_HALF |
+                     DF1704_SRO_SHARP|
+                     DF1704_LRP_H    |
+                     DF1704_I2S_ON);
+}
+
+void df1704_mute(void)
+{
+    df1704_write_reg(DF1704_MODE(2),
+                     DF1704_OW_24     |
+                     DF1704_IW_16_I2S |
+                     DF1704_DEM_OFF   |
+                     DF1704_MUTE_ON);
+}
+
+void df1704_unmute(void)
+{
+    df1704_write_reg(DF1704_MODE(2),
+                     DF1704_OW_24     |
+                     DF1704_IW_16_I2S |
+                     DF1704_DEM_OFF   |
+                     DF1704_MUTE_OFF);
+}
+
+void audiohw_preinit(void)
+{
+}
+
+void audiohw_set_frequency(int fsel)
+{
+    (void)fsel;
+}
+
+void audiohw_set_volume(int vol_l, int vol_r)
+{
+    df1704_write_reg(DF1704_MODE(0), DF1704_LDL_ON|vol_tenthdb2hw(vol_l));
+    df1704_write_reg(DF1704_MODE(1), DF1704_LDR_ON|vol_tenthdb2hw(vol_r));
+}
diff --git a/firmware/drivers/pca9555.c b/firmware/drivers/pca9555.c
new file mode 100644
index 0000000..78326f3
--- /dev/null
+++ b/firmware/drivers/pca9555.c
@@ -0,0 +1,64 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2013 Andrew Ryabinin
+ *
+ * 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.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "i2c-rk27xx.h"
+#include "pca9555.h"
+#include "system.h"
+
+static unsigned short pca9555_out_ports;
+static unsigned short pca9555_config = 0xffff;
+
+unsigned short pca9555_read_input(void)
+{
+    unsigned short ret;
+    i2c_read(PCA9555_I2C_ADDR, PCA9555_IN_CMD, sizeof(ret), (void*)&ret);
+    return letoh16(ret);
+}
+
+unsigned short pca9555_read_output(void)
+{
+    return pca9555_out_ports;
+}
+
+unsigned short pca9555_read_config(void)
+{
+    return pca9555_config;
+}
+
+void pca9555_write_output(const unsigned short data, const unsigned short mask)
+{
+    unsigned short le_data = htole16((data&mask) | (pca9555_out_ports&~(mask)));
+    i2c_write(PCA9555_I2C_ADDR, PCA9555_OUT_CMD, sizeof(le_data), (void*)&le_data);
+    pca9555_out_ports = letoh16(le_data);
+}
+
+void pca9555_write_config(const unsigned short data, const unsigned short mask)
+{
+    unsigned short le_data = htole16((data&mask) | (pca9555_config&~(mask)));
+    i2c_write(PCA9555_I2C_ADDR, PCA9555_CFG_CMD, sizeof(le_data), (void*)&le_data);
+    pca9555_config = letoh16(le_data);
+}
+
+
+void pca9555_init(void)
+{
+    pca9555_target_init();
+}
diff --git a/firmware/export/audiohw.h b/firmware/export/audiohw.h
index 4379c20..28fa1b0 100644
--- a/firmware/export/audiohw.h
+++ b/firmware/export/audiohw.h
@@ -106,6 +106,8 @@
 #include "imx233-codec.h"
 #elif defined(HAVE_DUMMY_CODEC)
 #include "dummy_codec.h"
+#elif defined(HAVE_DF1704_CODEC)
+#include "df1704.h"
 #elif (CONFIG_PLATFORM & (PLATFORM_ANDROID | PLATFORM_MAEMO\
        | PLATFORM_PANDORA | PLATFORM_SDL))
 #include "hosted_codec.h"
diff --git a/firmware/export/config.h b/firmware/export/config.h
index 7d7a18c..7252d62 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -147,6 +147,7 @@
 #define SAMSUNG_YPR0_PAD   53
 #define CREATIVE_ZENXFI2_PAD 54
 #define CREATIVE_ZENXFI3_PAD 55
+#define MA_PAD            56
 
 /* CONFIG_REMOTE_KEYPAD */
 #define H100_REMOTE   1
@@ -248,6 +249,7 @@
 #define LCD_YPR0      47
 #define LCD_CREATIVEZXFI2 48 /* as used by the Creative Zen X-Fi2 */
 #define LCD_CREATIVEZXFI3 49 /* as used by the Creative Zen X-Fi3 */
+#define LCD_ILI9342   50 /* as used by HiFi E.T MA9/MA8 */
 
 /* LCD_PIXELFORMAT */
 #define HORIZONTAL_PACKING 1
@@ -505,6 +507,8 @@
 #include "config/pandora.h"
 #elif defined(SAMSUNG_YPR0)
 #include "config/samsungypr0.h"
+#elif defined(MA9)
+#include "config/hifietma9.h"
 #else
 /* no known platform */
 #endif
diff --git a/firmware/export/config/hifietma9.h b/firmware/export/config/hifietma9.h
new file mode 100644
index 0000000..516d1fe
--- /dev/null
+++ b/firmware/export/config/hifietma9.h
@@ -0,0 +1,153 @@
+/*
+ * This config file is for HiFiMAN HM-60x reference design
+ */
+
+/* For Rolo and boot loader */
+#define MODEL_NUMBER 83
+
+#define MODEL_NAME   "HiFi E.T. MA9"
+
+/* define the bitmask of hardware sample rates */
+#define HW_SAMPR_CAPS   (SAMPR_CAP_96 | SAMPR_CAP_48 | SAMPR_CAP_44 | \
+                         SAMPR_CAP_32 | SAMPR_CAP_24 | SAMPR_CAP_22 | \
+                         SAMPR_CAP_16 | SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8)
+
+#define HAVE_DF1704_CODEC
+
+#define CODEC_SLAVE
+/* define this if you have a bitmap LCD display */
+#define HAVE_LCD_BITMAP
+
+/* define this if you can flip your LCD */
+/* #define HAVE_LCD_FLIP */
+
+/* define this if you have a colour LCD */
+#define HAVE_LCD_COLOR
+
+/* define this if you want album art for this target */
+#define HAVE_ALBUMART
+
+/* define this to enable bitmap scaling */
+#define HAVE_BMP_SCALING
+
+/* define this to enable JPEG decoding */
+#define HAVE_JPEG
+
+/* define this if you can invert the colours on your LCD */
+/* #define HAVE_LCD_INVERT */
+
+/* define this if you have access to the quickscreen */
+#define HAVE_QUICKSCREEN
+
+/* define this if you would like tagcache to build on this target */
+#define HAVE_TAGCACHE
+
+/* define this if you have a flash memory storage */
+#define HAVE_FLASH_STORAGE
+
+#define CONFIG_STORAGE (STORAGE_SD | STORAGE_NAND)
+
+#define CONFIG_NAND NAND_RK27XX
+#define HAVE_SW_TONE_CONTROLS
+
+/* commented for now */
+/* #define HAVE_HOTSWAP */
+
+#define NUM_DRIVES 2
+#define SECTOR_SIZE 512
+
+/* for small(ish) SD cards */
+#define HAVE_FAT16SUPPORT
+
+/* LCD dimensions */
+#define LCD_WIDTH  320
+#define LCD_HEIGHT 240
+#define LCD_DEPTH  16   /* pseudo 262.144 colors */
+#define LCD_PIXELFORMAT RGB565 /* rgb565 */
+
+/* Define this if your LCD can be enabled/disabled */
+#define HAVE_LCD_ENABLE
+
+#define CONFIG_KEYPAD MA_PAD
+
+/* Define this to enable morse code input */
+#define HAVE_MORSE_INPUT
+
+/* Define this if you do software codec */
+#define CONFIG_CODEC SWCODEC
+
+#define CONFIG_LCD LCD_ILI9342
+
+/* Define this for LCD backlight available */
+#define HAVE_BACKLIGHT
+#define HAVE_BACKLIGHT_BRIGHTNESS
+#define MIN_BRIGHTNESS_SETTING      0
+#define MAX_BRIGHTNESS_SETTING      31
+#define DEFAULT_BRIGHTNESS_SETTING   31
+#define CONFIG_BACKLIGHT_FADING BACKLIGHT_FADING_SW_HW_REG
+
+/* Define this if you have a software controlled poweroff */
+#define HAVE_SW_POWEROFF
+
+/* The number of bytes reserved for loadable codecs */
+#define CODEC_SIZE 0x100000
+
+/* The number of bytes reserved for loadable plugins */
+#define PLUGIN_BUFFER_SIZE 0x80000
+
+/* TODO: Figure out real values */
+#define BATTERY_CAPACITY_DEFAULT 600 /* default battery capacity */
+#define BATTERY_CAPACITY_MIN     300 /* min. capacity selectable */
+#define BATTERY_CAPACITY_MAX     600 /* max. capacity selectable */
+#define BATTERY_CAPACITY_INC      10 /* capacity increment */
+#define BATTERY_TYPES_COUNT        1 /* only one type */
+
+#define CONFIG_BATTERY_MEASURE VOLTAGE_MEASURE
+
+/* Hardware controlled charging with monitoring */
+#define CONFIG_CHARGING CHARGING_MONITOR
+
+/* USB On-the-go */
+#define CONFIG_USBOTG USBOTG_RK27XX
+
+/* enable these for the experimental usb stack */
+#define HAVE_USBSTACK
+
+#define USE_ROCKBOX_USB
+#define USB_VENDOR_ID 0x071b
+#define USB_PRODUCT_ID 0x3202
+#define HAVE_BOOTLOADER_USB_MODE
+
+/* Define this if your LCD can set contrast */
+/* #define HAVE_LCD_CONTRAST */
+
+/* The exact type of CPU */
+#define CONFIG_CPU RK27XX
+
+/* I2C interface */
+#define CONFIG_I2C I2C_RK27XX
+
+/* Define this to the CPU frequency */
+#define CPU_FREQ        200000000
+
+/* define this if the hardware can be powered off while charging */
+/* #define HAVE_POWEROFF_WHILE_CHARGING */
+
+/* Offset ( in the firmware file's header ) to the file CRC */
+#define FIRMWARE_OFFSET_FILE_CRC 0
+
+/* Offset ( in the firmware file's header ) to the real data */
+#define FIRMWARE_OFFSET_FILE_DATA 8
+
+#define STORAGE_NEEDS_ALIGN
+
+/* Define this if you have adjustable CPU frequency */
+#define HAVE_ADJUSTABLE_CPU_FREQ
+
+/* Virtual LED (icon) */
+#define CONFIG_LED LED_VIRTUAL
+
+#define RKW_FORMAT
+#define BOOTFILE_EXT "rkw"
+#define BOOTFILE "rockbox." BOOTFILE_EXT
+#define BOOTDIR "/.rockbox"
diff --git a/firmware/export/df1704.h b/firmware/export/df1704.h
new file mode 100644
index 0000000..59d1372
--- /dev/null
+++ b/firmware/export/df1704.h
@@ -0,0 +1,94 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ *
+ * Copyright (c) 2013 Andrew Ryabinin
+ *
+ * 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.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _DF1704_H
+#define _DF1704_H
+
+#define DF1704_VOLUME_MIN -1270
+#define DF1704_VOLUME_MAX 0
+
+AUDIOHW_SETTING(VOLUME, "dB", 0, 1, DF1704_VOLUME_MIN/10, DF1704_VOLUME_MAX/10, 0)
+
+#define DF1704_MODE(x) (((x)&0x03)<<9)
+
+/**
+ * MODE0 register settings
+ */
+/* Left channel attenuation data load control */
+#define DF1704_LDL_ON    (1<<8)
+#define DF1704_LDL_OFF   (0<<8)
+
+/**
+ * MODE1 register settings
+ */
+/* Right channel attenuation data load control */
+#define DF1704_LDR_ON    (1<<8)
+#define DF1704_LDR_OFF   (0<<8)
+
+/**
+ * MODE2 register settings
+ */
+#define DF1704_MUTE_ON   (0<<0)
+#define DF1704_MUTE_OFF  (1<<0)
+/* Digital De-Emphasis */
+#define DF1704_DEM_ON    (1<<1)
+#define DF1704_DEM_OFF   (0<<1)
+/* Input data format & word lengths */
+#define DF1704_IW_16_I2S (0<<3)
+#define DF1704_IW_24_I2S (1<<3)
+
+#define DF1704_IW_16_RJ  (0<<3)
+#define DF1704_IW_20_RJ  (1<<3)
+#define DF1704_IW_24_RJ  (2<<3)
+#define DF1704_IW_24_LJ  (3<<3)
+/* Output data format & word lengths */
+#define DF1704_OW_16     (0<<5)
+#define DF1704_OW_18     (1<<5)
+#define DF1704_OW_20     (2<<5)
+#define DF1704_OW_24     (3<<5)
+
+/**
+ * MODE3 register settings
+ */
+#define DF1704_I2S_OFF   (0<<0)
+#define DF1704_I2S_ON    (1<<0)
+#define DF1704_LRP_L     (0<<1)
+#define DF1704_LRP_H     (1<<1)
+#define DF1704_ATC_ON    (1<<2)
+#define DF1704_ATC_OFF   (0<<2)
+#define DF1704_SRO_SHARP (0<<3)
+#define DF1704_SRO_SLOW  (1<<3)
+/* CLKO output frequency selection */
+#define DF1704_CKO_FULL  (0<<5)
+#define DF1704_CKO_HALF  (1<<5)
+/* Sampling freq selection for the De-Emphasis */
+#define DF1704_SF_44     (0<<6)
+#define DF1704_SF_32     (3<<6)
+#define DF1704_SF_48     (2<<6)
+
+void df1704_init(void);
+void df1704_mute(void);
+void df1704_set_ml(const int);
+void df1704_set_mc(const int);
+void df1704_set_md(const int);
+void df1704_set_ml_dir(const int);
+#endif
diff --git a/firmware/export/pca9555.h b/firmware/export/pca9555.h
new file mode 100644
index 0000000..3180114
--- /dev/null
+++ b/firmware/export/pca9555.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2013 Andrew Ryabinin
+ *
+ * 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.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _PCA9555_H
+#define _PCA9555_H
+
+#include "pca9555-target.h"
+
+#define PCA9555_IN0_CMD      0
+#define PCA9555_IN1_CMD      1
+#define PCA9555_OUT0_CMD     2
+#define PCA9555_OUT1_CMD     3
+#define PCA9555_POL0_INV_CMD 4
+#define PCA9555_POL1_INV_CMD 5
+#define PCA9555_CFG0_CMD     6
+#define PCA9555_CFG1_CMD     7
+
+#define PCA9555_IN_CMD       PCA9555_IN0_CMD
+#define PCA9555_OUT_CMD      PCA9555_OUT0_CMD
+#define PCA9555_POL_INV_CMD  PCA9555_POL0_INV_CMD
+#define PCA9555_CFG_CMD      PCA9555_CFG0_CMD
+
+void pca9555_target_init(void);
+void pca9555_init(void);
+unsigned short pca9555_read_input(void);
+unsigned short pca9555_read_output(void);
+unsigned short pca9555_read_config(void);
+void pca9555_write_output(const unsigned short data, const unsigned short mask);
+void pca9555_write_config(const unsigned short data, const unsigned short mask);
+
+#endif
diff --git a/firmware/target/arm/rk27xx/backlight-rk27xx.c b/firmware/target/arm/rk27xx/backlight-rk27xx.c
index f95a63e..9ea9c99 100644
--- a/firmware/target/arm/rk27xx/backlight-rk27xx.c
+++ b/firmware/target/arm/rk27xx/backlight-rk27xx.c
@@ -61,6 +61,13 @@
     562, 579, 596, 616, 637, 660, 684, 711,
     739, 770, 802, 837, 874, 914, 955, 1000
 };
+#elif defined(MA9)
+static const unsigned short lin_brightness[] = {
+      2,   4,   7,  10,  15,  21,  28,  36,
+     46,  58,  72,  87, 104, 124, 146, 171,
+    198, 227, 260, 295, 334, 376, 421, 470,
+    522, 578, 638, 702, 770, 842, 918, 1000
+};
 #endif
 
 bool _backlight_init(void)
diff --git a/firmware/target/arm/rk27xx/debug-rk27xx.c b/firmware/target/arm/rk27xx/debug-rk27xx.c
index 98ceaf6..a73ca05 100644
--- a/firmware/target/arm/rk27xx/debug-rk27xx.c
+++ b/firmware/target/arm/rk27xx/debug-rk27xx.c
@@ -32,7 +32,7 @@
 
 #ifdef RK27_GENERIC
 #define DEBUG_CANCEL BUTTON_VOL
-#elif defined(HM60X) || defined(HM801)
+#elif defined(HM60X) || defined(HM801) || defined(MA9)
 #define DEBUG_CANCEL BUTTON_LEFT
 #endif
 
diff --git a/firmware/target/arm/rk27xx/lcdif-rk27xx.c b/firmware/target/arm/rk27xx/lcdif-rk27xx.c
index d584739..3f22057 100644
--- a/firmware/target/arm/rk27xx/lcdif-rk27xx.c
+++ b/firmware/target/arm/rk27xx/lcdif-rk27xx.c
@@ -56,7 +56,7 @@
     /* g = ((data & 0x00000300) >> 2) | ((data & 0x000000e0) >> 3); */
     g = ((data & 0x00000300) << 6) | ((data & 0x000000e0) << 5);
     b = (data & 0x00000001f) << 3;
-#elif defined(HM60X) || defined(HM801)
+#elif defined(HM60X) || defined(HM801) || defined(MA9)
     /* 16 bit interface */
     r = (data & 0x0000f800) << 8;
     g = (data & 0x000007e0) << 5;
diff --git a/firmware/target/arm/rk27xx/ma/audio-ma.c b/firmware/target/arm/rk27xx/ma/audio-ma.c
new file mode 100644
index 0000000..c870ca0
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ma/audio-ma.c
@@ -0,0 +1,85 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2013 Andrew Ryabinin
+ *
+ * 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.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "audiohw.h"
+#include "df1704.h"
+#include "pca9555.h"
+#include "i2c-rk27xx.h"
+#include "system.h"
+
+void df1704_set_ml_dir(const int dir)
+{
+    pca9555_write_config(dir<<8, (1<<8));
+}
+
+void df1704_set_ml(const int val)
+{
+    pca9555_write_output(val<<8, 1<<8);
+}
+
+void df1704_set_mc(const int val)
+{
+    pca9555_write_output(val<<1, 1<<1);
+}
+
+void df1704_set_md(const int val)
+{
+    pca9555_write_output(val<<0, 1<<0);
+}
+
+static void pop_ctrl(const int val)
+{
+    pca9555_write_output(val<<5, 1<<5);
+}
+
+static void amp_enable(const int val)
+{
+    pca9555_write_output(val<<3, 1<<3);
+}
+
+static void df1704_enable(const int val)
+{
+    pca9555_write_output(val<<4, 1<<4);
+}
+
+
+void audiohw_postinit(void)
+{
+    pop_ctrl(0);
+    sleep(HZ/4);
+    df1704_enable(1);
+    amp_enable(1);
+    sleep(HZ/100);
+    df1704_init();
+    sleep(HZ/4);
+    pop_ctrl(1);
+}
+
+void audiohw_close(void)
+{
+    df1704_mute();
+    pop_ctrl(0);
+    sleep(HZ/5);
+    amp_enable(0);
+    df1704_enable(0);
+    sleep(HZ/5);
+    pop_ctrl(1);
+}
diff --git a/firmware/target/arm/rk27xx/ma/button-ma.c b/firmware/target/arm/rk27xx/ma/button-ma.c
new file mode 100644
index 0000000..f8da786
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ma/button-ma.c
@@ -0,0 +1,74 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2013 Andrew Ryabinin
+ *
+ * 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.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+#include "system.h"
+#include "button.h"
+#include "adc.h"
+#include "backlight.h"
+#include "pca9555.h"
+
+extern unsigned short pca9555_in_ports;
+
+/* upper bounds of key's voltage values */
+#define ADV_KEYUP       0x05B + 0x10
+#define ADV_KEYDOWN     0x0F3 + 0x10
+#define ADV_KEYLEFT     0x190 + 0x10
+#define ADV_KEYRIGHT    0x22C + 0x10
+#define ADV_KEYMENU     0x2CA + 0x10
+
+
+void button_init_device(void) {
+    GPIO_PCCON &= ~(1<<1);
+    pca9555_init();
+}
+
+int button_read_device(void) {
+    int adc_val = adc_read(ADC_BUTTONS);
+    int button = 0;
+
+    if (adc_val < ADV_KEYLEFT) {
+        if (adc_val < ADV_KEYDOWN) {
+            if (adc_val < ADV_KEYUP) {
+                button = BUTTON_UP;
+            } else {
+                button =  BUTTON_DOWN;
+            }
+        } else {
+            button = BUTTON_LEFT;
+        }
+    } else {
+        if (adc_val < ADV_KEYRIGHT) {
+            button = BUTTON_RIGHT;
+        } else if (adc_val < ADV_KEYMENU) {
+            button = BUTTON_MENU;
+        }
+    }
+
+    if (GPIO_PCDR & (1<<1)) {
+        button |= BUTTON_PLAY;
+    }
+    if (((GPIO_PFDR&(1<<2)) == 0) &&
+        ((pca9555_in_ports & (1<<15)) == 0)) {
+        button |= BUTTON_BACK;
+    }
+    return button;
+}
diff --git a/firmware/target/arm/rk27xx/ma/button-target.h b/firmware/target/arm/rk27xx/ma/button-target.h
new file mode 100644
index 0000000..56e8e90
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ma/button-target.h
@@ -0,0 +1,40 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2013 Andrew Ryabinin
+ *
+ * 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.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _BUTTON_TARGET_H_
+#define _BUTTON_TARGET_H_
+
+#define BUTTON_UP          0x00000001
+#define BUTTON_DOWN        0x00000002
+#define BUTTON_LEFT        0x00000004
+#define BUTTON_RIGHT       0x00000008
+#define BUTTON_PLAY        0x00000010
+#define BUTTON_MENU        0x00000020
+#define BUTTON_BACK        0x00000040
+
+#define BUTTON_MAIN (BUTTON_UP|BUTTON_DOWN| \
+                     BUTTON_RIGHT|BUTTON_LEFT| \
+                     BUTTON_PLAY|BUTTON_MENU|BUTTON_BACK)
+
+#define POWEROFF_BUTTON BUTTON_PLAY
+#define POWEROFF_COUNT 30
+
+#endif /* _BUTTON_TARGET_H_ */
diff --git a/firmware/target/arm/rk27xx/ma/lcd-ma.c b/firmware/target/arm/rk27xx/ma/lcd-ma.c
new file mode 100644
index 0000000..ad67352
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ma/lcd-ma.c
@@ -0,0 +1,206 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C)  2013 Andrew Ryabinin
+ *
+ *
+ * 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.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+#include "kernel.h"
+#include "lcd.h"
+#include "system.h"
+#include "cpu.h"
+#include "lcdif-rk27xx.h"
+
+static bool display_on = false;
+
+
+void lcd_display_init(void)
+{
+    int i;
+    unsigned int x, y;
+
+    lcd_cmd(0x00B9);
+    lcd_data(0x00FF);
+    lcd_data(0x0093);
+    lcd_data(0x0042);
+
+    lcd_cmd(0x0021); /* display inversion on ??? */
+
+    /* memory access control */
+    lcd_cmd(0x0036);
+    lcd_data(0x00C9);
+
+    /* set 16-bit pixel format */
+    lcd_cmd(0x003A);
+    lcd_data(0x0005);
+
+    /* Setup color depth conversion lookup table */
+    lcd_cmd(0x002D);
+    /* red */
+    for(i = 0; i < 32; i++)
+        lcd_data(2*i);
+    /* green */
+    for(i = 0; i < 64; i++)
+        lcd_data(1*i);
+    /* blue */
+    for(i = 0; i < 32; i++)
+        lcd_data(2*i);
+
+    /* power control settings */
+    lcd_cmd(0x00C0);
+    lcd_data(0x0025); /* VREG1OUT 4.70V */
+    lcd_data(0x000A); /* VCOM 2.8V */
+
+    lcd_cmd(0x00C1);
+    lcd_data(0x0001);
+
+    lcd_cmd(0x00C5);
+    lcd_data(0x002F);
+    lcd_data(0x0027);
+
+    lcd_cmd(0x00C7);
+    lcd_data(0x00D3);
+
+    lcd_cmd(0x00B8);
+    lcd_data(0x000B);
+
+    /* Positive gamma correction */
+    lcd_cmd(0x00E0);
+    lcd_data(0x000F);
+    lcd_data(0x0022);
+    lcd_data(0x001D);
+    lcd_data(0x000B);
+    lcd_data(0x000F);
+    lcd_data(0x0007);
+    lcd_data(0x004C);
+    lcd_data(0x0076);
+    lcd_data(0x003C);
+    lcd_data(0x0009);
+    lcd_data(0x0016);
+    lcd_data(0x0007);
+    lcd_data(0x0012);
+    lcd_data(0x000B);
+    lcd_data(0x0008);
+
+    /* Negative Gamma Correction */
+    lcd_cmd(0x00E1);
+    lcd_data(0x0008);
+    lcd_data(0x001F);
+    lcd_data(0x0024);
+    lcd_data(0x0003);
+    lcd_data(0x000E);
+    lcd_data(0x0003);
+    lcd_data(0x0035);
+    lcd_data(0x0023);
+    lcd_data(0x0045);
+    lcd_data(0x0001);
+    lcd_data(0x000B);
+    lcd_data(0x0007);
+    lcd_data(0x002F);
+    lcd_data(0x0036);
+    lcd_data(0x000F);
+
+    lcd_cmd(0x00F2);
+    lcd_data(0x0000);
+
+    /* exit sleep */
+    lcd_cmd(0x0011);
+    udelay(5000);
+    lcd_cmd(0x0029);
+
+    lcd_cmd(0x002C);
+    for (x = 0; x < LCD_WIDTH; x++)
+        for(y=0; y < LCD_HEIGHT; y++)
+            lcd_data(0x00);
+
+    display_on = true;
+}
+
+void lcd_enable (bool on)
+{
+    if (on == display_on)
+        return;
+
+    lcdctrl_bypass(1);
+    LCDC_CTRL |= RGB24B;
+
+    if (on) {
+        lcd_cmd(0x11);
+    } else {
+        lcd_cmd(0x10);
+    }
+    udelay(5000);
+
+    display_on = on;
+    LCDC_CTRL &= ~RGB24B;
+}
+
+void lcd_set_gram_area(int x, int y, int width, int height)
+{
+    lcdctrl_bypass(1);
+    LCDC_CTRL |= RGB24B;
+
+    lcd_cmd(0x002A);
+    lcd_data((x&0xff00)>>8);
+    lcd_data(x&0x00ff);
+    lcd_data(((width-1)&0xff00)>>8);
+    lcd_data((width-1)&0x00ff);
+    lcd_cmd(0x002B);
+    lcd_data((y&0xff00)>>8);
+    lcd_data(y&0x00ff);
+    lcd_data(((height-1)&0xff00)>>8);
+    lcd_data((height-1)&0x00ff);
+
+    lcd_cmd(0x2c);
+    LCDC_CTRL &= ~RGB24B;
+}
+
+void lcd_update_rect(int x, int y, int width, int height)
+{
+    int px = x, py = y;
+    int pxmax = x + width, pymax = y + height;
+
+    lcd_set_gram_area(x, y, pxmax, pymax);
+
+    for (py = y; py < pymax; py++)
+        for (px = x; px < pxmax; px++)
+            LCD_DATA = (*FBADDR(px, py));
+
+}
+
+
+bool lcd_active()
+{
+    return display_on;
+}
+
+/* Blit a YUV bitmap directly to the LCD */
+void lcd_blit_yuv(unsigned char * const src[3],
+                  int src_x, int src_y, int stride,
+                  int x, int y, int width, int height)
+{
+    (void)src;
+    (void)src_x;
+    (void)src_y;
+    (void)stride;
+    (void)x;
+    (void)y;
+    (void)width;
+    (void)height;
+}
diff --git a/firmware/target/arm/rk27xx/ma/lcd-target.h b/firmware/target/arm/rk27xx/ma/lcd-target.h
new file mode 100644
index 0000000..f411a53
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ma/lcd-target.h
@@ -0,0 +1,27 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C)  2013 Andrew Ryabinin
+ *
+ *
+ * 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.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef LCD_TARGET_H
+#define LCD_TARGET_H
+
+#define LCD_DATABUS_WIDTH LCDIF_16BIT
+
+#endif
diff --git a/firmware/target/arm/rk27xx/ma/pca9555-ma.c b/firmware/target/arm/rk27xx/ma/pca9555-ma.c
new file mode 100644
index 0000000..9611d84
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ma/pca9555-ma.c
@@ -0,0 +1,93 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2013 Andrew Ryabinin
+ *
+ * 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.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "system.h"
+#include "i2c-rk27xx.h"
+#include "pca9555.h"
+
+static struct semaphore pca9555_sem;
+static char pca9555_thread_stack[DEFAULT_STACK_SIZE];
+volatile unsigned short pca9555_in_ports;
+
+void INT_GPIO1(void)
+{
+    if (GPIO1_ISR & (1<<10)) { /* GPIO F2 pin */
+        GPIO_IEF &= ~(1<<2);
+        GPIO_ICF |= (1<<2);
+        semaphore_release(&pca9555_sem);
+    }
+}
+
+static void pca9555_read_thread(void)
+{
+    while(1) {
+        if ((GPIO_PFDR&(1<<2)) == 0) {
+            pca9555_in_ports = pca9555_read_input();
+        } else {
+            pca9555_in_ports = (1<<15)|(1<<11); /* restore defaults */
+        }
+        sleep(HZ/20);
+        GPIO_IEF |= (1<<2);
+        semaphore_wait(&pca9555_sem, TIMEOUT_BLOCK);
+    }
+}
+
+static void pca9555_ports_init(void)
+{
+    unsigned short data = 0;
+
+    data = 0xf800; /* port0 - pins 0-7 output, port1 - pins 0-2 output, pins 3-7 input */
+    pca9555_write_config(data, 0xffff);
+
+    /*
+     *   IO0-7    IO0-6   IO0-5    IO0_4    IO0_3    IO0_2     IO0_1      IO0_0
+     * USB_SEL   KP_LED     POP   DAC_EN   AMP_EN   SPI_CS   SPI_CLK   SPI_DATA
+     *   1:MSD    1:OFF       1        0        0        1         1          1
+     */
+    data = ((1<<7)|(1<<6)|(1<<5)|(0<<4)|(0<<3)|(1<<2)|(1<<1)|(1<<0));
+
+    /*
+     *  IO1-2    IO1_1       IO1_0
+     * CHG_EN   DAC_EN   DF1704_CS
+     *      1        0           1
+     */
+    data |= ((1<<10)|(0<<9)|(1<<8));
+    pca9555_write_output(data, 0xffff);
+}
+
+void pca9555_target_init(void)
+{
+    GPIO_PFCON &= ~(1<<2); /* PF2 for PCA9555 input INT */
+
+    pca9555_ports_init();
+    semaphore_init(&pca9555_sem, 1, 0);
+
+    INTC_IMR |= IRQ_ARM_GPIO1;
+    INTC_IECR |= IRQ_ARM_GPIO1;
+    GPIO_ISF |= (1<<2);
+
+    create_thread(pca9555_read_thread,
+                  pca9555_thread_stack,
+                  sizeof(pca9555_thread_stack),
+                  0,
+                  "pca9555_read" IF_PRIO(, PRIORITY_SYSTEM)
+                  IF_COP(, CPU));
+}
diff --git a/firmware/target/arm/rk27xx/ma/pca9555-target.h b/firmware/target/arm/rk27xx/ma/pca9555-target.h
new file mode 100644
index 0000000..25cb1da
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ma/pca9555-target.h
@@ -0,0 +1,27 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2013 Andrew Ryabinin
+ *
+ * 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.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _PCA9555_TARGET_H
+#define _PCA9555_TARGET_H
+
+#define PCA9555_I2C_ADDR    0x40
+
+#endif
diff --git a/firmware/target/arm/rk27xx/ma/power-ma.c b/firmware/target/arm/rk27xx/ma/power-ma.c
new file mode 100644
index 0000000..fb7c232
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ma/power-ma.c
@@ -0,0 +1,58 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright © 2013 Andrew Ryabinin
+ *
+ * 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.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdbool.h>
+#include "config.h"
+#include "inttypes.h"
+#include "power.h"
+#include "panic.h"
+#include "system.h"
+#include "usb_core.h"   /* for usb_charging_maxcurrent_change */
+
+void power_off(void)
+{
+    GPIO_PCDR |= (1<<0);
+    GPIO_PCCON &= ~(1<<0);
+    while(1);
+}
+
+void power_init(void)
+{
+    GPIO_PCDR |= (1<<0);
+    GPIO_PCCON |= (1<<0);
+}
+
+unsigned int power_input_status(void)
+{
+    unsigned int status = POWER_INPUT_NONE;
+
+    if (charging_state())
+        status |= POWER_INPUT_MAIN_CHARGER;
+    return status;
+}
+
+extern unsigned short pca9555_in_ports;
+
+bool charging_state(void)
+{
+    return (((GPIO_PFDR&(1<<2)) == 0) && ((pca9555_in_ports&(1<<11)) == 0));
+}
+
diff --git a/firmware/target/arm/rk27xx/ma/powermgmt-ma.c b/firmware/target/arm/rk27xx/ma/powermgmt-ma.c
new file mode 100644
index 0000000..23196d1
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ma/powermgmt-ma.c
@@ -0,0 +1,61 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright © 2013 Andrew Ryabinin
+ *
+ * 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.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+#include "adc.h"
+#include "adc-target.h"
+#include "powermgmt.h"
+
+/**
+ * Battery voltage calculation and discharge/charge curves for the HiFi E.T MA9.
+ */
+
+const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
+{
+    /* TODO: this is just an initial guess */
+    6700
+};
+
+const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
+{
+    6600
+};
+
+/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */
+const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
+{
+    /* Uncalibrated curve */
+    { 6600, 6936, 7042, 7124, 7218, 7288, 7382, 7534, 7674, 7838, 8200 }
+};
+
+/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */
+const unsigned short percent_to_volt_charge[11] =
+    /* TODO: simple copy of discharge curve */
+    { 6600, 6936, 7042, 7124, 7218, 7288, 7382, 7534, 7674, 7838, 8200 };
+
+/* full-scale ADC readout (2^10) in millivolt */
+#define BATTERY_SCALE_FACTOR  9170
+
+/* Returns battery voltage from ADC [millivolts] */
+int _battery_voltage(void)
+{
+    return (adc_read(ADC_BATTERY) * BATTERY_SCALE_FACTOR) >> 10;
+}
diff --git a/firmware/target/arm/rk27xx/sd-rk27xx.c b/firmware/target/arm/rk27xx/sd-rk27xx.c
index a3ff344..cb870c9 100644
--- a/firmware/target/arm/rk27xx/sd-rk27xx.c
+++ b/firmware/target/arm/rk27xx/sd-rk27xx.c
@@ -132,6 +132,8 @@
     return !(GPIO_PCDR & 0x80);
 #elif defined(HM60X) || defined(HM801)
     return !(GPIO_PFDR & (1<<2));
+#elif defined(MA9)
+    return (GPIO_PCDR & 0x80);
 #else
 #error "Unknown target"
 #endif
diff --git a/tools/configure b/tools/configure
index 5e32247..efa9c33 100755
--- a/tools/configure
+++ b/tools/configure
@@ -1328,8 +1328,8 @@
  201) Android             ==ROCKCHIP==
  202) Nokia N8xx          180) rk27xx generic    ==HiFiMAN==
  203) Nokia N900                                 190) HM-60x
- 204) Pandora                                    191) HM-801
- 205) Samsung YP-R0
+ 204) Pandora             ==HiFi E.T.==          191) HM-801
+ 205) Samsung YP-R0       210) MA9
  206) Android MIPS
  207) Android x86
 EOF
@@ -3411,6 +3411,29 @@
     t_model="app"
     ;;
 
+   210|hifietma9)
+    target_id=83
+    modelname="hifietma9"
+    target="MA9"
+    memory=16
+    arm7ejscc
+    tool="$rootdir/tools/scramble -rkw -modelnum=83"
+    bmp2rb_mono="$rootdir/tools/bmp2rb -f 0"
+    bmp2rb_native="$rootdir/tools/bmp2rb -f 4"
+    output="rockbox.rkw"
+    bootoutput="bootloader.rkw"
+    appextra="recorder:gui"
+    plugins=""
+    swcodec="yes"
+    # toolset is the tools within the tools directory that we build for
+    # this particular target.
+    toolset="$genericbitmaptools"
+    # architecture, manufacturer and model for the target-tree build
+    t_cpu="arm"
+    t_manufacturer="rk27xx"
+    t_model="ma"
+    ;;
+
    *)
     echo "Please select a supported target platform!"
     exit 7