New port: Shanling Q1 native

- Audio playback works
- Touchscreen and buttons work
- Bootloader works and is capable of dual boot
- Plugins are working
- Cabbiev2 theme has been ported
- Stable for general usage

Thanks to Marc Aarts for porting Cabbiev2 and plugin bitmaps.

There's a few minor known issues:

- Bootloader must be installed manually using 'usbboot' as there is
  no support in jztool yet.

- Keymaps may be lacking, need further testing and feedback.

- Some plugins may not be fully adapted to the screen size and could
  benefit from further tweaking.

- LCD shows abnormal effects under some circumstances: for example,
  after viewing a mostly black screen an afterimage appears briefly
  when going back to a brightly-lit screen. Sudden power-off without
  proper shutdown of the backlight causes a "dissolving" effect.

- CW2015 battery reporting driver is buggy, and disabled for now.
  Battery reporting is currently voltage-based using the AXP192.

Change-Id: I635e83f02a880192c5a82cb0861ad3a61c137c3a
This commit is contained in:
Aidan MacDonald 2021-05-23 17:30:58 +01:00
parent 3abb7c5dd5
commit 4c60bc9e68
110 changed files with 2843 additions and 15 deletions

View File

@ -298,4 +298,6 @@ keymaps/keymap-fiiom3klinux.c
keymaps/keymap-fiiom3k.c keymaps/keymap-fiiom3k.c
#elif CONFIG_KEYPAD == EROSQ_PAD #elif CONFIG_KEYPAD == EROSQ_PAD
keymaps/keymap-erosq.c keymaps/keymap-erosq.c
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
keymaps/keymap-shanlingq1.c
#endif #endif

View File

@ -182,12 +182,12 @@ depth_3d
#endif #endif
/* This should be AUDIOHW_HAVE_FILTER_ROLL_OFF but that is only defined later */ /* 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 filter_roll_off
#endif #endif
/* This should be AUDIOHW_HAVE_POWER_MODE but that is not defined yet */ /* 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 dac_power_mode
#endif #endif
@ -195,6 +195,10 @@ dac_power_mode
es9018 es9018
#endif #endif
#if defined(HAVE_ES9218)
es9218
#endif
/* These features are only used by the manual so they won't break binary /* These features are only used by the manual so they won't break binary
* compatibility * compatibility
*/ */

View File

@ -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;
}
}

View File

@ -12204,6 +12204,142 @@
es9018: "Bypass" es9018: "Bypass"
</voice> </voice>
</phrase> </phrase>
<phrase>
id: LANG_FILTER_LINEAR_FAST
desc: in sound settings
user: core
<source>
*: none
es9218: "Linear Fast"
</source>
<dest>
*: none
es9218: "Linear Fast"
</dest>
<voice>
*: none
es9218: "Linear Fast"
</voice>
</phrase>
<phrase>
id: LANG_FILTER_LINEAR_SLOW
desc: in sound settings
user: core
<source>
*: none
es9218: "Linear Slow"
</source>
<dest>
*: none
es9218: "Linear Slow"
</dest>
<voice>
*: none
es9218: "Linear Slow"
</voice>
</phrase>
<phrase>
id: LANG_FILTER_MINIMUM_FAST
desc: in sound settings
user: core
<source>
*: none
es9218: "Minimum Fast"
</source>
<dest>
*: none
es9218: "Minimum Fast"
</dest>
<voice>
*: none
es9218: "Minimum Fast"
</voice>
</phrase>
<phrase>
id: LANG_FILTER_MINIMUM_SLOW
desc: in sound settings
user: core
<source>
*: none
es9218: "Minimum Slow"
</source>
<dest>
*: none
es9218: "Minimum Slow"
</dest>
<voice>
*: none
es9218: "Minimum Slow"
</voice>
</phrase>
<phrase>
id: LANG_FILTER_APODIZING_1
desc: in sound settings
user: core
<source>
*: none
es9218: "Apodizing type 1"
</source>
<dest>
*: none
es9218: "Apodizing type 1"
</dest>
<voice>
*: none
es9218: "Apodizing type 1"
</voice>
</phrase>
<phrase>
id: LANG_FILTER_APODIZING_2
desc: in sound settings
user: core
<source>
*: none
es9218: "Apodizing type 2"
</source>
<dest>
*: none
es9218: "Apodizing type 2"
</dest>
<voice>
*: none
es9218: "Apodizing type 2"
</voice>
</phrase>
<phrase>
id: LANG_FILTER_HYBRID_FAST
desc: in sound settings
user: core
<source>
*: none
es9218: "Hybrid Fast"
</source>
<dest>
*: none
es9218: "Hybrid Fast"
</dest>
<voice>
*: none
es9218: "Hybrid Fast"
</voice>
</phrase>
<phrase>
id: LANG_FILTER_BRICK_WALL
desc: in sound settings
user: core
<source>
*: none
es9218: "Brick Wall"
</source>
<dest>
*: none
es9218: "Brick Wall"
</dest>
<voice>
*: none
es9218: "Brick Wall"
</voice>
</phrase>
<phrase> <phrase>
id: LANG_DAC_POWER_MODE id: LANG_DAC_POWER_MODE
desc: in sound settings desc: in sound settings
@ -12211,14 +12347,17 @@
<source> <source>
*: none *: none
dac_power_mode: "DAC's power mode" dac_power_mode: "DAC's power mode"
es9218: "DAC's output level"
</source> </source>
<dest> <dest>
*: none *: none
dac_power_mode: "DAC's power mode" dac_power_mode: "DAC's power mode"
es9218: "DAC's output level"
</dest> </dest>
<voice> <voice>
*: none *: none
dac_power_mode: "DAC's power mode" dac_power_mode: "DAC's power mode"
es9218: "DAC's output level"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -12228,14 +12367,17 @@
<source> <source>
*: none *: none
dac_power_mode: "High performance" dac_power_mode: "High performance"
es9218: "High Gain (2 Vrms)"
</source> </source>
<dest> <dest>
*: none *: none
dac_power_mode: "High performance" dac_power_mode: "High performance"
es9218: "High Gain (2 Vrms)"
</dest> </dest>
<voice> <voice>
*: none *: none
dac_power_mode: "High performance" dac_power_mode: "High performance"
es9218: "High Gain (2 Vrms)"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -12245,14 +12387,17 @@
<source> <source>
*: none *: none
dac_power_mode: "Save battery" dac_power_mode: "Save battery"
es9218: "Low Gain (1 Vrms)"
</source> </source>
<dest> <dest>
*: none *: none
dac_power_mode: "Save battery" dac_power_mode: "Save battery"
es9218: "Low Gain (1 Vrms)"
</dest> </dest>
<voice> <voice>
*: none *: none
dac_power_mode: "Save battery" dac_power_mode: "Save battery"
es9218: "Low Gain (1 Vrms)"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>

