/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2012-2020. All rights reserved. * Description: boot lsadc driver */ #include #include "lsadc_priv.h" #include "common.h" #include "common_ext.h" #include "td_type.h" #include "uapi_lsadc.h" #ifdef CONFIG_CPU_T9 #define LSADC_REG_BASE 0xF8007000 #else #define LSADC_REG_BASE 0x00855000 #define LSADC_REG_BASE1 0x010E1000 #define LSADC_REG_BASE2 0x010E2000 #define LSADC_REG_BASE3 0x018E3000 static td_s32 g_lsadc_reg_base[] = { LSADC_REG_BASE, LSADC_REG_BASE1, LSADC_REG_BASE2, LSADC_REG_BASE3, }; #endif static struct lsadc_priv g_lsadc_local; static uapi_lsadc_config_s g_lsadc_param; #define LSADC_DEVICE_NAME "soc_lsadc" #define LSADC_CHANNALS 4 #define MAX_LSADC_GROUP 16 #define CMD_LSADC_SET_CONFIG 1 #define CMD_LSADC_GET_CONFIG 2 #define LSDAC_RESET_VALUE 0x000080FF static td_s32 lsadc_set_base(const td_u32 chan) { if (chan >= MAX_LSADC_GROUP) { printf("lsadc channel invalid\n"); return TD_FAILURE; } struct lsadc_priv *lsadc = &g_lsadc_local; #ifdef CONFIG_CPU_T9 lsadc->base = (void *)(LSADC_REG_BASE); #else lsadc->base = (void *)g_lsadc_reg_base[(chan / 0x4)]; /* 4 is lsadc ctrl num */ #endif return TD_SUCCESS; } static td_u32 lsadc_get_channel(td_u32 channel_mask) { td_s32 i; td_u32 cnt = 0; td_u32 temp_mask = channel_mask; for (i = 0; i < 32; i++) { /* 32 bit */ if ((temp_mask & 0x1) == 0x1) { return cnt; } temp_mask = temp_mask >> 1; cnt++; } return 0; } static td_s32 lsadc_set_param(uapi_lsadc_config_s *arg) { td_s32 ret = TD_SUCCESS; td_u32 value; ext_chip_name_id chip_name_id; struct lsadc_priv *lsadc = &g_lsadc_local; uapi_lsadc_config_s param = {0}; errno_t rc; td_u32 channel_mask = 0; if (arg == NULL) { return TD_FAILURE; } /* Config */ rc = memcpy_s(¶m, sizeof(param), arg, sizeof(uapi_lsadc_config_s)); if (rc != EOK) { printf("memcpy_s failed, err = %d\n", rc); return TD_FAILURE; } td_u32 channel = lsadc_get_channel(param.channel_mask); lsadc_set_base(channel); /* Stop */ writel(LSADC_STOP, lsadc->base + LSADC_CTRL8); ext_drv_sys_get_chip_name_id(&chip_name_id); g_lsadc_param = param; channel_mask = 0x1 << (channel % LSADC_CHANNALS); value = 0x0; value |= (param.active_bit & 0xFF) << 24; /* <<24 means Set Active bit[24-31] */ value |= (param.data_delta & 0xF) << 20; /* <<24 means Set data delta[20-23] */ value |= (param.deglitch_bypass & 0x1) << 17; /* <<17 means Set deglitch bypass[17] */ value |= (param.lsadc_reset & 0x1) << 15; /* <<15 means Set lsadc reset[15] */ value |= (param.power_downmod & 0x1) << 14; /* <<14 means Set power down model[14] */ value |= (param.model_sel & 0x1) << 13; /* <<13 means Set model sel[13] */ if (chip_name_id == CHIP_NAME_RESERVED5) { value |= (channel_mask & 0x3) << 10; /* <<10 means Enable channel[10-11] */ } else { value |= (channel_mask & 0xF) << 8; /* 8 means Enable channel[8-11] */ } value |= param.lsadc_zero & 0xFF; /* <<0xFF means Set lsadc zero[0-7] */ writel(value, lsadc->base + LSADC_CTRL0); // Set glitch sample writel(param.glitch_sample, lsadc->base + LSADC_CTRL1); // Set time scan writel(param.time_scan, lsadc->base + LSADC_CTRL2); mdelay(0x2); /* Start */ writel(LSADC_START, lsadc->base + LSADC_CTRL7); return ret; } static td_s32 lsadc_get_param(uapi_lsadc_config_s *arg) { td_s32 ret = TD_SUCCESS; td_u32 value; struct lsadc_priv *lsadc = &g_lsadc_local; uapi_lsadc_config_s param; errno_t rc; if (arg == NULL) { return TD_FAILURE; } rc = memset_s(¶m, sizeof(uapi_lsadc_config_s), 0, sizeof(uapi_lsadc_config_s)); if (rc != EOK) { printf("memset_s failed, err = %d\n", rc); return TD_FAILURE; } td_u32 channel = lsadc_get_channel(param.channel_mask); lsadc_set_base(channel); value = readl(lsadc->base + LSADC_CTRL0); param.active_bit = (value >> 24) & 0xFF; // [24-31] param.data_delta = (value >> 20) & 0xF; // [20-23] param.deglitch_bypass = (value >> 17) & 0x1; // [17] param.lsadc_reset = (value >> 15) & 0x1; // [15] param.power_downmod = (value >> 14) & 0x1; // [14] param.model_sel = (value >> 13) & 0x1; // [13] param.channel_mask = (value >> 10) & 0x3; // [10-11] param.lsadc_zero = value & 0xFF; // [0-7] param.glitch_sample = readl(lsadc->base + LSADC_CTRL1); param.time_scan = readl(lsadc->base + LSADC_CTRL2); rc = memcpy_s(arg, sizeof(uapi_lsadc_config_s), ¶m, sizeof(param)); if (rc != EOK) { printf("memcpy_s failed, err = %d\n", rc); return ret; } return ret; } static td_s32 lsadc_ioctl(unsigned int cmd, uapi_lsadc_config_s *arg) { td_s32 ret = 0; struct lsadc_priv *lsadc = &g_lsadc_local; if (lsadc->refcnt <= 0) { printf("lsadc has not been init\n"); return TD_FAILURE; } switch (cmd) { case CMD_LSADC_SET_CONFIG: ret = lsadc_set_param(arg); break; case CMD_LSADC_GET_CONFIG: ret = lsadc_get_param(arg); break; default: ret = TD_FAILURE; break; } return ret; } td_s32 uapi_lsadc_setconfig(uapi_lsadc_config_s_ptr pstlsadc_config) { return lsadc_ioctl(CMD_LSADC_SET_CONFIG, pstlsadc_config); } td_s32 uapi_lsadc_getconfig(uapi_lsadc_config_s_ptr pstlsadc_config) { return lsadc_ioctl(CMD_LSADC_GET_CONFIG, pstlsadc_config); } td_s32 uapi_lsadc_getvalue(td_u32 chan, td_u32 *value) { td_u32 value_tmp; td_u32 wait_cnt = 0; ext_chip_name_id chip_name_id; td_u8 chan_offset = 0; struct lsadc_priv *lsadc = &g_lsadc_local; td_u8 clr_flag = 0; td_u32 offset = 0; if (lsadc->refcnt != 1) { printf("lsadc has not been init\n"); return TD_FAILURE; } if (chan >= MAX_LSADC_GROUP || value == NULL) { printf("lsadc channel invalid\n"); return TD_FAILURE; } lsadc_set_base(chan); ext_drv_sys_get_chip_name_id(&chip_name_id); if (chip_name_id == CHIP_NAME_RESERVED5) { chan_offset = 0x2; } offset = chan % LSADC_CHANNALS; while (++wait_cnt != 0) { value_tmp = readl(lsadc->base + LSADC_CTRL5); mdelay(1); /* 1 means 1ms */ if (((value_tmp >> (offset + chan_offset)) & 0x1) == 0x1) { /* 4 means bit4, lsadc_auto_busy must be idle */ break; } if (wait_cnt >= 10) { /* 10 means 10 * 1 = 10ms */ printf("lsadc chanel %d get value time out.\n", chan); return TD_FAILURE; } } value_tmp = readl(lsadc->base + LSADC_CTRL3); if (chip_name_id == CHIP_NAME_RESERVED5) { *value = (value_tmp >> (8 * offset + 16)) & 0xFF; /* 8 means 8bits each channel; 16: bit[31:16] */ } else { *value = (value_tmp >> (8 * offset)) & 0xFF; /* 8 means 8bits each channel */ } clr_flag = 0x1 << (offset + chan_offset); writel(clr_flag, lsadc->base + LSADC_CTRL6); return TD_SUCCESS; } td_s32 uapi_lsadc_init(void) { struct lsadc_priv *lsadc = &g_lsadc_local; errno_t rc; rc = memset_s(lsadc, sizeof(struct lsadc_priv), 0, sizeof(struct lsadc_priv)); if (rc != EOK) { printf("memset_s failed, err = %d\n", rc); return TD_FAILURE; } lsadc->base = (void *)(LSADC_REG_BASE); lsadc->irq = LSADC_IRQ_NUM; rc = strncpy_s(lsadc->dev_name, LSADC_DEVICE_NAME_SIZE, LSADC_DEVICE_NAME, strlen(LSADC_DEVICE_NAME) > LSADC_DEVICE_NAME_SIZE ? LSADC_DEVICE_NAME_SIZE : strlen(LSADC_DEVICE_NAME)); if (rc != EOK) { printf("strncpy_s failed, err = %d\n", rc); return TD_FAILURE; } lsadc->dev_name[LSADC_DEVICE_NAME_SIZE - 1] = 0; lsadc->refcnt = 1; g_lsadc_param.channel_mask = 0; g_lsadc_param.active_bit = 0xFC; // 6bit 0xF8;//5bit g_lsadc_param.data_delta = 0x8; g_lsadc_param.deglitch_bypass = 0x1; g_lsadc_param.glitch_sample = 5; /* 5 means glitch sample */ g_lsadc_param.lsadc_reset = 0x0; g_lsadc_param.lsadc_zero = 0xFF; g_lsadc_param.model_sel = 0x1; g_lsadc_param.power_downmod = 0x0; g_lsadc_param.time_scan = 600; /* 600 means time scan */ return TD_SUCCESS; } td_s32 uapi_lsadc_open(td_u32 chan) { struct lsadc_priv *lsadc = &g_lsadc_local; if (lsadc->refcnt != 1) { printf("lsadc has not been init\n"); return TD_FAILURE; } if (chan >= MAX_LSADC_GROUP) { printf("lsadc channel invalid\n"); return TD_FAILURE; } g_lsadc_param.channel_mask = 1UL << chan; return lsadc_ioctl(CMD_LSADC_SET_CONFIG, &g_lsadc_param); } td_s32 uapi_lsadc_close(td_u32 chan) { struct lsadc_priv *lsadc = &g_lsadc_local; if (lsadc->refcnt != 1) { printf("lsadc has not been init\n"); return TD_FAILURE; } if (chan >= MAX_LSADC_GROUP) { printf("lsadc channel invalid\n"); return TD_FAILURE; } lsadc_set_base(chan); writel(LSADC_STOP, lsadc->base + LSADC_CTRL8); writel(LSDAC_RESET_VALUE, lsadc->base + LSADC_CTRL0); return TD_SUCCESS; }