413 lines
10 KiB
C
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;
|
|
}
|
|
|