Skip to content

Commit 953e58a

Browse files
fr0st61tejic23
authored andcommitted
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>
1 parent 7c7dac8 commit 953e58a

3 files changed

Lines changed: 288 additions & 0 deletions

File tree

drivers/iio/adc/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,17 @@ config MAX1363
745745
To compile this driver as a module, choose M here: the module will be
746746
called max1363.
747747

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+
748759
config MAX77541_ADC
749760
tristate "Analog Devices MAX77541 ADC driver"
750761
depends on MFD_MAX77541

drivers/iio/adc/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ obj-$(CONFIG_MAX11205) += max11205.o
6868
obj-$(CONFIG_MAX11410) += max11410.o
6969
obj-$(CONFIG_MAX1241) += max1241.o
7070
obj-$(CONFIG_MAX1363) += max1363.o
71+
obj-$(CONFIG_MAX34408) += max34408.o
7172
obj-$(CONFIG_MAX77541_ADC) += max77541-adc.o
7273
obj-$(CONFIG_MAX9611) += max9611.o
7374
obj-$(CONFIG_MCP320X) += mcp320x.o

drivers/iio/adc/max34408.c

Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
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");

0 commit comments

Comments
 (0)