1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2018 BayLibre, SAS 4 * Author: Neil Armstrong <narmstrong@baylibre.com> 5 */ 6#include <common.h> 7#include <command.h> 8#include <dm.h> 9#include <adc.h> 10#include <linux/printk.h> 11 12static int do_adc_list(struct cmd_tbl *cmdtp, int flag, int argc, 13 char *const argv[]) 14{ 15 struct udevice *dev; 16 int ret, err; 17 18 ret = err = uclass_first_device_check(UCLASS_ADC, &dev); 19 20 while (dev) { 21 printf("- %s status: %i\n", dev->name, ret); 22 23 ret = uclass_next_device_check(&dev); 24 if (ret) 25 err = ret; 26 } 27 28 return err ? CMD_RET_FAILURE : CMD_RET_SUCCESS; 29} 30 31static int do_adc_info(struct cmd_tbl *cmdtp, int flag, int argc, 32 char *const argv[]) 33{ 34 struct udevice *dev; 35 unsigned int data_mask, ch_mask; 36 int ret, vss, vdd; 37 38 if (argc < 2) 39 return CMD_RET_USAGE; 40 41 ret = uclass_get_device_by_name(UCLASS_ADC, argv[1], &dev); 42 if (ret) { 43 printf("Unknown ADC device %s\n", argv[1]); 44 return CMD_RET_FAILURE; 45 } 46 47 printf("ADC Device '%s' :\n", argv[1]); 48 49 ret = adc_channel_mask(dev, &ch_mask); 50 if (!ret) 51 printf("channel mask: %x\n", ch_mask); 52 53 ret = adc_data_mask(dev, &data_mask); 54 if (!ret) 55 printf("data mask: %x\n", data_mask); 56 57 ret = adc_vdd_value(dev, &vdd); 58 if (!ret) 59 printf("vdd: %duV\n", vdd); 60 61 ret = adc_vss_value(dev, &vss); 62 if (!ret) 63 printf("vss: %duV\n", vss); 64 65 return CMD_RET_SUCCESS; 66} 67 68static int do_adc_single(struct cmd_tbl *cmdtp, int flag, int argc, 69 char *const argv[]) 70{ 71 char *varname = NULL; 72 struct udevice *dev; 73 unsigned int data; 74 int ret, uV, val; 75 76 if (argc < 3) 77 return CMD_RET_USAGE; 78 79 if (argc >= 4) 80 varname = argv[3]; 81 82 ret = adc_channel_single_shot(argv[1], simple_strtol(argv[2], NULL, 0), 83 &data); 84 if (ret) { 85 printf("Error getting single shot for device %s channel %s (ret=%d)\n", 86 argv[1], argv[2], ret); 87 return CMD_RET_FAILURE; 88 } 89 90 ret = uclass_get_device_by_name(UCLASS_ADC, argv[1], &dev); 91 if (!ret && !adc_raw_to_uV(dev, data, &uV)) { 92 val = uV; 93 printf("%u, %d uV\n", data, uV); 94 } else { 95 val = data; 96 printf("%u\n", data); 97 } 98 99 if (varname) 100 env_set_ulong(varname, val); 101 102 return CMD_RET_SUCCESS; 103} 104 105static int do_adc_scan(struct cmd_tbl *cmdtp, int flag, int argc, 106 char *const argv[]) 107{ 108 struct adc_channel ch[ADC_MAX_CHANNEL]; 109 struct udevice *dev; 110 unsigned int ch_mask; 111 int i, chan, ret, uV; 112 113 if (argc < 2) 114 return CMD_RET_USAGE; 115 116 ret = uclass_get_device_by_name(UCLASS_ADC, argv[1], &dev); 117 if (ret) { 118 pr_err("Can't get the ADC %s: %d\n", argv[1], ret); 119 return CMD_RET_FAILURE; 120 } 121 122 switch (argc) { 123 case 3: 124 ch_mask = simple_strtoul(argv[2], NULL, 0); 125 if (ch_mask) 126 break; 127 case 2: 128 ret = adc_channel_mask(dev, &ch_mask); 129 if (ret) { 130 pr_err("Can't get mask for %s: %d\n", dev->name, ret); 131 return CMD_RET_FAILURE; 132 } 133 break; 134 } 135 136 ret = adc_channels_single_shot(dev->name, ch_mask, ch); 137 if (ret) { 138 pr_err("Can't get single shot for %s (chans mask: 0x%x): %d\n", 139 dev->name, ch_mask, ret); 140 return CMD_RET_FAILURE; 141 } 142 143 for (chan = 0, i = 0; chan < ADC_MAX_CHANNEL; chan++) { 144 if (!(ch_mask & ADC_CHANNEL(chan))) 145 continue; 146 if (!adc_raw_to_uV(dev, ch[i].data, &uV)) 147 printf("[%02d]: %u, %d uV\n", ch[i].id, ch[i].data, uV); 148 else 149 printf("[%02d]: %u\n", ch[i].id, ch[i].data); 150 i++; 151 } 152 153 return CMD_RET_SUCCESS; 154} 155 156static char adc_help_text[] = 157 "list - list ADC devices\n" 158 "adc info <name> - Get ADC device info\n" 159 "adc single <name> <channel> [varname] - Get Single data of ADC device channel\n" 160 "adc scan <name> [channel mask] - Scan all [or masked] ADC channels"; 161 162U_BOOT_CMD_WITH_SUBCMDS(adc, "ADC sub-system", adc_help_text, 163 U_BOOT_SUBCMD_MKENT(list, 1, 1, do_adc_list), 164 U_BOOT_SUBCMD_MKENT(info, 2, 1, do_adc_info), 165 U_BOOT_SUBCMD_MKENT(single, 4, 1, do_adc_single), 166 U_BOOT_SUBCMD_MKENT(scan, 3, 1, do_adc_scan)); 167