You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
319 lines
9.2 KiB
319 lines
9.2 KiB
4 months ago
|
/*
|
||
|
* Copyright (c) Hisilicon Technologies Co., Ltd. 2012-2020. All rights reserved.
|
||
|
* Description: boot lsadc driver
|
||
|
*/
|
||
|
|
||
|
#include <asm/io.h>
|
||
|
#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;
|
||
|
}
|