1*68ed8338SJoseph Chen /* 2*68ed8338SJoseph Chen * (C) Copyright 2017 Rockchip Electronics Co., Ltd 3*68ed8338SJoseph Chen * 4*68ed8338SJoseph Chen * SPDX-License-Identifier: GPL-2.0+ 5*68ed8338SJoseph Chen */ 6*68ed8338SJoseph Chen 7*68ed8338SJoseph Chen #include <dm.h> 8*68ed8338SJoseph Chen #include <dm/read.h> 9*68ed8338SJoseph Chen #include <adc.h> 10*68ed8338SJoseph Chen #include <common.h> 11*68ed8338SJoseph Chen #include <console.h> 12*68ed8338SJoseph Chen #include <errno.h> 13*68ed8338SJoseph Chen #include <fdtdec.h> 14*68ed8338SJoseph Chen #include <malloc.h> 15*68ed8338SJoseph Chen #include <key.h> 16*68ed8338SJoseph Chen #include <linux/input.h> 17*68ed8338SJoseph Chen 18*68ed8338SJoseph Chen #define ADC_MARGIN 30 19*68ed8338SJoseph Chen #define MAX_KEY_NR 10 20*68ed8338SJoseph Chen 21*68ed8338SJoseph Chen struct adc_key_priv { 22*68ed8338SJoseph Chen u32 key_nr; 23*68ed8338SJoseph Chen }; 24*68ed8338SJoseph Chen 25*68ed8338SJoseph Chen static int adc_keys_ofdata_to_platdata(struct udevice *dev) 26*68ed8338SJoseph Chen { 27*68ed8338SJoseph Chen struct adc_key_priv *priv = dev_get_priv(dev); 28*68ed8338SJoseph Chen struct input_key *key = dev_get_platdata(dev); 29*68ed8338SJoseph Chen u32 adc_channels[2], i = 0, microvolt; 30*68ed8338SJoseph Chen int vref, err; 31*68ed8338SJoseph Chen ofnode node; 32*68ed8338SJoseph Chen 33*68ed8338SJoseph Chen /* Get vref */ 34*68ed8338SJoseph Chen vref = dev_read_u32_default(dev, "keyup-threshold-microvolt", -1); 35*68ed8338SJoseph Chen if (vref < 0) { 36*68ed8338SJoseph Chen printf("failed to read 'keyup-threshold-microvolt', ret=%d\n", 37*68ed8338SJoseph Chen vref); 38*68ed8338SJoseph Chen return -EINVAL; 39*68ed8338SJoseph Chen } 40*68ed8338SJoseph Chen 41*68ed8338SJoseph Chen /* Get IO channel */ 42*68ed8338SJoseph Chen err = dev_read_u32_array(dev, "io-channels", adc_channels, 2); 43*68ed8338SJoseph Chen if (err) { 44*68ed8338SJoseph Chen printf("failed to read 'io-channels' of %s key, ret=%d\n", 45*68ed8338SJoseph Chen key->name, err); 46*68ed8338SJoseph Chen return -EINVAL; 47*68ed8338SJoseph Chen } 48*68ed8338SJoseph Chen 49*68ed8338SJoseph Chen /* Parse every adc key data */ 50*68ed8338SJoseph Chen dev_for_each_subnode(node, dev) { 51*68ed8338SJoseph Chen key[i].name = ofnode_read_string(node, "label"); 52*68ed8338SJoseph Chen key[i].vref = vref; 53*68ed8338SJoseph Chen key[i].margin = ADC_MARGIN; 54*68ed8338SJoseph Chen key[i].channel = adc_channels[1]; 55*68ed8338SJoseph Chen if (ofnode_read_u32(node, "linux,code", &key[i].code)) { 56*68ed8338SJoseph Chen printf("%s: failed to read 'linux,code', ret=%d\n", 57*68ed8338SJoseph Chen key[i].name, key[i].code); 58*68ed8338SJoseph Chen return -EINVAL; 59*68ed8338SJoseph Chen } 60*68ed8338SJoseph Chen if (ofnode_read_u32(node, "press-threshold-microvolt", 61*68ed8338SJoseph Chen µvolt)) { 62*68ed8338SJoseph Chen printf("%s: failed read 'press-threshold-microvolt', ret=%d\n", 63*68ed8338SJoseph Chen key[i].name, microvolt); 64*68ed8338SJoseph Chen return -EINVAL; 65*68ed8338SJoseph Chen } 66*68ed8338SJoseph Chen /* Convert microvolt to adc value */ 67*68ed8338SJoseph Chen key[i].value = microvolt / (key[i].vref / 1024); 68*68ed8338SJoseph Chen 69*68ed8338SJoseph Chen debug("%s: name=%s: code=%d, vref=%d, margin=%d, channel=%d, val=%d\n", 70*68ed8338SJoseph Chen __func__, key[i].name, key[i].code, key[i].vref, 71*68ed8338SJoseph Chen key[i].margin, key[i].channel, key[i].value); 72*68ed8338SJoseph Chen 73*68ed8338SJoseph Chen /* Next node */ 74*68ed8338SJoseph Chen i++; 75*68ed8338SJoseph Chen priv->key_nr = i; 76*68ed8338SJoseph Chen if (i >= MAX_KEY_NR) { 77*68ed8338SJoseph Chen printf("Too many keys, Max support: %d\n", MAX_KEY_NR); 78*68ed8338SJoseph Chen return -EINVAL; 79*68ed8338SJoseph Chen } 80*68ed8338SJoseph Chen } 81*68ed8338SJoseph Chen 82*68ed8338SJoseph Chen return 0; 83*68ed8338SJoseph Chen } 84*68ed8338SJoseph Chen 85*68ed8338SJoseph Chen static int adc_keys_read(struct udevice *dev, int code) 86*68ed8338SJoseph Chen { 87*68ed8338SJoseph Chen struct adc_key_priv *priv = dev_get_priv(dev); 88*68ed8338SJoseph Chen struct input_key *key = dev_get_platdata(dev); 89*68ed8338SJoseph Chen int report = KEY_NOT_EXIST; 90*68ed8338SJoseph Chen int max, min, i = 0; 91*68ed8338SJoseph Chen unsigned int adcval; 92*68ed8338SJoseph Chen 93*68ed8338SJoseph Chen for (i = 0; i < priv->key_nr; i++) { 94*68ed8338SJoseph Chen if (key[i].code != code) 95*68ed8338SJoseph Chen continue; 96*68ed8338SJoseph Chen 97*68ed8338SJoseph Chen if (adc_channel_single_shot("saradc", 98*68ed8338SJoseph Chen key[i].channel, &adcval)) { 99*68ed8338SJoseph Chen printf("%s: failed to read saradc\n", key[i].name); 100*68ed8338SJoseph Chen } else { 101*68ed8338SJoseph Chen /* Get min, max */ 102*68ed8338SJoseph Chen max = key[i].value + key[i].margin; 103*68ed8338SJoseph Chen if (key[i].value > key[i].margin) 104*68ed8338SJoseph Chen min = key[i].value - key[i].margin; 105*68ed8338SJoseph Chen else 106*68ed8338SJoseph Chen min = key[i].value; 107*68ed8338SJoseph Chen 108*68ed8338SJoseph Chen /* Check */ 109*68ed8338SJoseph Chen if ((adcval <= max) && (adcval >= min)) { 110*68ed8338SJoseph Chen report = KEY_PRESS_DOWN; 111*68ed8338SJoseph Chen printf("'%s' key pressed down\n", 112*68ed8338SJoseph Chen key[i].name); 113*68ed8338SJoseph Chen } else { 114*68ed8338SJoseph Chen report = KEY_PRESS_NONE; 115*68ed8338SJoseph Chen } 116*68ed8338SJoseph Chen } 117*68ed8338SJoseph Chen break; 118*68ed8338SJoseph Chen } 119*68ed8338SJoseph Chen 120*68ed8338SJoseph Chen return report; 121*68ed8338SJoseph Chen } 122*68ed8338SJoseph Chen 123*68ed8338SJoseph Chen static const struct dm_key_ops key_ops = { 124*68ed8338SJoseph Chen .name = "adc_keys", 125*68ed8338SJoseph Chen .read = adc_keys_read, 126*68ed8338SJoseph Chen }; 127*68ed8338SJoseph Chen 128*68ed8338SJoseph Chen static const struct udevice_id adc_keys_ids[] = { 129*68ed8338SJoseph Chen { .compatible = "adc-keys" }, 130*68ed8338SJoseph Chen { }, 131*68ed8338SJoseph Chen }; 132*68ed8338SJoseph Chen 133*68ed8338SJoseph Chen U_BOOT_DRIVER(adc_keys) = { 134*68ed8338SJoseph Chen .name = "adc-keys", 135*68ed8338SJoseph Chen .id = UCLASS_KEY, 136*68ed8338SJoseph Chen .ops = &key_ops, 137*68ed8338SJoseph Chen .of_match = adc_keys_ids, 138*68ed8338SJoseph Chen .ofdata_to_platdata = adc_keys_ofdata_to_platdata, 139*68ed8338SJoseph Chen .platdata_auto_alloc_size = sizeof(struct input_key) * MAX_KEY_NR, 140*68ed8338SJoseph Chen .priv_auto_alloc_size = sizeof(struct adc_key_priv), 141*68ed8338SJoseph Chen }; 142