diff --git a/apps/SOURCES b/apps/SOURCES index 5c49f0bbbc..6fdaea3ca8 100644 --- a/apps/SOURCES +++ b/apps/SOURCES @@ -298,4 +298,6 @@ keymaps/keymap-fiiom3klinux.c keymaps/keymap-fiiom3k.c #elif CONFIG_KEYPAD == EROSQ_PAD keymaps/keymap-erosq.c +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +keymaps/keymap-shanlingq1.c #endif diff --git a/apps/features.txt b/apps/features.txt index 4e7f986057..83c3f0a65f 100644 --- a/apps/features.txt +++ b/apps/features.txt @@ -182,12 +182,12 @@ depth_3d #endif /* This should be AUDIOHW_HAVE_FILTER_ROLL_OFF but that is only defined later */ -#if defined(DX50) || defined(HAVE_DF1704_CODEC) || defined(HAVE_PCM1792_CODEC) || defined(HAVE_CS4398) || defined(HAVE_WM8740) || defined(HAVE_ES9018) || defined(HAVE_XDUOO_LINUX_CODEC) || defined(HAVE_FIIO_LINUX_CODEC) || defined(HAVE_AK4376) +#if defined(DX50) || defined(HAVE_DF1704_CODEC) || defined(HAVE_PCM1792_CODEC) || defined(HAVE_CS4398) || defined(HAVE_WM8740) || defined(HAVE_ES9018) || defined(HAVE_XDUOO_LINUX_CODEC) || defined(HAVE_FIIO_LINUX_CODEC) || defined(HAVE_AK4376) || defined(HAVE_ES9218) filter_roll_off #endif /* This should be AUDIOHW_HAVE_POWER_MODE but that is not defined yet */ -#if defined(HAVE_AK4376) +#if defined(HAVE_AK4376) || defined(HAVE_ES9218) dac_power_mode #endif @@ -195,6 +195,10 @@ dac_power_mode es9018 #endif +#if defined(HAVE_ES9218) +es9218 +#endif + /* These features are only used by the manual so they won't break binary * compatibility */ diff --git a/apps/keymaps/keymap-shanlingq1.c b/apps/keymaps/keymap-shanlingq1.c new file mode 100644 index 0000000000..4745139e7a --- /dev/null +++ b/apps/keymaps/keymap-shanlingq1.c @@ -0,0 +1,77 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2021 Aidan MacDonald + * + * 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 Shanling Q1 target */ + +#include "config.h" +#include "action.h" +#include "button.h" +#include "settings.h" + +/* {Action Code, Button code, Prereq button code } */ + +static const struct button_mapping button_context_standard[] = { + {ACTION_STD_PREV, BUTTON_PREV, BUTTON_NONE}, + {ACTION_STD_NEXT, BUTTON_NEXT, BUTTON_NONE}, + {ACTION_STD_OK, BUTTON_PLAY|BUTTON_REL, BUTTON_PLAY}, + {ACTION_STD_CANCEL, BUTTON_POWER|BUTTON_REL, BUTTON_POWER}, + 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_NONE}, + {ACTION_WPS_VOLUP, BUTTON_VOL_UP|BUTTON_REL, BUTTON_NONE}, + {ACTION_WPS_VOLDOWN, BUTTON_VOL_DOWN|BUTTON_REL, BUTTON_NONE}, + {ACTION_WPS_SKIPNEXT, BUTTON_NEXT|BUTTON_REL, BUTTON_NEXT}, + {ACTION_WPS_SKIPPREV, BUTTON_PREV|BUTTON_REL, BUTTON_PREV}, + {ACTION_WPS_SEEKFWD, BUTTON_NEXT|BUTTON_REPEAT, BUTTON_NONE}, + {ACTION_WPS_STOPSEEK, BUTTON_NEXT|BUTTON_REL, BUTTON_NEXT|BUTTON_REPEAT}, + {ACTION_WPS_SEEKBACK, BUTTON_PREV|BUTTON_REPEAT, BUTTON_NONE}, + {ACTION_WPS_STOPSEEK, BUTTON_PREV|BUTTON_REL, BUTTON_PREV|BUTTON_REPEAT}, + {ACTION_STD_KEYLOCK, BUTTON_POWER|BUTTON_REL, BUTTON_POWER}, + LAST_ITEM_IN_LIST +}; /* button_context_wps */ + +static const struct button_mapping button_context_list[] = { + {ACTION_LIST_VOLUP, BUTTON_VOL_UP|BUTTON_REL, BUTTON_NONE}, + {ACTION_LIST_VOLDOWN, BUTTON_VOL_DOWN|BUTTON_REL, BUTTON_NONE}, + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) +}; /* button_context_list */ + +const struct button_mapping* target_get_context_mapping(int context) +{ + switch (context) + { + default: + case CONTEXT_STD: + return button_context_standard; + case CONTEXT_WPS: + return button_context_wps; + case CONTEXT_TREE: + case CONTEXT_CUSTOM|CONTEXT_TREE: + case CONTEXT_MAINMENU: + case CONTEXT_BOOKMARKSCREEN: + //return button_context_tree; + case CONTEXT_LIST: + return button_context_list; + } +} diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 4cbc6f30f6..f268434f60 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -12204,6 +12204,142 @@ es9018: "Bypass" + + id: LANG_FILTER_LINEAR_FAST + desc: in sound settings + user: core + + *: none + es9218: "Linear Fast" + + + *: none + es9218: "Linear Fast" + + + *: none + es9218: "Linear Fast" + + + + id: LANG_FILTER_LINEAR_SLOW + desc: in sound settings + user: core + + *: none + es9218: "Linear Slow" + + + *: none + es9218: "Linear Slow" + + + *: none + es9218: "Linear Slow" + + + + id: LANG_FILTER_MINIMUM_FAST + desc: in sound settings + user: core + + *: none + es9218: "Minimum Fast" + + + *: none + es9218: "Minimum Fast" + + + *: none + es9218: "Minimum Fast" + + + + id: LANG_FILTER_MINIMUM_SLOW + desc: in sound settings + user: core + + *: none + es9218: "Minimum Slow" + + + *: none + es9218: "Minimum Slow" + + + *: none + es9218: "Minimum Slow" + + + + id: LANG_FILTER_APODIZING_1 + desc: in sound settings + user: core + + *: none + es9218: "Apodizing type 1" + + + *: none + es9218: "Apodizing type 1" + + + *: none + es9218: "Apodizing type 1" + + + + id: LANG_FILTER_APODIZING_2 + desc: in sound settings + user: core + + *: none + es9218: "Apodizing type 2" + + + *: none + es9218: "Apodizing type 2" + + + *: none + es9218: "Apodizing type 2" + + + + id: LANG_FILTER_HYBRID_FAST + desc: in sound settings + user: core + + *: none + es9218: "Hybrid Fast" + + + *: none + es9218: "Hybrid Fast" + + + *: none + es9218: "Hybrid Fast" + + + + id: LANG_FILTER_BRICK_WALL + desc: in sound settings + user: core + + *: none + es9218: "Brick Wall" + + + *: none + es9218: "Brick Wall" + + + *: none + es9218: "Brick Wall" + + id: LANG_DAC_POWER_MODE desc: in sound settings @@ -12211,14 +12347,17 @@ *: none dac_power_mode: "DAC's power mode" + es9218: "DAC's output level" *: none dac_power_mode: "DAC's power mode" + es9218: "DAC's output level" *: none dac_power_mode: "DAC's power mode" + es9218: "DAC's output level" @@ -12228,14 +12367,17 @@ *: none dac_power_mode: "High performance" + es9218: "High Gain (2 Vrms)" *: none dac_power_mode: "High performance" + es9218: "High Gain (2 Vrms)" *: none dac_power_mode: "High performance" + es9218: "High Gain (2 Vrms)" @@ -12245,14 +12387,17 @@ *: none dac_power_mode: "Save battery" + es9218: "Low Gain (1 Vrms)" *: none dac_power_mode: "Save battery" + es9218: "Low Gain (1 Vrms)" *: none dac_power_mode: "Save battery" + es9218: "Low Gain (1 Vrms)" diff --git a/apps/plugins/battery_bench.c b/apps/plugins/battery_bench.c index 2534e3bebe..6c477cbd09 100644 --- a/apps/plugins/battery_bench.c +++ b/apps/plugins/battery_bench.c @@ -234,6 +234,9 @@ #define BATTERY_ON_TXT "Play" #define BATTERY_OFF_TXT "Power" +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error "No keymap defined!" #endif diff --git a/apps/plugins/bitmaps/mono/SOURCES b/apps/plugins/bitmaps/mono/SOURCES index e6a24b2bc5..eb00bd9e8a 100644 --- a/apps/plugins/bitmaps/mono/SOURCES +++ b/apps/plugins/bitmaps/mono/SOURCES @@ -19,7 +19,8 @@ bubbles_bubble.138x110x1.bmp ((LCD_WIDTH == 176) && (LCD_HEIGHT == 220)) bubbles_bubble.220x176x1.bmp #elif ((LCD_WIDTH == 320) && (LCD_HEIGHT == 240)) || \ - ((LCD_WIDTH == 240) && (LCD_HEIGHT >= 320)) + ((LCD_WIDTH == 240) && (LCD_HEIGHT >= 320)) || \ + ((LCD_WIDTH == 360) && (LCD_HEIGHT == 400)) bubbles_bubble.320x240x1.bmp #elif ((LCD_WIDTH == 640) && (LCD_HEIGHT == 480)) || \ ((LCD_WIDTH == 480) && (LCD_HEIGHT == 640)) diff --git a/apps/plugins/bitmaps/native/SOURCES b/apps/plugins/bitmaps/native/SOURCES index 48eb18dfa4..37d0060213 100644 --- a/apps/plugins/bitmaps/native/SOURCES +++ b/apps/plugins/bitmaps/native/SOURCES @@ -158,6 +158,9 @@ jackpot_slots.30x420x1.bmp ((LCD_WIDTH >= 480) && (LCD_HEIGHT >= 640)) bubbles_emblem.640x480x16.bmp bubbles_background.640x480x16.bmp +#elif (LCD_WIDTH >= 360) && (LCD_HEIGHT >= 400) +bubbles_emblem.360x400x16.bmp +bubbles_background.360x400x16.bmp #elif (LCD_WIDTH >= 320) && (LCD_HEIGHT >= 240) bubbles_emblem.320x240x16.bmp bubbles_background.320x240x16.bmp @@ -388,7 +391,9 @@ invadrox_shield.22x16x16.bmp invadrox_ufo.16x7x16.bmp invadrox_ufo_explode.21x8x16.bmp invadrox_numbers.50x7x16.bmp -#if LCD_WIDTH == 320 +#if LCD_WIDTH == 360 && LCD_HEIGHT == 400 +invadrox_background.360x400x16.bmp +#elif LCD_WIDTH == 320 invadrox_background.320x240x16.bmp #elif LCD_WIDTH == 240 invadrox_background.240x320x16.bmp @@ -457,6 +462,8 @@ jewels.220x176x16.bmp jewels.320x240x16.bmp #elif (LCD_WIDTH == 320) && (LCD_HEIGHT == 240) jewels.320x240x16.bmp +#elif (LCD_WIDTH == 360) && (LCD_HEIGHT == 400) +jewels.360x400x16.bmp #elif ((LCD_WIDTH == 640) && (LCD_HEIGHT == 480)) || \ ((LCD_WIDTH == 480) && (LCD_HEIGHT == 640)) jewels.640x480x16.bmp @@ -546,6 +553,8 @@ puzzles_cursor.11x16x24.bmp #if LCD_DEPTH >= 16 /* colour versions*/ #if (LCD_WIDTH == 640) && (LCD_HEIGHT == 480) rockblox_background.640x480x16.bmp +#elif (LCD_WIDTH == 360) && (LCD_HEIGHT == 400) +rockblox_background.360x400x16.bmp #elif (LCD_WIDTH >= 320) && (LCD_HEIGHT >= 240) rockblox_background.320x240x16.bmp #elif (LCD_WIDTH == 240) && (LCD_HEIGHT >= 320) @@ -603,6 +612,12 @@ snake2_header2.640x480x16.bmp snake2_left.640x480x16.bmp snake2_right.640x480x16.bmp snake2_bottom.640x480x16.bmp +#elif (LCD_WIDTH >= 360) && (LCD_HEIGHT >= 400) && (LCD_DEPTH >= 16) +snake2_header1.360x400x16.bmp +snake2_header2.360x400x16.bmp +snake2_left.360x400x16.bmp +snake2_right.360x400x16.bmp +snake2_bottom.360x400x16.bmp #elif (LCD_WIDTH >= 320) && (LCD_HEIGHT >= 240) && (LCD_DEPTH >= 16) snake2_header1.320x240x16.bmp snake2_header2.320x240x16.bmp @@ -874,7 +889,8 @@ superdom_boarditems.176x132x16.bmp #elif (LCD_WIDTH == 320 && LCD_HEIGHT == 240) superdom_boarditems.320x240x16.bmp #elif ((LCD_WIDTH == 240) && (LCD_HEIGHT == 320)) || \ - ((LCD_WIDTH == 240) && (LCD_HEIGHT == 400)) + ((LCD_WIDTH == 240) && (LCD_HEIGHT == 400)) || \ + ((LCD_WIDTH == 360) && (LCD_HEIGHT == 400)) superdom_boarditems.240x320x16.bmp #elif (LCD_WIDTH == 480 && LCD_HEIGHT == 640) superdom_boarditems.480x640x16.bmp @@ -911,6 +927,8 @@ sliding_puzzle.132x132x16.bmp sliding_puzzle.176x176x16.bmp #elif SMALLER_DIMENSION <= 240 sliding_puzzle.240x240x16.bmp +#elif SMALLER_DIMENSION <= 360 +sliding_puzzle.360x360x16.bmp #elif SMALLER_DIMENSION <= 480 sliding_puzzle.480x480x16.bmp #endif diff --git a/apps/plugins/bitmaps/native/bubbles_background.360x400x16.bmp b/apps/plugins/bitmaps/native/bubbles_background.360x400x16.bmp new file mode 100644 index 0000000000..46d8133911 Binary files /dev/null and b/apps/plugins/bitmaps/native/bubbles_background.360x400x16.bmp differ diff --git a/apps/plugins/bitmaps/native/bubbles_emblem.360x400x16.bmp b/apps/plugins/bitmaps/native/bubbles_emblem.360x400x16.bmp new file mode 100644 index 0000000000..d34e466749 Binary files /dev/null and b/apps/plugins/bitmaps/native/bubbles_emblem.360x400x16.bmp differ diff --git a/apps/plugins/bitmaps/native/invadrox_background.360x400x16.bmp b/apps/plugins/bitmaps/native/invadrox_background.360x400x16.bmp new file mode 100644 index 0000000000..14c687a940 Binary files /dev/null and b/apps/plugins/bitmaps/native/invadrox_background.360x400x16.bmp differ diff --git a/apps/plugins/bitmaps/native/jewels.360x400x16.bmp b/apps/plugins/bitmaps/native/jewels.360x400x16.bmp new file mode 100644 index 0000000000..5cd35f2162 Binary files /dev/null and b/apps/plugins/bitmaps/native/jewels.360x400x16.bmp differ diff --git a/apps/plugins/bitmaps/native/rockblox_background.360x400x16.bmp b/apps/plugins/bitmaps/native/rockblox_background.360x400x16.bmp new file mode 100644 index 0000000000..b2b1289045 Binary files /dev/null and b/apps/plugins/bitmaps/native/rockblox_background.360x400x16.bmp differ diff --git a/apps/plugins/bitmaps/native/sliding_puzzle.360x360x16.bmp b/apps/plugins/bitmaps/native/sliding_puzzle.360x360x16.bmp new file mode 100644 index 0000000000..e74e3ecb6f Binary files /dev/null and b/apps/plugins/bitmaps/native/sliding_puzzle.360x360x16.bmp differ diff --git a/apps/plugins/bitmaps/native/snake2_bottom.360x400x16.bmp b/apps/plugins/bitmaps/native/snake2_bottom.360x400x16.bmp new file mode 100644 index 0000000000..f6da503ab3 Binary files /dev/null and b/apps/plugins/bitmaps/native/snake2_bottom.360x400x16.bmp differ diff --git a/apps/plugins/bitmaps/native/snake2_header1.360x400x16.bmp b/apps/plugins/bitmaps/native/snake2_header1.360x400x16.bmp new file mode 100644 index 0000000000..f88acf2571 Binary files /dev/null and b/apps/plugins/bitmaps/native/snake2_header1.360x400x16.bmp differ diff --git a/apps/plugins/bitmaps/native/snake2_header2.360x400x16.bmp b/apps/plugins/bitmaps/native/snake2_header2.360x400x16.bmp new file mode 100644 index 0000000000..2acccd36b4 Binary files /dev/null and b/apps/plugins/bitmaps/native/snake2_header2.360x400x16.bmp differ diff --git a/apps/plugins/bitmaps/native/snake2_left.360x400x16.bmp b/apps/plugins/bitmaps/native/snake2_left.360x400x16.bmp new file mode 100644 index 0000000000..eac0c8e601 Binary files /dev/null and b/apps/plugins/bitmaps/native/snake2_left.360x400x16.bmp differ diff --git a/apps/plugins/bitmaps/native/snake2_right.360x400x16.bmp b/apps/plugins/bitmaps/native/snake2_right.360x400x16.bmp new file mode 100644 index 0000000000..316f40cb4c Binary files /dev/null and b/apps/plugins/bitmaps/native/snake2_right.360x400x16.bmp differ diff --git a/apps/plugins/blackjack.c b/apps/plugins/blackjack.c index 4242f5a89f..24cfbe583c 100644 --- a/apps/plugins/blackjack.c +++ b/apps/plugins/blackjack.c @@ -607,6 +607,10 @@ enum { #define BJACK_RIGHT BUTTON_RIGHT #define BJACK_LEFT BUTTON_LEFT +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +#define BJACK_QUIT BUTTON_POWER +#define BJACK_QUIT_NAME "QUIT" + #else #error No keymap defined! #endif diff --git a/apps/plugins/brickmania.c b/apps/plugins/brickmania.c index 92f8d4d161..4983d5a417 100644 --- a/apps/plugins/brickmania.c +++ b/apps/plugins/brickmania.c @@ -350,6 +350,9 @@ CONFIG_KEYPAD == SANSA_CONNECT_PAD #define UP BUTTON_UP #define DOWN BUTTON_DOWN +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +#define QUIT BUTTON_POWER + #else #error No keymap defined! #endif diff --git a/apps/plugins/bubbles.c b/apps/plugins/bubbles.c index 50de10fa23..ffc814e7a0 100644 --- a/apps/plugins/bubbles.c +++ b/apps/plugins/bubbles.c @@ -120,6 +120,17 @@ enum { #define XOFS 128 #define MAX_FPS 40 +#elif (LCD_WIDTH == 360) && (LCD_HEIGHT == 400) +#define XOFS 86 +#define YOFS 100 +#define SCORE_TXT_X 28 +#define SCORE_TXT_WIDTH 32 +#define SCORE_TXT_Y 48 +#define LEVEL_TXT_X 27 +#define LEVEL_TXT_WIDTH 32 +#define LEVEL_TXT_Y 5 +#define MAX_FPS 40 + /* 22x22 bubbles (iPod Video) */ #elif (LCD_HEIGHT == 240) && (LCD_WIDTH == 320) #define XOFS 72 diff --git a/apps/plugins/calculator.c b/apps/plugins/calculator.c index cbaea8aa7e..bd09330529 100644 --- a/apps/plugins/calculator.c +++ b/apps/plugins/calculator.c @@ -533,6 +533,9 @@ F3: equal to "=" #define CALCULATOR_CALC BUTTON_MENU #define CALCULATOR_CLEAR BUTTON_BACK +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +#define CALCULATOR_QUIT BUTTON_POWER + #else #error No keymap defined! #endif diff --git a/apps/plugins/calendar.c b/apps/plugins/calendar.c index e7f221a3c9..3299a81273 100644 --- a/apps/plugins/calendar.c +++ b/apps/plugins/calendar.c @@ -421,6 +421,9 @@ #define CALENDAR_NEXT_MONTH BUTTON_VOL_UP #define CALENDAR_PREV_MONTH BUTTON_VOL_DOWN +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error "No keypad setting." #endif diff --git a/apps/plugins/chessbox/chessbox_pgn.h b/apps/plugins/chessbox/chessbox_pgn.h index 827f045a4b..9d4f369ecc 100644 --- a/apps/plugins/chessbox/chessbox_pgn.h +++ b/apps/plugins/chessbox/chessbox_pgn.h @@ -581,6 +581,9 @@ #define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT) #define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT) +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif diff --git a/apps/plugins/chessclock.c b/apps/plugins/chessclock.c index 91b04e713a..3d03cb9f6a 100644 --- a/apps/plugins/chessclock.c +++ b/apps/plugins/chessclock.c @@ -395,6 +395,9 @@ #define CHC_SETTINGS_OK BUTTON_SELECT #define CHC_SETTINGS_CANCEL BUTTON_POWER +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +#define CHC_QUIT BUTTON_POWER + #else #error No keymap defined! #endif diff --git a/apps/plugins/chip8.c b/apps/plugins/chip8.c index 31866acd10..ac7f998690 100644 --- a/apps/plugins/chip8.c +++ b/apps/plugins/chip8.c @@ -1291,6 +1291,9 @@ CONFIG_KEYPAD == MROBE500_PAD #define CHIP8_KEY6 BUTTON_RIGHT #define CHIP8_KEY8 BUTTON_BACK +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif diff --git a/apps/plugins/clix.c b/apps/plugins/clix.c index c127a300f2..9cd66a8034 100644 --- a/apps/plugins/clix.c +++ b/apps/plugins/clix.c @@ -316,6 +316,9 @@ #define CLIX_BUTTON_RIGHT BUTTON_RIGHT #define CLIX_BUTTON_CLICK BUTTON_SELECT +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +#define CLIX_BUTTON_QUIT BUTTON_POWER + #else #error "no keymap" #endif diff --git a/apps/plugins/cube.c b/apps/plugins/cube.c index 857f2415d4..dfd7df8951 100644 --- a/apps/plugins/cube.c +++ b/apps/plugins/cube.c @@ -400,6 +400,9 @@ #define CUBE_PAUSE BUTTON_PLAY #define CUBE_HIGHSPEED BUTTON_BACK +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif diff --git a/apps/plugins/doom/i_video.c b/apps/plugins/doom/i_video.c index 2381a7614d..f5d07a8354 100644 --- a/apps/plugins/doom/i_video.c +++ b/apps/plugins/doom/i_video.c @@ -614,6 +614,10 @@ void I_ShutdownGraphics(void) #define DOOMBUTTON_WEAPON BUTTON_VOL_UP #define DOOMBUTTON_MAP BUTTON_VOL_DOWN +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +#define DOOMBUTTON_ESC BUTTON_POWER +#define DOOMBUTTON_MAP BUTTON_PREV + #else #error Keymap not defined! #endif diff --git a/apps/plugins/flipit.c b/apps/plugins/flipit.c index f6fb059f91..c659cf5ba5 100644 --- a/apps/plugins/flipit.c +++ b/apps/plugins/flipit.c @@ -496,6 +496,9 @@ #define FLIPIT_STEP_BY_STEP BUTTON_VOL_UP #define FLIPIT_TOGGLE BUTTON_SELECT +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif diff --git a/apps/plugins/fractals/fractal.h b/apps/plugins/fractals/fractal.h index b64bf942fe..8e9446df0d 100644 --- a/apps/plugins/fractals/fractal.h +++ b/apps/plugins/fractals/fractal.h @@ -504,6 +504,9 @@ #define FRACTAL_PRECISION_DEC BUTTON_BACK #define FRACTAL_RESET BUTTON_PLAY +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +#define FRACTAL_QUIT BUTTON_POWER + #else #error No keymap defined! #endif diff --git a/apps/plugins/imageviewer/imageviewer_button.h b/apps/plugins/imageviewer/imageviewer_button.h index d588de95ca..e6cd2ac089 100644 --- a/apps/plugins/imageviewer/imageviewer_button.h +++ b/apps/plugins/imageviewer/imageviewer_button.h @@ -539,6 +539,9 @@ #define IMGVIEW_MENU BUTTON_POWER #define IMGVIEW_SLIDE_SHOW BUTTON_PLAY +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif diff --git a/apps/plugins/invadrox.c b/apps/plugins/invadrox.c index c28ab7e830..5eedb6ffc5 100644 --- a/apps/plugins/invadrox.c +++ b/apps/plugins/invadrox.c @@ -296,6 +296,9 @@ CONFIG_KEYPAD == MROBE500_PAD #define RIGHT BUTTON_RIGHT #define FIRE BUTTON_SELECT +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error INVADROX: Unsupported keypad #endif @@ -648,6 +651,23 @@ CONFIG_KEYPAD == MROBE500_PAD #define LIVES_X 8 #define MAX_Y 15 +#elif (LCD_WIDTH == 360) && (LCD_HEIGHT == 400) + +/* Shanling Q1 + */ +#define ARCADISH_GRAPHICS +#define PLAYFIELD_X 32 +#define SHIP_Y (PLAYFIELD_Y - 3 * SHIP_HEIGHT) +#define ALIEN_START_Y (UFO_Y + 3 * ALIEN_HEIGHT) +/* Redefine SCORE_Y */ +#undef SCORE_Y +#define SCORE_Y 80 +#define SCORENUM_X (PLAYFIELD_X + NUMBERS_WIDTH) +#define SCORENUM_Y SCORE_Y + (2 * (FONT_HEIGHT + 1) + 1) +#define HISCORENUM_X (LCD_WIDTH - PLAYFIELD_X - 1 - 6 * NUMBERS_WIDTH - 5 * NUM_SPACING) +#define SHIELD_Y (PLAYFIELD_Y - 6 * SHIP_HEIGHT) +#define LIVES_X 10 +#define MAX_Y 18 #else #error INVADROX: Unsupported LCD type diff --git a/apps/plugins/jewels.c b/apps/plugins/jewels.c index 7f7965b07d..3f209ae556 100644 --- a/apps/plugins/jewels.c +++ b/apps/plugins/jewels.c @@ -377,6 +377,9 @@ CONFIG_KEYPAD == MROBE500_PAD #define HK_SELECT "SELECT" #define HK_CANCEL "BACK" +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif diff --git a/apps/plugins/lib/keymaps.h b/apps/plugins/lib/keymaps.h index b660d4d85e..2cbca9e5ad 100644 --- a/apps/plugins/lib/keymaps.h +++ b/apps/plugins/lib/keymaps.h @@ -255,6 +255,15 @@ #define BTN_FIRE BUTTON_SELECT #define BTN_PAUSE BUTTON_POWER +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +#define BTN_FIRE BUTTON_CENTER +#define BTN_PAUSE BUTTON_POWER +#define BTN_HAVE_DIAGONAL +#define BTN_DOWN_LEFT BUTTON_BOTTOMLEFT +#define BTN_DOWN_RIGHT BUTTON_BOTTOMRIGHT +#define BTN_UP_LEFT BUTTON_TOPLEFT +#define BTN_UP_RIGHT BUTTON_TOPRIGHT + #else #error Unsupported keypad #endif @@ -272,7 +281,8 @@ #elif (CONFIG_KEYPAD != COWON_D2_PAD) && \ (CONFIG_KEYPAD != DX50_PAD) && \ (CONFIG_KEYPAD != ONDAVX777_PAD) && \ - (CONFIG_KEYPAD != CREATIVE_ZENXFI2_PAD) + (CONFIG_KEYPAD != CREATIVE_ZENXFI2_PAD) && \ + (CONFIG_KEYPAD != SHANLING_Q1_PAD) #define BTN_FIRE BUTTON_BOTTOMLEFT #define BTN_PAUSE BUTTON_TOPLEFT #endif diff --git a/apps/plugins/lib/pluginlib_actions.c b/apps/plugins/lib/pluginlib_actions.c index 028472d9a8..4115177eaa 100644 --- a/apps/plugins/lib/pluginlib_actions.c +++ b/apps/plugins/lib/pluginlib_actions.c @@ -499,6 +499,8 @@ const struct button_mapping pla_main_ctx[] = {PLA_SELECT, BUTTON_SELECT, BUTTON_NONE}, {PLA_SELECT_REL, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT}, {PLA_SELECT_REPEAT, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_NONE}, +#elif (CONFIG_KEYPAD == SHANLING_Q1_PAD) + {PLA_EXIT, BUTTON_POWER, BUTTON_NONE}, #else # ifndef HAVE_TOUCHSCREEN # error pluginlib_actions: No actions defined diff --git a/apps/plugins/midi/midiplay.c b/apps/plugins/midi/midiplay.c index a28d1d3862..6345d3c741 100644 --- a/apps/plugins/midi/midiplay.c +++ b/apps/plugins/midi/midiplay.c @@ -325,6 +325,9 @@ #define MIDI_VOL_DOWN BUTTON_VOL_DOWN #define MIDI_PLAYPAUSE BUTTON_PLAY +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif diff --git a/apps/plugins/minesweeper.c b/apps/plugins/minesweeper.c index 19a6b99f12..a3c718d79f 100644 --- a/apps/plugins/minesweeper.c +++ b/apps/plugins/minesweeper.c @@ -443,6 +443,9 @@ CONFIG_KEYPAD == MROBE500_PAD # define MINESWP_DISCOVER (BUTTON_SELECT|BUTTON_REPEAT) # define MINESWP_INFO BUTTON_MENU +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif diff --git a/apps/plugins/mp3_encoder.c b/apps/plugins/mp3_encoder.c index db10185c91..99671815ca 100644 --- a/apps/plugins/mp3_encoder.c +++ b/apps/plugins/mp3_encoder.c @@ -2580,6 +2580,9 @@ CONFIG_KEYPAD == MROBE500_PAD #define MP3ENC_DONE BUTTON_POWER #define MP3ENC_SELECT BUTTON_SELECT +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif diff --git a/apps/plugins/mpegplayer/mpeg_settings.c b/apps/plugins/mpegplayer/mpeg_settings.c index 505f3aa33d..b1445781d0 100644 --- a/apps/plugins/mpegplayer/mpeg_settings.c +++ b/apps/plugins/mpegplayer/mpeg_settings.c @@ -354,6 +354,9 @@ struct mpeg_settings settings; #define MPEG_START_TIME_DOWN BUTTON_DOWN #define MPEG_START_TIME_EXIT BUTTON_POWER +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +#define MPEG_START_TIME_EXIT BUTTON_POWER + #else #error No keymap defined! #endif diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c index 34eafd5d9c..e66b4df146 100644 --- a/apps/plugins/mpegplayer/mpegplayer.c +++ b/apps/plugins/mpegplayer/mpegplayer.c @@ -486,6 +486,9 @@ CONFIG_KEYPAD == SANSA_M200_PAD #define MPEG_RW BUTTON_LEFT #define MPEG_FF BUTTON_RIGHT +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif diff --git a/apps/plugins/oscilloscope.c b/apps/plugins/oscilloscope.c index 881295d6ab..ae84e14f7f 100644 --- a/apps/plugins/oscilloscope.c +++ b/apps/plugins/oscilloscope.c @@ -548,6 +548,9 @@ #define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP #define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif diff --git a/apps/plugins/pacbox/pacbox.h b/apps/plugins/pacbox/pacbox.h index a3d42b099c..aa8c41fa95 100644 --- a/apps/plugins/pacbox/pacbox.h +++ b/apps/plugins/pacbox/pacbox.h @@ -398,6 +398,16 @@ #define PACMAN_1UP BUTTON_VOL_UP #define PACMAN_COIN BUTTON_PLAY +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +#define PACMAN_UP BUTTON_TOPMIDDLE +#define PACMAN_DOWN BUTTON_BOTTOMMIDDLE +#define PACMAN_LEFT BUTTON_MIDLEFT +#define PACMAN_RIGHT BUTTON_MIDRIGHT +#define PACMAN_MENU BUTTON_TOPLEFT +#define PACMAN_1UP BUTTON_BOTTOMLEFT +#define PACMAN_2UP BUTTON_BOTTOMRIGHT +#define PACMAN_COIN BUTTON_CENTER + #else #error Keymap not defined! diff --git a/apps/plugins/pegbox.c b/apps/plugins/pegbox.c index f089c38023..cb6361547d 100644 --- a/apps/plugins/pegbox.c +++ b/apps/plugins/pegbox.c @@ -711,6 +711,9 @@ CONFIG_KEYPAD == MROBE500_PAD #define LVL_UP_TEXT "VOL+" #define LVL_DOWN_TEXT "VOL-" +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error "Unsupported keymap!" #endif diff --git a/apps/plugins/pong.c b/apps/plugins/pong.c index 22484d0bc9..4a2c48e94c 100644 --- a/apps/plugins/pong.c +++ b/apps/plugins/pong.c @@ -325,6 +325,9 @@ CONFIG_KEYPAD == MROBE500_PAD #define PONG_RIGHT_UP BUTTON_BACK #define PONG_RIGHT_DOWN BUTTON_RIGHT +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif diff --git a/apps/plugins/reversi/reversi-gui.h b/apps/plugins/reversi/reversi-gui.h index 7e031e6103..926a71e1a2 100644 --- a/apps/plugins/reversi/reversi-gui.h +++ b/apps/plugins/reversi/reversi-gui.h @@ -361,6 +361,9 @@ #define REVERSI_BUTTON_MAKE_MOVE BUTTON_SELECT #define REVERSI_BUTTON_MENU BUTTON_MENU +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif diff --git a/apps/plugins/rockblox.c b/apps/plugins/rockblox.c index 07a15bfb62..927710b37b 100644 --- a/apps/plugins/rockblox.c +++ b/apps/plugins/rockblox.c @@ -465,6 +465,9 @@ #define ROCKBLOX_DROP BUTTON_PLAY #define ROCKBLOX_RESTART BUTTON_BACK +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif @@ -534,6 +537,22 @@ #define LEVEL_Y 142 #define LINES_Y 218 +#elif (LCD_WIDTH == 360) && (LCD_HEIGHT == 400) + +#define BLOCK_WIDTH 19 +#define BLOCK_HEIGHT 19 +#define BOARD_X 27 +#define BOARD_Y 0 +#define LABEL_X 258 +#define SCORE_Y 40 +#define LEVEL_Y 92 +#define LINES_Y 140 +#define HIGH_LABEL_X 258 +#define HIGH_SCORE_Y 200 +#define HIGH_LEVEL_Y 258 +#define PREVIEW_X 258 +#define PREVIEW_Y 300 + #elif (LCD_WIDTH == 320) && (LCD_HEIGHT == 240) #define BLOCK_WIDTH 12 diff --git a/apps/plugins/rockboy/rockboy.c b/apps/plugins/rockboy/rockboy.c index d2c56ff6cc..2c5c6e4dbf 100644 --- a/apps/plugins/rockboy/rockboy.c +++ b/apps/plugins/rockboy/rockboy.c @@ -468,6 +468,9 @@ static void setoptions (void) options.SELECT = BUTTON_VOL_UP; options.MENU = BUTTON_POWER; +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD + /* use touchscreen */ + #else #error No Keymap Defined! #endif diff --git a/apps/plugins/rockpaint.c b/apps/plugins/rockpaint.c index 0d3211d4d2..98fdb468d3 100644 --- a/apps/plugins/rockpaint.c +++ b/apps/plugins/rockpaint.c @@ -404,6 +404,9 @@ #define ROCKPAINT_LEFT BUTTON_LEFT #define ROCKPAINT_RIGHT BUTTON_RIGHT +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error "Please define keys for this keypad" #endif diff --git a/apps/plugins/sliding_puzzle.c b/apps/plugins/sliding_puzzle.c index d1820b2f50..a34cb77669 100644 --- a/apps/plugins/sliding_puzzle.c +++ b/apps/plugins/sliding_puzzle.c @@ -357,6 +357,9 @@ CONFIG_KEYPAD == MROBE500_PAD #define PUZZLE_SHUFFLE BUTTON_BACK #define PUZZLE_PICTURE BUTTON_PLAY +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif diff --git a/apps/plugins/snake.c b/apps/plugins/snake.c index 459d345fa2..25c89b264b 100644 --- a/apps/plugins/snake.c +++ b/apps/plugins/snake.c @@ -313,6 +313,9 @@ dir is the current direction of the snake - 0=up, 1=right, 2=down, 3=left; #define SNAKE_DOWN BUTTON_DOWN #define SNAKE_PLAYPAUSE BUTTON_PLAY +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif diff --git a/apps/plugins/snake2.c b/apps/plugins/snake2.c index 1536840daf..094fd854eb 100644 --- a/apps/plugins/snake2.c +++ b/apps/plugins/snake2.c @@ -62,6 +62,18 @@ Head and Tail are stored #define TOP_X4 548 /* x-coord of the lowerright item (hi-score) */ #define TOP_Y1 8 /* y-coord of the top row of items */ #define TOP_Y2 50 /* y-coord of the bottom row of items */ +#elif (LCD_WIDTH >= 360) && (LCD_HEIGHT >= 400) + #define MULTIPLIER 12 /*Modifier for porting on other screens*/ + #define MODIFIER_1 12 + #define MODIFIER_2 10 + #define CENTER_X 12 + #define CENTER_Y 40 + #define TOP_X1 34 /* x-coord of the upperleft item (game type) */ + #define TOP_X2 320 /* x-coord of the upperright item (maze type) */ + #define TOP_X3 42 /* x-coord of the lowerleft item (speed) */ + #define TOP_X4 314 /* x-coord of the lowerright item (hi-score) */ + #define TOP_Y1 4 /* y-coord of the top row of items */ + #define TOP_Y2 25 /* y-coord of the bottom row of items */ #elif (LCD_WIDTH >= 320) && (LCD_HEIGHT >= 240) #define MULTIPLIER 10 /*Modifier for porting on other screens*/ #define MODIFIER_1 10 @@ -446,6 +458,9 @@ CONFIG_KEYPAD == MROBE500_PAD #define SNAKE2_PLAYPAUSE BUTTON_PLAY #define SNAKE2_PLAYPAUSE_TEXT "PLAY" +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif diff --git a/apps/plugins/sokoban.c b/apps/plugins/sokoban.c index 41c671a38c..247663a5c2 100644 --- a/apps/plugins/sokoban.c +++ b/apps/plugins/sokoban.c @@ -696,6 +696,9 @@ #define BUTTON_SAVE BUTTON_BACK #define BUTTON_SAVE_NAME "BACK" +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif diff --git a/apps/plugins/solitaire.c b/apps/plugins/solitaire.c index 2d737df678..a48bfbc9be 100644 --- a/apps/plugins/solitaire.c +++ b/apps/plugins/solitaire.c @@ -741,6 +741,9 @@ CONFIG_KEYPAD == MROBE500_PAD # define HK_CUR2STACK "HOLD SELECT" # define HK_REM2STACK "VOL+" +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +# define SOL_QUIT BUTTON_POWER + #else #error No keymap defined! #endif diff --git a/apps/plugins/spacerocks.c b/apps/plugins/spacerocks.c index 2d39c26b3d..8203fad612 100644 --- a/apps/plugins/spacerocks.c +++ b/apps/plugins/spacerocks.c @@ -372,6 +372,9 @@ #define AST_RIGHT BUTTON_RIGHT #define AST_FIRE BUTTON_PLAY +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif diff --git a/apps/plugins/star.c b/apps/plugins/star.c index c186474ae3..874afc1cf1 100644 --- a/apps/plugins/star.c +++ b/apps/plugins/star.c @@ -668,6 +668,10 @@ #define STAR_LEVEL_DOWN_NAME "VOL-" #define STAR_LEVEL_REPEAT_NAME "BACK" +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +#define STAR_QUIT BUTTON_POWER +#define STAR_QUIT_NAME "POWER" + #else #error No keymap defined! #endif diff --git a/apps/plugins/stopwatch.lua b/apps/plugins/stopwatch.lua index 578ba7f42c..34a3c57d72 100644 --- a/apps/plugins/stopwatch.lua +++ b/apps/plugins/stopwatch.lua @@ -280,7 +280,7 @@ function arrangeButtons(btns) end end -rb.touchscreen_set_mode(rb.TOUCHSCREEN_POINT) +rb.touchscreen_mode(rb.TOUCHSCREEN_POINT) LapsView:init() diff --git a/apps/plugins/sudoku/sudoku.h b/apps/plugins/sudoku/sudoku.h index 1332a9a80f..e06581fdc9 100644 --- a/apps/plugins/sudoku/sudoku.h +++ b/apps/plugins/sudoku/sudoku.h @@ -460,6 +460,9 @@ #define SUDOKU_BUTTON_MENU BUTTON_MENU #define SUDOKU_BUTTON_POSSIBLE BUTTON_BACK +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif diff --git a/apps/plugins/test_touchscreen.c b/apps/plugins/test_touchscreen.c index 120ca8ac34..0d8e91f6a9 100644 --- a/apps/plugins/test_touchscreen.c +++ b/apps/plugins/test_touchscreen.c @@ -37,12 +37,17 @@ #elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD #define TOUCHSCREEN_QUIT BUTTON_POWER #define TOUCHSCREEN_TOGGLE BUTTON_MENU +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +#define TOUCHSCREEN_QUIT BUTTON_POWER +#define TOUCHSCREEN_TOGGLE BUTTON_PLAY #elif (CONFIG_KEYPAD == ANDROID_PAD) #define TOUCHSCREEN_QUIT BUTTON_BACK #define TOUCHSCREEN_TOGGLE BUTTON_MENU #elif (CONFIG_KEYPAD == SDL_PAD) #define TOUCHSCREEN_QUIT BUTTON_MIDLEFT #define TOUCHSCREEN_TOGGLE BUTTON_CENTER +#else +# error "No keymap defined!" #endif /* plugin entry point */ diff --git a/apps/plugins/text_viewer/tv_button.h b/apps/plugins/text_viewer/tv_button.h index d9a57d114f..4d45fbba03 100644 --- a/apps/plugins/text_viewer/tv_button.h +++ b/apps/plugins/text_viewer/tv_button.h @@ -572,6 +572,9 @@ #define TV_LINE_DOWN BUTTON_SCROLL_FWD #define TV_BOOKMARK BUTTON_PLAY +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +#define TV_BOOKMARK BUTTON_PLAY + #else #error No keymap defined! #endif diff --git a/apps/plugins/vu_meter.c b/apps/plugins/vu_meter.c index e24ad8dcdc..356a7fdd93 100644 --- a/apps/plugins/vu_meter.c +++ b/apps/plugins/vu_meter.c @@ -452,6 +452,9 @@ #define LABEL_MENU "MENU" #define LABEL_VOLUME "VOL+/VOL-" +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif diff --git a/apps/plugins/wormlet.c b/apps/plugins/wormlet.c index d76f6a7d5a..162cea6208 100644 --- a/apps/plugins/wormlet.c +++ b/apps/plugins/wormlet.c @@ -407,6 +407,9 @@ CONFIG_KEYPAD == MROBE500_PAD #define BTN_QUIT BUTTON_POWER #define BTN_STOPRESET BUTTON_BACK +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error No keymap defined! #endif @@ -492,7 +495,8 @@ CONFIG_KEYPAD == MROBE500_PAD #define SPEED 4 #define MAX_WORM_SEGMENTS 512 #elif ((LCD_WIDTH == 320) && (LCD_HEIGHT == 240)) || \ - ((LCD_WIDTH == 240) && ((LCD_HEIGHT == 320) || (LCD_HEIGHT == 400))) + ((LCD_WIDTH == 240) && ((LCD_HEIGHT == 320) || (LCD_HEIGHT == 400))) || \ + ((LCD_WIDTH == 360) && (LCD_HEIGHT == 400)) #define FOOD_SIZE 7 #define ARGH_SIZE 8 #define SPEED 4 diff --git a/apps/plugins/xobox.c b/apps/plugins/xobox.c index cf959ad7f5..b8b1964db4 100644 --- a/apps/plugins/xobox.c +++ b/apps/plugins/xobox.c @@ -351,6 +351,9 @@ CONFIG_KEYPAD == MROBE500_PAD #define DOWN BUTTON_DOWN #define PAUSE BUTTON_PLAY +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error "No keymap defined!" #endif diff --git a/apps/plugins/zxbox/keymaps.h b/apps/plugins/zxbox/keymaps.h index e9316a301b..e95a1d8c94 100644 --- a/apps/plugins/zxbox/keymaps.h +++ b/apps/plugins/zxbox/keymaps.h @@ -290,6 +290,9 @@ #define ZX_UP BUTTON_UP #define ZX_DOWN BUTTON_DOWN +#elif CONFIG_KEYPAD == SHANLING_Q1_PAD +/* use touchscreen */ + #else #error Keymap not defined! diff --git a/apps/settings_list.c b/apps/settings_list.c index c13df734e6..1cdbc4115d 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c @@ -242,6 +242,9 @@ static const char graphic_numeric[] = "graphic,numeric"; #define DEFAULT_FONT_HEIGHT 12 #elif LCD_HEIGHT <= 320 #define DEFAULT_FONT_HEIGHT 15 +#elif defined(SHANLING_Q1) + /* 16pt font looks pretty aliased & ugly */ + #define DEFAULT_FONT_HEIGHT 18 #elif LCD_HEIGHT <= 400 #define DEFAULT_FONT_HEIGHT 16 #elif LCD_HEIGHT <= 480 && LCD_WIDTH < 800 @@ -261,7 +264,7 @@ static const char graphic_numeric[] = "graphic,numeric"; #endif #ifdef HAVE_LCD_COLOR - #if DEFAULT_FONT_HEIGHT >= 31 + #if DEFAULT_FONT_HEIGHT >= 31 || defined(SHANLING_Q1) #define DEFAULT_ICONSET "tango_icons.32x32" #define DEFAULT_VIEWERS_ICONSET "tango_icons_viewers.32x32" #elif DEFAULT_FONT_HEIGHT >= 23 @@ -848,7 +851,11 @@ const struct settings_list settings[] = { #ifdef AUDIOHW_HAVE_FILTER_ROLL_OFF CHOICE_SETTING(F_SOUNDSETTING, roll_off, LANG_FILTER_ROLL_OFF, 0, -#if defined(AUDIOHW_HAVE_SHORT2_ROLL_OFF) +#if defined(AUDIOHW_HAVE_ES9218_ROLL_OFF) + "roll_off", "linear fast,linear slow,minimum fast,minimum slow,apodizing 1,apodizing 2,hybrid fast,brick wall", sound_set_filter_roll_off, + 8, ID2P(LANG_FILTER_LINEAR_FAST), ID2P(LANG_FILTER_LINEAR_SLOW), ID2P(LANG_FILTER_MINIMUM_FAST), ID2P(LANG_FILTER_MINIMUM_SLOW), + ID2P(LANG_FILTER_APODIZING_1), ID2P(LANG_FILTER_APODIZING_2), ID2P(LANG_FILTER_HYBRID_FAST), ID2P(LANG_FILTER_BRICK_WALL)), +#elif defined(AUDIOHW_HAVE_SHORT2_ROLL_OFF) "roll_off", "sharp,slow,short sharp,short slow", sound_set_filter_roll_off, 4, ID2P(LANG_FILTER_SHARP), ID2P(LANG_FILTER_SLOW), ID2P(LANG_FILTER_SHORT_SHARP), ID2P(LANG_FILTER_SHORT_SLOW)), #elif defined(AUDIOHW_HAVE_SHORT_ROLL_OFF) diff --git a/backdrops/cabbiev2.360x400x16.bmp b/backdrops/cabbiev2.360x400x16.bmp new file mode 100644 index 0000000000..e007b185d1 Binary files /dev/null and b/backdrops/cabbiev2.360x400x16.bmp differ diff --git a/bootloader/SOURCES b/bootloader/SOURCES index f72c58a0b7..6cdcd41ece 100644 --- a/bootloader/SOURCES +++ b/bootloader/SOURCES @@ -89,6 +89,6 @@ show_logo.c #elif defined(SANSA_CONNECT) sansaconnect.c show_logo.c -#elif defined(FIIO_M3K) +#elif defined(FIIO_M3K) || defined(SHANLING_Q1) x1000.c #endif diff --git a/bootloader/x1000.c b/bootloader/x1000.c index 2c61773b11..3467547684 100644 --- a/bootloader/x1000.c +++ b/bootloader/x1000.c @@ -66,6 +66,17 @@ # define BL_SELECT_NAME "PLAY" # define BL_QUIT_NAME "POWER" # define BOOTBACKUP_FILE "/fiiom3k-boot.bin" +#elif defined(SHANLING_Q1) +# define BL_RECOVERY BUTTON_NEXT +# define BL_UP BUTTON_PREV +# define BL_DOWN BUTTON_NEXT +# define BL_SELECT BUTTON_PLAY +# define BL_QUIT BUTTON_POWER +# define BL_UP_NAME "PREV" +# define BL_DOWN_NAME "NEXT" +# define BL_SELECT_NAME "PLAY" +# define BL_QUIT_NAME "POWER" +# define BOOTBACKUP_FILE "/shanlingq1-boot.bin" #else # error "Missing keymap!" #endif diff --git a/docs/CREDITS b/docs/CREDITS index 7dee2ce527..613aa1f660 100644 --- a/docs/CREDITS +++ b/docs/CREDITS @@ -706,6 +706,7 @@ Caleb Connolly Spencer Brennessel Dana Conrad Albert Song +Marc Aarts The libmad team The wavpack team diff --git a/firmware/SOURCES b/firmware/SOURCES index 2414682bb4..e055558b57 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -503,6 +503,8 @@ drivers/audio/pcm1792.c drivers/audio/cs4398.c #elif defined (HAVE_ES9018) drivers/audio/es9018.c +#elif defined (HAVE_ES9218) +drivers/audio/es9218.c #endif /* defined(HAVE_*) */ #else /* PLATFORM_HOSTED */ #if defined(SAMSUNG_YPR0) && defined(HAVE_AS3514) @@ -1716,6 +1718,15 @@ target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c #endif /* FIIO_M3K */ +#if defined(SHANLING_Q1) +target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c +target/mips/ingenic_x1000/shanlingq1/backlight-shanlingq1.c +target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c +target/mips/ingenic_x1000/shanlingq1/lcd-shanlingq1.c +target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c +target/mips/ingenic_x1000/shanlingq1/spl-shanlingq1.c +#endif /* SHANLING_Q1 */ + #if defined(LYRE_PROTO1) target/arm/at91sam/lyre_proto1/adc-lyre_proto1.c target/arm/at91sam/lyre_proto1/backlight-lyre_proto1.c @@ -1948,6 +1959,9 @@ drivers/axp-pmu.c #ifdef HAVE_FT6x06 drivers/ft6x06.c #endif +#ifdef HAVE_CW2015 +drivers/cw2015.c +#endif #endif /* firmware/kernel section */ diff --git a/firmware/drivers/audio/es9218.c b/firmware/drivers/audio/es9218.c new file mode 100644 index 0000000000..76d387221a --- /dev/null +++ b/firmware/drivers/audio/es9218.c @@ -0,0 +1,226 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2021 Aidan MacDonald + * + * 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 "system.h" +#include "i2c-async.h" + +struct es9218_state { + enum es9218_clock_gear clk_gear; + uint32_t fsr; + uint32_t nco; +}; + +static struct es9218_state es9218; + +void es9218_open(void) +{ + /* Enable power supply */ + es9218_set_power_pin(1); + + /* "Wiggle" reset pin to get the internal oscillator to stabilize. + * This should also work if using an external powered oscillator, + * although in that case it's unnecessary to do this dance. */ + es9218_set_reset_pin(1); + udelay(75); + es9218_set_reset_pin(0); + udelay(50); + es9218_set_reset_pin(1); + mdelay(2); + + /* Initialize driver state */ + es9218.clk_gear = ES9218_CLK_GEAR_1; + es9218.fsr = 0; + es9218.nco = 0; +} + +void es9218_close(void) +{ + /* Turn off power supply */ + es9218_set_power_pin(0); + es9218_set_reset_pin(0); +} + +static void recalc_nco(void) +{ + /* nco * CLK * + * fsr = --------- * + * 2**32 */ + + uint32_t clk = es9218_get_mclk(); + clk >>= (int)es9218.clk_gear; + + uint64_t nco64 = es9218.fsr; + nco64 <<= 32; + nco64 /= clk; + + /* let's just ignore overflow... */ + uint32_t nco = nco64; + if(nco != es9218.nco) { + es9218.nco = nco; + + /* registers must be written in this order */ + es9218_write(ES9218_REG_PROG_NCO_BIT0_7, (nco >> 0) & 0xff); + es9218_write(ES9218_REG_PROG_NCO_BIT8_15, (nco >> 8) & 0xff); + es9218_write(ES9218_REG_PROG_NCO_BIT16_23, (nco >> 16) & 0xff); + es9218_write(ES9218_REG_PROG_NCO_BIT24_31, (nco >> 24) & 0xff); + } +} + +void es9218_set_clock_gear(enum es9218_clock_gear gear) +{ + if(gear != es9218.clk_gear) { + es9218.clk_gear = gear; + es9218_update(ES9218_REG_SYSTEM, 0x0c, (uint8_t)(gear & 3) << 2); + recalc_nco(); + } +} + +void es9218_set_nco_frequency(uint32_t fsr) +{ + if(fsr != es9218.fsr) { + es9218.fsr = fsr; + recalc_nco(); + } +} + +void es9218_recompute_nco(void) +{ + recalc_nco(); +} + +void es9218_set_amp_mode(enum es9218_amp_mode mode) +{ + es9218_update(ES9218_REG_AMP_CONFIG, 0x03, (uint8_t)mode & 3); +} + +void es9218_set_amp_powered(bool en) +{ + /* this doesn't seem to be necessary..? */ + es9218_update(ES9218_REG_ANALOG_CTRL, 0x40, en ? 0x40 : 0x00); +} + +void es9218_set_iface_role(enum es9218_iface_role role) +{ + /* asrc is used to lock onto the incoming audio frequency and is + * only used in aysnchronous slave mode. In synchronous operation, + * including master mode, it can be disabled to save power. */ + int asrc_en = (role == ES9218_IFACE_ROLE_SLAVE ? 1 : 0); + int master_mode = (role == ES9218_IFACE_ROLE_MASTER ? 1 : 0); + + es9218_update(ES9218_REG_MASTER_MODE_CONFIG, 1 << 7, master_mode << 7); + es9218_update(ES9218_REG_GENERAL_CONFIG, 1 << 7, asrc_en << 7); +} + +void es9218_set_iface_format(enum es9218_iface_format fmt, + enum es9218_iface_bits bits) +{ + uint8_t val = 0; + val |= ((uint8_t)bits & 3) << 6; + val |= ((uint8_t)fmt & 3) << 4; + /* keep low 4 bits zero -> use normal I2S mode, disable DSD mode */ + es9218_write(ES9218_REG_INPUT_SEL, val); +} + +static int dig_vol_to_hw(int x) +{ + x = MIN(x, ES9218_DIG_VOLUME_MAX); + x = MAX(x, ES9218_DIG_VOLUME_MIN); + return 0xff - (x - ES9218_DIG_VOLUME_MIN) / ES9218_DIG_VOLUME_STEP; +} + +static int amp_vol_to_hw(int x) +{ + x = MIN(x, ES9218_AMP_VOLUME_MAX); + x = MAX(x, ES9218_AMP_VOLUME_MIN); + return 24 - (x - ES9218_AMP_VOLUME_MIN) / ES9218_AMP_VOLUME_STEP; +} + +void es9218_set_dig_volume(int vol_l, int vol_r) +{ + es9218_write(ES9218_REG_VOLUME_LEFT, dig_vol_to_hw(vol_l)); + es9218_write(ES9218_REG_VOLUME_RIGHT, dig_vol_to_hw(vol_r)); +} + +void es9218_set_amp_volume(int vol) +{ + es9218_update(ES9218_REG_ANALOG_VOL, 0x1f, amp_vol_to_hw(vol)); +} + +void es9218_mute(bool en) +{ + es9218_update(ES9218_REG_FILTER_SYS_MUTE, 1, en ? 1 : 0); +} + +void es9218_set_filter(enum es9218_filter_type filt) +{ + es9218_update(ES9218_REG_FILTER_SYS_MUTE, 0xe0, ((int)filt & 7) << 5); +} + +void es9218_set_automute_time(int time) +{ + if(time < 0) time = 0; + if(time > 255) time = 255; + es9218_write(ES9218_REG_AUTOMUTE_TIME, time); +} + +void es9218_set_automute_level(int dB) +{ + es9218_update(ES9218_REG_AUTOMUTE_LEVEL, 0x7f, dB); +} + +void es9218_set_automute_fast_mode(bool en) +{ + es9218_update(ES9218_REG_MIX_AUTOMUTE, 0x10, en ? 0x10 : 0x00); +} + +void es9218_set_dpll_bandwidth(int knob) +{ + es9218_update(ES9218_REG_ASRC_DPLL_BANDWIDTH, 0xf0, (knob & 0xf) << 4); +} + +void es9218_set_thd_compensation(bool en) +{ + es9218_update(ES9218_REG_THD_COMP_BYPASS, 0x40, en ? 0x40 : 0); +} + +void es9218_set_thd_coeffs(uint16_t c2, uint16_t c3) +{ + es9218_write(ES9218_REG_THD_COMP_C2_LO, c2 & 0xff); + es9218_write(ES9218_REG_THD_COMP_C2_HI, (c2 >> 8) & 0xff); + es9218_write(ES9218_REG_THD_COMP_C3_LO, c3 & 0xff); + es9218_write(ES9218_REG_THD_COMP_C3_HI, (c3 >> 8) & 0xff); +} + +int es9218_read(int reg) +{ + return i2c_reg_read1(ES9218_BUS, ES9218_ADDR, reg); +} + +void es9218_write(int reg, uint8_t val) +{ + i2c_reg_write1(ES9218_BUS, ES9218_ADDR, reg, val); +} + +void es9218_update(int reg, uint8_t msk, uint8_t val) +{ + i2c_reg_modify1(ES9218_BUS, ES9218_ADDR, reg, msk, val, NULL); +} diff --git a/firmware/drivers/cw2015.c b/firmware/drivers/cw2015.c new file mode 100644 index 0000000000..705ca16e22 --- /dev/null +++ b/firmware/drivers/cw2015.c @@ -0,0 +1,191 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2021 Aidan MacDonald + * + * 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 "cw2015.h" +#include "i2c-async.h" +#include +#include "system.h" + +/* Headers for the debug menu */ +#ifndef BOOTLOADER +# include "action.h" +# include "list.h" +# include +#endif + +/* Battery profile info is an opaque blob. According to this, + * https://lore.kernel.org/linux-pm/20200503154855.duwj2djgqfiyleq5@earth.universe/T/#u + * the blob only comes from Cellwise testing a physical battery and cannot be + * obtained any other way. It's specific to a given battery so each target has + * its own profile. + * + * Profile data seems to be retained on the chip so it's not a hard requirement + * to define this. Provided you don't lose power in the meantime, it should be + * enough to just boot the OF, then boot Rockbox and read out the battery info + * from the CW2015 debug screen. + */ +#if defined(SHANLING_Q1) +static const uint8_t device_batinfo[CW2015_SIZE_BATINFO] = { + 0x15, 0x7E, 0x61, 0x59, 0x57, 0x55, 0x56, 0x4C, + 0x4E, 0x4D, 0x50, 0x4C, 0x45, 0x3A, 0x2D, 0x27, + 0x22, 0x1E, 0x19, 0x1E, 0x2A, 0x3C, 0x48, 0x45, + 0x1D, 0x94, 0x08, 0xF6, 0x15, 0x29, 0x48, 0x51, + 0x5D, 0x60, 0x63, 0x66, 0x45, 0x1D, 0x83, 0x38, + 0x09, 0x43, 0x16, 0x42, 0x76, 0x98, 0xA5, 0x1B, + 0x41, 0x76, 0x99, 0xBF, 0x80, 0xC0, 0xEF, 0xCB, + 0x2F, 0x00, 0x64, 0xA5, 0xB5, 0x0E, 0x30, 0x29, +}; +#else +# define NO_BATINFO +#endif + +static uint8_t chip_batinfo[CW2015_SIZE_BATINFO]; + +/* TODO: Finish implementing this + * + * Although this chip might give a better battery estimate than voltage does, + * the mainline linux driver has a lot of weird hacks due to oddities like the + * SoC getting stuck during charging, and from limited testing it seems this + * may occur for the Q1 too. + */ + +static int cw2015_read_bat_info(uint8_t* data) +{ + for(int i = 0; i < CW2015_SIZE_BATINFO; ++i) { + int r = i2c_reg_read1(CW2015_BUS, CW2015_ADDR, CW2015_REG_BATINFO + i); + if(r < 0) + return r; + + data[i] = r & 0xff; + } + + return 0; +} + +void cw2015_init(void) +{ + /* mdelay(100); */ + int rc = cw2015_read_bat_info(&chip_batinfo[0]); + if(rc < 0) + memset(chip_batinfo, 0, sizeof(chip_batinfo)); +} + +int cw2015_get_vcell(void) +{ + int vcell_msb = i2c_reg_read1(CW2015_BUS, CW2015_ADDR, CW2015_REG_VCELL); + int vcell_lsb = i2c_reg_read1(CW2015_BUS, CW2015_ADDR, CW2015_REG_VCELL+1); + + if(vcell_msb < 0 || vcell_lsb < 0) + return -1; + + /* 14 bits, resolution 305 uV */ + int v_raw = ((vcell_msb & 0x3f) << 8) | vcell_lsb; + return v_raw * 61 / 200; +} + +int cw2015_get_soc(void) +{ + int soc_msb = i2c_reg_read1(CW2015_BUS, CW2015_ADDR, CW2015_REG_SOC); + + if(soc_msb < 0) + return -1; + + /* MSB is the state of charge in percentage. + * the LSB contains fractional information not useful to Rockbox. */ + return soc_msb & 0xff; +} + +int cw2015_get_rrt(void) +{ + int rrt_msb = i2c_reg_read1(CW2015_BUS, CW2015_ADDR, CW2015_REG_RRT_ALERT); + int rrt_lsb = i2c_reg_read1(CW2015_BUS, CW2015_ADDR, CW2015_REG_RRT_ALERT+1); + + if(rrt_msb < 0 || rrt_lsb < 0) + return -1; + + /* 13 bits, resolution 1 minute */ + return ((rrt_msb & 0x1f) << 8) | rrt_lsb; +} + +const uint8_t* cw2015_get_bat_info(void) +{ + return &chip_batinfo[0]; +} + +#ifndef BOOTLOADER +enum { + CW2015_DEBUG_VCELL = 0, + CW2015_DEBUG_SOC, + CW2015_DEBUG_RRT, + CW2015_DEBUG_BATINFO, + CW2015_DEBUG_BATINFO_LAST = CW2015_DEBUG_BATINFO + 7, + CW2015_DEBUG_NUM_ENTRIES, +}; + +static int cw2015_debug_menu_cb(int action, struct gui_synclist* lists) +{ + (void)lists; + + if(action == ACTION_NONE) + action = ACTION_REDRAW; + + return action; +} + +static const char* cw2015_debug_menu_get_name(int item, void* data, + char* buf, size_t buflen) +{ + (void)data; + + /* hexdump of battery info */ + if(item >= CW2015_DEBUG_BATINFO && item <= CW2015_DEBUG_BATINFO_LAST) { + int i = item - CW2015_DEBUG_BATINFO; + const uint8_t* batinfo = cw2015_get_bat_info(); + snprintf(buf, buflen, "BatInfo%d: %02x %02x %02x %02x %02x %02x %02x %02x", i, + batinfo[8*i + 0], batinfo[8*i + 1], batinfo[8*i + 2], batinfo[8*i + 3], + batinfo[8*i + 4], batinfo[8*i + 5], batinfo[8*i + 6], batinfo[8*i + 7]); + return buf; + } + + switch(item) { + case CW2015_DEBUG_VCELL: + snprintf(buf, buflen, "VCell: %d mV", cw2015_get_vcell()); + return buf; + case CW2015_DEBUG_SOC: + snprintf(buf, buflen, "SOC: %d%%", cw2015_get_soc()); + return buf; + case CW2015_DEBUG_RRT: + snprintf(buf, buflen, "Runtime: %d min", cw2015_get_rrt()); + return buf; + default: + return "---"; + } +} + +bool cw2015_debug_menu(void) +{ + struct simplelist_info info; + simplelist_info_init(&info, "CW2015 debug", CW2015_DEBUG_NUM_ENTRIES, NULL); + info.action_callback = cw2015_debug_menu_cb; + info.get_name = cw2015_debug_menu_get_name; + return simplelist_show_list(&info); +} +#endif diff --git a/firmware/export/audiohw.h b/firmware/export/audiohw.h index ceafc6ebf7..5b2815149d 100644 --- a/firmware/export/audiohw.h +++ b/firmware/export/audiohw.h @@ -216,6 +216,8 @@ struct sound_settings_info #include "cs4398.h" #elif defined(HAVE_ES9018) #include "es9018.h" +#elif defined(HAVE_ES9218) +#include "es9218.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 fdf3bf420d..5e7b2be6e4 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h @@ -160,6 +160,7 @@ #define FIIO_M3K_LINUX_PAD 71 #define EROSQ_PAD 72 #define FIIO_M3K_PAD 73 +#define SHANLING_Q1_PAD 74 /* CONFIG_REMOTE_KEYPAD */ #define H100_REMOTE 1 @@ -274,6 +275,7 @@ #define LCD_IHIFI770C 67 /* as used by IHIFI 770C */ #define LCD_IHIFI800 68 /* as used by IHIFI 800 */ #define LCD_FIIOM3K 69 /* as used by the FiiO M3K */ +#define LCD_SHANLING_Q1 70 /* as used by the Shanling Q1 */ /* LCD_PIXELFORMAT */ #define HORIZONTAL_PACKING 1 @@ -592,6 +594,8 @@ Lyre prototype 1 */ #include "config/fiiom3k.h" #elif defined(EROS_Q) #include "config/aigoerosq.h" +#elif defined(SHANLING_Q1) +#include "config/shanlingq1.h" #else //#error "unknown hwardware platform!" #endif diff --git a/firmware/export/config/shanlingq1.h b/firmware/export/config/shanlingq1.h new file mode 100644 index 0000000000..88175b9160 --- /dev/null +++ b/firmware/export/config/shanlingq1.h @@ -0,0 +1,119 @@ +/* RoLo-related defines */ +#define MODEL_NAME "Shanling Q1" +#define MODEL_NUMBER 115 +#define BOOTFILE_EXT "q1" +#define BOOTFILE "rockbox." BOOTFILE_EXT +#define BOOTDIR "/.rockbox" +#define FIRMWARE_OFFSET_FILE_CRC 0 +#define FIRMWARE_OFFSET_FILE_DATA 8 + +/* CPU defines */ +#define CONFIG_CPU X1000 +#define X1000_EXCLK_FREQ 24000000 +#define CPU_FREQ 1008000000 + +#ifndef SIMULATOR +#define TIMER_FREQ X1000_EXCLK_FREQ +#endif + +/* Kernel defines */ +#define INCLUDE_TIMEOUT_API +#define HAVE_SEMAPHORE_OBJECTS + +/* Drivers */ +#define HAVE_I2C_ASYNC + +/* Buffer for plugins and codecs. */ +#define PLUGIN_BUFFER_SIZE 0x200000 /* 2 MiB */ +#define CODEC_SIZE 0x100000 /* 1 MiB */ + +/* LCD defines */ +#define CONFIG_LCD LCD_SHANLING_Q1 +#define LCD_WIDTH 360 +#define LCD_HEIGHT 400 +#define LCD_DEPTH 16 +#define LCD_PIXELFORMAT RGB565 +#define LCD_DPI 200 +#define HAVE_LCD_COLOR +#define HAVE_LCD_BITMAP +#define HAVE_LCD_ENABLE +#define LCD_X1000_FASTSLEEP +#define LCD_X1000_DMA_WAIT_FOR_FRAME + +/* Backlight defines */ +#define HAVE_BACKLIGHT +#define HAVE_BACKLIGHT_BRIGHTNESS +#define MIN_BRIGHTNESS_SETTING 1 +#define MAX_BRIGHTNESS_SETTING 100 +#define BRIGHTNESS_STEP 5 +#define DEFAULT_BRIGHTNESS_SETTING 70 +#define CONFIG_BACKLIGHT_FADING BACKLIGHT_FADING_SW_SETTING + +/* Codec / audio hardware defines */ +#define HW_SAMPR_CAPS SAMPR_CAP_ALL_192 +#define HAVE_ES9218 +#define HAVE_SW_TONE_CONTROLS + +/* Button defines */ +#define CONFIG_KEYPAD SHANLING_Q1_PAD +#define HAVE_TOUCHSCREEN +#define HAVE_BUTTON_DATA +#define HAVE_FT6x06 +#define HAVE_HEADPHONE_DETECTION + +/* Storage defines */ +#define CONFIG_STORAGE STORAGE_SD +#define HAVE_HOTSWAP +#define HAVE_HOTSWAP_STORAGE_AS_MAIN +#define HAVE_MULTIDRIVE +#define NUM_DRIVES 1 +#define STORAGE_WANTS_ALIGN +#define STORAGE_NEEDS_BOUNCE_BUFFER + +/* RTC settings */ +#define CONFIG_RTC RTC_X1000 +/* TODO: implement HAVE_RTC_ALARM */ + +/* Power management */ +#define CONFIG_BATTERY_MEASURE (VOLTAGE_MEASURE) +#define CONFIG_CHARGING CHARGING_MONITOR +#define HAVE_SW_POWEROFF + +#ifndef SIMULATOR +/* TODO: get the CW2015 driver working correctly */ +/* #define HAVE_CW2015 */ +#define HAVE_AXP_PMU 192 /* Presumed */ +#define HAVE_POWEROFF_WHILE_CHARGING +#endif + +/* Only one battery type */ +#define BATTERY_CAPACITY_DEFAULT 1100 +#define BATTERY_CAPACITY_MIN 1100 +#define BATTERY_CAPACITY_MAX 1100 +#define BATTERY_CAPACITY_INC 0 +#define BATTERY_TYPES_COUNT 1 + +/* USB support */ +#ifndef SIMULATOR +#define CONFIG_USBOTG USBOTG_DESIGNWARE +#define USB_DW_ARCH_SLAVE +#define USB_DW_TURNAROUND 5 +#define HAVE_USBSTACK +#define USB_VENDOR_ID 0x0525 /* Same as the xDuuo X3, for some reason. */ +#define USB_PRODUCT_ID 0xa4a5 /* Nb. DAC mode uses 20b1:301f 'XMOS Ltd' */ +#define USB_DEVBSS_ATTR __attribute__((aligned(32))) +#define HAVE_USB_POWER +#define HAVE_USB_CHARGING_ENABLE +#define HAVE_BOOTLOADER_USB_MODE +#endif + +/* Rockbox capabilities */ +#define HAVE_FAT16SUPPORT +#define HAVE_ALBUMART +#define HAVE_BMP_SCALING +#define HAVE_JPEG +#define HAVE_TAGCACHE +#define HAVE_VOLUME_IN_LIST +#define HAVE_QUICKSCREEN +#define HAVE_HOTKEY +#define AB_REPEAT_ENABLE diff --git a/firmware/export/cw2015.h b/firmware/export/cw2015.h new file mode 100644 index 0000000000..c810d1b7b5 --- /dev/null +++ b/firmware/export/cw2015.h @@ -0,0 +1,57 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2021 Aidan MacDonald + * + * 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 __CW2015_H__ +#define __CW2015_H__ + +#include +#include + +/* Driver for I2C battery fuel gauge IC CW2015. */ + +#define CW2015_REG_VERSION 0x00 +#define CW2015_REG_VCELL 0x02 /* 14 bits, registers 0x02 - 0x03 */ +#define CW2015_REG_SOC 0x04 /* 16 bits, registers 0x04 - 0x05 */ +#define CW2015_REG_RRT_ALERT 0x06 /* 13 bit RRT + alert flag, 0x06-0x07 */ +#define CW2015_REG_CONFIG 0x08 +#define CW2015_REG_MODE 0x0a +#define CW2015_REG_BATINFO 0x10 /* cf. mainline Linux CW2015 driver */ +#define CW2015_SIZE_BATINFO 64 + +extern void cw2015_init(void); + +/* Read the battery terminal voltage, converted to millivolts. */ +extern int cw2015_get_vcell(void); + +/* Read the SOC, in percent (0-100%). */ +extern int cw2015_get_soc(void); + +/* Get the estimated remaining run time, in minutes. + * Not a linearly varying quantity, according to the datasheet. */ +extern int cw2015_get_rrt(void); + +/* Read the current battery profile */ +extern const uint8_t* cw2015_get_bat_info(void); + +/* Debug screen */ +extern bool cw2015_debug_menu(void); + +#endif /* __CW2015_H__ */ diff --git a/firmware/export/es9218.h b/firmware/export/es9218.h new file mode 100644 index 0000000000..1492304c67 --- /dev/null +++ b/firmware/export/es9218.h @@ -0,0 +1,230 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2021 Aidan MacDonald + * + * 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 __ES9218_H__ +#define __ES9218_H__ + +#include +#include + +#define AUDIOHW_CAPS (FILTER_ROLL_OFF_CAP|POWER_MODE_CAP) +#define AUDIOHW_HAVE_ES9218_ROLL_OFF + +#define ES9218_DIG_VOLUME_MIN (-1275) +#define ES9218_DIG_VOLUME_MAX 0 +#define ES9218_DIG_VOLUME_STEP 5 + +#define ES9218_AMP_VOLUME_MIN (-240) +#define ES9218_AMP_VOLUME_MAX 0 +#define ES9218_AMP_VOLUME_STEP 10 + +AUDIOHW_SETTING(VOLUME, "dB", 1, ES9218_DIG_VOLUME_STEP, + ES9218_DIG_VOLUME_MIN, ES9218_DIG_VOLUME_MAX, -200) +AUDIOHW_SETTING(FILTER_ROLL_OFF, "", 0, 1, 0, 7, 0) +AUDIOHW_SETTING(POWER_MODE, "", 0, 1, 0, 1, 0) + +/* Register addresses */ +#define ES9218_REG_SYSTEM 0x00 +#define ES9218_REG_INPUT_SEL 0x01 +#define ES9218_REG_MIX_AUTOMUTE 0x02 +#define ES9218_REG_ANALOG_VOL 0x03 +#define ES9218_REG_AUTOMUTE_TIME 0x04 +#define ES9218_REG_AUTOMUTE_LEVEL 0x05 +#define ES9218_REG_DOP_VOLUME_RAMP 0x06 +#define ES9218_REG_FILTER_SYS_MUTE 0x07 +#define ES9218_REG_GPIO1_2_CONFIG 0x08 +#define ES9218_REG_RESERVED_1 0x09 +#define ES9218_REG_MASTER_MODE_CONFIG 0x0a +#define ES9218_REG_OVERCURRENT_PROT 0x0b +#define ES9218_REG_ASRC_DPLL_BANDWIDTH 0x0c +#define ES9218_REG_THD_COMP_BYPASS 0x0d +#define ES9218_REG_SOFT_START_CONFIG 0x0e +#define ES9218_REG_VOLUME_LEFT 0x0f +#define ES9218_REG_VOLUME_RIGHT 0x10 +#define ES9218_REG_MASTER_TRIM_BIT0_7 0x11 +#define ES9218_REG_MASTER_TRIM_BIT8_15 0x12 +#define ES9218_REG_MASTER_TRIM_BIT16_23 0x13 +#define ES9218_REG_MASTER_TRIM_BIT24_31 0x14 +#define ES9218_REG_GPIO_INPUT_SEL 0x15 +#define ES9218_REG_THD_COMP_C2_LO 0x16 +#define ES9218_REG_THD_COMP_C2_HI 0x17 +#define ES9218_REG_THD_COMP_C3_LO 0x18 +#define ES9218_REG_THD_COMP_C3_HI 0x19 +#define ES9218_REG_CHARGE_PUMP_SS_DELAY 0x1a +#define ES9218_REG_GENERAL_CONFIG 0x1b +#define ES9218_REG_RESERVED_2 0x1c +#define ES9218_REG_GPIO_INV_CLOCK_GEAR 0x1d +#define ES9218_REG_CHARGE_PUMP_CLK_LO 0x1e +#define ES9218_REG_CHARGE_PUMP_CLK_HI 0x1f +#define ES9218_REG_AMP_CONFIG 0x20 +#define ES9218_REG_INTERRUPT_MASK 0x21 +#define ES9218_REG_PROG_NCO_BIT0_7 0x22 +#define ES9218_REG_PROG_NCO_BIT8_15 0x23 +#define ES9218_REG_PROG_NCO_BIT16_23 0x24 +#define ES9218_REG_PROG_NCO_BIT24_31 0x25 +#define ES9218_REG_RESERVED_3 0x27 +#define ES9218_REG_FIR_RAM_ADDR 0x28 +#define ES9218_REG_FIR_DATA_BIT0_7 0x29 +#define ES9218_REG_FIR_DATA_BIT8_15 0x2a +#define ES9218_REG_FIR_DATA_BIT16_23 0x2b +#define ES9218_REG_PROG_FIR_CONFIG 0x2c +#define ES9218_REG_ANALOG_OVERRIDE_1 0x2d +#define ES9218_REG_ANALOG_OVERRIDE_2 0x2e +#define ES9218_REG_ANALOG_OVERRIDE_3 0x2f +#define ES9218_REG_ANALOG_CTRL 0x30 +#define ES9218_REG_CLKGEAR_CFG_BIT0_7 0x31 +#define ES9218_REG_CLKGEAR_CFG_BIT8_15 0x32 +#define ES9218_REG_CLKGEAR_CFG_BIT16_23 0x33 +#define ES9218_REG_RESERVED_4 0x34 +#define ES9218_REG_THD_COMP_C2_CH2_LO 0x35 +#define ES9218_REG_THD_COMP_C2_CH2_HI 0x36 +#define ES9218_REG_THD_COMP_C3_CH2_LO 0x37 +#define ES9218_REG_THD_COMP_C3_CH2_HI 0x38 +#define ES9218_REG_RESERVED_5 0x39 +#define ES9218_REG_RESERVED_6 0x3a +#define ES9218_REG_RESERVED_7 0x3b +#define ES9218_REG_RESERVED_8 0x3c +#define ES9218_REG_CHIP_ID_AND_STATUS 0x40 +#define ES9218_REG_GPIO_AND_CLOCK_GEAR 0x41 +#define ES9218_REG_DPLL_NUMBER_BIT0_7 0x42 +#define ES9218_REG_DPLL_NUMBER_BIT8_15 0x43 +#define ES9218_REG_DPLL_NUMBER_BIT16_23 0x44 +#define ES9218_REG_DPLL_NUMBER_BIT24_31 0x45 +#define ES9218_REG_INPUT_MUTE_STATUS 0x48 +#define ES9218_REG_FIR_READ_BIT0_7 0x49 +#define ES9218_REG_FIR_READ_BIT8_15 0x4a +#define ES9218_REG_FIR_READ_BIT16_23 0x4b + +enum es9218_clock_gear { + ES9218_CLK_GEAR_1 = 0, /* CLK = XI/1 */ + ES9218_CLK_GEAR_2 = 1, /* CLK = XI/2 */ + ES9218_CLK_GEAR_4 = 2, /* CLK = XI/4 */ + ES9218_CLK_GEAR_8 = 3, /* CLK = XI/8 */ +}; + +enum es9218_amp_mode { + ES9218_AMP_MODE_CORE_ON = 0, + ES9218_AMP_MODE_LOWFI = 1, + ES9218_AMP_MODE_1VRMS = 2, + ES9218_AMP_MODE_2VRMS = 3, +}; + +enum es9218_iface_role { + ES9218_IFACE_ROLE_SLAVE = 0, + ES9218_IFACE_ROLE_MASTER = 1, +}; + +enum es9218_iface_format { + ES9218_IFACE_FORMAT_I2S = 0, + ES9218_IFACE_FORMAT_LJUST = 1, + ES9218_IFACE_FORMAT_RJUST = 2, +}; + +enum es9218_iface_bits { + ES9218_IFACE_BITS_16 = 0, + ES9218_IFACE_BITS_24 = 1, + ES9218_IFACE_BITS_32 = 2, +}; + +enum es9218_filter_type { + ES9218_FILTER_LINEAR_FAST = 0, + ES9218_FILTER_LINEAR_SLOW = 1, + ES9218_FILTER_MINIMUM_FAST = 2, + ES9218_FILTER_MINIMUM_SLOW = 3, + ES9218_FILTER_APODIZING_1 = 4, + ES9218_FILTER_APODIZING_2 = 5, + ES9218_FILTER_HYBRID_FAST = 6, + ES9218_FILTER_BRICK_WALL = 7, +}; + +/* Power DAC on or off */ +extern void es9218_open(void); +extern void es9218_close(void); + +/* Clock controls + * + * - Clock gear divides the input master clock to produce the DAC's clock. + * Frequency can be lowered to save power when using lower sample rates. + * + * - NCO (numerically controller oscillator), according to the datasheet, + * defines the ratio between the DAC's clock and the FSR (for PCM modes, + * this is I2S frame clock = sample rate). In master mode it effectively + * controls the sampling frequency by setting the I2S frame clock output. + * It can also be used in slave mode, but other parts of the datasheet + * say contradictory things about synchronous operation in slave mode. + * + * - If using NCO mode and a varying MCLK input (eg. input from the SoC) then + * you will need to call es9218_recompute_nco() when changing MCLK in order + * to refresh the NCO setting. + */ +extern void es9218_set_clock_gear(enum es9218_clock_gear gear); +extern void es9218_set_nco_frequency(uint32_t fsr); +extern void es9218_recompute_nco(void); + +/* Amplifier controls */ +extern void es9218_set_amp_mode(enum es9218_amp_mode mode); +extern void es9218_set_amp_powered(bool en); + +/* Interface selection */ +extern void es9218_set_iface_role(enum es9218_iface_role role); +extern void es9218_set_iface_format(enum es9218_iface_format fmt, + enum es9218_iface_bits bits); + +/* Volume controls, all volumes given in units of dB/10 */ +extern void es9218_set_dig_volume(int vol_l, int vol_r); +extern void es9218_set_amp_volume(int vol); + +/* System mute */ +extern void es9218_mute(bool muted); + +/* Oversampling filter */ +extern void es9218_set_filter(enum es9218_filter_type filt); + +/* Automute settings */ +extern void es9218_set_automute_time(int time); +extern void es9218_set_automute_level(int dB); +extern void es9218_set_automute_fast_mode(bool en); + +/* DPLL bandwidth setting (knob = 0-15) */ +extern void es9218_set_dpll_bandwidth(int knob); + +/* THD compensation */ +extern void es9218_set_thd_compensation(bool en); +extern void es9218_set_thd_coeffs(uint16_t c2, uint16_t c3); + +/* Direct register read/write/update operations */ +extern int es9218_read(int reg); +extern void es9218_write(int reg, uint8_t val); +extern void es9218_update(int reg, uint8_t msk, uint8_t val); + +/* GPIO pin setting callbacks */ +extern void es9218_set_power_pin(int level); +extern void es9218_set_reset_pin(int level); + +/* XI(MCLK) getter -- supplied by the target. + * + * Note: when changing the supplied MCLK frequency, the NCO will need to be + * reprogrammed for the new master clock. Call es9218_recompute_nco() to + * force this. Not necessary if you're not using NCO mode. + */ +extern uint32_t es9218_get_mclk(void); + +#endif /* __ES9218_H__ */ diff --git a/firmware/target/hosted/sdl/sim-ui-defines.h b/firmware/target/hosted/sdl/sim-ui-defines.h index 5b4030bd37..5b83c1bf12 100644 --- a/firmware/target/hosted/sdl/sim-ui-defines.h +++ b/firmware/target/hosted/sdl/sim-ui-defines.h @@ -529,6 +529,14 @@ #define UI_LCD_POSY 15 +#elif defined(SHANLING_Q1) +#define UI_TITLE "Shanling Q1" +#define UI_WIDTH 466 +#define UI_HEIGHT 526 +#define UI_LCD_POSX 46 +#define UI_LCD_POSY 61 + + #elif defined(SIMULATOR) #error no UI defines #endif diff --git a/firmware/target/mips/ingenic_x1000/debug-x1000.c b/firmware/target/mips/ingenic_x1000/debug-x1000.c index fe469b1a72..1965b0b74e 100644 --- a/firmware/target/mips/ingenic_x1000/debug-x1000.c +++ b/firmware/target/mips/ingenic_x1000/debug-x1000.c @@ -152,6 +152,9 @@ extern bool dbg_fiiom3k_touchpad(void); #ifdef HAVE_AXP_PMU extern bool axp_debug_menu(void); #endif +#ifdef HAVE_CW2015 +extern bool cw2015_debug_menu(void); +#endif /* Menu definition */ static const struct { @@ -170,6 +173,9 @@ static const struct { #ifdef HAVE_AXP_PMU {"Power stats", &axp_debug_menu}, #endif +#ifdef HAVE_CW2015 + {"CW2015 debug", &cw2015_debug_menu}, +#endif }; static int hw_info_menu_action_cb(int btn, struct gui_synclist* lists) diff --git a/firmware/target/mips/ingenic_x1000/msc-x1000.c b/firmware/target/mips/ingenic_x1000/msc-x1000.c index 3b7df1dd01..d0359a53e2 100644 --- a/firmware/target/mips/ingenic_x1000/msc-x1000.c +++ b/firmware/target/mips/ingenic_x1000/msc-x1000.c @@ -42,7 +42,7 @@ #define DEBOUNCE_TIME (HZ/10) static const msc_config msc_configs[] = { -#ifdef FIIO_M3K +#if defined(FIIO_M3K) #define MSC_CLOCK_SOURCE X1000_CLK_SCLK_A { .msc_nr = 0, @@ -52,6 +52,17 @@ static const msc_config msc_configs[] = { .cd_gpio = GPIO_MSC0_CD, .cd_active_level = 0, }, +#elif defined(SHANLING_Q1) +#define MSC_CLOCK_SOURCE X1000_CLK_MPLL + { + .msc_nr = 0, + .msc_type = MSC_TYPE_SD, + .bus_width = 4, + .label = "microSD", + .cd_gpio = GPIO_MSC0_CD, + .cd_active_level = 0, + }, + /* NOTE: SDIO wifi card is on msc1 */ #else # error "Please add X1000 MSC config" #endif diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.c b/firmware/target/mips/ingenic_x1000/nand-x1000.c index b76efe65e5..de6eb2fb67 100644 --- a/firmware/target/mips/ingenic_x1000/nand-x1000.c +++ b/firmware/target/mips/ingenic_x1000/nand-x1000.c @@ -58,7 +58,7 @@ #define FREG_STATUS_ECC_UNCOR_ERR (2 << 4) const nand_chip supported_nand_chips[] = { -#if defined(FIIO_M3K) +#if defined(FIIO_M3K) || defined(SHANLING_Q1) { /* ATO25D1GA */ .mf_id = 0x9b, diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/adc-target.h b/firmware/target/mips/ingenic_x1000/shanlingq1/adc-target.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c b/firmware/target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c new file mode 100644 index 0000000000..7314f20412 --- /dev/null +++ b/firmware/target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c @@ -0,0 +1,191 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2021 Aidan MacDonald + * + * 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 "system.h" +#include "pcm_sampr.h" +#include "aic-x1000.h" +#include "i2c-x1000.h" +#include "gpio-x1000.h" +#include "x1000/aic.h" +#include "x1000/cpm.h" + +/* Codec has an dedicated oscillator connected, so it can operate + * as i2s master or slave. I can't distinguish any difference in + * terms of audio quality or power consumption. Code is left here + * for reference in case it proves useful to change it. */ +#define CODEC_MASTER_MODE 0 + +static int cur_fsel = HW_FREQ_48; +static int cur_vol_l = 0, cur_vol_r = 0; +static int cur_filter = 0; +static enum es9218_amp_mode cur_amp_mode = ES9218_AMP_MODE_1VRMS; + +static void codec_start(void) +{ + es9218_open(); + es9218_mute(true); + es9218_set_iface_role(CODEC_MASTER_MODE ? ES9218_IFACE_ROLE_MASTER + : ES9218_IFACE_ROLE_SLAVE); + es9218_set_iface_format(ES9218_IFACE_FORMAT_I2S, ES9218_IFACE_BITS_32); + es9218_set_dpll_bandwidth(10); + es9218_set_thd_compensation(true); + es9218_set_thd_coeffs(0, 0); + audiohw_set_filter_roll_off(cur_filter); + audiohw_set_frequency(cur_fsel); + audiohw_set_volume(cur_vol_l, cur_vol_r); + es9218_set_amp_mode(cur_amp_mode); +} + +static void codec_stop(void) +{ + es9218_mute(true); + es9218_close(); + mdelay(1); +} + +void audiohw_init(void) +{ + /* Configure AIC */ + aic_set_external_codec(true); + aic_set_i2s_mode(CODEC_MASTER_MODE ? AIC_I2S_SLAVE_MODE + : AIC_I2S_MASTER_MODE); + aic_enable_i2s_bit_clock(true); + + /* Open DAC driver */ + i2c_x1000_set_freq(1, I2C_FREQ_400K); + codec_start(); +} + +void audiohw_postinit(void) +{ + es9218_mute(false); +} + +void audiohw_close(void) +{ + codec_stop(); +} + +void audiohw_set_frequency(int fsel) +{ + int sampr = hw_freq_sampr[fsel]; + + /* choose clock gear setting, in line with the OF */ + enum es9218_clock_gear clkgear; + if(sampr <= 48000) + clkgear = ES9218_CLK_GEAR_4; + else if(sampr <= 96000) + clkgear = ES9218_CLK_GEAR_2; + else + clkgear = ES9218_CLK_GEAR_1; + + aic_enable_i2s_bit_clock(false); + es9218_set_clock_gear(clkgear); + + if(CODEC_MASTER_MODE) + es9218_set_nco_frequency(sampr); + else + aic_set_i2s_clock(X1000_CLK_SCLK_A, sampr, 64); + + aic_enable_i2s_bit_clock(true); + + /* save frequency selection */ + cur_fsel = fsel; +} + +static int round_step_up(int x, int step) +{ + int rem = x % step; + if(rem > 0) + rem -= step; + return x - rem; +} + +void audiohw_set_volume(int vol_l, int vol_r) +{ + /* save volume */ + cur_vol_l = vol_l; + cur_vol_r = vol_r; + + /* adjust the amp setting first */ + int amp = round_step_up(MAX(vol_l, vol_r), ES9218_AMP_VOLUME_STEP); + amp = MIN(amp, ES9218_AMP_VOLUME_MAX); + amp = MAX(amp, ES9218_AMP_VOLUME_MIN); + + /* adjust digital volumes */ + vol_l -= amp; + vol_l = MIN(vol_l, ES9218_DIG_VOLUME_MAX); + vol_l = MAX(vol_l, ES9218_DIG_VOLUME_MIN); + + vol_r -= amp; + vol_r = MIN(vol_r, ES9218_DIG_VOLUME_MAX); + vol_r = MAX(vol_r, ES9218_DIG_VOLUME_MIN); + + /* program DAC */ + es9218_set_amp_volume(amp); + es9218_set_dig_volume(vol_l, vol_r); +} + +void audiohw_set_filter_roll_off(int value) +{ + cur_filter = value; + es9218_set_filter(value); +} + +void audiohw_set_power_mode(int mode) +{ + enum es9218_amp_mode new_amp_mode; + if(mode == 0) + new_amp_mode = ES9218_AMP_MODE_2VRMS; + else + new_amp_mode = ES9218_AMP_MODE_1VRMS; + + if(new_amp_mode != cur_amp_mode) { + codec_stop(); + cur_amp_mode = new_amp_mode; + codec_start(); + es9218_mute(false); + } +} + +void es9218_set_power_pin(int level) +{ + gpio_set_level(GPIO_ES9218_POWER, level ? 1 : 0); +} + +void es9218_set_reset_pin(int level) +{ + gpio_set_level(GPIO_ES9218_RESET, level ? 1 : 0); +} + +uint32_t es9218_get_mclk(void) +{ + /* Measured by running the DAC in asynchronous I2S slave mode, + * and reading back the DPLL number from regs 0x42-0x45 while + * playing back 44.1 KHz audio. + * + * CLK = (44_100 * 2**32) / 0x4b46e5 + * = 38_393_403.29532737 + * ~ 38.4 Mhz + */ + return 38400000; +} diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/backlight-shanlingq1.c b/firmware/target/mips/ingenic_x1000/shanlingq1/backlight-shanlingq1.c new file mode 100644 index 0000000000..32c1b902aa --- /dev/null +++ b/firmware/target/mips/ingenic_x1000/shanlingq1/backlight-shanlingq1.c @@ -0,0 +1,63 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2021 Aidan MacDonald + * + * 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 "backlight.h" +#include "backlight-target.h" +#include "lcd.h" +#include "pwm-x1000.h" + +#define BL_LCD_CHN 0 +#define BL_LCD_PERIOD 10000 + +static int backlight_calc_duty(int period, int min_duty, int brightness) +{ + return min_duty + (period - min_duty) * brightness / MAX_BRIGHTNESS_SETTING; +} + +bool backlight_hw_init(void) +{ + pwm_init(BL_LCD_CHN); + pwm_enable(BL_LCD_CHN); + backlight_hw_brightness(MAX_BRIGHTNESS_SETTING); + return true; +} + +void backlight_hw_on(void) +{ + pwm_enable(BL_LCD_CHN); +#ifdef HAVE_LCD_ENABLE + lcd_enable(true); +#endif +} + +void backlight_hw_off(void) +{ + pwm_disable(BL_LCD_CHN); +#ifdef HAVE_LCD_ENABLE + lcd_enable(false); +#endif +} + +void backlight_hw_brightness(int brightness) +{ + int duty_ns = backlight_calc_duty(BL_LCD_PERIOD, 0, brightness); + pwm_set_period(BL_LCD_CHN, BL_LCD_PERIOD, duty_ns); +} diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/backlight-target.h b/firmware/target/mips/ingenic_x1000/shanlingq1/backlight-target.h new file mode 100644 index 0000000000..7298c1c06a --- /dev/null +++ b/firmware/target/mips/ingenic_x1000/shanlingq1/backlight-target.h @@ -0,0 +1,33 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2021 Aidan MacDonald + * + * 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 __BACKLIGHT_TARGET_H__ +#define __BACKLIGHT_TARGET_H__ + +#include + +extern bool backlight_hw_init(void); + +extern void backlight_hw_on(void); +extern void backlight_hw_off(void); +extern void backlight_hw_brightness(int brightness); + +#endif /* __BACKLIGHT_TARGET_H__ */ diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/boot.make b/firmware/target/mips/ingenic_x1000/shanlingq1/boot.make new file mode 100644 index 0000000000..639f570ea3 --- /dev/null +++ b/firmware/target/mips/ingenic_x1000/shanlingq1/boot.make @@ -0,0 +1,31 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# + +include $(ROOTDIR)/lib/microtar/microtar.make + +.SECONDEXPANSION: + +# FIXME(q1): verify NAND parameters +$(BUILDDIR)/spl.q1: $(BUILDDIR)/spl.bin + $(call PRINTS,MKSPL $(@F))$(TOOLSDIR)/mkspl-x1000 -type=nand -ppb=2 -bpp=2 $< $@ + +$(BUILDDIR)/bootloader.ucl: $(BUILDDIR)/bootloader.bin + $(call PRINTS,UCLPACK $(@F))$(TOOLSDIR)/uclpack --nrv2e -9 $< $@ >/dev/null + +.PHONY: $(BUILDDIR)/bootloader-info.txt +$(BUILDDIR)/bootloader-info.txt: + $(call PRINTS,GEN $(@F))echo $(SVNVERSION) > $@ + +$(BUILDDIR)/$(BINARY): $(BUILDDIR)/spl.q1 \ + $(BUILDDIR)/bootloader.ucl \ + $(BUILDDIR)/bootloader-info.txt + $(call PRINTS,TAR $(@F))tar -C $(BUILDDIR) \ + --numeric-owner --no-acls --no-xattrs --no-selinux \ + --mode=0644 --owner=0 --group=0 \ + -cf $@ $(call full_path_subst,$(BUILDDIR)/%,%,$^) diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c b/firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c new file mode 100644 index 0000000000..27c49a7bd7 --- /dev/null +++ b/firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c @@ -0,0 +1,195 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2021 Aidan MacDonald + * Copyright (C) 2021 Dana Conrad + * + * 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 "button.h" +#include "touchscreen.h" +#include "ft6x06.h" +#include "axp-pmu.h" +#include "kernel.h" +#include "backlight.h" +#include "powermgmt.h" +#include "gpio-x1000.h" +#include "irq-x1000.h" +#include "i2c-x1000.h" +#include + +/* Volume wheel rotation */ +static volatile int wheel_pos = 0; + +/* Value of headphone detect register */ +static uint8_t hp_detect_reg = 0x00; + +/* Interval to poll the register */ +#define HPD_POLL_TIME (HZ/2) + +static int hp_detect_tmo_cb(struct timeout* tmo) +{ + i2c_descriptor* d = (i2c_descriptor*)tmo->data; + i2c_async_queue(AXP_PMU_BUS, TIMEOUT_NOBLOCK, I2C_Q_ADD, 0, d); + return HPD_POLL_TIME; +} + +static void hp_detect_init(void) +{ + /* TODO: replace this copy paste cruft with an API in axp-pmu */ + static struct timeout tmo; + static const uint8_t gpio_reg = AXP192_REG_GPIOSTATE1; + static i2c_descriptor desc = { + .slave_addr = AXP_PMU_ADDR, + .bus_cond = I2C_START | I2C_STOP, + .tran_mode = I2C_READ, + .buffer[0] = (void*)&gpio_reg, + .count[0] = 1, + .buffer[1] = &hp_detect_reg, + .count[1] = 1, + .callback = NULL, + .arg = 0, + .next = NULL, + }; + + /* Headphone detect is wired to AXP192 GPIO: set it to input state */ + i2c_reg_write1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP192_REG_GPIO1FUNCTION, 0x01); + + /* Get an initial reading before startup */ + int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, gpio_reg); + if(r >= 0) + hp_detect_reg = r; + + /* Poll the register every second */ + timeout_register(&tmo, &hp_detect_tmo_cb, HPD_POLL_TIME, (intptr_t)&desc); +} + +void button_init_device(void) +{ + /* Setup interrupts for the volume wheel */ + gpio_set_function(GPIO_WHEEL1, GPIOF_IRQ_EDGE(0)); + gpio_set_function(GPIO_WHEEL2, GPIOF_IRQ_EDGE(0)); + gpio_flip_edge_irq(GPIO_WHEEL1); + gpio_flip_edge_irq(GPIO_WHEEL2); + gpio_enable_irq(GPIO_WHEEL1); + gpio_enable_irq(GPIO_WHEEL2); + + /* Init touchscreen driver */ + i2c_x1000_set_freq(FT6x06_BUS, I2C_FREQ_400K); + ft6x06_init(); + + /* Reset touch controller */ + gpio_set_level(GPIO_FT6x06_POWER, 1); + gpio_set_level(GPIO_FT6x06_RESET, 0); + mdelay(5); + gpio_set_level(GPIO_FT6x06_RESET, 1); + + /* Enable ft6x06 interrupt */ + system_set_irq_handler(GPIO_TO_IRQ(GPIO_FT6x06_INTERRUPT), ft6x06_irq_handler); + gpio_set_function(GPIO_FT6x06_INTERRUPT, GPIOF_IRQ_EDGE(0)); + gpio_enable_irq(GPIO_FT6x06_INTERRUPT); + + /* Headphone detection */ + hp_detect_init(); +} + +int button_read_device(int* data) +{ + int r = 0; + + /* Read GPIO buttons, these are all active low */ + uint32_t b = REG_GPIO_PIN(GPIO_B); + if((b & (1 << 21)) == 0) r |= BUTTON_PREV; + if((b & (1 << 22)) == 0) r |= BUTTON_NEXT; + if((b & (1 << 28)) == 0) r |= BUTTON_PLAY; + if((b & (1 << 31)) == 0) r |= BUTTON_POWER; + + /* Check the wheel */ + int wheel_btn = 0; + int whpos = wheel_pos; + if(whpos > 3) + wheel_btn = BUTTON_VOL_DOWN; + else if(whpos < -3) + wheel_btn = BUTTON_VOL_UP; + + if(wheel_btn) { + wheel_pos = 0; + + /* Post the event (rapid motion is more reliable this way) */ + queue_post(&button_queue, wheel_btn, 0); + queue_post(&button_queue, wheel_btn|BUTTON_REL, 0); + + /* Poke the backlight */ + backlight_on(); + reset_poweroff_timer(); + } + + /* Handle touchscreen + * + * TODO: Support 2-point multitouch (useful for 3x3 grid mode) + * TODO: Support simple gestures by converting them to fake buttons + */ + int t = touchscreen_to_pixels(ft6x06_state.pos_x, ft6x06_state.pos_y, data); + if(ft6x06_state.event == FT6x06_EVT_PRESS || + ft6x06_state.event == FT6x06_EVT_CONTACT) { + /* Only set the button bit if the screen is being touched. */ + r |= t; + } + + return r; +} + +void touchscreen_enable_device(bool en) +{ + ft6x06_enable(en); + /* TODO: check if it's worth shutting off the power pin */ +} + +bool headphones_inserted(void) +{ + /* TODO: Also check if the headset button is detectable via an ADC. + * The AXP driver should probably get proper interrupt handling, + * that would be useful for more things than just GPIO polling. */ + return hp_detect_reg & 0x20 ? true : false; +} + +static void handle_wheel_irq(void) +{ + /* Wheel stuff adapted from button-erosqnative.c */ + static const int delta[16] = { 0, -1, 1, 0, + 1, 0, 0, -1, + -1, 0, 0, 1, + 0, 1, -1, 0 }; + static uint32_t state = 0; + state <<= 2; + state |= (REG_GPIO_PIN(GPIO_D) >> 2) & 3; + state &= 0xf; + + wheel_pos += delta[state]; +} + +void GPIOD02(void) +{ + handle_wheel_irq(); + gpio_flip_edge_irq(GPIO_WHEEL1); +} + +void GPIOD03(void) +{ + handle_wheel_irq(); + gpio_flip_edge_irq(GPIO_WHEEL2); +} diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/button-target.h b/firmware/target/mips/ingenic_x1000/shanlingq1/button-target.h new file mode 100644 index 0000000000..905d148afa --- /dev/null +++ b/firmware/target/mips/ingenic_x1000/shanlingq1/button-target.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2021 Aidan MacDonald + * + * 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__ + +#include + +/* physical buttons */ +#define BUTTON_POWER 0x00000001 +#define BUTTON_VOL_UP 0x00000002 /* up = wheel clockwise */ +#define BUTTON_VOL_DOWN 0x00000004 +#define BUTTON_PLAY 0x00000008 /* circle */ +#define BUTTON_NEXT 0x00000010 /* down */ +#define BUTTON_PREV 0x00000020 /* up */ + +/* compatibility hacks */ +#define BUTTON_LEFT BUTTON_MIDLEFT +#define BUTTON_RIGHT BUTTON_MIDRIGHT + +/* touchscreen "buttons" */ +#define BUTTON_TOPLEFT 0x00000040 +#define BUTTON_TOPMIDDLE 0x00000080 +#define BUTTON_TOPRIGHT 0x00000100 +#define BUTTON_MIDLEFT 0x00000200 +#define BUTTON_CENTER 0x00000400 +#define BUTTON_MIDRIGHT 0x00000800 +#define BUTTON_BOTTOMLEFT 0x00001000 +#define BUTTON_BOTTOMMIDDLE 0x00002000 +#define BUTTON_BOTTOMRIGHT 0x00004000 + +#define BUTTON_MAIN (BUTTON_POWER|BUTTON_VOL_UP|BUTTON_VOL_DOWN|\ + BUTTON_PLAY|BUTTON_NEXT|BUTTON_PREV) + +#define POWEROFF_BUTTON BUTTON_POWER +#define POWEROFF_COUNT 30 + +#endif /* __BUTTON_TARGET_H__ */ diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/gpio-target.h b/firmware/target/mips/ingenic_x1000/shanlingq1/gpio-target.h new file mode 100644 index 0000000000..7c71d12888 --- /dev/null +++ b/firmware/target/mips/ingenic_x1000/shanlingq1/gpio-target.h @@ -0,0 +1,32 @@ +/* Name Port Pins Function */ +DEFINE_PINGROUP(LCD_DATA, GPIO_A, 0xffff << 0, GPIOF_DEVICE(1)) +DEFINE_PINGROUP(LCD_CONTROL, GPIO_B, 0x1a << 16, GPIOF_DEVICE(1)) +DEFINE_PINGROUP(MSC0, GPIO_A, 0x3f << 20, GPIOF_DEVICE(1)) +DEFINE_PINGROUP(SFC, GPIO_A, 0x3f << 26, GPIOF_DEVICE(1)) +DEFINE_PINGROUP(I2S, GPIO_B, 0x1f << 0, GPIOF_DEVICE(1)) +DEFINE_PINGROUP(I2C0, GPIO_B, 3 << 23, GPIOF_DEVICE(0)) +DEFINE_PINGROUP(I2C1, GPIO_C, 3 << 26, GPIOF_DEVICE(0)) +DEFINE_PINGROUP(I2C2, GPIO_D, 3 << 0, GPIOF_DEVICE(1)) + +/* Name Pin Function */ +DEFINE_GPIO(FT6x06_INTERRUPT, GPIO_PA(16), GPIOF_INPUT) +DEFINE_GPIO(USB_DETECT, GPIO_PA(17), GPIOF_INPUT) +DEFINE_GPIO(FT6x06_RESET, GPIO_PA(19), GPIOF_OUTPUT(0)) +DEFINE_GPIO(LCD_PWR, GPIO_PB(6), GPIOF_OUTPUT(1)) +DEFINE_GPIO(FT6x06_POWER, GPIO_PB(8), GPIOF_OUTPUT(0)) +DEFINE_GPIO(MSC0_CD, GPIO_PB(9), GPIOF_INPUT) +DEFINE_GPIO(ES9218_POWER, GPIO_PB(13), GPIOF_OUTPUT(0)) +DEFINE_GPIO(LCD_RST, GPIO_PB(15), GPIOF_OUTPUT(1)) +DEFINE_GPIO(LCD_RD, GPIO_PB(16), GPIOF_OUTPUT(1)) +DEFINE_GPIO(LCD_CE, GPIO_PB(18), GPIOF_OUTPUT(1)) +DEFINE_GPIO(BTN_PREV, GPIO_PB(21), GPIOF_INPUT) +DEFINE_GPIO(BTN_NEXT, GPIO_PB(22), GPIOF_INPUT) +DEFINE_GPIO(USB_DRVVBUS, GPIO_PB(25), GPIOF_OUTPUT(0)) +DEFINE_GPIO(BTN_PLAY, GPIO_PB(28), GPIOF_INPUT) +DEFINE_GPIO(BTN_POWER, GPIO_PB(31), GPIOF_INPUT) +DEFINE_GPIO(AXP_IRQ, GPIO_PC(21), GPIOF_INPUT) +DEFINE_GPIO(USB_ID, GPIO_PC(23), GPIOF_INPUT) +DEFINE_GPIO(WHEEL1, GPIO_PD(2), GPIOF_INPUT) +DEFINE_GPIO(WHEEL2, GPIO_PD(3), GPIOF_INPUT) +DEFINE_GPIO(ES9218_GPIO2, GPIO_PD(4), GPIOF_OUTPUT(0)) +DEFINE_GPIO(ES9218_RESET, GPIO_PD(5), GPIOF_OUTPUT(0)) diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/i2c-target.h b/firmware/target/mips/ingenic_x1000/shanlingq1/i2c-target.h new file mode 100644 index 0000000000..af19aeb28c --- /dev/null +++ b/firmware/target/mips/ingenic_x1000/shanlingq1/i2c-target.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2021 Aidan MacDonald + * + * 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 __I2C_TARGET_H__ +#define __I2C_TARGET_H__ + +#define I2C_ASYNC_BUS_COUNT 3 +#define I2C_ASYNC_QUEUE_SIZE 4 + +#define FT6x06_BUS 0 +#define FT6x06_ADDR 0x38 + +#define ES9218_BUS 1 +#define ES9218_ADDR 0x48 + +#define AXP_PMU_BUS 2 +#define AXP_PMU_ADDR 0x34 + +#define CW2015_BUS 2 +#define CW2015_ADDR 0x62 + +#endif /* __I2C_TARGET_H__ */ diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/lcd-shanlingq1.c b/firmware/target/mips/ingenic_x1000/shanlingq1/lcd-shanlingq1.c new file mode 100644 index 0000000000..532a149185 --- /dev/null +++ b/firmware/target/mips/ingenic_x1000/shanlingq1/lcd-shanlingq1.c @@ -0,0 +1,399 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2021 Aidan MacDonald + * + * 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 "lcd.h" +#include "system.h" +#include "lcd-x1000.h" +#include "gpio-x1000.h" + +/* LCD controller is probably an RM68090. + */ + +static const uint32_t q1_lcd_cmd_enable[] = { + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0xbe, + LCD_INSTR_DAT, 0xc3, + LCD_INSTR_DAT, 0x29, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x01, + LCD_INSTR_DAT, 0x01, + LCD_INSTR_DAT, 0x04, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x02, + LCD_INSTR_DAT, 0x01, + LCD_INSTR_DAT, 0x00, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x03, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x10, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x05, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x00, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x06, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x00, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x07, + LCD_INSTR_DAT, 0x01, + LCD_INSTR_DAT, 0x03, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x08, + LCD_INSTR_DAT, 0x03, + LCD_INSTR_DAT, 0x03, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x0d, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x00, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x10, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0xc1, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x11, + LCD_INSTR_DAT, 0xb1, + LCD_INSTR_DAT, 0x08, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x12, + LCD_INSTR_DAT, 0xb1, + LCD_INSTR_DAT, 0x08, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x13, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x0f, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x14, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x14, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x15, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x04, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x16, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x00, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x22, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x00, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x23, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x00, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x30, + LCD_INSTR_DAT, 0x7c, + LCD_INSTR_DAT, 0x3f, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x32, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x00, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x70, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x01, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x91, + LCD_INSTR_DAT, 0x01, + LCD_INSTR_DAT, 0x00, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0xe0, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x01, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0xe1, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x61, + + LCD_INSTR_CMD, 0x01, + LCD_INSTR_CMD, 0x00, + LCD_INSTR_DAT, 0x10, + LCD_INSTR_DAT, 0x30, + + LCD_INSTR_CMD, 0x01, + LCD_INSTR_CMD, 0x01, + LCD_INSTR_DAT, 0xf6, + LCD_INSTR_DAT, 0x3f, + + LCD_INSTR_CMD, 0x01, + LCD_INSTR_CMD, 0x02, + LCD_INSTR_DAT, 0x50, + LCD_INSTR_DAT, 0x1f, + + LCD_INSTR_CMD, 0x01, + LCD_INSTR_CMD, 0x03, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x30, + + LCD_INSTR_CMD, 0x01, + LCD_INSTR_CMD, 0x08, + LCD_INSTR_DAT, 0x03, + LCD_INSTR_DAT, 0x00, + + LCD_INSTR_CMD, 0x01, + LCD_INSTR_CMD, 0x11, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x01, + + LCD_INSTR_CMD, 0x01, + LCD_INSTR_CMD, 0x35, + LCD_INSTR_DAT, 0x76, + LCD_INSTR_DAT, 0x66, + + LCD_INSTR_CMD, 0x01, + LCD_INSTR_CMD, 0x39, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x26, + + LCD_INSTR_CMD, 0x04, + LCD_INSTR_CMD, 0x00, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0xc7, + + LCD_INSTR_CMD, 0x04, + LCD_INSTR_CMD, 0x01, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x00, + + LCD_INSTR_CMD, 0x06, + LCD_INSTR_CMD, 0x06, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x00, + + LCD_INSTR_CMD, 0x03, + LCD_INSTR_CMD, 0x00, + LCD_INSTR_DAT, 0x0d, + LCD_INSTR_DAT, 0x0e, + + LCD_INSTR_CMD, 0x03, + LCD_INSTR_CMD, 0x01, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x03, + + LCD_INSTR_CMD, 0x03, + LCD_INSTR_CMD, 0x02, + LCD_INSTR_DAT, 0x08, + LCD_INSTR_DAT, 0x08, + + LCD_INSTR_CMD, 0x03, + LCD_INSTR_CMD, 0x03, + LCD_INSTR_DAT, 0x02, + LCD_INSTR_DAT, 0x01, + + LCD_INSTR_CMD, 0x03, + LCD_INSTR_CMD, 0x04, + LCD_INSTR_DAT, 0x03, + LCD_INSTR_DAT, 0x01, + + LCD_INSTR_CMD, 0x03, + LCD_INSTR_CMD, 0x05, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x04, + + LCD_INSTR_CMD, 0x03, + LCD_INSTR_CMD, 0x06, + LCD_INSTR_DAT, 0x1b, + LCD_INSTR_DAT, 0x21, + + LCD_INSTR_CMD, 0x03, + LCD_INSTR_CMD, 0x07, + LCD_INSTR_DAT, 0x0f, + LCD_INSTR_DAT, 0x0e, + + LCD_INSTR_CMD, 0x03, + LCD_INSTR_CMD, 0x08, + LCD_INSTR_DAT, 0x01, + LCD_INSTR_DAT, 0x04, + + LCD_INSTR_CMD, 0x03, + LCD_INSTR_CMD, 0x09, + LCD_INSTR_DAT, 0x08, + LCD_INSTR_DAT, 0x08, + + LCD_INSTR_CMD, 0x03, + LCD_INSTR_CMD, 0x0a, + LCD_INSTR_DAT, 0x02, + LCD_INSTR_DAT, 0x01, + + LCD_INSTR_CMD, 0x03, + LCD_INSTR_CMD, 0x0b, + LCD_INSTR_DAT, 0x03, + LCD_INSTR_DAT, 0x01, + + LCD_INSTR_CMD, 0x03, + LCD_INSTR_CMD, 0x0c, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x03, + + LCD_INSTR_CMD, 0x03, + LCD_INSTR_CMD, 0x0d, + LCD_INSTR_DAT, 0x31, + LCD_INSTR_DAT, 0x34, + + /* X start */ + LCD_INSTR_CMD, 0x02, + LCD_INSTR_CMD, 0x10, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x1e, /* 30 */ + + /* X end */ + LCD_INSTR_CMD, 0x02, + LCD_INSTR_CMD, 0x11, + LCD_INSTR_DAT, 0x01, + LCD_INSTR_DAT, 0x85, /* 389 */ + + /* Y start */ + LCD_INSTR_CMD, 0x02, + LCD_INSTR_CMD, 0x12, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x00, /* 0 */ + + /* Y end */ + LCD_INSTR_CMD, 0x02, + LCD_INSTR_CMD, 0x13, + LCD_INSTR_DAT, 0x01, + LCD_INSTR_DAT, 0x8f, /* 399 */ + + /* RAM write start X? */ + LCD_INSTR_CMD, 0x02, + LCD_INSTR_CMD, 0x00, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x1e, + + /* RAM write start Y? */ + LCD_INSTR_CMD, 0x02, + LCD_INSTR_CMD, 0x01, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x00, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x03, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x30, + + LCD_INSTR_CMD, 0x02, + LCD_INSTR_CMD, 0x02, + LCD_INSTR_END, +}; + +/* NOTE this sleep mode may not be saving power, but it gets rid of the + * ghost image that would otherwise remain on the display */ +static const uint32_t q1_lcd_cmd_sleep[] = { + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x10, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0x03, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x07, + LCD_INSTR_DAT, 0x01, + LCD_INSTR_DAT, 0x01, + + LCD_INSTR_END, +}; + +static const uint32_t q1_lcd_cmd_wake[] = { + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x07, + LCD_INSTR_DAT, 0x01, + LCD_INSTR_DAT, 0x03, + + LCD_INSTR_CMD, 0x00, + LCD_INSTR_CMD, 0x10, + LCD_INSTR_DAT, 0x00, + LCD_INSTR_DAT, 0xc1, + + LCD_INSTR_END, +}; + +static const uint8_t __attribute__((aligned(64))) + q1_lcd_dma_wr_cmd[] = {0x02, 0x02, 0x02, 0x02}; + +const struct lcd_tgt_config lcd_tgt_config = { + .bus_width = 8, + .cmd_width = 8, + .use_6800_mode = 0, + .use_serial = 0, + .clk_polarity = 0, + .dc_polarity = 0, + .wr_polarity = 1, + .te_enable = 0, + .big_endian = 1, + .dma_wr_cmd_buf = &q1_lcd_dma_wr_cmd, + .dma_wr_cmd_size = sizeof(q1_lcd_dma_wr_cmd), +}; + +void lcd_tgt_enable(bool enable) +{ + if(enable) { + /* power on the panel */ + gpio_set_level(GPIO_LCD_PWR, 1); + gpio_set_level(GPIO_LCD_RST, 1); + gpio_set_level(GPIO_LCD_CE, 1); + gpio_set_level(GPIO_LCD_RD, 1); + mdelay(50); + gpio_set_level(GPIO_LCD_RST, 0); + mdelay(100); + gpio_set_level(GPIO_LCD_RST, 1); + mdelay(50); + gpio_set_level(GPIO_LCD_CE, 0); + + /* Start the controller */ + lcd_set_clock(X1000_CLK_MPLL, 50000000); + lcd_exec_commands(q1_lcd_cmd_enable); + } else { + /* FIXME: Shanling Q1 LCD power down sequence + * not important because we don't use it but it'd be nice to know */ + } +} + +void lcd_tgt_sleep(bool sleep) +{ + if(sleep) + lcd_exec_commands(q1_lcd_cmd_sleep); + else + lcd_exec_commands(q1_lcd_cmd_wake); +} diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c b/firmware/target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c new file mode 100644 index 0000000000..17fbe1cede --- /dev/null +++ b/firmware/target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c @@ -0,0 +1,140 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2021 Aidan MacDonald + * + * 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 "power.h" +#include "adc.h" +#include "system.h" +#include "axp-pmu.h" +#ifdef HAVE_CW2015 +# include "cw2015.h" +#endif +#ifdef HAVE_USB_CHARGING_ENABLE +# include "usb_core.h" +#endif + +#include "i2c-x1000.h" + +/* TODO: Better(?) battery reporting for Q1 using CW2015 driver + * + * The CW2015 has its own quirks so the driver has to be more complicated + * than "read stuff from I2C," unfortunately. Without fixing the quirks it + * is probably worse than the simple voltage-based method. + * + * A bigger problem is that it shares an I2C bus with the AXP192, but when + * we attempt to communicate with both chips, they start returning bogus + * data intermittently. Ususally, reads will return 0 but sometimes they + * can return other nonzero bogus data. It could be that one or the other is + * pulling the bus line down inappropriately, or maybe the hardware does not + * respect the bus free time between start/stop conditions and one of the + * devices is getting confused. + */ + +const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = +{ + 3470 +}; + +/* the OF shuts down at this voltage */ +const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] = +{ + 3400 +}; + +/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */ +const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] = +{ + { 3400, 3639, 3697, 3723, 3757, 3786, 3836, 3906, 3980, 4050, 4159 } +}; + +/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */ +const unsigned short percent_to_volt_charge[11] = +{ + 3485, 3780, 3836, 3857, 3890, 3930, 3986, 4062, 4158, 4185, 4196 +}; + +void power_init(void) +{ + i2c_x1000_set_freq(AXP_PMU_BUS, I2C_FREQ_400K); + axp_init(); +#ifdef HAVE_CW2015 + cw2015_init(); +#endif + + /* Change supply voltage from the default of 1250 mV to 1200 mV, + * this matches the original firmware's settings. Didn't observe + * any obviously bad behavior at 1250 mV, but better to be safe. */ + axp_supply_set_voltage(AXP_SUPPLY_DCDC2, 1200); + + /* For now, just turn everything on... definitely the touchscreen + * is powered by one of the outputs */ + i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, + AXP_REG_PWROUTPUTCTRL1, 0, 0x05, NULL); + i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, + AXP_REG_PWROUTPUTCTRL2, 0, 0x0f, NULL); + i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, + AXP_REG_DCDCWORKINGMODE, 0, 0xc0, NULL); + + /* Delay to give power output time to stabilize */ + mdelay(20); +} + +#ifdef HAVE_USB_CHARGING_ENABLE +void usb_charging_maxcurrent_change(int maxcurrent) +{ + axp_set_charge_current(maxcurrent); +} +#endif + +void power_off(void) +{ + axp_power_off(); + while(1); +} + +bool charging_state(void) +{ + return axp_battery_status() == AXP_BATT_CHARGING; +} + +int _battery_voltage(void) +{ + /* CW2015 can also read battery voltage, but the AXP consistently + * reads ~20-30 mV higher so I suspect it's the "real" voltage. */ + return axp_adc_read(ADC_BATTERY_VOLTAGE); +} + +#if defined(HAVE_CW2015) && (CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE) != 0 +int _battery_level(void) +{ + return cw2015_get_soc(); +} +#endif + +#if defined(HAVE_CW2015) && (CONFIG_BATTERY_MEASURE & TIME_MEASURE) != 0 +int _battery_time(void) +{ + return cw2015_get_rrt(); +} +#endif + +void adc_init(void) +{ +} diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/spl-shanlingq1.c b/firmware/target/mips/ingenic_x1000/shanlingq1/spl-shanlingq1.c new file mode 100644 index 0000000000..33303c5e6b --- /dev/null +++ b/firmware/target/mips/ingenic_x1000/shanlingq1/spl-shanlingq1.c @@ -0,0 +1,116 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2021 Aidan MacDonald + * + * 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 "clk-x1000.h" +#include "spl-x1000.h" +#include "gpio-x1000.h" + +#define CMDLINE_COMMON \ + "mem=64M@0x0 no_console_suspend console=ttyS2,115200n8 lpj=5009408 ip=off" +#define CMDLINE_NORMAL \ + " init=/linuxrc ubi.mtd=5 root=ubi0:rootfs ubi.mtd=6 rootfstype=ubifs rw" + +static int dualboot_setup(void) +{ + spl_dualboot_init_clocktree(); + spl_dualboot_init_uart2(); + + /* load PDMA MCU firmware */ + jz_writef(CPM_CLKGR, PDMA(0)); + return spl_storage_read(0x4000, 0x2000, (void*)0xb3422000); +} + +const struct spl_boot_option spl_boot_options[] = { + [BOOT_OPTION_ROCKBOX] = { + .storage_addr = 0x6800, + .storage_size = 102 * 1024, + .load_addr = X1000_DRAM_BASE, + .exec_addr = X1000_DRAM_BASE, + .flags = BOOTFLAG_UCLPACK, + }, + [BOOT_OPTION_OFW_PLAYER] = { + .storage_addr = 0x140000, + .storage_size = 8 * 1024 * 1024, + .load_addr = 0x80efffc0, + .exec_addr = 0x80f00000, + .cmdline = CMDLINE_COMMON CMDLINE_NORMAL, + .cmdline_addr = 0x80004000, + .setup = dualboot_setup, + }, + [BOOT_OPTION_OFW_RECOVERY] = { + .storage_addr = 0x940000, + .storage_size = 10 * 1024 * 1024, + .load_addr = 0x80efffc0, + .exec_addr = 0x80f00000, + .cmdline = CMDLINE_COMMON, + .cmdline_addr = 0x80004000, + .setup = dualboot_setup, + }, +}; + +int spl_get_boot_option(void) +{ + /* Button debounce time in OST clock cycles */ + const uint32_t btn_stable_time = 100 * (X1000_EXCLK_FREQ / 4000); + + /* Buttons to poll */ + const unsigned port = GPIO_B; + const uint32_t recov_pin = (1 << 22); /* Next */ + const uint32_t orig_fw_pin = (1 << 21); /* Prev */ + + uint32_t pin = -1, lastpin = 0; + uint32_t deadline = 0; + int iter_count = 30; /* to avoid an infinite loop */ + + /* set GPIOs to input state */ + gpioz_configure(port, recov_pin|orig_fw_pin, GPIOF_INPUT); + + /* Poll until we get a stable reading */ + do { + lastpin = pin; + pin = ~REG_GPIO_PIN(port) & (recov_pin|orig_fw_pin); + if(pin != lastpin) { + deadline = __ost_read32() + btn_stable_time; + iter_count -= 1; + } + } while(iter_count > 0 && __ost_read32() < deadline); + + if(iter_count >= 0 && (pin & orig_fw_pin)) { + if(pin & recov_pin) + return BOOT_OPTION_OFW_RECOVERY; + else + return BOOT_OPTION_OFW_PLAYER; + } + + return BOOT_OPTION_ROCKBOX; +} + +void spl_error(void) +{ + /* Flash the backlight */ + int level = 0; + while(1) { + gpio_set_function(GPIO_PC(25), GPIOF_OUTPUT(level)); + mdelay(100); + level = 1 - level; + } +} diff --git a/firmware/target/mips/ingenic_x1000/spl-x1000.c b/firmware/target/mips/ingenic_x1000/spl-x1000.c index 284b963e97..72dc53b2b7 100644 --- a/firmware/target/mips/ingenic_x1000/spl-x1000.c +++ b/firmware/target/mips/ingenic_x1000/spl-x1000.c @@ -34,7 +34,7 @@ #include "ucl_decompress.h" #include -#ifdef FIIO_M3K +#if defined(FIIO_M3K) || defined(SHANLING_Q1) # define SPL_DDR_MEMORYSIZE 64 # define SPL_DDR_AUTOSR_EN 1 # define SPL_DDR_NEED_BYPASS 1 diff --git a/tools/configure b/tools/configure index 2e06b03717..f32c5d514d 100755 --- a/tools/configure +++ b/tools/configure @@ -1597,7 +1597,8 @@ cat < ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2021 by Aidan MacDonald + * + * 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 +#include "button.h" +#include "buttonmap.h" + +int key_to_button(int keyboard_button) +{ + int new_btn = BUTTON_NONE; + switch (keyboard_button) + { + case SDLK_KP8: + case SDLK_UP: + new_btn = BUTTON_PREV; + break; + + case SDLK_KP2: + case SDLK_DOWN: + new_btn = BUTTON_NEXT; + break; + + case SDLK_KP5: + case SDLK_RETURN: + case SDLK_SPACE: + new_btn = BUTTON_PLAY; + break; + + case SDLK_ESCAPE: + new_btn = BUTTON_POWER; + break; + + case SDLK_KP_PLUS: + case SDLK_EQUALS: + new_btn = BUTTON_VOL_UP; + break; + + case SDLK_KP_MINUS: + case SDLK_MINUS: + new_btn = BUTTON_VOL_DOWN; + break; + } + return new_btn; +} + +struct button_map bm[] = { + { SDLK_KP_PLUS, 426, 140, 40, "Volume +" }, + { SDLK_KP_MINUS, 426, 180, 40, "Volume -" }, + { SDLK_SPACE, 0, 244, 40, "Play" }, + { SDLK_UP, 0, 133, 40, "Previous" }, + { SDLK_DOWN, 0, 357, 40, "Next" }, + { 0, 0, 0, 0, "None" } +}; diff --git a/wps/AUTHORS b/wps/AUTHORS index 4f0d852286..0afa5b9896 100644 --- a/wps/AUTHORS +++ b/wps/AUTHORS @@ -16,6 +16,7 @@ Cabbie v2.0: Johannes Voggenthaler Jonathan Gordon Keith Perri + Marc Aarts Marc Guay Marcin Bukat Marianne Arnold diff --git a/wps/WPSLIST b/wps/WPSLIST index 70970dee58..efb1030585 100644 --- a/wps/WPSLIST +++ b/wps/WPSLIST @@ -82,6 +82,7 @@ RSBS: no wps.800x480x(16|24): cabbiev2.800x480x16.wps wps.480x800x(16|24): cabbiev2.480x800x16.wps wps.400x240x(16|24): cabbiev2.400x240x16.wps +wps.360x400x16: cabbiev2.360x400x16.wps wps.320x480x(16|24): cabbiev2.320x480x16.wps wps.320x240x(16|24|32): cabbiev2.320x240x16.wps wps.240x400x(16|24): cabbiev2.240x400x16.wps @@ -111,6 +112,7 @@ fms.128x128x2: cabbiev2-128x128x2.fms Font.800x480x(16|24): 35-Adobe-Helvetica.fnt Font.480x800x(16|24): 35-Adobe-Helvetica.fnt Font.400x240x(16|24): 15-Adobe-Helvetica.fnt +Font.360x400x16: 18-Adobe-Helvetica.fnt Font.320x480x(16|24): 27-Adobe-Helvetica.fnt Font.320x240x(16|24): 15-Adobe-Helvetica.fnt Font.240x400x(16|24): 16-Adobe-Helvetica.fnt @@ -144,6 +146,7 @@ filetype colours: - backdrop.800x480x(16|24): backdrops/cabbiev2.800x480x16.bmp backdrop.480x800x(16|24): backdrops/cabbiev2.480x800x16.bmp backdrop.400x240x(16|24): backdrops/cabbiev2.400x240x16.bmp +backdrop.360x400x16: backdrops/cabbiev2.360x400x16.bmp backdrop.320x480x(16|24): backdrops/cabbiev2.320x480x16.bmp backdrop.320x240x(16|24): backdrops/cabbiev2.320x240x16.bmp backdrop.128x128x(16|24): backdrops/cabbiev2.128x128x16.bmp @@ -170,6 +173,7 @@ selector type..+x2: bar (inverse) iconset.800x480x(16|24): icons/tango_icons.32x32.bmp iconset.480x800x(16|24): icons/tango_icons.32x32.bmp iconset.400x240x(16|24): icons/tango_icons.16x16.bmp +iconset.360x400x16: icons/tango_icons.32x32.bmp iconset.320x480x(16|24): icons/tango_icons.24x24.bmp iconset.320x240x(16|24|32): icons/tango_icons.16x16.bmp iconset.128x128x(16|24): icons/tango_icons.12x12.bmp @@ -189,6 +193,7 @@ iconset..+x2: icons/tango_small_mono.bmp viewers iconset.800x480x(16|24): icons/tango_icons_viewers.32x32.bmp viewers iconset.480x800x(16|24): icons/tango_icons_viewers.32x32.bmp viewers iconset.400x240x(16|24): icons/tango_icons_viewers.16x16.bmp +viewers iconset.360x400x16: icons/tango_icons_viewers.32x32.bmp viewers iconset.320x480x(16|24): icons/tango_icons_viewers.24x24.bmp viewers iconset.320x240x(16|24): icons/tango_icons_viewers.16x16.bmp viewers iconset.128x128x(16|24): icons/tango_icons_viewers.12x12.bmp diff --git a/wps/cabbiev2.360x400x16.wps b/wps/cabbiev2.360x400x16.wps new file mode 100644 index 0000000000..163d749e50 --- /dev/null +++ b/wps/cabbiev2.360x400x16.wps @@ -0,0 +1,81 @@ +# Cabbie v2.0 +# (C) 2007-2012 The Authors (see /rockbox/wps/AUTHORS) +# Derived from "cabbie" (C) Yohann Misquitta +# +# Disable Status Bar +%wd +# +# Load Backdrop +%X(wpsbackdrop-360x400x16.bmp) +# +# Preload Images +%xl(A,lock-360x400x16.bmp,0,0,2) +%xl(B,battery-360x400x16.bmp,0,0,10) +%xl(C,volume-360x400x16.bmp,0,0,10) +%xl(D,shuffle-360x400x16.bmp,0,0) +%xl(E,repeat-360x400x16.bmp,0,0,4) +%xl(F,playmode-360x400x16.bmp,0,0,5) +# +# Album Art/Info Viewport Conditional +%?C<%Vd(a)|%Vd(b)> +# +# Progress Bar +%V(33,316,300,20,-) +%pb(0,0,-,20,pb-360x400x16.bmp) +# +# Hold +%V(16,365,38,29,-) +%?mh<%xd(Aa)|%xd(Ab)> +# +# Battery +%V(69,365,66,29,-) +%?bp<%?bc<%xd(Ba)|%xd(Bb)>|%?bl<|%xd(Bc)|%xd(Bd)|%xd(Be)|%xd(Bf)|%xd(Bg)|%xd(Bh)|%xd(Bi)|%xd(Bj)>> +# +# Volume +%V(147,365,50,29,-) +%?pv<%xd(Ca)|%xd(Cb)|%xd(Cc)|%xd(Cd)|%xd(Ce)|%xd(Cf)|%xd(Cg)|%xd(Ch)|%xd(Ci)|%xd(Cj)> +# +# Shuffle +%V(208,365,55,29,-) +%?ps<%xd(D)> +# +# Repeat +%V(273,365,27,29,-) +%?mm<|%xd(Ea)|%xd(Eb)|%xd(Ec)|%xd(Ed)> +# +# Playmode +%V(309,365,36,29,-) +%?mp<%xd(Fa)|%xd(Fb)|%xd(Fc)|%xd(Fd)|%xd(Fe)> +# +# Time Elapsed/Remaining +%V(32,339,300,20,-) +%al%pc%ac%?Sr<%pe %Sx(of) %pp|%pp %Sx(of) %pe>%ar%pr +# +# Album Art +%ax%Vl(a,82,38,195,161,-) +%Cl(0,0,195,161,c,c) +%Cd +# +# Track Info - Album Art +%ax%Vl(a,0,206,-,98,1) +%s%ac%?it<%it|%fn> +%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>> +%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>> + +%s%ac%Sx(Next:) %?Ia<%Ia|%?IA<%IA|%?D(2)<%D(2)|%(root%)>>> - %?It<%It|%Fn> +# +# Track Info - No Album Art +%Vl(b,0,56,-,247,1) +%s%ac%?it<%it|%fn> +%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>> +%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>> +%ac%?iy<%iy|> + +%ac%?ig<%ig|> +%ac%?fv<%(vbr%) |>%fb kbit/s %fc + + +%ac%Sx(Next Track:) +%ac%s%?It<%It|%Fn> +%s%ac%?Ia<%Ia|%?IA<%IA|%?D(2)<%D(2)|%(root%)>>> +%s%ac%?Id<%Id|%?D(1)<%D(1)|%(root%)>> diff --git a/wps/cabbiev2/battery-360x400x16.bmp b/wps/cabbiev2/battery-360x400x16.bmp new file mode 100644 index 0000000000..d00b4c1c5d Binary files /dev/null and b/wps/cabbiev2/battery-360x400x16.bmp differ diff --git a/wps/cabbiev2/lock-360x400x16.bmp b/wps/cabbiev2/lock-360x400x16.bmp new file mode 100644 index 0000000000..70c419e875 Binary files /dev/null and b/wps/cabbiev2/lock-360x400x16.bmp differ diff --git a/wps/cabbiev2/pb-360x400x16.bmp b/wps/cabbiev2/pb-360x400x16.bmp new file mode 100644 index 0000000000..6b5884d059 Binary files /dev/null and b/wps/cabbiev2/pb-360x400x16.bmp differ diff --git a/wps/cabbiev2/playmode-360x400x16.bmp b/wps/cabbiev2/playmode-360x400x16.bmp new file mode 100644 index 0000000000..148376b127 Binary files /dev/null and b/wps/cabbiev2/playmode-360x400x16.bmp differ diff --git a/wps/cabbiev2/repeat-360x400x16.bmp b/wps/cabbiev2/repeat-360x400x16.bmp new file mode 100644 index 0000000000..f6fb08d909 Binary files /dev/null and b/wps/cabbiev2/repeat-360x400x16.bmp differ diff --git a/wps/cabbiev2/shuffle-360x400x16.bmp b/wps/cabbiev2/shuffle-360x400x16.bmp new file mode 100644 index 0000000000..1b16153176 Binary files /dev/null and b/wps/cabbiev2/shuffle-360x400x16.bmp differ diff --git a/wps/cabbiev2/volume-360x400x16.bmp b/wps/cabbiev2/volume-360x400x16.bmp new file mode 100644 index 0000000000..7d8b8e40e8 Binary files /dev/null and b/wps/cabbiev2/volume-360x400x16.bmp differ diff --git a/wps/cabbiev2/wpsbackdrop-360x400x16.bmp b/wps/cabbiev2/wpsbackdrop-360x400x16.bmp new file mode 100644 index 0000000000..aa7399bd53 Binary files /dev/null and b/wps/cabbiev2/wpsbackdrop-360x400x16.bmp differ