diff --git a/apps/features.txt b/apps/features.txt index 4f394d5eef..0ddccced3c 100644 --- a/apps/features.txt +++ b/apps/features.txt @@ -24,6 +24,8 @@ backlight_brightness backlight_fade_pwm #elif defined(USE_BACKLIGHT_SW_FADING) backlight_fade_sw +#elif defined(USE_BACKLIGHT_CUSTOM_FADING_BOOL) +backlight_fade_custom_bool #endif #if BATTERY_TYPES_COUNT > 1 diff --git a/apps/menus/display_menu.c b/apps/menus/display_menu.c index 744a9e9354..488b0ff570 100644 --- a/apps/menus/display_menu.c +++ b/apps/menus/display_menu.c @@ -92,7 +92,8 @@ MENUITEM_SETTING(backlight_on_button_hold, #endif MENUITEM_SETTING(caption_backlight, &global_settings.caption_backlight, NULL); #if (defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR)) || \ - defined(USE_BACKLIGHT_SW_FADING) + defined(USE_BACKLIGHT_SW_FADING) || \ + defined(USE_BACKLIGHT_CUSTOM_FADING_BOOL) MENUITEM_SETTING(backlight_fade_in, &global_settings.backlight_fade_in, NULL); MENUITEM_SETTING(backlight_fade_out, &global_settings.backlight_fade_out, NULL); #endif @@ -132,7 +133,8 @@ MAKE_MENU(lcd_settings,ID2P(LANG_LCD_MENU), # endif ,&caption_backlight #if (defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR)) || \ - defined(USE_BACKLIGHT_SW_FADING) + defined(USE_BACKLIGHT_SW_FADING) || \ + defined(USE_BACKLIGHT_CUSTOM_FADING_BOOL) ,&backlight_fade_in, &backlight_fade_out #endif ,&bl_filter_first_keypress diff --git a/apps/settings.c b/apps/settings.c index 2cab26a4a1..609cb3f93f 100644 --- a/apps/settings.c +++ b/apps/settings.c @@ -769,7 +769,8 @@ void settings_apply(bool read_disk) backlight_set_timeout_plugged(global_settings.backlight_timeout_plugged); #endif #if (defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR)) \ - || defined(USE_BACKLIGHT_SW_FADING) + || defined(USE_BACKLIGHT_SW_FADING) \ + || defined(USE_BACKLIGHT_CUSTOM_FADING_BOOL) backlight_set_fade_in(global_settings.backlight_fade_in); backlight_set_fade_out(global_settings.backlight_fade_out); #endif diff --git a/apps/settings.h b/apps/settings.h index 56b7d3e80a..be83689368 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -424,7 +424,8 @@ struct user_settings #if defined(HAVE_BACKLIGHT_PWM_FADING) int backlight_fade_in; /* backlight fade in timing: 0..3 */ int backlight_fade_out; /* backlight fade in timing: 0..7 */ -#elif defined(USE_BACKLIGHT_SW_FADING) +#elif defined(USE_BACKLIGHT_SW_FADING) \ + || defined(USE_BACKLIGHT_CUSTOM_FADING_BOOL) bool backlight_fade_in; bool backlight_fade_out; #endif diff --git a/apps/settings_list.c b/apps/settings_list.c index f4519f5975..fe379ca229 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c @@ -679,7 +679,8 @@ const struct settings_list settings[] = { UNIT_MS, formatter_unit_0_is_off, getlang_unit_0_is_off, backlight_set_fade_out, 10, 0,100,200,300,500,1000,2000,3000,5000,10000), -#elif defined(USE_BACKLIGHT_SW_FADING) +#elif defined(USE_BACKLIGHT_SW_FADING) \ + || defined(USE_BACKLIGHT_CUSTOM_FADING_BOOL) OFFON_SETTING(0, backlight_fade_in, LANG_BACKLIGHT_FADE_IN, true, "backlight fade in", backlight_set_fade_in), OFFON_SETTING(0, backlight_fade_out, LANG_BACKLIGHT_FADE_OUT, diff --git a/firmware/export/backlight.h b/firmware/export/backlight.h index 506a9f6b03..cb081a5301 100644 --- a/firmware/export/backlight.h +++ b/firmware/export/backlight.h @@ -38,7 +38,8 @@ int backlight_get_current_timeout(void); void backlight_set_fade_in(int value); void backlight_set_fade_out(int value); #endif -#ifdef USE_BACKLIGHT_SW_FADING +#if defined(USE_BACKLIGHT_SW_FADING) \ + || defined(USE_BACKLIGHT_CUSTOM_FADING_BOOL) void backlight_set_fade_in(bool value); void backlight_set_fade_out(bool value); #endif diff --git a/firmware/export/config-gigabeat-s.h b/firmware/export/config-gigabeat-s.h index e6fa6c9fc6..4359c90279 100644 --- a/firmware/export/config-gigabeat-s.h +++ b/firmware/export/config-gigabeat-s.h @@ -94,6 +94,9 @@ #ifndef SIMULATOR +/* Implementation-defined fading type with bool settings */ +#define USE_BACKLIGHT_CUSTOM_FADING_BOOL + /* The LCD on a Gigabeat is 240x320 - it is portrait */ #define HAVE_PORTRAIT_LCD diff --git a/firmware/target/arm/imx31/gigabeat-s/backlight-imx31.c b/firmware/target/arm/imx31/gigabeat-s/backlight-imx31.c index 535c0a0051..7e40b95437 100644 --- a/firmware/target/arm/imx31/gigabeat-s/backlight-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/backlight-imx31.c @@ -65,50 +65,124 @@ static const struct }; #endif /* HAVE_BACKLIGHT_BRIGHTNESS */ +/* Bits always combined with ramping bits */ +#define MC13783_LED_CONTROL0_BITS \ + (MC13783_LEDEN | MC13783_BOOSTEN | MC13783_ABMODE_MONCH_LEDMD1234 | \ + MC13783_ABREF_400MV) + +static struct mutex backlight_mutex; /* Block brightness change while + * setting up fading */ +static bool backlight_on_status = true; /* Is on or off? */ +static uint32_t backlight_pwm_bits; /* Final PWM setting for fade-in */ + +/* Backlight ramping settings */ +static uint32_t led_ramp_mask = MC13783_LEDMDRAMPDOWN | MC13783_LEDMDRAMPUP; + bool _backlight_init(void) { - mc13783_write(MC13783_LED_CONTROL0, - MC13783_LEDEN | - MC13783_LEDMDRAMPUP | - MC13783_LEDMDRAMPDOWN | - MC13783_BOOSTEN | - MC13783_ABMODE_MONCH_LEDMD1234 | - MC13783_ABREF_400MV); + mutex_init(&backlight_mutex); + + /* Set default LED register value */ + mc13783_write(MC13783_LED_CONTROL0, MC13783_LED_CONTROL0_BITS); + + /* Our PWM and I-Level is different than retailos (but same apparent + * brightness), so init to our default. */ + _backlight_set_brightness(DEFAULT_BRIGHTNESS_SETTING); return true; } +void backlight_set_fade_out(bool value) +{ + if (value) + led_ramp_mask |= MC13783_LEDMDRAMPDOWN; + else + led_ramp_mask &= ~MC13783_LEDMDRAMPDOWN; +} + +void backlight_set_fade_in(bool value) +{ + if (value) + led_ramp_mask |= MC13783_LEDMDRAMPUP; + else + led_ramp_mask &= ~MC13783_LEDMDRAMPUP; +} + void _backlight_on(void) { - /* LEDEN=1 */ - mc13783_set(MC13783_LED_CONTROL0, MC13783_LEDEN); + static const char regs[2] = + { + MC13783_LED_CONTROL0, + MC13783_LED_CONTROL2 + }; + + uint32_t data[2]; + + mutex_lock(&backlight_mutex); + + /* Set/clear LEDRAMPUP bit, clear LEDRAMPDOWN bit */ + data[0] = MC13783_LED_CONTROL0_BITS; + + if (!backlight_on_status) + data[0] |= led_ramp_mask & MC13783_LEDMDRAMPUP; + + backlight_on_status = true; + + /* Specify final PWM setting */ + data[1] = mc13783_read(MC13783_LED_CONTROL2); + + if (data[1] != MC13783_DATA_ERROR) + { + data[1] &= ~MC13783_LEDMDDC; + data[1] |= backlight_pwm_bits; + + /* Write regs within 30us of each other (requires single xfer) */ + mc13783_write_regset(regs, data, 2); + } + + mutex_unlock(&backlight_mutex); } void _backlight_off(void) { - /* LEDEN=0 */ - mc13783_clear(MC13783_LED_CONTROL0, MC13783_LEDEN); + uint32_t ctrl0 = MC13783_LED_CONTROL0_BITS; + + mutex_lock(&backlight_mutex); + + if (backlight_on_status) + ctrl0 |= led_ramp_mask & MC13783_LEDMDRAMPDOWN; + + backlight_on_status = false; + + /* Set/clear LEDRAMPDOWN bit, clear LEDRAMPUP bit */ + mc13783_write(MC13783_LED_CONTROL0, ctrl0); + + /* Wait 100us - 500ms */ + sleep(HZ/100); + + /* Write final PWM setting */ + mc13783_write_masked(MC13783_LED_CONTROL2, MC13783_LEDMDDCw(0), + MC13783_LEDMDDC); + + mutex_unlock(&backlight_mutex); } #ifdef HAVE_BACKLIGHT_BRIGHTNESS -/* Assumes that the backlight has been initialized */ +/* Assumes that the backlight has been initialized - parameter should + * already be range-checked in public interface. */ void _backlight_set_brightness(int brightness) { - uint32_t data, md, pwm; + uint32_t md; - if ((unsigned)brightness >= ARRAYLEN(led_md_pwm_table)) - brightness = DEFAULT_BRIGHTNESS_SETTING; - - data = mc13783_read(MC13783_LED_CONTROL2); - - if (data == (uint32_t)-1) - return; + mutex_lock(&backlight_mutex); md = led_md_pwm_table[brightness].md; - pwm = led_md_pwm_table[brightness].pwm; + backlight_pwm_bits = backlight_on_status ? + MC13783_LEDMDDCw(led_md_pwm_table[brightness].pwm) : 0; - data &= ~(MC13783_LEDMD | MC13783_LEDMDDC); - data |= MC13783_LEDMDw(md) | MC13783_LEDMDDCw(pwm); + mc13783_write_masked(MC13783_LED_CONTROL2, + MC13783_LEDMDw(md) | backlight_pwm_bits, + MC13783_LEDMD | MC13783_LEDMDDC); - mc13783_write(MC13783_LED_CONTROL2, data); + mutex_unlock(&backlight_mutex); } #endif /* HAVE_BACKLIGHT_BRIGHTNESS */