/* * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "drivers/led_controller.h" #include "board/board.h" #include "drivers/gpio.h" #include "drivers/i2c.h" #include "drivers/periph_config.h" #include "system/logging.h" #include "system/passert.h" #define STM32F2_COMPATIBLE #define STM32F4_COMPATIBLE #include enum { RegShutdown = 0x00, RegLedCtrl = 0x01, RegConfig1 = 0x03, RegConfig2 = 0x04, RegRampingMode = 0x05, RegBreathingMark = 0x06, RegPwmOut1 = 0x07, RegPwmOut2 = 0x08, RegPwmOut3 = 0x09, RegPwmOut4 = 0x0a, RegPwmOut5 = 0x0b, RegPwmOut6 = 0x0c, RegDataUpdate = 0x10, RegT0Out1 = 0x11, RegT0Out2 = 0x12, RegT0Out3 = 0x13, RegT0Out4 = 0x14, RegT0Out5 = 0x15, RegT0Out6 = 0x16, RegT1T3Rgb1 = 0x1a, RegT1T3Rgb2 = 0x1b, RegT4Out1 = 0x1d, RegT4Out2 = 0x1e, RegT4Out3 = 0x1f, RegT4Out4 = 0x20, RegT4Out5 = 0x21, RegT4Out6 = 0x22, RegTimeUpdate = 0x26, RegReset = 0xff }; static bool s_backlight_off; static bool s_initialized = false; static uint32_t s_rgb_current_color = LED_BLACK; static bool write_register(uint8_t register_address, uint8_t value) { return i2c_write_register(I2C_LED, register_address, value); } // used to bring hardware shutdown pin on led controller low, this brings down our shutdown current static void prv_shutdown(bool shutdown) { periph_config_acquire_lock(); gpio_output_set(&BOARD_CONFIG_BACKLIGHT.ctl, !shutdown); periph_config_release_lock(); } static void prv_init_pins(void) { periph_config_acquire_lock(); gpio_output_init(&BOARD_CONFIG_BACKLIGHT.ctl, GPIO_OType_PP, GPIO_Speed_2MHz); gpio_output_set(&BOARD_CONFIG_BACKLIGHT.ctl, false); periph_config_release_lock(); } void led_controller_init(void) { PBL_ASSERTN(BOARD_CONFIG_BACKLIGHT.options & ActuatorOptions_IssiI2C); prv_init_pins(); prv_shutdown(false); i2c_use(I2C_LED); // reset the LED controller if (!write_register(RegReset, 0xaa)) { PBL_LOG(LOG_LEVEL_ERROR, "LED Controller is MIA"); goto cleanup; } else { s_initialized = true; } // take the led controller out of shutdown write_register(RegShutdown, 0x01); // set config1 to 0x00 (PWM, Audio disable, AGC enable, AGC fast mode) write_register(RegConfig1, 0x00); // set config2 to 0x40 (master control, 25mA drive, 0dB gain) write_register(RegConfig2, 0x70); // set ramping_mode to 0x00 (disable ramping) // TODO: this is potentially quite useful for us write_register(RegRampingMode, 0x00); // set breathing mark to 0x00 (disable breathing) // TODO: this is potentially quite useful for us for the RGB LEDs write_register(RegBreathingMark, 0x00); s_backlight_off = true; s_rgb_current_color = LED_BLACK; cleanup: i2c_release(I2C_LED); prv_shutdown(true); } void led_controller_backlight_set_brightness(uint8_t brightness) { if ((BOARD_CONFIG_BACKLIGHT.options & ActuatorOptions_IssiI2C) == 0 || !s_initialized) { return; } prv_shutdown(false); i2c_use(I2C_LED); write_register(RegPwmOut1, brightness); write_register(RegPwmOut2, brightness); write_register(RegPwmOut3, brightness); write_register(RegDataUpdate, 0xaa); i2c_release(I2C_LED); s_backlight_off = (brightness == 0); if (s_backlight_off && s_rgb_current_color == LED_BLACK) { prv_shutdown(true); } } void led_controller_rgb_set_color(uint32_t rgb_color) { if ((BOARD_CONFIG_BACKLIGHT.options & ActuatorOptions_IssiI2C) == 0 || !s_initialized) { return; } s_rgb_current_color = rgb_color; uint8_t red = (s_rgb_current_color & 0x00FF0000) >> 16; uint8_t green = (s_rgb_current_color & 0x0000FF00) >> 8; uint8_t blue = (s_rgb_current_color & 0x000000FF); prv_shutdown(false); i2c_use(I2C_LED); write_register(RegPwmOut4, red); write_register(RegPwmOut6, blue); write_register(RegPwmOut5, green); write_register(RegDataUpdate, 0xaa); i2c_release(I2C_LED); if (s_backlight_off && s_rgb_current_color == LED_BLACK) { prv_shutdown(true); } } uint32_t led_controller_rgb_get_color(void) { return s_rgb_current_color; } void command_rgb_set_color(const char* color) { uint32_t color_val = strtol(color, NULL, 16); led_controller_rgb_set_color(color_val); }