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

Configure Feed

Select the types of activity you want to include in your feed.

iio: adc: Add driver support for MAX34408/9

The MAX34408/MAX34409 are two- and four-channel current monitors that are
configured and monitored with a standard I2C/SMBus serial interface. Each
unidirectional current sensor offers precision high-side operation with a
low full-scale sense voltage. The devices automatically sequence through
two or four channels and collect the current-sense samples and average them
to reduce the effect of impulse noise. The raw ADC samples are compared to
user-programmable digital thresholds to indicate overcurrent conditions.
Overcurrent conditions trigger a hardware output to provide an immediate
indication to shut down any necessary external circuitry.

Add as ADC driver which only supports current monitoring for now.

Link: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX34408-MAX34409.pdf

Signed-off-by: Ivan Mikhaylov <fr0st61te@gmail.com>
Link: https://lore.kernel.org/r/20231014211254.16719-3-fr0st61te@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Ivan Mikhaylov and committed by
Jonathan Cameron
cf277758 f0d1a9b7

+288
+11
drivers/iio/adc/Kconfig
··· 745 745 To compile this driver as a module, choose M here: the module will be 746 746 called max1363. 747 747 748 + config MAX34408 749 + tristate "Maxim max34408/max344089 ADC driver" 750 + depends on I2C 751 + help 752 + Say yes here to build support for Maxim max34408/max34409 current sense 753 + monitor with 8-bits ADC interface with overcurrent delay/threshold and 754 + shutdown delay. 755 + 756 + To compile this driver as a module, choose M here: the module will be 757 + called max34408. 758 + 748 759 config MAX77541_ADC 749 760 tristate "Analog Devices MAX77541 ADC driver" 750 761 depends on MFD_MAX77541
+1
drivers/iio/adc/Makefile
··· 68 68 obj-$(CONFIG_MAX11410) += max11410.o 69 69 obj-$(CONFIG_MAX1241) += max1241.o 70 70 obj-$(CONFIG_MAX1363) += max1363.o 71 + obj-$(CONFIG_MAX34408) += max34408.o 71 72 obj-$(CONFIG_MAX77541_ADC) += max77541-adc.o 72 73 obj-$(CONFIG_MAX9611) += max9611.o 73 74 obj-$(CONFIG_MCP320X) += mcp320x.o
+276
drivers/iio/adc/max34408.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * IIO driver for Maxim MAX34409/34408 ADC, 4-Channels/2-Channels, 8bits, I2C 4 + * 5 + * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX34408-MAX34409.pdf 6 + * 7 + * TODO: ALERT interrupt, Overcurrent delay, Shutdown delay 8 + */ 9 + 10 + #include <linux/bitfield.h> 11 + #include <linux/init.h> 12 + #include <linux/i2c.h> 13 + #include <linux/module.h> 14 + #include <linux/mod_devicetable.h> 15 + #include <linux/property.h> 16 + #include <linux/regmap.h> 17 + 18 + #include <linux/iio/iio.h> 19 + #include <linux/iio/types.h> 20 + 21 + #define MAX34408_STATUS_REG 0x0 22 + #define MAX34408_CONTROL_REG 0x1 23 + #define MAX34408_OCDELAY_REG 0x2 24 + #define MAX34408_SDDELAY_REG 0x3 25 + 26 + #define MAX34408_ADC1_REG 0x4 27 + #define MAX34408_ADC2_REG 0x5 28 + /* ADC3 & ADC4 always returns 0x0 on 34408 */ 29 + #define MAX34409_ADC3_REG 0x6 30 + #define MAX34409_ADC4_REG 0x7 31 + 32 + #define MAX34408_OCT1_REG 0x8 33 + #define MAX34408_OCT2_REG 0x9 34 + #define MAX34409_OCT3_REG 0xA 35 + #define MAX34409_OCT4_REG 0xB 36 + 37 + #define MAX34408_DID_REG 0xC 38 + #define MAX34408_DCYY_REG 0xD 39 + #define MAX34408_DCWW_REG 0xE 40 + 41 + /* Bit masks for status register */ 42 + #define MAX34408_STATUS_OC_MSK GENMASK(1, 0) 43 + #define MAX34409_STATUS_OC_MSK GENMASK(3, 0) 44 + #define MAX34408_STATUS_SHTDN BIT(4) 45 + #define MAX34408_STATUS_ENA BIT(5) 46 + 47 + /* Bit masks for control register */ 48 + #define MAX34408_CONTROL_AVG0 BIT(0) 49 + #define MAX34408_CONTROL_AVG1 BIT(1) 50 + #define MAX34408_CONTROL_AVG2 BIT(2) 51 + #define MAX34408_CONTROL_ALERT BIT(3) 52 + 53 + #define MAX34408_DEFAULT_AVG 0x4 54 + 55 + /* Bit masks for over current delay */ 56 + #define MAX34408_OCDELAY_OCD_MSK GENMASK(6, 0) 57 + #define MAX34408_OCDELAY_RESET BIT(7) 58 + 59 + /* Bit masks for shutdown delay */ 60 + #define MAX34408_SDDELAY_SHD_MSK GENMASK(6, 0) 61 + #define MAX34408_SDDELAY_RESET BIT(7) 62 + 63 + #define MAX34408_DEFAULT_RSENSE 1000 64 + 65 + /** 66 + * struct max34408_data - max34408/max34409 specific data. 67 + * @regmap: device register map. 68 + * @dev: max34408 device. 69 + * @lock: lock for protecting access to device hardware registers, mostly 70 + * for read modify write cycles for control registers. 71 + * @input_rsense: Rsense values in uOhm, will be overwritten by 72 + * values from channel nodes. 73 + */ 74 + struct max34408_data { 75 + struct regmap *regmap; 76 + struct device *dev; 77 + struct mutex lock; 78 + u32 input_rsense[4]; 79 + }; 80 + 81 + static const struct regmap_config max34408_regmap_config = { 82 + .reg_bits = 8, 83 + .val_bits = 8, 84 + .max_register = MAX34408_DCWW_REG, 85 + }; 86 + 87 + struct max34408_adc_model_data { 88 + const char *model_name; 89 + const struct iio_chan_spec *channels; 90 + const int num_channels; 91 + }; 92 + 93 + #define MAX34008_CHANNEL(_index, _address) \ 94 + { \ 95 + .type = IIO_CURRENT, \ 96 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 97 + BIT(IIO_CHAN_INFO_SCALE) | \ 98 + BIT(IIO_CHAN_INFO_OFFSET), \ 99 + .channel = (_index), \ 100 + .address = (_address), \ 101 + .indexed = 1, \ 102 + } 103 + 104 + static const struct iio_chan_spec max34408_channels[] = { 105 + MAX34008_CHANNEL(0, MAX34408_ADC1_REG), 106 + MAX34008_CHANNEL(1, MAX34408_ADC2_REG), 107 + }; 108 + 109 + static const struct iio_chan_spec max34409_channels[] = { 110 + MAX34008_CHANNEL(0, MAX34408_ADC1_REG), 111 + MAX34008_CHANNEL(1, MAX34408_ADC2_REG), 112 + MAX34008_CHANNEL(2, MAX34409_ADC3_REG), 113 + MAX34008_CHANNEL(3, MAX34409_ADC4_REG), 114 + }; 115 + 116 + static int max34408_read_adc_avg(struct max34408_data *max34408, 117 + const struct iio_chan_spec *chan, int *val) 118 + { 119 + unsigned int ctrl; 120 + int rc; 121 + 122 + guard(mutex)(&max34408->lock); 123 + rc = regmap_read(max34408->regmap, MAX34408_CONTROL_REG, (u32 *)&ctrl); 124 + if (rc) 125 + return rc; 126 + 127 + /* set averaging (0b100) default values*/ 128 + rc = regmap_write(max34408->regmap, MAX34408_CONTROL_REG, 129 + MAX34408_DEFAULT_AVG); 130 + if (rc) { 131 + dev_err(max34408->dev, 132 + "Error (%d) writing control register\n", rc); 133 + return rc; 134 + } 135 + 136 + rc = regmap_read(max34408->regmap, chan->address, val); 137 + if (rc) 138 + return rc; 139 + 140 + /* back to old values */ 141 + rc = regmap_write(max34408->regmap, MAX34408_CONTROL_REG, ctrl); 142 + if (rc) 143 + dev_err(max34408->dev, 144 + "Error (%d) writing control register\n", rc); 145 + 146 + return rc; 147 + } 148 + 149 + static int max34408_read_raw(struct iio_dev *indio_dev, 150 + struct iio_chan_spec const *chan, 151 + int *val, int *val2, long mask) 152 + { 153 + struct max34408_data *max34408 = iio_priv(indio_dev); 154 + int rc; 155 + 156 + switch (mask) { 157 + case IIO_CHAN_INFO_RAW: 158 + rc = max34408_read_adc_avg(max34408, chan, val); 159 + if (rc) 160 + return rc; 161 + return IIO_VAL_INT; 162 + case IIO_CHAN_INFO_SCALE: 163 + /* 164 + * calcluate current for 8bit ADC with Rsense 165 + * value. 166 + * 10 mV * 1000 / Rsense uOhm = max current 167 + * (max current * adc val * 1000) / (2^8 - 1) mA 168 + */ 169 + *val = 10000 / max34408->input_rsense[chan->channel]; 170 + *val2 = 8; 171 + return IIO_VAL_FRACTIONAL_LOG2; 172 + default: 173 + return -EINVAL; 174 + } 175 + } 176 + 177 + static const struct iio_info max34408_info = { 178 + .read_raw = max34408_read_raw, 179 + }; 180 + 181 + static const struct max34408_adc_model_data max34408_model_data = { 182 + .model_name = "max34408", 183 + .channels = max34408_channels, 184 + .num_channels = 2, 185 + }; 186 + 187 + static const struct max34408_adc_model_data max34409_model_data = { 188 + .model_name = "max34409", 189 + .channels = max34409_channels, 190 + .num_channels = 4, 191 + }; 192 + 193 + static int max34408_probe(struct i2c_client *client) 194 + { 195 + const struct max34408_adc_model_data *model_data; 196 + struct device *dev = &client->dev; 197 + struct max34408_data *max34408; 198 + struct fwnode_handle *node; 199 + struct iio_dev *indio_dev; 200 + struct regmap *regmap; 201 + int rc, i = 0; 202 + 203 + model_data = i2c_get_match_data(client); 204 + if (!model_data) 205 + return -EINVAL; 206 + 207 + regmap = devm_regmap_init_i2c(client, &max34408_regmap_config); 208 + if (IS_ERR(regmap)) { 209 + dev_err_probe(dev, PTR_ERR(regmap), 210 + "regmap_init failed\n"); 211 + return PTR_ERR(regmap); 212 + } 213 + 214 + indio_dev = devm_iio_device_alloc(dev, sizeof(*max34408)); 215 + if (!indio_dev) 216 + return -ENOMEM; 217 + 218 + max34408 = iio_priv(indio_dev); 219 + max34408->regmap = regmap; 220 + max34408->dev = dev; 221 + mutex_init(&max34408->lock); 222 + 223 + device_for_each_child_node(dev, node) { 224 + fwnode_property_read_u32(node, "maxim,rsense-val-micro-ohms", 225 + &max34408->input_rsense[i]); 226 + i++; 227 + } 228 + 229 + /* disable ALERT and averaging */ 230 + rc = regmap_write(max34408->regmap, MAX34408_CONTROL_REG, 0x0); 231 + if (rc) 232 + return rc; 233 + 234 + indio_dev->channels = model_data->channels; 235 + indio_dev->num_channels = model_data->num_channels; 236 + indio_dev->name = model_data->model_name; 237 + 238 + indio_dev->info = &max34408_info; 239 + indio_dev->modes = INDIO_DIRECT_MODE; 240 + 241 + return devm_iio_device_register(dev, indio_dev); 242 + } 243 + 244 + static const struct of_device_id max34408_of_match[] = { 245 + { 246 + .compatible = "maxim,max34408", 247 + .data = &max34408_model_data, 248 + }, 249 + { 250 + .compatible = "maxim,max34409", 251 + .data = &max34409_model_data, 252 + }, 253 + {} 254 + }; 255 + MODULE_DEVICE_TABLE(of, max34408_of_match); 256 + 257 + static const struct i2c_device_id max34408_id[] = { 258 + { "max34408", (kernel_ulong_t)&max34408_model_data }, 259 + { "max34409", (kernel_ulong_t)&max34409_model_data }, 260 + {} 261 + }; 262 + MODULE_DEVICE_TABLE(i2c, max34408_id); 263 + 264 + static struct i2c_driver max34408_driver = { 265 + .driver = { 266 + .name = "max34408", 267 + .of_match_table = max34408_of_match, 268 + }, 269 + .probe = max34408_probe, 270 + .id_table = max34408_id, 271 + }; 272 + module_i2c_driver(max34408_driver); 273 + 274 + MODULE_AUTHOR("Ivan Mikhaylov <fr0st61te@gmail.com>"); 275 + MODULE_DESCRIPTION("Maxim MAX34408/34409 ADC driver"); 276 + MODULE_LICENSE("GPL");