mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-07 13:45:03 -05:00
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:
parent
3abb7c5dd5
commit
4c60bc9e68
110 changed files with 2843 additions and 15 deletions
|
|
@ -503,6 +503,8 @@ drivers/audio/pcm1792.c
|
|||
drivers/audio/cs4398.c
|
||||
#elif defined (HAVE_ES9018)
|
||||
drivers/audio/es9018.c
|
||||
#elif defined (HAVE_ES9218)
|
||||
drivers/audio/es9218.c
|
||||
#endif /* defined(HAVE_*) */
|
||||
#else /* PLATFORM_HOSTED */
|
||||
#if defined(SAMSUNG_YPR0) && defined(HAVE_AS3514)
|
||||
|
|
@ -1716,6 +1718,15 @@ target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c
|
|||
target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c
|
||||
#endif /* FIIO_M3K */
|
||||
|
||||
#if defined(SHANLING_Q1)
|
||||
target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c
|
||||
target/mips/ingenic_x1000/shanlingq1/backlight-shanlingq1.c
|
||||
target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c
|
||||
target/mips/ingenic_x1000/shanlingq1/lcd-shanlingq1.c
|
||||
target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c
|
||||
target/mips/ingenic_x1000/shanlingq1/spl-shanlingq1.c
|
||||
#endif /* SHANLING_Q1 */
|
||||
|
||||
#if defined(LYRE_PROTO1)
|
||||
target/arm/at91sam/lyre_proto1/adc-lyre_proto1.c
|
||||
target/arm/at91sam/lyre_proto1/backlight-lyre_proto1.c
|
||||
|
|
@ -1948,6 +1959,9 @@ drivers/axp-pmu.c
|
|||
#ifdef HAVE_FT6x06
|
||||
drivers/ft6x06.c
|
||||
#endif
|
||||
#ifdef HAVE_CW2015
|
||||
drivers/cw2015.c
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* firmware/kernel section */
|
||||
|
|
|
|||
226
firmware/drivers/audio/es9218.c
Normal file
226
firmware/drivers/audio/es9218.c
Normal 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
191
firmware/drivers/cw2015.c
Normal 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
|
||||
|
|
@ -216,6 +216,8 @@ struct sound_settings_info
|
|||
#include "cs4398.h"
|
||||
#elif defined(HAVE_ES9018)
|
||||
#include "es9018.h"
|
||||
#elif defined(HAVE_ES9218)
|
||||
#include "es9218.h"
|
||||
#elif (CONFIG_PLATFORM & (PLATFORM_ANDROID | PLATFORM_MAEMO \
|
||||
| PLATFORM_PANDORA | PLATFORM_SDL))
|
||||
#include "hosted_codec.h"
|
||||
|
|
|
|||
|
|
@ -160,6 +160,7 @@
|
|||
#define FIIO_M3K_LINUX_PAD 71
|
||||
#define EROSQ_PAD 72
|
||||
#define FIIO_M3K_PAD 73
|
||||
#define SHANLING_Q1_PAD 74
|
||||
|
||||
/* CONFIG_REMOTE_KEYPAD */
|
||||
#define H100_REMOTE 1
|
||||
|
|
@ -274,6 +275,7 @@
|
|||
#define LCD_IHIFI770C 67 /* as used by IHIFI 770C */
|
||||
#define LCD_IHIFI800 68 /* as used by IHIFI 800 */
|
||||
#define LCD_FIIOM3K 69 /* as used by the FiiO M3K */
|
||||
#define LCD_SHANLING_Q1 70 /* as used by the Shanling Q1 */
|
||||
|
||||
/* LCD_PIXELFORMAT */
|
||||
#define HORIZONTAL_PACKING 1
|
||||
|
|
@ -592,6 +594,8 @@ Lyre prototype 1 */
|
|||
#include "config/fiiom3k.h"
|
||||
#elif defined(EROS_Q)
|
||||
#include "config/aigoerosq.h"
|
||||
#elif defined(SHANLING_Q1)
|
||||
#include "config/shanlingq1.h"
|
||||
#else
|
||||
//#error "unknown hwardware platform!"
|
||||
#endif
|
||||
|
|
|
|||
119
firmware/export/config/shanlingq1.h
Normal file
119
firmware/export/config/shanlingq1.h
Normal 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
57
firmware/export/cw2015.h
Normal 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
230
firmware/export/es9218.h
Normal 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__ */
|
||||
|
|
@ -529,6 +529,14 @@
|
|||
#define UI_LCD_POSY 15
|
||||
|
||||
|
||||
#elif defined(SHANLING_Q1)
|
||||
#define UI_TITLE "Shanling Q1"
|
||||
#define UI_WIDTH 466
|
||||
#define UI_HEIGHT 526
|
||||
#define UI_LCD_POSX 46
|
||||
#define UI_LCD_POSY 61
|
||||
|
||||
|
||||
#elif defined(SIMULATOR)
|
||||
#error no UI defines
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -152,6 +152,9 @@ extern bool dbg_fiiom3k_touchpad(void);
|
|||
#ifdef HAVE_AXP_PMU
|
||||
extern bool axp_debug_menu(void);
|
||||
#endif
|
||||
#ifdef HAVE_CW2015
|
||||
extern bool cw2015_debug_menu(void);
|
||||
#endif
|
||||
|
||||
/* Menu definition */
|
||||
static const struct {
|
||||
|
|
@ -170,6 +173,9 @@ static const struct {
|
|||
#ifdef HAVE_AXP_PMU
|
||||
{"Power stats", &axp_debug_menu},
|
||||
#endif
|
||||
#ifdef HAVE_CW2015
|
||||
{"CW2015 debug", &cw2015_debug_menu},
|
||||
#endif
|
||||
};
|
||||
|
||||
static int hw_info_menu_action_cb(int btn, struct gui_synclist* lists)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
#define DEBOUNCE_TIME (HZ/10)
|
||||
|
||||
static const msc_config msc_configs[] = {
|
||||
#ifdef FIIO_M3K
|
||||
#if defined(FIIO_M3K)
|
||||
#define MSC_CLOCK_SOURCE X1000_CLK_SCLK_A
|
||||
{
|
||||
.msc_nr = 0,
|
||||
|
|
@ -52,6 +52,17 @@ static const msc_config msc_configs[] = {
|
|||
.cd_gpio = GPIO_MSC0_CD,
|
||||
.cd_active_level = 0,
|
||||
},
|
||||
#elif defined(SHANLING_Q1)
|
||||
#define MSC_CLOCK_SOURCE X1000_CLK_MPLL
|
||||
{
|
||||
.msc_nr = 0,
|
||||
.msc_type = MSC_TYPE_SD,
|
||||
.bus_width = 4,
|
||||
.label = "microSD",
|
||||
.cd_gpio = GPIO_MSC0_CD,
|
||||
.cd_active_level = 0,
|
||||
},
|
||||
/* NOTE: SDIO wifi card is on msc1 */
|
||||
#else
|
||||
# error "Please add X1000 MSC config"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@
|
|||
#define FREG_STATUS_ECC_UNCOR_ERR (2 << 4)
|
||||
|
||||
const nand_chip supported_nand_chips[] = {
|
||||
#if defined(FIIO_M3K)
|
||||
#if defined(FIIO_M3K) || defined(SHANLING_Q1)
|
||||
{
|
||||
/* ATO25D1GA */
|
||||
.mf_id = 0x9b,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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__ */
|
||||
31
firmware/target/mips/ingenic_x1000/shanlingq1/boot.make
Normal file
31
firmware/target/mips/ingenic_x1000/shanlingq1/boot.make
Normal 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)/%,%,$^)
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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__ */
|
||||
32
firmware/target/mips/ingenic_x1000/shanlingq1/gpio-target.h
Normal file
32
firmware/target/mips/ingenic_x1000/shanlingq1/gpio-target.h
Normal 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))
|
||||
40
firmware/target/mips/ingenic_x1000/shanlingq1/i2c-target.h
Normal file
40
firmware/target/mips/ingenic_x1000/shanlingq1/i2c-target.h
Normal 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__ */
|
||||
399
firmware/target/mips/ingenic_x1000/shanlingq1/lcd-shanlingq1.c
Normal file
399
firmware/target/mips/ingenic_x1000/shanlingq1/lcd-shanlingq1.c
Normal 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);
|
||||
}
|
||||
140
firmware/target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c
Normal file
140
firmware/target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c
Normal 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)
|
||||
{
|
||||
}
|
||||
116
firmware/target/mips/ingenic_x1000/shanlingq1/spl-shanlingq1.c
Normal file
116
firmware/target/mips/ingenic_x1000/shanlingq1/spl-shanlingq1.c
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
#include "ucl_decompress.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef FIIO_M3K
|
||||
#if defined(FIIO_M3K) || defined(SHANLING_Q1)
|
||||
# define SPL_DDR_MEMORYSIZE 64
|
||||
# define SPL_DDR_AUTOSR_EN 1
|
||||
# define SPL_DDR_NEED_BYPASS 1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue