| // 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 ch7_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; |
| int ret; |
| char *endp; |
| |
| ret = uclass_get_device_by_name(UCLASS_ADC, "adc", &dev); |
| if (ret) |
| return ret; |
| |
| channel = simple_strtoul(argv[1], NULL, 10); |
| 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[10]; |
| unsigned int val; |
| int ret; |
| |
| if (current_channel < 0) { |
| pr_err("SARADC channel[%d] is invalid\n", current_channel); |
| return -EINVAL; |
| }; |
| |
| 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; |
| |
| ret = uclass_get_device_by_name(UCLASS_ADC, "adc", &dev); |
| if (ret) |
| return ret; |
| |
| ret = adc_set_mode(dev, SARADC_CH_SELF_TEST, ADC_MODE_AVERAGE); |
| if (ret) |
| return ret; |
| |
| printf("saradc self-test by ch7:\n"); |
| |
| for (i = 0; i < ARRAY_SIZE(ch7_voltage); i++) { |
| ret = adc_select_input_voltage(dev, SARADC_CH_SELF_TEST, i); |
| if (ret) |
| return ret; |
| |
| udelay(10); |
| |
| ret = adc_start_channel(dev, SARADC_CH_SELF_TEST); |
| if (ret) |
| return ret; |
| |
| ret = adc_channel_data(dev, SARADC_CH_SELF_TEST, &val); |
| if (ret) |
| return ret; |
| |
| printf("%-7s : %d\n", ch7_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[10]; |
| int max, min; |
| unsigned int val; |
| int ret; |
| |
| ret = adc_channel_single_shot_mode("adc", current_mode, |
| current_channel, &val); |
| if (ret) |
| return ret; |
| |
| 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 2:high precision 3:high resolution 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> - return 0 if current value in the range of current channel\n" |
| ); |