Files
OpenTXW81X/sdk/driver/led/hgled_v0.c
T
2025-08-27 09:51:58 +01:00

413 lines
10 KiB
C

/**
* @file hgled_v0.c
* @author bxd
* @brief led
* @version
* TXW80X
* @date 2023-08-02
*
* @copyright Copyright (c) 2023
*
*/
#include "typesdef.h"
#include "list.h"
#include "errno.h"
#include "dev.h"
#include "osal/irq.h"
#include "osal/string.h"
#include "hal/led.h"
#include "dev/led/hgled_v0.h"
#include "hgled_v0_hw.h"
/**********************************************************************************/
/* LOW LAYER FUNCTION */
/**********************************************************************************/
static int32 hgled_v0_switch_hal_led_work_mode(enum led_work_mode param) {
switch (param) {
case (LED_WORK_MODE_COMMON_ANODE):
return 1;
break;
case (LED_WORK_MODE_COMMON_CATHODE):
return 0;
break;
default:
return -1;
break;
}
}
static int32 hgled_v0_switch_hal_led_seg_cnt(enum led_seg_cnt param) {
switch (param) {
case (LED_SEG_CNT_1):
return 0x10001;
break;
case (LED_SEG_CNT_2):
return 0x20003;
break;
case (LED_SEG_CNT_3):
return 0x30007;
break;
case (LED_SEG_CNT_4):
return 0x4000f;
break;
case (LED_SEG_CNT_5):
return 0x5001f;
break;
case (LED_SEG_CNT_6):
return 0x6003f;
break;
case (LED_SEG_CNT_7):
return 0x7007f;
break;
case (LED_SEG_CNT_8):
return 0x800ff;
break;
case (LED_SEG_CNT_9):
return 0x901ff;
break;
case (LED_SEG_CNT_10):
return 0xa03ff;
break;
case (LED_SEG_CNT_11):
return 0xb07ff;
break;
case (LED_SEG_CNT_12):
return 0xc0fff;
break;
default:
return -1;
break;
}
}
static int32 hgled_v0_switch_hal_led_com_cnt(enum led_com_cnt param) {
switch (param) {
case (LED_COM_CNT_1):
return 0x10001;
break;
case (LED_COM_CNT_2):
return 0x20003;
break;
case (LED_COM_CNT_3):
return 0x30007;
break;
case (LED_COM_CNT_4):
return 0x4000f;
break;
case (LED_COM_CNT_5):
return 0x5001f;
break;
case (LED_COM_CNT_6):
return 0x6003f;
break;
case (LED_COM_CNT_7):
return 0x7007f;
break;
case (LED_COM_CNT_8):
return 0x800ff;
break;
default:
return -1;
break;
}
}
static int32 hgled_v0_switch_hal_led_irq_flag(enum led_irq_flag param) {
switch (param) {
case (LED_IRQ_FLAG_INT):
return 0;
break;
default:
return -1;
break;
}
}
static int32 hgled_v0_switch_hal_led_ioctl_cmd(enum led_ioctl_cmd param) {
switch (param) {
case (LED_IOCTL_CMD_SET_SCAN_FREQ):
return 0;
break;
default:
return -1;
break;
}
}
static inline void hgled_v0_enable(struct hgled_v0_hw *p_led) {
(p_led)->CON |= LL_LED_CON_EN;
}
static inline void hgled_v0_disable(struct hgled_v0_hw *p_led) {
(p_led)->CON &= ~LL_LED_CON_EN;
}
static inline void hgled_v0_clear_interrupt_pending(struct hgled_v0_hw *p_led) {
(p_led)->CON |= LL_LED_CON_PENDING_CLR;
}
static inline int32 hgled_v0_set_scan_freq(struct hgled_v0_hw *p_led, uint32 param1, uint32 param2) {
(p_led)->TIME = ((p_led)->TIME &~ LL_LED_TIME_CLK_PSC(0xFFF)) | LL_LED_TIME_CLK_PSC(param1);
(p_led)->TIME = ((p_led)->TIME &~ LL_LED_TIME_LEN(0xFF )) | LL_LED_TIME_LEN(param2 );
return RET_OK;
}
/**********************************************************************************/
/* ATTCH FUNCTION */
/**********************************************************************************/
static int32 hgled_v0_open(struct led_device *led, enum led_work_mode work_mode, enum led_seg_cnt seg_cnt, enum led_com_cnt com_cnt) {
struct hgled_v0 *dev = (struct hgled_v0 *)led;
struct hgled_v0_hw *hw = (struct hgled_v0_hw *)dev->hw;
int32 work_mode_to_reg = 0;
int32 seg_cnt_to_reg = 0;
int32 com_cnt_to_reg = 0;
if (dev->opened) {
return -EBUSY;
}
/* hal enum */
work_mode_to_reg = hgled_v0_switch_hal_led_work_mode(work_mode);
seg_cnt_to_reg = hgled_v0_switch_hal_led_seg_cnt(seg_cnt );
com_cnt_to_reg = hgled_v0_switch_hal_led_com_cnt(com_cnt );
if (((-1) == work_mode_to_reg) ||
((-1) == seg_cnt_to_reg ) ||
((-1) == com_cnt_to_reg ) ) {
return RET_ERR;
}
/* pin config */
if (pin_func(dev->dev.dev.dev_id , 1) != RET_OK) {
return RET_ERR;
}
#ifdef TXW80X
sysctrl_tk_clk_en();
#endif
/* reg config */
hw->CON = LL_LED_CON_SEG_EN(seg_cnt_to_reg & 0xFFFF) | \
LL_LED_CON_COM_EN(com_cnt_to_reg & 0xFFFF) | \
LL_LED_CON_SCAN_SEL(work_mode_to_reg ) | \
LL_LED_CON_PENDING_CLR;
hw->TIME = LL_LED_TIME_CLK_PSC(59) | /* default clk psc */
LL_LED_TIME_GRAY(0) |
LL_LED_TIME_LEN(99); /* default time len */
hw->DATA0 = 0x0000;
hw->DATA1 = 0x0000;
hw->DATA2 = 0x0000;
hw->DATA3 = 0x0000;
hw->CON |= LL_LED_CON_LOAD_DATA_EN;
hw->CON |= LL_LED_CON_EN;
dev->opened = 1;
dev->com_cnt = com_cnt_to_reg >> 16;
dev->seg_cnt = seg_cnt_to_reg >> 16;
dev->tube_type = work_mode;
return RET_OK;
}
static int32 hgled_v0_on(struct led_device *led, uint32 num, enum led_com_cnt pos) {
struct hgled_v0 *dev = (struct hgled_v0 *)led;
struct hgled_v0_hw *hw = (struct hgled_v0_hw *)dev->hw;
const uint16 num_tbl[10] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
int32 i = 0;
uint32 e = 0;
uint32 *led_ptr = (uint32 *)(&(hw->DATA0));
uint32 data_temp = 0;
i = hgled_v0_switch_hal_led_com_cnt(pos);
if ((-1) == i) {
return RET_ERR;
}
i = (i >> 16);
if (i > dev->com_cnt) {
return RET_ERR;
}
i -= 1;
e = num % 10;
//update pointer by pos, 16 bits for seg
led_ptr = led_ptr + (i/2);
data_temp = *(led_ptr);
data_temp = (data_temp &~ (0xFF << (16*(i%2)))) | (num_tbl[e] << (16*(i%2)));
//write data to show
*(led_ptr) = data_temp;
return RET_OK;
}
static int32 hgled_v0_off(struct led_device *led, enum led_com_cnt pos) {
struct hgled_v0 *dev = (struct hgled_v0 *)led;
struct hgled_v0_hw *hw = (struct hgled_v0_hw *)dev->hw;
int32 i = 0;
uint32 *led_ptr = (uint32 *)(&(hw->DATA0));
uint32 data_temp = 0;
i = hgled_v0_switch_hal_led_com_cnt(pos);
if ((-1) == i) {
return RET_ERR;
}
i = (i >> 16);
if (i > dev->com_cnt) {
return RET_ERR;
}
i -= 1;
//update pointer by pos, 16 bits for seg
led_ptr = led_ptr + (i/2);
data_temp = *(led_ptr);
//write 0 to data register for turn off the tube
data_temp = (data_temp &~ (0xFF << (16*(i%2))));
*(led_ptr) = data_temp;
return RET_OK;
}
static int32 hgled_v0_close(struct led_device *led) {
struct hgled_v0 *dev = (struct hgled_v0 *)led;
struct hgled_v0_hw *hw = (struct hgled_v0_hw *)dev->hw;
if (!dev->opened) {
return RET_OK;
}
hgled_v0_disable(hw );
irq_disable(dev->irq_num );
pin_func(dev->dev.dev.dev_id, 0);
#ifdef TXW80X
sysctrl_tk_clk_dis();
#endif
dev->opened = 0;
dev->tube_type = 0;
dev->seg_cnt = 0;
dev->com_cnt = 0;
return RET_OK;
}
static int32 hgled_v0_ioctl(struct led_device *led, enum led_ioctl_cmd ioctl_cmd, uint32 param1, uint32 param2) {
int32 ret_val = RET_OK;
struct hgled_v0 *dev = (struct hgled_v0 *)led;
struct hgled_v0_hw *hw = (struct hgled_v0_hw *)dev->hw;
switch (ioctl_cmd) {
case (LED_IOCTL_CMD_SET_SCAN_FREQ):
ret_val = hgled_v0_set_scan_freq(hw, param1, param2);
break;
default:
ret_val = -ENOTSUPP;
break;
}
return ret_val;
}
static void hgled_v0_irq_handler(void *data) {
struct hgled_v0 *dev = (struct hgled_v0 *)data;
struct hgled_v0_hw *hw = (struct hgled_v0_hw *)dev->hw;
if((hw->CON & LL_LED_CON_PENDING) && (hw->CON & LL_LED_CON_IE)) {
hgled_v0_clear_interrupt_pending(hw);
if (dev->irq_hdl) {
dev->irq_hdl(LED_IRQ_FLAG_INT, dev->irq_data);
}
}
}
static int32 hgled_v0_request_irq(struct led_device *led, enum led_irq_flag irq_flag, led_irq_hdl irq_hdl, uint32 irq_data) {
struct hgled_v0 *dev = (struct hgled_v0 *)led;
struct hgled_v0_hw *hw = (struct hgled_v0_hw *)dev->hw;
dev->irq_hdl = irq_hdl;
dev->irq_data = irq_data;
request_irq(dev->irq_num, hgled_v0_irq_handler, dev);
if (irq_flag & LED_IRQ_FLAG_INT) {
hw->CON |= LL_LED_CON_IE;
}
irq_enable(dev->irq_num);
return RET_OK;
}
static int32 hgled_v0_release_irq(struct led_device *led, enum led_irq_flag irq_flag) {
struct hgled_v0 *dev = (struct hgled_v0 *)led;
struct hgled_v0_hw *hw = (struct hgled_v0_hw *)dev->hw;
irq_disable(dev->irq_num);
hw->CON &= ~ LL_LED_CON_IE;
return RET_OK;
}
static const struct led_hal_ops led_ops = {
.open = hgled_v0_open,
.close = hgled_v0_close,
.on = hgled_v0_on,
.off = hgled_v0_off,
.ioctl = hgled_v0_ioctl,
.request_irq = hgled_v0_request_irq,
.release_irq = hgled_v0_release_irq,
};
int32 hgled_v0_attach(uint32 dev_id, struct hgled_v0 *led) {
led->opened = 0;
led->seg_cnt = 0;
led->com_cnt = 0;
led->tube_type = 0;
led->irq_hdl = NULL;
led->irq_data = 0;
led->dev.dev.ops =(const struct devobj_ops *)&led_ops;
irq_disable(led->irq_num);
dev_register(dev_id, (struct dev_obj *)led);
return RET_OK;
}