View File

@ -234,6 +234,9 @@
#define BATTERY_ON_TXT "Play" #define BATTERY_ON_TXT "Play"
#define BATTERY_OFF_TXT "Power" #define BATTERY_OFF_TXT "Power"
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error "No keymap defined!" #error "No keymap defined!"
#endif #endif

View File

@ -19,7 +19,8 @@ bubbles_bubble.138x110x1.bmp
((LCD_WIDTH == 176) && (LCD_HEIGHT == 220)) ((LCD_WIDTH == 176) && (LCD_HEIGHT == 220))
bubbles_bubble.220x176x1.bmp bubbles_bubble.220x176x1.bmp
#elif ((LCD_WIDTH == 320) && (LCD_HEIGHT == 240)) || \ #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 bubbles_bubble.320x240x1.bmp
#elif ((LCD_WIDTH == 640) && (LCD_HEIGHT == 480)) || \ #elif ((LCD_WIDTH == 640) && (LCD_HEIGHT == 480)) || \
((LCD_WIDTH == 480) && (LCD_HEIGHT == 640)) ((LCD_WIDTH == 480) && (LCD_HEIGHT == 640))

View File

@ -158,6 +158,9 @@ jackpot_slots.30x420x1.bmp
((LCD_WIDTH >= 480) && (LCD_HEIGHT >= 640)) ((LCD_WIDTH >= 480) && (LCD_HEIGHT >= 640))
bubbles_emblem.640x480x16.bmp bubbles_emblem.640x480x16.bmp
bubbles_background.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) #elif (LCD_WIDTH >= 320) && (LCD_HEIGHT >= 240)
bubbles_emblem.320x240x16.bmp bubbles_emblem.320x240x16.bmp
bubbles_background.320x240x16.bmp bubbles_background.320x240x16.bmp
@ -388,7 +391,9 @@ invadrox_shield.22x16x16.bmp
invadrox_ufo.16x7x16.bmp invadrox_ufo.16x7x16.bmp
invadrox_ufo_explode.21x8x16.bmp invadrox_ufo_explode.21x8x16.bmp
invadrox_numbers.50x7x16.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 invadrox_background.320x240x16.bmp
#elif LCD_WIDTH == 240 #elif LCD_WIDTH == 240
invadrox_background.240x320x16.bmp invadrox_background.240x320x16.bmp
@ -457,6 +462,8 @@ jewels.220x176x16.bmp
jewels.320x240x16.bmp jewels.320x240x16.bmp
#elif (LCD_WIDTH == 320) && (LCD_HEIGHT == 240) #elif (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
jewels.320x240x16.bmp jewels.320x240x16.bmp
#elif (LCD_WIDTH == 360) && (LCD_HEIGHT == 400)
jewels.360x400x16.bmp
#elif ((LCD_WIDTH == 640) && (LCD_HEIGHT == 480)) || \ #elif ((LCD_WIDTH == 640) && (LCD_HEIGHT == 480)) || \
((LCD_WIDTH == 480) && (LCD_HEIGHT == 640)) ((LCD_WIDTH == 480) && (LCD_HEIGHT == 640))
jewels.640x480x16.bmp jewels.640x480x16.bmp
@ -546,6 +553,8 @@ puzzles_cursor.11x16x24.bmp
#if LCD_DEPTH >= 16 /* colour versions*/ #if LCD_DEPTH >= 16 /* colour versions*/
#if (LCD_WIDTH == 640) && (LCD_HEIGHT == 480) #if (LCD_WIDTH == 640) && (LCD_HEIGHT == 480)
rockblox_background.640x480x16.bmp rockblox_background.640x480x16.bmp
#elif (LCD_WIDTH == 360) && (LCD_HEIGHT == 400)
rockblox_background.360x400x16.bmp
#elif (LCD_WIDTH >= 320) && (LCD_HEIGHT >= 240) #elif (LCD_WIDTH >= 320) && (LCD_HEIGHT >= 240)
rockblox_background.320x240x16.bmp rockblox_background.320x240x16.bmp
#elif (LCD_WIDTH == 240) && (LCD_HEIGHT >= 320) #elif (LCD_WIDTH == 240) && (LCD_HEIGHT >= 320)
@ -603,6 +612,12 @@ snake2_header2.640x480x16.bmp
snake2_left.640x480x16.bmp snake2_left.640x480x16.bmp
snake2_right.640x480x16.bmp snake2_right.640x480x16.bmp
snake2_bottom.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) #elif (LCD_WIDTH >= 320) && (LCD_HEIGHT >= 240) && (LCD_DEPTH >= 16)
snake2_header1.320x240x16.bmp snake2_header1.320x240x16.bmp
snake2_header2.320x240x16.bmp snake2_header2.320x240x16.bmp
@ -874,7 +889,8 @@ superdom_boarditems.176x132x16.bmp
#elif (LCD_WIDTH == 320 && LCD_HEIGHT == 240) #elif (LCD_WIDTH == 320 && LCD_HEIGHT == 240)
superdom_boarditems.320x240x16.bmp superdom_boarditems.320x240x16.bmp
#elif ((LCD_WIDTH == 240) && (LCD_HEIGHT == 320)) || \ #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 superdom_boarditems.240x320x16.bmp
#elif (LCD_WIDTH == 480 && LCD_HEIGHT == 640) #elif (LCD_WIDTH == 480 && LCD_HEIGHT == 640)
superdom_boarditems.480x640x16.bmp superdom_boarditems.480x640x16.bmp
@ -911,6 +927,8 @@ sliding_puzzle.132x132x16.bmp
sliding_puzzle.176x176x16.bmp sliding_puzzle.176x176x16.bmp
#elif SMALLER_DIMENSION <= 240 #elif SMALLER_DIMENSION <= 240
sliding_puzzle.240x240x16.bmp sliding_puzzle.240x240x16.bmp
#elif SMALLER_DIMENSION <= 360
sliding_puzzle.360x360x16.bmp
#elif SMALLER_DIMENSION <= 480 #elif SMALLER_DIMENSION <= 480
sliding_puzzle.480x480x16.bmp sliding_puzzle.480x480x16.bmp
#endif #endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -607,6 +607,10 @@ enum {
#define BJACK_RIGHT BUTTON_RIGHT #define BJACK_RIGHT BUTTON_RIGHT
#define BJACK_LEFT BUTTON_LEFT #define BJACK_LEFT BUTTON_LEFT
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
#define BJACK_QUIT BUTTON_POWER
#define BJACK_QUIT_NAME "QUIT"
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -350,6 +350,9 @@ CONFIG_KEYPAD == SANSA_CONNECT_PAD
#define UP BUTTON_UP #define UP BUTTON_UP
#define DOWN BUTTON_DOWN #define DOWN BUTTON_DOWN
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
#define QUIT BUTTON_POWER
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -120,6 +120,17 @@ enum {
#define XOFS 128 #define XOFS 128
#define MAX_FPS 40 #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) */ /* 22x22 bubbles (iPod Video) */
#elif (LCD_HEIGHT == 240) && (LCD_WIDTH == 320) #elif (LCD_HEIGHT == 240) && (LCD_WIDTH == 320)
#define XOFS 72 #define XOFS 72

View File

@ -533,6 +533,9 @@ F3: equal to "="
#define CALCULATOR_CALC BUTTON_MENU #define CALCULATOR_CALC BUTTON_MENU
#define CALCULATOR_CLEAR BUTTON_BACK #define CALCULATOR_CLEAR BUTTON_BACK
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
#define CALCULATOR_QUIT BUTTON_POWER
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -421,6 +421,9 @@
#define CALENDAR_NEXT_MONTH BUTTON_VOL_UP #define CALENDAR_NEXT_MONTH BUTTON_VOL_UP
#define CALENDAR_PREV_MONTH BUTTON_VOL_DOWN #define CALENDAR_PREV_MONTH BUTTON_VOL_DOWN
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error "No keypad setting." #error "No keypad setting."
#endif #endif

View File

@ -581,6 +581,9 @@
#define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT) #define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT)
#define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT) #define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT)
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -395,6 +395,9 @@
#define CHC_SETTINGS_OK BUTTON_SELECT #define CHC_SETTINGS_OK BUTTON_SELECT
#define CHC_SETTINGS_CANCEL BUTTON_POWER #define CHC_SETTINGS_CANCEL BUTTON_POWER
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
#define CHC_QUIT BUTTON_POWER
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -1291,6 +1291,9 @@ CONFIG_KEYPAD == MROBE500_PAD
#define CHIP8_KEY6 BUTTON_RIGHT #define CHIP8_KEY6 BUTTON_RIGHT
#define CHIP8_KEY8 BUTTON_BACK #define CHIP8_KEY8 BUTTON_BACK
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -316,6 +316,9 @@
#define CLIX_BUTTON_RIGHT BUTTON_RIGHT #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
#define CLIX_BUTTON_CLICK BUTTON_SELECT #define CLIX_BUTTON_CLICK BUTTON_SELECT
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
#define CLIX_BUTTON_QUIT BUTTON_POWER
#else #else
#error "no keymap" #error "no keymap"
#endif #endif

View File

@ -400,6 +400,9 @@
#define CUBE_PAUSE BUTTON_PLAY #define CUBE_PAUSE BUTTON_PLAY
#define CUBE_HIGHSPEED BUTTON_BACK #define CUBE_HIGHSPEED BUTTON_BACK
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -614,6 +614,10 @@ void I_ShutdownGraphics(void)
#define DOOMBUTTON_WEAPON BUTTON_VOL_UP #define DOOMBUTTON_WEAPON BUTTON_VOL_UP
#define DOOMBUTTON_MAP BUTTON_VOL_DOWN #define DOOMBUTTON_MAP BUTTON_VOL_DOWN
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
#define DOOMBUTTON_ESC BUTTON_POWER
#define DOOMBUTTON_MAP BUTTON_PREV
#else #else
#error Keymap not defined! #error Keymap not defined!
#endif #endif

View File

@ -496,6 +496,9 @@
#define FLIPIT_STEP_BY_STEP BUTTON_VOL_UP #define FLIPIT_STEP_BY_STEP BUTTON_VOL_UP
#define FLIPIT_TOGGLE BUTTON_SELECT #define FLIPIT_TOGGLE BUTTON_SELECT
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -504,6 +504,9 @@
#define FRACTAL_PRECISION_DEC BUTTON_BACK #define FRACTAL_PRECISION_DEC BUTTON_BACK
#define FRACTAL_RESET BUTTON_PLAY #define FRACTAL_RESET BUTTON_PLAY
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
#define FRACTAL_QUIT BUTTON_POWER
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -539,6 +539,9 @@
#define IMGVIEW_MENU BUTTON_POWER #define IMGVIEW_MENU BUTTON_POWER
#define IMGVIEW_SLIDE_SHOW BUTTON_PLAY #define IMGVIEW_SLIDE_SHOW BUTTON_PLAY
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -296,6 +296,9 @@ CONFIG_KEYPAD == MROBE500_PAD
#define RIGHT BUTTON_RIGHT #define RIGHT BUTTON_RIGHT
#define FIRE BUTTON_SELECT #define FIRE BUTTON_SELECT
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error INVADROX: Unsupported keypad #error INVADROX: Unsupported keypad
#endif #endif
@ -648,6 +651,23 @@ CONFIG_KEYPAD == MROBE500_PAD
#define LIVES_X 8 #define LIVES_X 8
#define MAX_Y 15 #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 #else
#error INVADROX: Unsupported LCD type #error INVADROX: Unsupported LCD type

View File

@ -377,6 +377,9 @@ CONFIG_KEYPAD == MROBE500_PAD
#define HK_SELECT "SELECT" #define HK_SELECT "SELECT"
#define HK_CANCEL "BACK" #define HK_CANCEL "BACK"
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -255,6 +255,15 @@
#define BTN_FIRE BUTTON_SELECT #define BTN_FIRE BUTTON_SELECT
#define BTN_PAUSE BUTTON_POWER #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 #else
#error Unsupported keypad #error Unsupported keypad
#endif #endif
@ -272,7 +281,8 @@
#elif (CONFIG_KEYPAD != COWON_D2_PAD) && \ #elif (CONFIG_KEYPAD != COWON_D2_PAD) && \
(CONFIG_KEYPAD != DX50_PAD) && \ (CONFIG_KEYPAD != DX50_PAD) && \
(CONFIG_KEYPAD != ONDAVX777_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_FIRE BUTTON_BOTTOMLEFT
#define BTN_PAUSE BUTTON_TOPLEFT #define BTN_PAUSE BUTTON_TOPLEFT
#endif #endif

View File

@ -499,6 +499,8 @@ const struct button_mapping pla_main_ctx[] =
{PLA_SELECT, BUTTON_SELECT, BUTTON_NONE}, {PLA_SELECT, BUTTON_SELECT, BUTTON_NONE},
{PLA_SELECT_REL, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT}, {PLA_SELECT_REL, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT},
{PLA_SELECT_REPEAT, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_NONE}, {PLA_SELECT_REPEAT, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_NONE},
#elif (CONFIG_KEYPAD == SHANLING_Q1_PAD)
{PLA_EXIT, BUTTON_POWER, BUTTON_NONE},
#else #else
# ifndef HAVE_TOUCHSCREEN # ifndef HAVE_TOUCHSCREEN
# error pluginlib_actions: No actions defined # error pluginlib_actions: No actions defined

View File

@ -325,6 +325,9 @@
#define MIDI_VOL_DOWN BUTTON_VOL_DOWN #define MIDI_VOL_DOWN BUTTON_VOL_DOWN
#define MIDI_PLAYPAUSE BUTTON_PLAY #define MIDI_PLAYPAUSE BUTTON_PLAY
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -443,6 +443,9 @@ CONFIG_KEYPAD == MROBE500_PAD
# define MINESWP_DISCOVER (BUTTON_SELECT|BUTTON_REPEAT) # define MINESWP_DISCOVER (BUTTON_SELECT|BUTTON_REPEAT)
# define MINESWP_INFO BUTTON_MENU # define MINESWP_INFO BUTTON_MENU
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -2580,6 +2580,9 @@ CONFIG_KEYPAD == MROBE500_PAD
#define MP3ENC_DONE BUTTON_POWER #define MP3ENC_DONE BUTTON_POWER
#define MP3ENC_SELECT BUTTON_SELECT #define MP3ENC_SELECT BUTTON_SELECT
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -354,6 +354,9 @@ struct mpeg_settings settings;
#define MPEG_START_TIME_DOWN BUTTON_DOWN #define MPEG_START_TIME_DOWN BUTTON_DOWN
#define MPEG_START_TIME_EXIT BUTTON_POWER #define MPEG_START_TIME_EXIT BUTTON_POWER
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
#define MPEG_START_TIME_EXIT BUTTON_POWER
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -486,6 +486,9 @@ CONFIG_KEYPAD == SANSA_M200_PAD
#define MPEG_RW BUTTON_LEFT #define MPEG_RW BUTTON_LEFT
#define MPEG_FF BUTTON_RIGHT #define MPEG_FF BUTTON_RIGHT
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -548,6 +548,9 @@
#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP #define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN #define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -398,6 +398,16 @@
#define PACMAN_1UP BUTTON_VOL_UP #define PACMAN_1UP BUTTON_VOL_UP
#define PACMAN_COIN BUTTON_PLAY #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 #else
#error Keymap not defined! #error Keymap not defined!

View File

@ -711,6 +711,9 @@ CONFIG_KEYPAD == MROBE500_PAD
#define LVL_UP_TEXT "VOL+" #define LVL_UP_TEXT "VOL+"
#define LVL_DOWN_TEXT "VOL-" #define LVL_DOWN_TEXT "VOL-"
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error "Unsupported keymap!" #error "Unsupported keymap!"
#endif #endif

View File

@ -325,6 +325,9 @@ CONFIG_KEYPAD == MROBE500_PAD
#define PONG_RIGHT_UP BUTTON_BACK #define PONG_RIGHT_UP BUTTON_BACK
#define PONG_RIGHT_DOWN BUTTON_RIGHT #define PONG_RIGHT_DOWN BUTTON_RIGHT
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -361,6 +361,9 @@
#define REVERSI_BUTTON_MAKE_MOVE BUTTON_SELECT #define REVERSI_BUTTON_MAKE_MOVE BUTTON_SELECT
#define REVERSI_BUTTON_MENU BUTTON_MENU #define REVERSI_BUTTON_MENU BUTTON_MENU
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -465,6 +465,9 @@
#define ROCKBLOX_DROP BUTTON_PLAY #define ROCKBLOX_DROP BUTTON_PLAY
#define ROCKBLOX_RESTART BUTTON_BACK #define ROCKBLOX_RESTART BUTTON_BACK
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif
@ -534,6 +537,22 @@
#define LEVEL_Y 142 #define LEVEL_Y 142
#define LINES_Y 218 #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) #elif (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
#define BLOCK_WIDTH 12 #define BLOCK_WIDTH 12

View File

@ -468,6 +468,9 @@ static void setoptions (void)
options.SELECT = BUTTON_VOL_UP; options.SELECT = BUTTON_VOL_UP;
options.MENU = BUTTON_POWER; options.MENU = BUTTON_POWER;
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No Keymap Defined! #error No Keymap Defined!
#endif #endif

View File

@ -404,6 +404,9 @@
#define ROCKPAINT_LEFT BUTTON_LEFT #define ROCKPAINT_LEFT BUTTON_LEFT
#define ROCKPAINT_RIGHT BUTTON_RIGHT #define ROCKPAINT_RIGHT BUTTON_RIGHT
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error "Please define keys for this keypad" #error "Please define keys for this keypad"
#endif #endif

View File

@ -357,6 +357,9 @@ CONFIG_KEYPAD == MROBE500_PAD
#define PUZZLE_SHUFFLE BUTTON_BACK #define PUZZLE_SHUFFLE BUTTON_BACK
#define PUZZLE_PICTURE BUTTON_PLAY #define PUZZLE_PICTURE BUTTON_PLAY
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -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_DOWN BUTTON_DOWN
#define SNAKE_PLAYPAUSE BUTTON_PLAY #define SNAKE_PLAYPAUSE BUTTON_PLAY
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -62,6 +62,18 @@ Head and Tail are stored
#define TOP_X4 548 /* x-coord of the lowerright item (hi-score) */ #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_Y1 8 /* y-coord of the top row of items */
#define TOP_Y2 50 /* y-coord of the bottom 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) #elif (LCD_WIDTH >= 320) && (LCD_HEIGHT >= 240)
#define MULTIPLIER 10 /*Modifier for porting on other screens*/ #define MULTIPLIER 10 /*Modifier for porting on other screens*/
#define MODIFIER_1 10 #define MODIFIER_1 10
@ -446,6 +458,9 @@ CONFIG_KEYPAD == MROBE500_PAD
#define SNAKE2_PLAYPAUSE BUTTON_PLAY #define SNAKE2_PLAYPAUSE BUTTON_PLAY
#define SNAKE2_PLAYPAUSE_TEXT "PLAY" #define SNAKE2_PLAYPAUSE_TEXT "PLAY"
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -696,6 +696,9 @@
#define BUTTON_SAVE BUTTON_BACK #define BUTTON_SAVE BUTTON_BACK
#define BUTTON_SAVE_NAME "BACK" #define BUTTON_SAVE_NAME "BACK"
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -741,6 +741,9 @@ CONFIG_KEYPAD == MROBE500_PAD
# define HK_CUR2STACK "HOLD SELECT" # define HK_CUR2STACK "HOLD SELECT"
# define HK_REM2STACK "VOL+" # define HK_REM2STACK "VOL+"
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
# define SOL_QUIT BUTTON_POWER
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -372,6 +372,9 @@
#define AST_RIGHT BUTTON_RIGHT #define AST_RIGHT BUTTON_RIGHT
#define AST_FIRE BUTTON_PLAY #define AST_FIRE BUTTON_PLAY
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -668,6 +668,10 @@
#define STAR_LEVEL_DOWN_NAME "VOL-" #define STAR_LEVEL_DOWN_NAME "VOL-"
#define STAR_LEVEL_REPEAT_NAME "BACK" #define STAR_LEVEL_REPEAT_NAME "BACK"
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
#define STAR_QUIT BUTTON_POWER
#define STAR_QUIT_NAME "POWER"
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -280,7 +280,7 @@ function arrangeButtons(btns)
end end
end end
rb.touchscreen_set_mode(rb.TOUCHSCREEN_POINT) rb.touchscreen_mode(rb.TOUCHSCREEN_POINT)
LapsView:init() LapsView:init()

View File

@ -460,6 +460,9 @@
#define SUDOKU_BUTTON_MENU BUTTON_MENU #define SUDOKU_BUTTON_MENU BUTTON_MENU
#define SUDOKU_BUTTON_POSSIBLE BUTTON_BACK #define SUDOKU_BUTTON_POSSIBLE BUTTON_BACK
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -37,12 +37,17 @@
#elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD #elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD
#define TOUCHSCREEN_QUIT BUTTON_POWER #define TOUCHSCREEN_QUIT BUTTON_POWER
#define TOUCHSCREEN_TOGGLE BUTTON_MENU #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) #elif (CONFIG_KEYPAD == ANDROID_PAD)
#define TOUCHSCREEN_QUIT BUTTON_BACK #define TOUCHSCREEN_QUIT BUTTON_BACK
#define TOUCHSCREEN_TOGGLE BUTTON_MENU #define TOUCHSCREEN_TOGGLE BUTTON_MENU
#elif (CONFIG_KEYPAD == SDL_PAD) #elif (CONFIG_KEYPAD == SDL_PAD)
#define TOUCHSCREEN_QUIT BUTTON_MIDLEFT #define TOUCHSCREEN_QUIT BUTTON_MIDLEFT
#define TOUCHSCREEN_TOGGLE BUTTON_CENTER #define TOUCHSCREEN_TOGGLE BUTTON_CENTER
#else
# error "No keymap defined!"
#endif #endif
/* plugin entry point */ /* plugin entry point */

View File

@ -572,6 +572,9 @@
#define TV_LINE_DOWN BUTTON_SCROLL_FWD #define TV_LINE_DOWN BUTTON_SCROLL_FWD
#define TV_BOOKMARK BUTTON_PLAY #define TV_BOOKMARK BUTTON_PLAY
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
#define TV_BOOKMARK BUTTON_PLAY
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -452,6 +452,9 @@
#define LABEL_MENU "MENU" #define LABEL_MENU "MENU"
#define LABEL_VOLUME "VOL+/VOL-" #define LABEL_VOLUME "VOL+/VOL-"
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif

View File

@ -407,6 +407,9 @@ CONFIG_KEYPAD == MROBE500_PAD
#define BTN_QUIT BUTTON_POWER #define BTN_QUIT BUTTON_POWER
#define BTN_STOPRESET BUTTON_BACK #define BTN_STOPRESET BUTTON_BACK
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error No keymap defined! #error No keymap defined!
#endif #endif
@ -492,7 +495,8 @@ CONFIG_KEYPAD == MROBE500_PAD
#define SPEED 4 #define SPEED 4
#define MAX_WORM_SEGMENTS 512 #define MAX_WORM_SEGMENTS 512
#elif ((LCD_WIDTH == 320) && (LCD_HEIGHT == 240)) || \ #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 FOOD_SIZE 7
#define ARGH_SIZE 8 #define ARGH_SIZE 8
#define SPEED 4 #define SPEED 4

View File

@ -351,6 +351,9 @@ CONFIG_KEYPAD == MROBE500_PAD
#define DOWN BUTTON_DOWN #define DOWN BUTTON_DOWN
#define PAUSE BUTTON_PLAY #define PAUSE BUTTON_PLAY
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error "No keymap defined!" #error "No keymap defined!"
#endif #endif

View File

@ -290,6 +290,9 @@
#define ZX_UP BUTTON_UP #define ZX_UP BUTTON_UP
#define ZX_DOWN BUTTON_DOWN #define ZX_DOWN BUTTON_DOWN
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else #else
#error Keymap not defined! #error Keymap not defined!

View File

@ -242,6 +242,9 @@ static const char graphic_numeric[] = "graphic,numeric";
#define DEFAULT_FONT_HEIGHT 12 #define DEFAULT_FONT_HEIGHT 12
#elif LCD_HEIGHT <= 320 #elif LCD_HEIGHT <= 320
#define DEFAULT_FONT_HEIGHT 15 #define DEFAULT_FONT_HEIGHT 15
#elif defined(SHANLING_Q1)
/* 16pt font looks pretty aliased & ugly */
#define DEFAULT_FONT_HEIGHT 18
#elif LCD_HEIGHT <= 400 #elif LCD_HEIGHT <= 400
#define DEFAULT_FONT_HEIGHT 16 #define DEFAULT_FONT_HEIGHT 16
#elif LCD_HEIGHT <= 480 && LCD_WIDTH < 800 #elif LCD_HEIGHT <= 480 && LCD_WIDTH < 800
@ -261,7 +264,7 @@ static const char graphic_numeric[] = "graphic,numeric";
#endif #endif
#ifdef HAVE_LCD_COLOR #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_ICONSET "tango_icons.32x32"
#define DEFAULT_VIEWERS_ICONSET "tango_icons_viewers.32x32" #define DEFAULT_VIEWERS_ICONSET "tango_icons_viewers.32x32"
#elif DEFAULT_FONT_HEIGHT >= 23 #elif DEFAULT_FONT_HEIGHT >= 23
@ -848,7 +851,11 @@ const struct settings_list settings[] = {
#ifdef AUDIOHW_HAVE_FILTER_ROLL_OFF #ifdef AUDIOHW_HAVE_FILTER_ROLL_OFF
CHOICE_SETTING(F_SOUNDSETTING, roll_off, LANG_FILTER_ROLL_OFF, 0, 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, "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)), 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) #elif defined(AUDIOHW_HAVE_SHORT_ROLL_OFF)

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 KiB

View File

@ -89,6 +89,6 @@ show_logo.c
#elif defined(SANSA_CONNECT) #elif defined(SANSA_CONNECT)
sansaconnect.c sansaconnect.c
show_logo.c show_logo.c
#elif defined(FIIO_M3K) #elif defined(FIIO_M3K) || defined(SHANLING_Q1)
x1000.c x1000.c
#endif #endif

View File

@ -66,6 +66,17 @@
# define BL_SELECT_NAME "PLAY" # define BL_SELECT_NAME "PLAY"
# define BL_QUIT_NAME "POWER" # define BL_QUIT_NAME "POWER"
# define BOOTBACKUP_FILE "/fiiom3k-boot.bin" # 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 #else
# error "Missing keymap!" # error "Missing keymap!"
#endif #endif

View File

@ -706,6 +706,7 @@ Caleb Connolly
Spencer Brennessel Spencer Brennessel
Dana Conrad Dana Conrad
Albert Song Albert Song
Marc Aarts
The libmad team The libmad team
The wavpack team The wavpack team

View File

@ -503,6 +503,8 @@ drivers/audio/pcm1792.c
drivers/audio/cs4398.c drivers/audio/cs4398.c
#elif defined (HAVE_ES9018) #elif defined (HAVE_ES9018)
drivers/audio/es9018.c drivers/audio/es9018.c
#elif defined (HAVE_ES9218)
drivers/audio/es9218.c
#endif /* defined(HAVE_*) */ #endif /* defined(HAVE_*) */
#else /* PLATFORM_HOSTED */ #else /* PLATFORM_HOSTED */
#if defined(SAMSUNG_YPR0) && defined(HAVE_AS3514) #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 target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c
#endif /* FIIO_M3K */ #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) #if defined(LYRE_PROTO1)
target/arm/at91sam/lyre_proto1/adc-lyre_proto1.c target/arm/at91sam/lyre_proto1/adc-lyre_proto1.c
target/arm/at91sam/lyre_proto1/backlight-lyre_proto1.c target/arm/at91sam/lyre_proto1/backlight-lyre_proto1.c
@ -1948,6 +1959,9 @@ drivers/axp-pmu.c
#ifdef HAVE_FT6x06 #ifdef HAVE_FT6x06
drivers/ft6x06.c drivers/ft6x06.c
#endif #endif
#ifdef HAVE_CW2015
drivers/cw2015.c
#endif
#endif #endif
/* firmware/kernel section */ /* firmware/kernel section */

View File

@ -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);
}

191
firmware/drivers/cw2015.c Normal file
View File

@ -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 <string.h>
#include "system.h"
/* Headers for the debug menu */
#ifndef BOOTLOADER
# include "action.h"
# include "list.h"
# include <stdio.h>
#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

View File

@ -216,6 +216,8 @@ struct sound_settings_info
#include "cs4398.h" #include "cs4398.h"
#elif defined(HAVE_ES9018) #elif defined(HAVE_ES9018)
#include "es9018.h" #include "es9018.h"
#elif defined(HAVE_ES9218)
#include "es9218.h"
#elif (CONFIG_PLATFORM & (PLATFORM_ANDROID | PLATFORM_MAEMO \ #elif (CONFIG_PLATFORM & (PLATFORM_ANDROID | PLATFORM_MAEMO \
| PLATFORM_PANDORA | PLATFORM_SDL)) | PLATFORM_PANDORA | PLATFORM_SDL))
#include "hosted_codec.h" #include "hosted_codec.h"

