blob: 3769f7b7048e41d9edb587ef87783d9a6165177d [file] [log] [blame]
/*
* 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;
}