sdk-hwV1.3/lichee/brandy-2.0/u-boot-2018/drivers/led/sunxi_ledc.c

255 lines
5.1 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* sunxi LEDC driver for uboot.
*
* Copyright (C) 2018
* 2019.1.7 lihuaxing <lihuxing@allwinnertech.com>
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <led.h>
#include <asm/io.h>
#include <dm/lists.h>
#include <asm/arch/gpio.h>
#include <sunxi_ledc.h>
#include <fdt_support.h>
static int sunxi_ledc_pin_init(void)
{
int ledc_nodeoffset;
ledc_nodeoffset = fdt_path_offset(working_fdt, "ledc");
if (ledc_nodeoffset < 0) {
printf("ledc: get node offset error\n");
return -1;
}
if (fdt_set_all_pin("ledc", "pinctrl-0")) {
printf("ledc pin init failed!\n");
return -1;
}
return 0;
}
static int ledc_set_reset_ns(void)
{
struct sunxi_ledc_reg *ledc = (struct sunxi_ledc_reg *)(LEDC_BASE_ADDR);
uint32_t mask = 0x3FFF;
int shift = 16;
int n = 1; //42*(6+1)
ledc->rst_t &= ~(mask << shift);
ledc->rst_t |= n << shift;
return 0;
}
static int ledc_set_t01_ns(void)
{
struct sunxi_ledc_reg *ledc = (struct sunxi_ledc_reg *)(LEDC_BASE_ADDR);
uint32_t mask0 = 0x7FF;
int n0l = 19;
int n0h = 8;
uint32_t mask1 = 0x7FF;
int shift1 = 16;
int n1l = 9;
int n1h = 18;
ledc->time01 &= ~mask0;
ledc->time01 |= ((n0h << 6)|(n0l));
ledc->time01 &= ~(mask1 << shift1);
ledc->time01 |= ((n1h << 21)|(n1l << 16));
return 0;
}
static int ledc_set_wait0_ns(void)
{
struct sunxi_ledc_reg *ledc = (struct sunxi_ledc_reg *)(LEDC_BASE_ADDR);
uint32_t mask = 0xFF;
int shift = 0;
int n = 1;
ledc->t0_ctrl &= ~(mask << shift);
ledc->t0_ctrl |= n << shift;
return 0;
}
static int ledc_set_wait1_ns(void)
{
struct sunxi_ledc_reg *ledc = (struct sunxi_ledc_reg *)(LEDC_BASE_ADDR);
uint32_t mask = 0x7FFFFFFF;
int shift = 0;
int n = 1;
ledc->t1_ctrl &= ~(mask << shift);
ledc->t1_ctrl |= n << shift;
return 0;
}
static void ledc_irq_enable(uint32_t mask)
{
struct sunxi_ledc_reg *ledc = (struct sunxi_ledc_reg *)(LEDC_BASE_ADDR);
ledc->irq_ctrl |= mask;
}
static void ledc_irq_disable(uint32_t mask)
{
struct sunxi_ledc_reg *ledc = (struct sunxi_ledc_reg *)(LEDC_BASE_ADDR);
ledc->irq_ctrl &= ~mask;
}
static void sunxi_ledc_enable(void)
{
struct sunxi_ledc_reg *ledc = (struct sunxi_ledc_reg *)(LEDC_BASE_ADDR);
ledc->ctrl |= 1;
}
static void sunxi_ledc_reset(void)
{
struct sunxi_ledc_reg *ledc = (struct sunxi_ledc_reg *)(LEDC_BASE_ADDR);
ledc_irq_disable(LEDC_TRANS_FINISH_INT_EN | LEDC_FIFO_CPUREQ_INT_EN
| LEDC_WAITDATA_TIMEOUT_INT_EN | LEDC_FIFO_OVERFLOW_INT_EN
| LEDC_GLOBAL_INT_EN);
ledc->ctrl |= 1 << 1;
}
static void sunxi_ledc_set_output_mode(void)
{
struct sunxi_ledc_reg *ledc = (struct sunxi_ledc_reg *)(LEDC_BASE_ADDR);
uint32_t mask = 0x7;
int shift = 6;
ledc->ctrl &= ~(mask << shift);
ledc->ctrl |= (0 << shift);
}
static void sunxi_ledc_set_cpu_mode(void)
{
struct sunxi_ledc_reg *ledc = (struct sunxi_ledc_reg *)(LEDC_BASE_ADDR);
int shift = 5;
ledc->DMA_ctrl &= ~(1 << shift);
ledc_irq_enable(LEDC_FIFO_CPUREQ_INT_EN);
}
static void sunxi_ledc_set_length(unsigned int length)
{
struct sunxi_ledc_reg *ledc = (struct sunxi_ledc_reg *)(LEDC_BASE_ADDR);
uint32_t mask = 0x1FFF;
int shift = 16;
ledc->ctrl &= ~(mask << shift);
ledc->ctrl |= length << shift; //data length
ledc->rst_t &= ~(0x3FF);
ledc->rst_t |= length - 1; //lights num
}
/*
static void sunxi_ledc_set_color(unsigned int g, unsigned int r, unsigned int b)
{
uint32_t mask = ((g << 16)|(r << 8)|(b));
data[i] = mask;
}
*/
static void sunxi_ledc_write_data(unsigned int length,
unsigned int g, unsigned int r, unsigned int b)
{
struct sunxi_ledc_reg *ledc = (struct sunxi_ledc_reg *)(LEDC_BASE_ADDR);
int i;
for (i = 0; i < length; i++)
ledc->data_reg = ((g << 16)|(r << 8)|(b));
}
static void sunxi_ledc_clk_init(void)
{
struct sunxi_ccmu_reg *clk = (struct sunxi_ccmu_reg *)(LEDC_CLOCK_ADDR);
clk->model_clk = (1 << 31)|(0 << 24)|(0 << 8)|(0);
clk->bus_gate |= (0 << 16);
clk->bus_gate |= (1 << 16);
clk->bus_gate |= (1);
}
static void sunxi_ledc_clk_exit(void)
{
struct sunxi_ccmu_reg *clk = (struct sunxi_ccmu_reg *)(LEDC_CLOCK_ADDR);
clk->model_clk = 0;
clk->bus_gate |= (0);
clk->bus_gate |= (0 << 16);
}
/* this api is use to ctrol the light.
*@length : the num of light.
*@g : the green color
*@r : the red color.
*@b : the blue color.
*e.g: sunxi_set_led_brightness(5, 255, 255, 255);
*/
int sunxi_set_led_brightness(unsigned int length, unsigned int g, unsigned int r, unsigned int b)
{
sunxi_ledc_set_output_mode();
sunxi_ledc_set_cpu_mode();
sunxi_ledc_set_length(length);
ledc_irq_enable(LEDC_TRANS_FINISH_INT_EN | LEDC_WAITDATA_TIMEOUT_INT_EN
| LEDC_FIFO_OVERFLOW_INT_EN | LEDC_GLOBAL_INT_EN);
sunxi_ledc_enable();
sunxi_ledc_write_data(length, g, r, b);
return 0;
}
/*init*/
int sunxi_ledc_init(void)
{
sunxi_ledc_clk_init();
sunxi_ledc_pin_init();
ledc_set_reset_ns();
ledc_set_t01_ns();
ledc_set_wait0_ns();
ledc_set_wait1_ns();
printf("ledc_init ok\n");
return 0;
}
/*exit*/
int sunxi_ledc_exit(void)
{
sunxi_ledc_reset();
sunxi_ledc_clk_exit();
return 0;
}
/*e.g*/
#if 0
main()
{
sunxi_ledc_init();
sunxi_set_led_brightness(3, 100, 255, 0);
sunxi_ledc_exit();
}
#endif