| /* |
| * 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); |
| } |
| |
| |