View File

@ -160,6 +160,7 @@
#define FIIO_M3K_LINUX_PAD 71 #define FIIO_M3K_LINUX_PAD 71
#define EROSQ_PAD 72 #define EROSQ_PAD 72
#define FIIO_M3K_PAD 73 #define FIIO_M3K_PAD 73
#define SHANLING_Q1_PAD 74
/* CONFIG_REMOTE_KEYPAD */ /* CONFIG_REMOTE_KEYPAD */
#define H100_REMOTE 1 #define H100_REMOTE 1
@ -274,6 +275,7 @@
#define LCD_IHIFI770C 67 /* as used by IHIFI 770C */ #define LCD_IHIFI770C 67 /* as used by IHIFI 770C */
#define LCD_IHIFI800 68 /* as used by IHIFI 800 */ #define LCD_IHIFI800 68 /* as used by IHIFI 800 */
#define LCD_FIIOM3K 69 /* as used by the FiiO M3K */ #define LCD_FIIOM3K 69 /* as used by the FiiO M3K */
#define LCD_SHANLING_Q1 70 /* as used by the Shanling Q1 */
/* LCD_PIXELFORMAT */ /* LCD_PIXELFORMAT */
#define HORIZONTAL_PACKING 1 #define HORIZONTAL_PACKING 1
@ -592,6 +594,8 @@ Lyre prototype 1 */
#include "config/fiiom3k.h" #include "config/fiiom3k.h"
#elif defined(EROS_Q) #elif defined(EROS_Q)
#include "config/aigoerosq.h" #include "config/aigoerosq.h"
#elif defined(SHANLING_Q1)
#include "config/shanlingq1.h"
#else #else
//#error "unknown hwardware platform!" //#error "unknown hwardware platform!"
#endif #endif

