blob: 7a014eae5555f7e8dcf572166f1c4f6ec9e00968 [file] [log] [blame]
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* arch/arm/cpu/armv8/tm2/firmware/scp_task/aml_led.c
*
* Copyright (C) 2020 Amlogic, Inc. All rights reserved.
*
*/
#include <amlogic/aml_led.h>
#define LED_STA_IDLE 0
#define LED_STA_FLASH_ON 1
#define LED_STA_FLASH_OFF 2
#define LED_STA_BREATH 3
static int curve_approximate(struct coord *c, int num, int x)
{
int x0, y0, x1, y1, y=-1;
int i;
for (i=1; i<num; i++) {
if (x < c[i].x) {
x0 = c[i-1].x;
y0 = c[i-1].y;
x1 = c[i].x;
y1 = c[i].y;
if (y1 == y0)
y = y0;
else
y = y0 + (y1-y0)*(x-x0)/(x1-x0);
break;
}
}
return y;
}
void aml_led_init(struct aml_led *led, struct aml_led_config *config)
{
int i;
led->config = config;
for (i=0; i<LED_EVENT_BUF_SIZE; i++)
led->event[i] = LED_EVENT_NULL;
led->count = 0;
led->time = 0;
led->state = LED_STA_IDLE;
}
void aml_led_event(struct aml_led *led, int event, int event_data)
{
int i;
for (i=0; i<LED_EVENT_BUF_SIZE; i++) {
if (led->event[i] == LED_EVENT_NULL) {
led->event[i] = event;
led->event_data[i] = event_data;
break;
}
}
}
static void aml_led_event_handle(struct aml_led *led)
{
struct aml_led_config *config = led->config;
int event;
int i;
for (i=0; i<LED_EVENT_BUF_SIZE; i++) {
event = led->event[i];
if (event != LED_EVENT_NULL) {
led->event[i] = LED_EVENT_NULL;
switch (event) {
case LED_EVENT_ON:
led->brightness = config->on_brightness;
config->set_brightness(led->brightness);
led->state = LED_STA_IDLE;
break;
case LED_EVENT_OFF:
led->brightness = config->off_brightness;
config->set_brightness(led->brightness);
led->state = LED_STA_IDLE;
break;
case LED_EVENT_FLASH:
led->count = led->event_data[i];
if (led->event_data[i])
led->count++;
led->time = config->flash_off_time/LED_TIMER_INTERVAL;
led->brightness = config->flash_off_brightness;
config->set_brightness(led->brightness);
led->state = LED_STA_FLASH_OFF;
break;
case LED_EVENT_BREATH:
led->time = 0;
led->state = LED_STA_BREATH;
break;
default:
break;
}
break;
}
}
}
void aml_led_timer_proc(struct aml_led *led)
{
struct aml_led_config *config = led->config;
switch (led->state) {
case LED_STA_IDLE:
aml_led_event_handle(led);
break;
case LED_STA_FLASH_ON:
if (--led->time == 0) {
led->time = config->flash_off_time/LED_TIMER_INTERVAL;
led->brightness = config->flash_off_brightness;
config->set_brightness(led->brightness);
led->state = LED_STA_FLASH_OFF;
}
break;
case LED_STA_FLASH_OFF:
if (--led->time == 0) {
if ((led->count == 0)
|| ((led->count>0) && (--led->count))) {
led->time = config->flash_on_time/LED_TIMER_INTERVAL;
led->brightness = config->flash_on_brightness;
config->set_brightness(led->brightness);
led->state = LED_STA_FLASH_ON;
if (led->count == 0)
aml_led_event_handle(led);
}
else {
led->state = LED_STA_IDLE;
aml_led_event_handle(led);
}
}
break;
case LED_STA_BREATH:
led->brightness = curve_approximate(
config->breath_inflections,
config->breath_inflections_num,
led->time);
if (led->brightness < 0)
led->time = 0;
else {
config->set_brightness(led->brightness);
led->time += LED_TIMER_INTERVAL;
}
aml_led_event_handle(led);
break;
default:
break;
}
}