mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 12:57:06 +09:00
power: rk816-battery: support temperature charge v2
Set charge current according to bat temperature. Change-Id: I409bf33614c9e689f7a85382d6033af6b18755e1 Signed-off-by: Joseph Chen <chenjh@rock-chips.com>
This commit is contained in:
@@ -181,6 +181,7 @@ struct rk816_battery {
|
||||
struct delayed_work host_work;
|
||||
struct delayed_work discnt_work;
|
||||
struct extcon_dev *cable_edev;
|
||||
int charger_changed;
|
||||
int bat_res;
|
||||
int chrg_status;
|
||||
int res_fac;
|
||||
@@ -1489,18 +1490,30 @@ static void rk816_bat_update_leds(struct rk816_battery *di, int prop)
|
||||
}
|
||||
}
|
||||
|
||||
static void rk816_bat_set_current(struct rk816_battery *di, int charge_current)
|
||||
static void rk816_bat_set_chrg_current(struct rk816_battery *di,
|
||||
u8 chrg_current)
|
||||
{
|
||||
u8 chrg_ctrl_reg1;
|
||||
|
||||
chrg_ctrl_reg1 = rk816_bat_read(di, RK816_CHRG_CTRL_REG1);
|
||||
chrg_ctrl_reg1 &= ~CHRG_CUR_MSK;
|
||||
chrg_ctrl_reg1 |= (chrg_current);
|
||||
rk816_bat_write(di, RK816_CHRG_CTRL_REG1, chrg_ctrl_reg1);
|
||||
}
|
||||
|
||||
static void rk816_bat_set_input_current(struct rk816_battery *di,
|
||||
int input_current)
|
||||
{
|
||||
u8 usb_ctrl;
|
||||
|
||||
if (di->pdata->bat_mode == MODE_VIRTUAL) {
|
||||
BAT_INFO("virtual power test mode, set max input current\n");
|
||||
charge_current = di->chrg_cur_input;
|
||||
input_current = di->chrg_cur_input;
|
||||
}
|
||||
|
||||
usb_ctrl = rk816_bat_read(di, RK816_USB_CTRL_REG);
|
||||
usb_ctrl &= ~INPUT_CUR_MSK;
|
||||
usb_ctrl |= (charge_current);
|
||||
usb_ctrl |= (input_current);
|
||||
rk816_bat_write(di, RK816_USB_CTRL_REG, usb_ctrl);
|
||||
}
|
||||
|
||||
@@ -1517,7 +1530,8 @@ static void rk816_bat_set_chrg_param(struct rk816_battery *di,
|
||||
di->ac_in = 0;
|
||||
di->dc_in = 0;
|
||||
di->prop_status = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
rk816_bat_set_current(di, INPUT_CUR450MA);
|
||||
rk816_bat_set_chrg_current(di, di->chrg_cur_sel);
|
||||
rk816_bat_set_input_current(di, INPUT_CUR450MA);
|
||||
power_supply_changed(di->bat);
|
||||
power_supply_changed(di->usb);
|
||||
power_supply_changed(di->ac);
|
||||
@@ -1527,7 +1541,8 @@ static void rk816_bat_set_chrg_param(struct rk816_battery *di,
|
||||
di->ac_in = 0;
|
||||
if (di->dc_in == 0) {
|
||||
di->prop_status = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
rk816_bat_set_current(di, INPUT_CUR450MA);
|
||||
rk816_bat_set_chrg_current(di, di->chrg_cur_sel);
|
||||
rk816_bat_set_input_current(di, INPUT_CUR450MA);
|
||||
}
|
||||
power_supply_changed(di->usb);
|
||||
power_supply_changed(di->ac);
|
||||
@@ -1536,29 +1551,35 @@ static void rk816_bat_set_chrg_param(struct rk816_battery *di,
|
||||
di->usb_in = 1;
|
||||
di->ac_in = 0;
|
||||
di->prop_status = POWER_SUPPLY_STATUS_CHARGING;
|
||||
if (di->dc_in == 0)
|
||||
rk816_bat_set_current(di, INPUT_CUR450MA);
|
||||
if (di->dc_in == 0) {
|
||||
rk816_bat_set_chrg_current(di, di->chrg_cur_sel);
|
||||
rk816_bat_set_input_current(di, INPUT_CUR450MA);
|
||||
}
|
||||
power_supply_changed(di->usb);
|
||||
break;
|
||||
case USB_TYPE_CDP_CHARGER:
|
||||
di->usb_in = 1;
|
||||
di->ac_in = 0;
|
||||
di->prop_status = POWER_SUPPLY_STATUS_CHARGING;
|
||||
if (di->dc_in == 0)
|
||||
rk816_bat_set_current(di, INPUT_CUR1500MA);
|
||||
if (di->dc_in == 0) {
|
||||
rk816_bat_set_chrg_current(di, di->chrg_cur_sel);
|
||||
rk816_bat_set_input_current(di, INPUT_CUR1500MA);
|
||||
}
|
||||
power_supply_changed(di->usb);
|
||||
break;
|
||||
case USB_TYPE_AC_CHARGER:
|
||||
di->ac_in = 1;
|
||||
di->usb_in = 0;
|
||||
di->prop_status = POWER_SUPPLY_STATUS_CHARGING;
|
||||
rk816_bat_set_current(di, di->chrg_cur_input);
|
||||
rk816_bat_set_chrg_current(di, di->chrg_cur_sel);
|
||||
rk816_bat_set_input_current(di, di->chrg_cur_input);
|
||||
power_supply_changed(di->ac);
|
||||
break;
|
||||
case DC_TYPE_DC_CHARGER:
|
||||
di->dc_in = 1;
|
||||
di->prop_status = POWER_SUPPLY_STATUS_CHARGING;
|
||||
rk816_bat_set_current(di, di->chrg_cur_input);
|
||||
rk816_bat_set_chrg_current(di, di->chrg_cur_sel);
|
||||
rk816_bat_set_input_current(di, di->chrg_cur_input);
|
||||
power_supply_changed(di->ac);
|
||||
break;
|
||||
case DC_TYPE_NONE_CHARGER:
|
||||
@@ -1573,9 +1594,11 @@ static void rk816_bat_set_chrg_param(struct rk816_battery *di,
|
||||
di->ac_in = 0;
|
||||
di->usb_in = 0;
|
||||
di->prop_status = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
rk816_bat_set_current(di, INPUT_CUR450MA);
|
||||
rk816_bat_set_chrg_current(di, di->chrg_cur_sel);
|
||||
rk816_bat_set_input_current(di, INPUT_CUR450MA);
|
||||
} else if (di->usb_in) {
|
||||
rk816_bat_set_current(di, INPUT_CUR450MA);
|
||||
rk816_bat_set_chrg_current(di, di->chrg_cur_sel);
|
||||
rk816_bat_set_input_current(di, INPUT_CUR450MA);
|
||||
di->prop_status = POWER_SUPPLY_STATUS_CHARGING;
|
||||
}
|
||||
power_supply_changed(di->usb);
|
||||
@@ -1586,6 +1609,8 @@ static void rk816_bat_set_chrg_param(struct rk816_battery *di,
|
||||
break;
|
||||
}
|
||||
|
||||
di->charger_changed = 1;
|
||||
|
||||
usb_ctrl = rk816_bat_read(di, RK816_USB_CTRL_REG);
|
||||
chrg_ctrl1 = rk816_bat_read(di, RK816_CHRG_CTRL_REG1);
|
||||
BAT_INFO("set charger type: %s, current: input=%d, chrg=%d\n",
|
||||
@@ -2129,58 +2154,81 @@ static void rk816_bat_select_sample_res(struct rk816_battery *di)
|
||||
}
|
||||
}
|
||||
|
||||
static void rk816_bat_select_chrg_cv(struct rk816_battery *di)
|
||||
static u8 rk816_bat_decode_input_current(struct rk816_battery *di,
|
||||
u32 input_current)
|
||||
{
|
||||
int index, chrg_vol_sel, chrg_cur_sel, chrg_cur_input;
|
||||
|
||||
di->chrg_vol_sel = DEFAULT_CHRG_VOL_SEL;
|
||||
di->chrg_cur_input = DEFAULT_CHRG_CUR_INPUT;
|
||||
di->chrg_cur_sel = DEFAULT_CHRG_CUR_SEL;
|
||||
di->chrg_cur_lp_input = 0;
|
||||
|
||||
chrg_vol_sel = di->pdata->max_chrg_voltage;
|
||||
chrg_cur_sel = di->pdata->max_chrg_current;
|
||||
chrg_cur_input = di->pdata->max_input_current;
|
||||
|
||||
if (di->pdata->sample_res < 20) {
|
||||
if (chrg_cur_sel > 2000)
|
||||
chrg_cur_sel = RES_FAC_DIV(chrg_cur_sel, di->res_fac);
|
||||
else
|
||||
chrg_cur_sel = 1000;
|
||||
} else if (di->pdata->sample_res > 20) {
|
||||
chrg_cur_sel = RES_FAC_MUX(chrg_cur_sel, di->res_fac);
|
||||
if (chrg_cur_sel > 2400)
|
||||
chrg_cur_sel = 2400;
|
||||
if (chrg_cur_sel < 1000)
|
||||
chrg_cur_sel = 1000;
|
||||
}
|
||||
|
||||
for (index = 0; index < ARRAY_SIZE(CHRG_VOL_SEL); index++) {
|
||||
if (chrg_vol_sel < CHRG_VOL_SEL[index])
|
||||
break;
|
||||
di->chrg_vol_sel = (index << CHRG_VOL_SEL_SHIFT);
|
||||
}
|
||||
u8 val = DEFAULT_CHRG_CUR_INPUT;
|
||||
u8 index;
|
||||
|
||||
for (index = 2; index < ARRAY_SIZE(CHRG_CUR_INPUT); index++) {
|
||||
if (chrg_cur_input < 850 && chrg_cur_input > 80) {
|
||||
di->chrg_cur_input = 0x0;
|
||||
if (input_current < 850 && input_current > 80) {
|
||||
val = 0x0;/* 450mA */
|
||||
break;
|
||||
} else if (chrg_cur_input <= 80) {
|
||||
di->chrg_cur_input = 0x1;
|
||||
} else if (input_current <= 80) {
|
||||
val = 0x1;/* 80mA */
|
||||
break;
|
||||
} else {
|
||||
if (chrg_cur_input < CHRG_CUR_INPUT[index])
|
||||
if (input_current < CHRG_CUR_INPUT[index])
|
||||
break;
|
||||
di->chrg_cur_input = (index << CHRG_CRU_INPUT_SHIFT);
|
||||
val = (index << CHRG_CRU_INPUT_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
for (index = 0; index < ARRAY_SIZE(CHRG_CUR_SEL); index++) {
|
||||
if (chrg_cur_sel < CHRG_CUR_SEL[index])
|
||||
break;
|
||||
di->chrg_cur_sel = (index << CHRG_CRU_SEL_SHIFT);
|
||||
return val;
|
||||
}
|
||||
|
||||
static u8 rk816_bat_decode_chrg_current(struct rk816_battery *di,
|
||||
u32 chrg_current)
|
||||
{
|
||||
u8 val = DEFAULT_CHRG_CUR_SEL;
|
||||
u8 index;
|
||||
|
||||
if (di->pdata->sample_res < 20) {
|
||||
if (chrg_current > 2000)
|
||||
chrg_current = RES_FAC_DIV(chrg_current, di->res_fac);
|
||||
else
|
||||
chrg_current = 1000;
|
||||
} else if (di->pdata->sample_res > 20) {
|
||||
chrg_current = RES_FAC_MUX(chrg_current, di->res_fac);
|
||||
if (chrg_current > 2400)
|
||||
chrg_current = 2400;
|
||||
if (chrg_current < 1000)
|
||||
chrg_current = 1000;
|
||||
}
|
||||
|
||||
for (index = 0; index < ARRAY_SIZE(CHRG_CUR_SEL); index++) {
|
||||
if (chrg_current < CHRG_CUR_SEL[index])
|
||||
break;
|
||||
val = (index << CHRG_CRU_SEL_SHIFT);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static u8 rk816_bat_decode_chrg_vol(struct rk816_battery *di,
|
||||
u32 chrg_vol)
|
||||
{
|
||||
u8 val = DEFAULT_CHRG_VOL_SEL;
|
||||
u8 index;
|
||||
|
||||
for (index = 0; index < ARRAY_SIZE(CHRG_VOL_SEL); index++) {
|
||||
if (chrg_vol < CHRG_VOL_SEL[index])
|
||||
break;
|
||||
val = (index << CHRG_VOL_SEL_SHIFT);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void rk816_bat_select_chrg_cv(struct rk816_battery *di)
|
||||
{
|
||||
di->chrg_vol_sel = rk816_bat_decode_chrg_vol(di,
|
||||
di->pdata->max_chrg_voltage);
|
||||
di->chrg_cur_input = rk816_bat_decode_input_current(di,
|
||||
di->pdata->max_input_current);
|
||||
di->chrg_cur_sel = rk816_bat_decode_chrg_current(di,
|
||||
di->pdata->max_chrg_current);
|
||||
|
||||
DBG("<%s>. vol = 0x%x, input = 0x%x, sel = 0x%x\n",
|
||||
__func__, di->chrg_vol_sel, di->chrg_cur_input, di->chrg_cur_sel);
|
||||
}
|
||||
@@ -3655,6 +3703,78 @@ static int rk816_bat_get_ntc_res(struct rk816_battery *di)
|
||||
return res;
|
||||
}
|
||||
|
||||
static int rk816_bat_temperature_chrg(struct rk816_battery *di, int temp)
|
||||
{
|
||||
static int temp_triggered, config_index = -1;
|
||||
int i, up_temp, down_temp, cfg_current;
|
||||
u8 usb_ctrl, chrg_ctrl1;
|
||||
int now_temp = temp;
|
||||
int cur;
|
||||
|
||||
for (i = 0; i < di->pdata->tc_count; i++) {
|
||||
up_temp = di->pdata->tc_table[i].temp_up;
|
||||
down_temp = di->pdata->tc_table[i].temp_down;
|
||||
cfg_current = di->pdata->tc_table[i].chrg_current;
|
||||
|
||||
if (now_temp >= down_temp && now_temp <= up_temp) {
|
||||
/* Temp range or charger are not update, return */
|
||||
if (config_index == i && !di->charger_changed)
|
||||
return 0;
|
||||
|
||||
config_index = i;
|
||||
di->charger_changed = 0;
|
||||
temp_triggered = 1;
|
||||
|
||||
if (di->pdata->tc_table[i].set_chrg_current) {
|
||||
rk816_bat_set_chrg_current(di, cfg_current);
|
||||
if (!di->over_20mR)
|
||||
cur =
|
||||
RES_FAC_MUX(CHRG_CUR_SEL[cfg_current],
|
||||
di->res_fac);
|
||||
else
|
||||
cur =
|
||||
RES_FAC_DIV(CHRG_CUR_SEL[cfg_current],
|
||||
di->res_fac);
|
||||
BAT_INFO("temperature = %d'C[%d~%d'C], chrg current = %d\n",
|
||||
now_temp, down_temp, up_temp, cur);
|
||||
} else {
|
||||
rk816_bat_set_input_current(di, cfg_current);
|
||||
BAT_INFO("temperature = %d'C[%d~%d'C], input current = %d\n",
|
||||
now_temp, down_temp, up_temp,
|
||||
CHRG_CUR_INPUT[cfg_current]);
|
||||
}
|
||||
return 0; /* return after configure */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* means: current temperature not covers above case, temperature rolls
|
||||
* back to normal range, so restore default value
|
||||
*/
|
||||
if (temp_triggered) {
|
||||
temp_triggered = 0;
|
||||
config_index = -1;
|
||||
rk816_bat_set_chrg_current(di, di->chrg_cur_sel);
|
||||
if (di->ac_in || di->dc_in)
|
||||
rk816_bat_set_input_current(di, di->chrg_cur_input);
|
||||
else
|
||||
rk816_bat_set_input_current(di, INPUT_CUR450MA);
|
||||
usb_ctrl = rk816_bat_read(di, RK816_USB_CTRL_REG);
|
||||
chrg_ctrl1 = rk816_bat_read(di, RK816_CHRG_CTRL_REG1);
|
||||
cfg_current = chrg_ctrl1 & 0x0f;
|
||||
if (!di->over_20mR)
|
||||
cur =
|
||||
RES_FAC_MUX(CHRG_CUR_SEL[cfg_current], di->res_fac);
|
||||
else
|
||||
cur =
|
||||
RES_FAC_DIV(CHRG_CUR_SEL[cfg_current], di->res_fac);
|
||||
BAT_INFO("roll back temp %d'C, current chrg = %d, input = %d\n",
|
||||
now_temp, cur, CHRG_CUR_INPUT[(usb_ctrl & 0x0f)]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rk816_bat_update_temperature(struct rk816_battery *di)
|
||||
{
|
||||
u32 ntc_size, *ntc_table;
|
||||
@@ -3668,14 +3788,18 @@ static void rk816_bat_update_temperature(struct rk816_battery *di)
|
||||
res = rk816_bat_get_ntc_res(di);
|
||||
if (res < ntc_table[ntc_size - 1]) {
|
||||
BAT_INFO("bat ntc upper max degree: R=%d\n", res);
|
||||
rk816_bat_set_input_current(di, INPUT_CUR80MA);
|
||||
} else if (res > ntc_table[0]) {
|
||||
BAT_INFO("bat ntc lower min degree: R=%d\n", res);
|
||||
rk816_bat_set_input_current(di, INPUT_CUR80MA);
|
||||
} else {
|
||||
for (i = 0; i < ntc_size; i++) {
|
||||
if (res >= ntc_table[i])
|
||||
break;
|
||||
}
|
||||
|
||||
di->temperature = (i + di->pdata->ntc_degree_from) * 10;
|
||||
rk816_bat_temperature_chrg(di, di->temperature / 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4410,6 +4534,62 @@ static int rk816_bat_read_ocv_tables(struct rk816_battery *di,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_temperature_chrg_table(struct rk816_battery *di,
|
||||
struct device_node *np)
|
||||
{
|
||||
int size, count;
|
||||
int i, chrg_current;
|
||||
const __be32 *list;
|
||||
|
||||
if (!of_find_property(np, "temperature_chrg_table_v2", &size))
|
||||
return 0;
|
||||
|
||||
list = of_get_property(np, "temperature_chrg_table_v2", &size);
|
||||
size /= sizeof(u32);
|
||||
if (!size || (size % 3)) {
|
||||
dev_err(di->dev,
|
||||
"invalid temperature_chrg_table: size=%d\n", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
count = size / 3;
|
||||
di->pdata->tc_count = count;
|
||||
di->pdata->tc_table = devm_kzalloc(di->dev,
|
||||
count * sizeof(*di->pdata->tc_table),
|
||||
GFP_KERNEL);
|
||||
if (!di->pdata->tc_table)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
/* temperature */
|
||||
di->pdata->tc_table[i].temp_down = be32_to_cpu(*list++);
|
||||
di->pdata->tc_table[i].temp_up = be32_to_cpu(*list++);
|
||||
|
||||
/*
|
||||
* because charge current lowest level is 1000mA:
|
||||
* higher than or equal 1000ma, select charge current;
|
||||
* lower than 1000ma, must select input current.
|
||||
*/
|
||||
chrg_current = be32_to_cpu(*list++);
|
||||
if (chrg_current >= 1000) {
|
||||
di->pdata->tc_table[i].set_chrg_current = 1;
|
||||
di->pdata->tc_table[i].chrg_current =
|
||||
rk816_bat_decode_chrg_current(di, chrg_current);
|
||||
} else {
|
||||
di->pdata->tc_table[i].chrg_current =
|
||||
rk816_bat_decode_input_current(di, chrg_current);
|
||||
}
|
||||
|
||||
DBG("temp%d: [%d, %d], chrg_current=%d\n",
|
||||
i, di->pdata->tc_table[i].temp_down,
|
||||
di->pdata->tc_table[i].temp_up,
|
||||
di->pdata->tc_table[i].chrg_current);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int rk816_bat_parse_dt(struct rk816_battery *di)
|
||||
{
|
||||
u32 out_value;
|
||||
@@ -4606,18 +4786,13 @@ static int rk816_bat_parse_dt(struct rk816_battery *di)
|
||||
pdata->ntc_size = 0;
|
||||
} else {
|
||||
/* get ntc degree base value */
|
||||
ret = of_property_read_u32_index(np, "ntc_degree_from", 1,
|
||||
&pdata->ntc_degree_from);
|
||||
ret = of_property_read_s32(np, "ntc_degree_from_v2",
|
||||
&pdata->ntc_degree_from);
|
||||
if (ret) {
|
||||
dev_err(dev, "invalid ntc_degree_from\n");
|
||||
dev_err(dev, "invalid ntc_degree_from_v2\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
of_property_read_u32_index(np, "ntc_degree_from", 0,
|
||||
&out_value);
|
||||
if (out_value)
|
||||
pdata->ntc_degree_from = -pdata->ntc_degree_from;
|
||||
|
||||
pdata->ntc_size = length / sizeof(u32);
|
||||
}
|
||||
|
||||
@@ -4643,6 +4818,10 @@ static int rk816_bat_parse_dt(struct rk816_battery *di)
|
||||
pdata->ntc_factor = NTC_CALC_FACTOR_20UA;
|
||||
}
|
||||
|
||||
ret = parse_temperature_chrg_table(di, np);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
DBG("the battery dts info dump:\n"
|
||||
"bat_res:%d\n"
|
||||
"res_sample:%d\n"
|
||||
@@ -4664,7 +4843,7 @@ static int rk816_bat_parse_dt(struct rk816_battery *di)
|
||||
"dc_det_adc:%d\n"
|
||||
"ntc_factor:%d\n"
|
||||
"ntc_size=%d\n"
|
||||
"ntc_degree_from:%d\n"
|
||||
"ntc_degree_from_v2:%d\n"
|
||||
"ntc_degree_to:%d\n",
|
||||
pdata->bat_res, pdata->sample_res, pdata->max_input_current,
|
||||
pdata->max_chrg_current, pdata->max_chrg_voltage,
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
#define CHRG_CT_EN (1 << 7)
|
||||
#define INPUT_CUR_MSK (0x0f)
|
||||
#define FINISH_CUR_MSK 0xc0
|
||||
#define CHRG_CUR_MSK (0x0f)
|
||||
|
||||
/* BAT_CTRL_REG */
|
||||
#define USB_SYS_EN BIT(6)
|
||||
@@ -69,7 +70,7 @@
|
||||
|
||||
/*CHGR_CUR_INPUT*/
|
||||
#define INPUT_CUR450MA (0x00)
|
||||
#define INPUT_CUR800MA (0x01)
|
||||
#define INPUT_CUR80MA (0x01)
|
||||
#define INPUT_CUR850MA (0x02)
|
||||
#define INPUT_CUR1000MA (0x03)
|
||||
#define INPUT_CUR1250MA (0x04)
|
||||
@@ -156,9 +157,18 @@
|
||||
#define MAX_INT 0x7FFF
|
||||
#define MAX_INTERPOLATE 1000
|
||||
|
||||
struct temp_chrg_table {
|
||||
int temp_down;
|
||||
int temp_up;
|
||||
u32 chrg_current;
|
||||
u8 set_chrg_current;
|
||||
};
|
||||
|
||||
struct battery_platform_data {
|
||||
u32 *ocv_table;
|
||||
u32 *zero_table;
|
||||
struct temp_chrg_table *tc_table;
|
||||
u32 tc_count;
|
||||
|
||||
u32 table_t[4][21];
|
||||
int temp_t[4];
|
||||
|
||||
Reference in New Issue
Block a user