View File

@ -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

57
firmware/export/cw2015.h Normal file
View File

@ -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 <stdint.h>
#include <stdbool.h>
/* 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__ */

230
firmware/export/es9218.h Normal file
View File

@ -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 <stdbool.h>
#include <stdint.h>
#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__ */

View File

@ -529,6 +529,14 @@
#define UI_LCD_POSY 15 #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) #elif defined(SIMULATOR)
#error no UI defines #error no UI defines
#endif #endif

View File

@ -152,6 +152,9 @@ extern bool dbg_fiiom3k_touchpad(void);
#ifdef HAVE_AXP_PMU #ifdef HAVE_AXP_PMU
extern bool axp_debug_menu(void); extern bool axp_debug_menu(void);
#endif #endif
#ifdef HAVE_CW2015
extern bool cw2015_debug_menu(void);
#endif
/* Menu definition */ /* Menu definition */
static const struct { static const struct {
@ -170,6 +173,9 @@ static const struct {
#ifdef HAVE_AXP_PMU #ifdef HAVE_AXP_PMU
{"Power stats", &axp_debug_menu}, {"Power stats", &axp_debug_menu},
#endif #endif
#ifdef HAVE_CW2015
{"CW2015 debug", &cw2015_debug_menu},
#endif
}; };
static int hw_info_menu_action_cb(int btn, struct gui_synclist* lists) static int hw_info_menu_action_cb(int btn, struct gui_synclist* lists)

View File

@ -42,7 +42,7 @@
#define DEBOUNCE_TIME (HZ/10) #define DEBOUNCE_TIME (HZ/10)
static const msc_config msc_configs[] = { static const msc_config msc_configs[] = {
#ifdef FIIO_M3K #if defined(FIIO_M3K)
#define MSC_CLOCK_SOURCE X1000_CLK_SCLK_A #define MSC_CLOCK_SOURCE X1000_CLK_SCLK_A
{ {
.msc_nr = 0, .msc_nr = 0,
@ -52,6 +52,17 @@ static const msc_config msc_configs[] = {
.cd_gpio = GPIO_MSC0_CD, .cd_gpio = GPIO_MSC0_CD,
.cd_active_level = 0, .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 #else
# error "Please add X1000 MSC config" # error "Please add X1000 MSC config"
#endif #endif

View File

@ -58,7 +58,7 @@
#define FREG_STATUS_ECC_UNCOR_ERR (2 << 4) #define FREG_STATUS_ECC_UNCOR_ERR (2 << 4)
const nand_chip supported_nand_chips[] = { const nand_chip supported_nand_chips[] = {
#if defined(FIIO_M3K) #if defined(FIIO_M3K) || defined(SHANLING_Q1)
{ {
/* ATO25D1GA */ /* ATO25D1GA */
.mf_id = 0x9b, .mf_id = 0x9b,

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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 <stdbool.h>
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__ */

View File

@ -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)/%,%,$^)

View File

@ -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 <stdbool.h>
/* 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);
}

View File

@ -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 <stdbool.h>
/* 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__ */

View File

@ -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))

View File

@ -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__ */

View File

@ -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);
}

View File

@ -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)
{
}

View File

@ -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;
}
}

View File

@ -34,7 +34,7 @@
#include "ucl_decompress.h" #include "ucl_decompress.h"
#include <string.h> #include <string.h>
#ifdef FIIO_M3K #if defined(FIIO_M3K) || defined(SHANLING_Q1)
# define SPL_DDR_MEMORYSIZE 64 # define SPL_DDR_MEMORYSIZE 64
# define SPL_DDR_AUTOSR_EN 1 # define SPL_DDR_AUTOSR_EN 1
# define SPL_DDR_NEED_BYPASS 1 # define SPL_DDR_NEED_BYPASS 1

27
tools/configure vendored
View File

@ -1597,7 +1597,8 @@ cat <<EOF
240) Rocker 228) NWZ-A860 series 240) Rocker 228) NWZ-A860 series
==FiiO== 229) NWZ-S750 series ==FiiO== 229) NWZ-S750 series
==AIGO== 244) M3K Linux ==AIGO== 244) M3K Linux
245) Eros Q / K 246) M3K baremetal 245) Eros Q / K 246) M3K baremetal ==Shanling==
260) Q1
EOF EOF
buildfor=`input`; buildfor=`input`;
@ -4108,6 +4109,30 @@ fi
t_model="fiiom3k" t_model="fiiom3k"
;; ;;
260|shanlingq1)
target_id=115
modelname="shanlingq1"
target="SHANLING_Q1"
memory=64
mipsr2elcc
appextra="recorder:gui"
plugins="yes"
tool="$rootdir/tools/scramble -add=shq1 "
boottool="" # not used
output="rockbox.q1"
bootoutput="bootloader.q1"
sysfontbl="16-Terminus"
# toolset is the tools within the tools directory that we build for
# this particular target.
toolset="$x1000tools"
bmp2rb_mono="$rootdir/tools/bmp2rb -f 0"
bmp2rb_native="$rootdir/tools/bmp2rb -f 4"
# architecture, manufacturer and model for the target-tree build
t_cpu="mips"
t_manufacturer="ingenic_x1000"
t_model="shanlingq1"
;;
*) *)
echo "Please select a supported target platform!" echo "Please select a supported target platform!"
exit 7 exit 7

