Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iio: amplifiers: hmc425a: Add support for HMC425A attenuator

This patch adds support for the HMC425A 0.5 dB LSB GaAs MMIC 6-BIT
DIGITAL POSITIVE CONTROL ATTENUATOR, 2.2 - 8.0 GHz.

Datasheet:
https://www.analog.com/media/en/technical-documentation/data-sheets/hmc425A.pdf

Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
Signed-off-by: Beniamin Bia <beniamin.bia@analog.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Michael Hennerich and committed by
Jonathan Cameron
a76838df 0cc97f2e

+259
+10
drivers/iio/amplifiers/Kconfig
··· 22 22 To compile this driver as a module, choose M here: the 23 23 module will be called ad8366. 24 24 25 + config HMC425 26 + tristate "Analog Devices HMC425A and similar GPIO Gain Amplifiers" 27 + depends on GPIOLIB 28 + help 29 + Say yes here to build support for Analog Devices HMC425A and similar 30 + gain amplifiers or step attenuators. 31 + 32 + To compile this driver as a module, choose M here: the 33 + module will be called hmc425a. 34 + 25 35 endmenu
+1
drivers/iio/amplifiers/Makefile
··· 5 5 6 6 # When adding new entries keep the list in alphabetical order 7 7 obj-$(CONFIG_AD8366) += ad8366.o 8 + obj-$(CONFIG_HMC425) += hmc425a.o
+248
drivers/iio/amplifiers/hmc425a.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * HMC425A and similar Gain Amplifiers 4 + * 5 + * Copyright 2020 Analog Devices Inc. 6 + */ 7 + 8 + #include <linux/device.h> 9 + #include <linux/err.h> 10 + #include <linux/gpio/consumer.h> 11 + #include <linux/iio/iio.h> 12 + #include <linux/iio/sysfs.h> 13 + #include <linux/kernel.h> 14 + #include <linux/module.h> 15 + #include <linux/of_device.h> 16 + #include <linux/of_platform.h> 17 + #include <linux/platform_device.h> 18 + #include <linux/slab.h> 19 + #include <linux/regulator/consumer.h> 20 + #include <linux/sysfs.h> 21 + 22 + enum hmc425a_type { 23 + ID_HMC425A, 24 + }; 25 + 26 + struct hmc425a_chip_info { 27 + const char *name; 28 + const struct iio_chan_spec *channels; 29 + unsigned int num_channels; 30 + unsigned int num_gpios; 31 + int gain_min; 32 + int gain_max; 33 + int default_gain; 34 + }; 35 + 36 + struct hmc425a_state { 37 + struct regulator *reg; 38 + struct mutex lock; /* protect sensor state */ 39 + struct hmc425a_chip_info *chip_info; 40 + struct gpio_descs *gpios; 41 + enum hmc425a_type type; 42 + u32 gain; 43 + }; 44 + 45 + static int hmc425a_write(struct iio_dev *indio_dev, u32 value) 46 + { 47 + struct hmc425a_state *st = iio_priv(indio_dev); 48 + DECLARE_BITMAP(values, BITS_PER_TYPE(value)); 49 + 50 + values[0] = value; 51 + 52 + gpiod_set_array_value_cansleep(st->gpios->ndescs, st->gpios->desc, 53 + NULL, values); 54 + return 0; 55 + } 56 + 57 + static int hmc425a_read_raw(struct iio_dev *indio_dev, 58 + struct iio_chan_spec const *chan, int *val, 59 + int *val2, long m) 60 + { 61 + struct hmc425a_state *st = iio_priv(indio_dev); 62 + int code, gain = 0; 63 + int ret; 64 + 65 + mutex_lock(&st->lock); 66 + switch (m) { 67 + case IIO_CHAN_INFO_HARDWAREGAIN: 68 + code = st->gain; 69 + 70 + switch (st->type) { 71 + case ID_HMC425A: 72 + gain = ~code * -500; 73 + break; 74 + } 75 + 76 + *val = gain / 1000; 77 + *val2 = (gain % 1000) * 1000; 78 + 79 + ret = IIO_VAL_INT_PLUS_MICRO_DB; 80 + break; 81 + default: 82 + ret = -EINVAL; 83 + } 84 + mutex_unlock(&st->lock); 85 + 86 + return ret; 87 + }; 88 + 89 + static int hmc425a_write_raw(struct iio_dev *indio_dev, 90 + struct iio_chan_spec const *chan, int val, 91 + int val2, long mask) 92 + { 93 + struct hmc425a_state *st = iio_priv(indio_dev); 94 + struct hmc425a_chip_info *inf = st->chip_info; 95 + int code = 0, gain; 96 + int ret; 97 + 98 + if (val < 0) 99 + gain = (val * 1000) - (val2 / 1000); 100 + else 101 + gain = (val * 1000) + (val2 / 1000); 102 + 103 + if (gain > inf->gain_max || gain < inf->gain_min) 104 + return -EINVAL; 105 + 106 + switch (st->type) { 107 + case ID_HMC425A: 108 + code = ~((abs(gain) / 500) & 0x3F); 109 + break; 110 + } 111 + 112 + mutex_lock(&st->lock); 113 + switch (mask) { 114 + case IIO_CHAN_INFO_HARDWAREGAIN: 115 + st->gain = code; 116 + 117 + ret = hmc425a_write(indio_dev, st->gain); 118 + break; 119 + default: 120 + ret = -EINVAL; 121 + } 122 + mutex_unlock(&st->lock); 123 + 124 + return ret; 125 + } 126 + 127 + static int hmc425a_write_raw_get_fmt(struct iio_dev *indio_dev, 128 + struct iio_chan_spec const *chan, 129 + long mask) 130 + { 131 + switch (mask) { 132 + case IIO_CHAN_INFO_HARDWAREGAIN: 133 + return IIO_VAL_INT_PLUS_MICRO_DB; 134 + default: 135 + return -EINVAL; 136 + } 137 + } 138 + 139 + static const struct iio_info hmc425a_info = { 140 + .read_raw = &hmc425a_read_raw, 141 + .write_raw = &hmc425a_write_raw, 142 + .write_raw_get_fmt = &hmc425a_write_raw_get_fmt, 143 + }; 144 + 145 + #define HMC425A_CHAN(_channel) \ 146 + { \ 147 + .type = IIO_VOLTAGE, \ 148 + .output = 1, \ 149 + .indexed = 1, \ 150 + .channel = _channel, \ 151 + .info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ 152 + } 153 + 154 + static const struct iio_chan_spec hmc425a_channels[] = { 155 + HMC425A_CHAN(0), 156 + }; 157 + 158 + /* Match table for of_platform binding */ 159 + static const struct of_device_id hmc425a_of_match[] = { 160 + { .compatible = "adi,hmc425a", .data = (void *)ID_HMC425A }, 161 + {}, 162 + }; 163 + MODULE_DEVICE_TABLE(of, hmc425a_of_match); 164 + 165 + static void hmc425a_reg_disable(void *data) 166 + { 167 + struct hmc425a_state *st = data; 168 + 169 + regulator_disable(st->reg); 170 + } 171 + 172 + static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = { 173 + [ID_HMC425A] = { 174 + .name = "hmc425a", 175 + .channels = hmc425a_channels, 176 + .num_channels = ARRAY_SIZE(hmc425a_channels), 177 + .num_gpios = 6, 178 + .gain_min = -31500, 179 + .gain_max = 0, 180 + .default_gain = -0x40, /* set default gain -31.5db*/ 181 + }, 182 + }; 183 + 184 + static int hmc425a_probe(struct platform_device *pdev) 185 + { 186 + struct iio_dev *indio_dev; 187 + struct hmc425a_state *st; 188 + int ret; 189 + 190 + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*st)); 191 + if (!indio_dev) 192 + return -ENOMEM; 193 + 194 + st = iio_priv(indio_dev); 195 + st->type = (enum hmc425a_type)of_device_get_match_data(&pdev->dev); 196 + 197 + st->chip_info = &hmc425a_chip_info_tbl[st->type]; 198 + indio_dev->num_channels = st->chip_info->num_channels; 199 + indio_dev->channels = st->chip_info->channels; 200 + indio_dev->name = st->chip_info->name; 201 + st->gain = st->chip_info->default_gain; 202 + 203 + st->gpios = devm_gpiod_get_array(&pdev->dev, "ctrl", GPIOD_OUT_LOW); 204 + if (IS_ERR(st->gpios)) { 205 + ret = PTR_ERR(st->gpios); 206 + if (ret != -EPROBE_DEFER) 207 + dev_err(&pdev->dev, "failed to get gpios\n"); 208 + return ret; 209 + } 210 + 211 + if (st->gpios->ndescs != st->chip_info->num_gpios) { 212 + dev_err(&pdev->dev, "%d GPIOs needed to operate\n", 213 + st->chip_info->num_gpios); 214 + return -ENODEV; 215 + } 216 + 217 + st->reg = devm_regulator_get(&pdev->dev, "vcc-supply"); 218 + if (IS_ERR(st->reg)) 219 + return PTR_ERR(st->reg); 220 + 221 + ret = regulator_enable(st->reg); 222 + if (ret) 223 + return ret; 224 + ret = devm_add_action_or_reset(&pdev->dev, hmc425a_reg_disable, st); 225 + if (ret) 226 + return ret; 227 + 228 + mutex_init(&st->lock); 229 + 230 + indio_dev->dev.parent = &pdev->dev; 231 + indio_dev->info = &hmc425a_info; 232 + indio_dev->modes = INDIO_DIRECT_MODE; 233 + 234 + return devm_iio_device_register(&pdev->dev, indio_dev); 235 + } 236 + 237 + static struct platform_driver hmc425a_driver = { 238 + .driver = { 239 + .name = KBUILD_MODNAME, 240 + .of_match_table = hmc425a_of_match, 241 + }, 242 + .probe = hmc425a_probe, 243 + }; 244 + module_platform_driver(hmc425a_driver); 245 + 246 + MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); 247 + MODULE_DESCRIPTION("Analog Devices HMC425A and similar GPIO control Gain Amplifiers"); 248 + MODULE_LICENSE("GPL v2");