150 lines
2.9 KiB
C
150 lines
2.9 KiB
C
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
|
|
/*
|
|
* drivers/misc/aml_led_pwm.c
|
|
*
|
|
* Copyright (C) 2020 Amlogic, Inc. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
#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);
|
|
}
|
|
|
|
|