blob: 09bc8bcf3b7a30377c9373eaf05318fbba6068f5 [file] [log] [blame]
/*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
* *
This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* *
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.
* *
You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* *
Description:
*/
#include <common.h>
#include <asm/arch/secure_apb.h>
#include <asm/arch/io.h>
#include <asm/arch/mailbox.h>
#include <amlogic/aml_led.h>
#define LED_DEFAULT_PWM_FREQ 100000
#define FIN_FREQ (24 * 1000)
#define DUTY_MAX 1024
static int pwm_calc(int duty, unsigned int pwm_freq, unsigned int *setting)
{
unsigned int div;
unsigned int pwm_cnt;
unsigned int pwm_lo, pwm_hi;
if (duty < 0)
duty = 0;
else if (duty > DUTY_MAX)
duty = DUTY_MAX;
for (div = 0; div < 0x7f; div++) {
pwm_cnt = FIN_FREQ * 1000 / (pwm_freq * (div + 1)) - 2;
if (pwm_cnt <= 0xffff)
break;
}
if (duty == 0) {
pwm_hi = 0;
pwm_lo = pwm_cnt;
}
else if (duty == DUTY_MAX) {
pwm_hi = pwm_cnt;
pwm_lo = 0;
}
else {
pwm_hi = pwm_cnt * duty;
pwm_hi /= DUTY_MAX;
pwm_lo = pwm_cnt - pwm_hi;
}
setting[0] = div;
setting[1] = pwm_lo;
setting[2] = pwm_hi;
return 0;
}
/*
static void pled_gpio_ctrl(int on)
{
unsigned int value;
value = readl(AO_RTI_PIN_MUX_REG);
value &= ~(3<<19);
writel(value, AO_RTI_PIN_MUX_REG);
value = readl(AO_GPIO_O_EN_N);
value &= ~((1<<11)|(1<<27));
#ifdef CONFIG_LED_PWM_INVERT
on = !on;
#endif
value |= (on<<27);
//printf("on=%d, value=0x%x\n", on, value);
writel(value, AO_GPIO_O_EN_N);
}
*/
static void pled_mux_to_pwm(void)
{
unsigned int value;
// GPIOAO_11 mux as PWM_AO_A
value = readl(AO_RTI_PIN_MUX_REG);
value |= (1<<19);
value &= ~(1<<20);
writel(value, AO_RTI_PIN_MUX_REG);
}
static void pled_set_brightness(int brightness)
{
unsigned int value;
unsigned int setting[3] = {0};
#ifdef CONFIG_LED_PWM_INVERT
brightness = DUTY_MAX - brightness;
#endif
pwm_calc(brightness, LED_DEFAULT_PWM_FREQ, &setting[0]);
value = readl(AO_PWM_MISC_REG_AB);
// clk div
value &= ~(0x7f<<8);
value |= (setting[0]<<8);
//clk enable
value |= 1<<15;
writel(value, AO_PWM_MISC_REG_AB);
// duty cycle
writel((setting[2] << 16) | setting[1], AO_PWM_PWM_A);
// enable PWM_AO_A
value = readl(AO_PWM_MISC_REG_AB);
value |= 0x3;
writel(value, AO_PWM_MISC_REG_AB);
}
static void __led_blink (led_id_t mask, int count)
{
struct led_timer_strc{
unsigned int expires;
unsigned int expires_count;
unsigned int led_mode;
} led_val;
led_val.led_mode = 0;
lwm_set_suspend(led_val.led_mode, RECOVERY_MODE);
led_val.expires = 1000*1000; //1000ms
led_val.expires_count = count;
if (send_usr_data(SCPI_CL_LED_TIMER,(unsigned int *)&led_val,sizeof(led_val)))
printf("send_led_timer_data send error!...\n");
}
void __led_toggle (led_id_t mask)
{
__led_blink(mask, -1);
}
void __led_set (led_id_t mask, int state)
{
__led_blink(mask, 0);
if (state == STATUS_LED_ON)
pled_set_brightness(DUTY_MAX);
else
pled_set_brightness(0);
}
void __led_init (led_id_t mask, int state)
{
pled_mux_to_pwm();
__led_set(mask, state);
}