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

/*
* 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(&param, 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(&param, 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), &param, 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;
}