Add indicators for fastboot mode
There were no indicators on Fairphone 2 for users to be in fastboot mode.
The device would appear to be stuck on boot logo, leading users to
think that something went wrong.
This commit adds a 3 fast vibrations on fastboot enter, plus a persistent
blinking blue LED while in this mode.
Issue: FP2N-342
Change-Id: I58c9da8c0d7e81a28ece741d49bf858a9e0fcc30
diff --git a/target/FP2/rgb_led.c b/target/FP2/rgb_led.c
new file mode 100644
index 0000000..3769f7b
--- /dev/null
+++ b/target/FP2/rgb_led.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2018 Fairphone B.V.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <target/rgb_led.h>
+
+rgb_led_return_code led_init()
+{
+ /* Enable RGB module, Select Vph_pwr as power source */
+ pm8x41_reg_write( SLAVE_ID + RGB_DRIVER_BASE_ADDR + RGB_DRIVER_LED_SRC_SEL, 0x01);
+
+ return RGB_LED_SUCCESS;
+}
+
+rgb_led_return_code led_enable(uint8_t led, rgb_led_brightness brightness)
+{
+ uint32_t led_lpg_value = 0;
+ switch(led)
+ {
+ case RGB_LED_VALUE_RED:
+ led_lpg_value = LPG_DRIVER_LED_RED;
+ break;
+ case RGB_LED_VALUE_GREEN:
+ led_lpg_value = LPG_DRIVER_LED_GREEN;
+ break;
+ case RGB_LED_VALUE_BLUE:
+ led_lpg_value = LPG_DRIVER_LED_BLUE;
+ break;
+ default:
+ return RGB_LED_INVALID_PARAMETER;
+ }
+ /* Building LED specific base address */
+ const uint32_t led_lpg_base_address = SLAVE_ID + LPG_DRIVER_BASE_ADDR + led_lpg_value;
+ /* Enable selected LED, preserving the previous value */
+ uint8_t val = pm8x41_reg_read( SLAVE_ID + RGB_DRIVER_BASE_ADDR + RGB_DRIVER_EN_CTL );
+ val |= led;
+ pm8x41_reg_write( SLAVE_ID + RGB_DRIVER_BASE_ADDR + RGB_DRIVER_EN_CTL, val);
+ /*
+ * Enable PWM at requested duty cycle
+ * For a always-on behaviour no pattern is needed.
+ * PWM is set to 7-bit mode in order to be able to use both PWM channels (4 mA + 8 mA).
+ * PWM frequency is set to 390 Hz (Pre-divide=5, Exponent=7).
+ * The type config is not used here but is mandatory to set the register.
+ * PWM value acts here as brightness parameter. 0xFF is the full-scale value.
+ * PWM value MSB is useless here.
+ * PWM is enabled by writing 0xE4 in the enable register.
+ */
+ pm8x41_reg_write( led_lpg_base_address + LPG_PATTERN_CONFIG, 0x00);
+ pm8x41_reg_write( led_lpg_base_address + LPG_PWM_SIZE_CLK, 0x13);
+ pm8x41_reg_write( led_lpg_base_address + LPG_PWM_FREQ_PREDIV, 0x47);
+ pm8x41_reg_write( led_lpg_base_address + LPG_PWM_TYPE_CONFIG, 0x00);
+ pm8x41_reg_write( led_lpg_base_address + LPG_VALUE_LSB, brightness);
+ pm8x41_reg_write( led_lpg_base_address + LPG_VALUE_MSB, 0x00);
+ pm8x41_reg_write( led_lpg_base_address + LPG_ENABLE_CONTROL, 0xE4);
+
+ return RGB_LED_SUCCESS;
+}
+
+rgb_led_return_code led_blink_enable(uint8_t led, uint8_t pwm_freq, uint8_t duty_cycle)
+{
+ if(duty_cycle > 0x3F)
+ {
+ return RGB_LED_INVALID_PARAMETER;
+ }
+
+ uint32_t led_lpg_value = 0;
+ switch(led)
+ {
+ case RGB_LED_VALUE_RED:
+ led_lpg_value = LPG_DRIVER_LED_RED;
+ break;
+ case RGB_LED_VALUE_GREEN:
+ led_lpg_value = LPG_DRIVER_LED_GREEN;
+ break;
+ case RGB_LED_VALUE_BLUE:
+ led_lpg_value = LPG_DRIVER_LED_BLUE;
+ break;
+ default:
+ return RGB_LED_INVALID_PARAMETER;
+ }
+ /* Building LED specific base address */
+ const uint32_t led_lpg_base_address = SLAVE_ID + LPG_DRIVER_BASE_ADDR + led_lpg_value;
+ /* Enable selected LED, preserving the previous value */
+ uint8_t val = pm8x41_reg_read( SLAVE_ID + RGB_DRIVER_BASE_ADDR + RGB_DRIVER_EN_CTL );
+ val |= led;
+ pm8x41_reg_write( SLAVE_ID + RGB_DRIVER_BASE_ADDR + RGB_DRIVER_EN_CTL, val);
+ /*
+ * Enable PWM at requested duty cycle
+ * For a simple blinking behaviour no pattern is needed.
+ * PWM is set to 6-bit mode. This results in a clock of 1 KHz.
+ * PWM frequency is set as desidered. Refer to docs to properly set this parameter.
+ * The type config is not used here but is mandatory to set the register.
+ * PWM value acts here as duty cycle value. 0x3F is the full-scale value.
+ * PWM value MSB is useless here.
+ * PWM is enabled by writing 0xE4 in the enable register.
+ */
+ pm8x41_reg_write( led_lpg_base_address + LPG_PATTERN_CONFIG, 0x00);
+ pm8x41_reg_write( led_lpg_base_address + LPG_PWM_SIZE_CLK, 0x01);
+ pm8x41_reg_write( led_lpg_base_address + LPG_PWM_FREQ_PREDIV, pwm_freq);
+ pm8x41_reg_write( led_lpg_base_address + LPG_PWM_TYPE_CONFIG, 0x00);
+ pm8x41_reg_write( led_lpg_base_address + LPG_VALUE_LSB, duty_cycle);
+ pm8x41_reg_write( led_lpg_base_address + LPG_VALUE_MSB, 0x00);
+ pm8x41_reg_write( led_lpg_base_address + LPG_ENABLE_CONTROL, 0xE4);
+
+ return RGB_LED_SUCCESS;
+}
+
+rgb_led_return_code led_disable(uint8_t led)
+{
+ uint32_t led_lpg_value = 0;
+ switch(led)
+ {
+ case RGB_LED_VALUE_RED:
+ led_lpg_value = LPG_DRIVER_LED_RED;
+ break;
+ case RGB_LED_VALUE_GREEN:
+ led_lpg_value = LPG_DRIVER_LED_GREEN;
+ break;
+ case RGB_LED_VALUE_BLUE:
+ led_lpg_value = LPG_DRIVER_LED_BLUE;
+ break;
+ default:
+ return RGB_LED_INVALID_PARAMETER;
+ }
+ /* Building LED specific base address */
+ const uint32_t led_lpg_base_address = SLAVE_ID + LPG_DRIVER_BASE_ADDR + led_lpg_value;
+ /* Disable selected LED, preserving the previous value */
+ uint8_t val = pm8x41_reg_read( SLAVE_ID + RGB_DRIVER_BASE_ADDR + RGB_DRIVER_EN_CTL );
+ val &= ~(led);
+ pm8x41_reg_write( SLAVE_ID + RGB_DRIVER_BASE_ADDR + RGB_DRIVER_EN_CTL, val);
+
+ /* Clear LPG registers */
+ pm8x41_reg_write( led_lpg_base_address + LPG_PATTERN_CONFIG, 0x00);
+ pm8x41_reg_write( led_lpg_base_address + LPG_PWM_SIZE_CLK, 0x00);
+ pm8x41_reg_write( led_lpg_base_address + LPG_PWM_FREQ_PREDIV, 0x00);
+ pm8x41_reg_write( led_lpg_base_address + LPG_PWM_TYPE_CONFIG, 0x00);
+ pm8x41_reg_write( led_lpg_base_address + LPG_VALUE_LSB, 0x00);
+ pm8x41_reg_write( led_lpg_base_address + LPG_VALUE_MSB, 0x00);
+ pm8x41_reg_write( led_lpg_base_address + LPG_ENABLE_CONTROL, 0x00);
+
+ return RGB_LED_SUCCESS;
+}
+
+rgb_led_return_code led_deinit()
+{
+ rgb_led_return_code rc;
+ rc = led_disable(RGB_LED_VALUE_RED);
+ if(rc != RGB_LED_SUCCESS)
+ {
+ return rc;
+ }
+ rc = led_disable(RGB_LED_VALUE_GREEN);
+ if(rc != RGB_LED_SUCCESS)
+ {
+ return rc;
+ }
+ rc = led_disable(RGB_LED_VALUE_BLUE);
+ if(rc != RGB_LED_SUCCESS)
+ {
+ return rc;
+ }
+
+ /* Power off the RGB module by setting no power source */
+ pm8x41_reg_write( SLAVE_ID + RGB_DRIVER_BASE_ADDR + RGB_DRIVER_LED_SRC_SEL, 0x00);
+
+ return RGB_LED_SUCCESS;
+}