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/include/target/rgb_led.h b/target/FP2/include/target/rgb_led.h
new file mode 100644
index 0000000..b6f6fd6
--- /dev/null
+++ b/target/FP2/include/target/rgb_led.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef _TARGET_FP2_RGB_LED_H_
+#define _TARGET_FP2_RGB_LED_H_
+
+#include <pm8x41.h>
+
+// Slave-ID
+#define SLAVE_ID 0x10000
+
+// RGB module registers
+#define RGB_DRIVER_BASE_ADDR 0xD000
+#define RGB_DRIVER_LED_SRC_SEL 0x45
+#define RGB_DRIVER_EN_CTL 0x46
+#define RGB_LED_VALUE_RED 0x80
+#define RGB_LED_VALUE_GREEN 0x40
+#define RGB_LED_VALUE_BLUE 0x20
+
+// LPG module registers
+#define LPG_DRIVER_BASE_ADDR 0xB000
+#define LPG_DRIVER_LED_RED 0x700
+#define LPG_DRIVER_LED_GREEN 0x600
+#define LPG_DRIVER_LED_BLUE 0x500
+#define LPG_PATTERN_CONFIG 0x40
+#define LPG_PWM_SIZE_CLK 0x41
+#define LPG_PWM_FREQ_PREDIV 0x42
+#define LPG_PWM_TYPE_CONFIG 0x43
+#define LPG_VALUE_LSB 0x44
+#define LPG_VALUE_MSB 0x45
+#define LPG_ENABLE_CONTROL 0x46
+
+typedef enum rgb_led_return_code
+{
+ RGB_LED_SUCCESS,
+ RGB_LED_GENERIC_ERROR,
+ RGB_LED_INVALID_PARAMETER
+} rgb_led_return_code;
+
+typedef enum rgb_led_brightness
+{
+ RGB_LED_BRIGHTNESS_LOW = 0x80,
+ RGB_LED_BRIGHTNESS_MID = 0x7F,
+ RGB_LED_BRIGHTNESS_HIG = 0xFF
+} rgb_led_brightness;
+
+rgb_led_return_code led_init(void);
+rgb_led_return_code led_enable(uint8_t led, rgb_led_brightness brightness);
+rgb_led_return_code led_blink_enable(uint8_t led, uint8_t pwm_freq, uint8_t duty_cycle);
+rgb_led_return_code led_disable(uint8_t led);
+
+rgb_led_return_code led_deinit(void);
+
+#endif //_TARGET_FP2_RGB_LED_H_
diff --git a/target/FP2/init.c b/target/FP2/init.c
index c15bb59..1035038 100644
--- a/target/FP2/init.c
+++ b/target/FP2/init.c
@@ -1,4 +1,5 @@
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright 2018 Fairphone B.V.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -42,6 +43,7 @@
#include <baseband.h>
#include <dev/keys.h>
#include <pm8x41.h>
+#include <target/rgb_led.h>
#include <crypto5_wrapper.h>
#include <hsusb.h>
#include <clock.h>
@@ -465,6 +467,17 @@
clock_ce_enable(SSD_CE_INSTANCE_1);
ssd_load_keystore_from_emmc();
#endif
+
+ /* Vibration pattern, 3 fast vibes in a row */
+ vibrator_enable();
+ thread_sleep(150);
+ vibrator_enable();
+ thread_sleep(150);
+ vibrator_enable();
+ thread_sleep(150);
+ /* Enable blinking of Blue LED */
+ led_init();
+ led_blink_enable(RGB_LED_VALUE_BLUE, 0x06, 0x2C); // 0x06 means 0.25 KHz PWM frequency (4 secs duty cycle duration), 0x2C means about 70% of the duty cycle
}
/* Detect the target type */
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;
+}
diff --git a/target/FP2/rules.mk b/target/FP2/rules.mk
index ab9a431..8ed30db 100644
--- a/target/FP2/rules.mk
+++ b/target/FP2/rules.mk
@@ -41,4 +41,5 @@
$(LOCAL_DIR)/init.o \
$(LOCAL_DIR)/meminfo.o \
$(LOCAL_DIR)/target_display.o \
- $(LOCAL_DIR)/oem_panel.o
+ $(LOCAL_DIR)/oem_panel.o \
+ $(LOCAL_DIR)/rgb_led.o