View File

@ -333,6 +333,8 @@ int main (int argc, char** argv)
modelnum = 109; modelnum = 109;
else if (!strcmp(&argv[1][5], "fiiom3k")) /* FiiO M3K */ else if (!strcmp(&argv[1][5], "fiiom3k")) /* FiiO M3K */
modelnum = 114; modelnum = 114;
else if (!strcmp(&argv[1][5], "shq1")) /* Shanling Q1 */
modelnum = 115;
else { else {
fprintf(stderr, "unsupported model: %s\n", &argv[1][5]); fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
return 2; return 2;

Binary file not shown.

After

Width:  |  Height:  |  Size: 719 KiB

View File

@ -85,5 +85,7 @@ ihifi2.c
erosq.c erosq.c
#elif CONFIG_KEYPAD == FIIO_M3K_PAD #elif CONFIG_KEYPAD == FIIO_M3K_PAD
fiio-m3k.c fiio-m3k.c
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
shanling-q1.c
#endif #endif
#endif /* SIMULATOR */ #endif /* SIMULATOR */

View File

@ -0,0 +1,72 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* 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 <SDL.h>
#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" }
};

View File

@ -16,6 +16,7 @@ Cabbie v2.0:
Johannes Voggenthaler Johannes Voggenthaler
Jonathan Gordon Jonathan Gordon
Keith Perri Keith Perri
Marc Aarts
Marc Guay Marc Guay
Marcin Bukat Marcin Bukat
Marianne Arnold Marianne Arnold

Some files were not shown because too many files have changed in this diff Show More