blob: 3bcf9aaad13bdfde0d42d5bb31ddbc34ddfd976e [file] [log] [blame] [edit]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <common.h>
#include <command.h>
#include <dm/uclass.h>
#include <amlogic/saradc.h>
#define ENV_SARADC_VALUE "saradc_val"
struct meson_saradc_mode {
unsigned int sample_mode;
const char *mode_name;
};
static const struct meson_saradc_mode mode_table[] = {
{ADC_MODE_AVERAGE, "average"}, /* default mode */
{ADC_MODE_AVERAGE, "average"},
{ADC_MODE_HIGH_PRECISION, "high precision"},
{ADC_MODE_HIGH_RESOLUTION, "high resolution"},
{ADC_MODE_DECIM_FILTER, "decim filter"}
};
static const char * const test_voltage[] = {
"gnd",
"vdd/4",
"vdd/2",
"vdd*3/4",
"vdd",
};
static int current_channel = -1;
static unsigned int current_mode;
static int do_saradc_open(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
struct udevice *dev;
int channel;
int mode = ADC_MODE_AVERAGE;
int ret;
char *endp = NULL;
if (argc < 2) {
pr_err("Invalid parameter: channel number must be specified\n");
return -1;
}
ret = uclass_get_device_by_name(UCLASS_ADC, "adc", &dev);
if (ret)
ret = uclass_first_device_err(UCLASS_ADC, &dev);
if (ret)
return ret;
channel = simple_strtoul(argv[1], NULL, 10);
if (argc >= 3)
mode = simple_strtoul(argv[2], &endp, 10);
if ((channel < 0) || (channel >= MESON_SARADC_CH_MAX)) {
pr_err("No such channel(%d) in SARADC! open failed!\n",
channel);
return -1;
}
if ((mode < 0) || (mode >= sizeof(mode_table)/sizeof(mode_table[0])) ||
(endp && !mode)) {
pr_err("No such mode(%d) in SARADC! open failed!\n", mode);
return -1;
}
ret = adc_set_mode(dev, channel, mode_table[mode].sample_mode);
if (ret) {
pr_err("current platform does not support [%s] mode\n",
mode_table[mode].mode_name);
return ret;
}
current_mode = mode_table[mode].sample_mode;
current_channel = channel;
printf("SARADC mode is %s\n", mode_table[mode].mode_name);
return 0;
}
static int do_saradc_close(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
current_channel = -1;
printf("SARADC closed.\n");
return 0;
}
static int do_saradc_getval(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
char value_str[20];
unsigned int val;
int ret;
if (current_channel < 0) {
pr_err("SARADC channel[%d] is invalid\n", current_channel);
return -EINVAL;
};
memset(value_str, 0, sizeof(value_str));
ret = adc_channel_single_shot_mode("adc", current_mode,
current_channel, &val);
if (ret)
return ret;
printf("SARADC channel(%d) is %d.\n", current_channel, val);
sprintf(value_str, "0x%x", val);
env_set(ENV_SARADC_VALUE, value_str);
return 0;
}
static int do_saradc_test(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
struct udevice *dev;
unsigned int val;
int ret;
int i;
int channel;
ret = uclass_get_device_by_name(UCLASS_ADC, "adc", &dev);
if (ret)
ret = uclass_first_device_err(UCLASS_ADC, &dev);
if (ret)
return ret;
ret = adc_get_test_channel(dev);
if (ret < 0)
return ret;
channel = ret;
ret = adc_set_mode(dev, channel, ADC_MODE_AVERAGE);
if (ret)
return ret;
printf("saradc self-test by channel %d:\n", channel);
for (i = 0; i < ARRAY_SIZE(test_voltage); i++) {
ret = adc_select_input_voltage(dev, channel, i);
if (ret)
return ret;
udelay(10);
ret = adc_start_channel(dev, channel);
if (ret)
return ret;
ret = adc_channel_data(dev, channel, &val);
if (ret)
return ret;
printf("%-7s : %d\n", test_voltage[i], val);
}
return 0;
}
static int do_saradc_get_in_range(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
char value_str[20];
int max, min;
unsigned int val;
int ret;
ret = adc_channel_single_shot_mode("adc", current_mode,
current_channel, &val);
if (ret)
return ret;
memset(value_str, 0, sizeof(value_str));
min = simple_strtoul(argv[1], NULL, 10);
max = simple_strtoul(argv[2], NULL, 10);
int donot_setenv = 0;
if (argc > 3) {
donot_setenv = simple_strtoul(argv[2], NULL, 10);
}
if ((val < min) || (val > max)) {
debug("SARADC channel(%d) is %d, Out of range(%d~%d)!\n",
current_channel, val, min, max);
return -1;
}
debug("SARADC channel(%d) is %d (%d~%d).\n",
current_channel, val, min, max);
sprintf(value_str, "0x%x", val);
if (!donot_setenv)
env_set(ENV_SARADC_VALUE, value_str);
return 0;
}
static cmd_tbl_t cmd_saradc_sub[] = {
U_BOOT_CMD_MKENT(open, 3, 0, do_saradc_open, "", ""),
U_BOOT_CMD_MKENT(close, 1, 0, do_saradc_close, "", ""),
U_BOOT_CMD_MKENT(getval, 1, 0, do_saradc_getval, "", ""),
U_BOOT_CMD_MKENT(test, 1, 0, do_saradc_test, "", ""),
U_BOOT_CMD_MKENT(get_in_range, 3, 0, do_saradc_get_in_range, "", ""),
};
static int do_saradc(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
cmd_tbl_t *c;
/* Strip off leading 'bmp' command argument */
argc--;
argv++;
c = find_cmd_tbl(argv[0], &cmd_saradc_sub[0],
ARRAY_SIZE(cmd_saradc_sub));
if (c) {
return c->cmd(cmdtp, flag, argc, argv);
} else {
cmd_usage(cmdtp);
return 1;
}
}
U_BOOT_CMD(
saradc, CONFIG_SYS_MAXARGS, 0, do_saradc,
"saradc sub-system",
"saradc open <channel> <mode> - open a SARADC channel\n"
" mode: 1: average\n"
" 2: high precision\n"
" 3: high resolution\n"
" 4: decim filter\n"
"saradc close - close the SARADC\n"
"saradc getval - get the value in current channel\n"
"saradc test - test the SARADC by channel-7\n"
"saradc get_in_range <min> <max>\n"
" - return 0 if current value in the range of current channel\n"
);