drm/tests: hdmi: Fix memory leaks in drm_display_mode_from_cea_vic()
[drm/drm-misc.git] / drivers / iio / adc / ltc2309.c
blob5f0d947d06157e70281747e96d1b9149696bfef9
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * The LTC2309 is an 8-Channel, 12-Bit SAR ADC with an I2C Interface.
5 * Datasheet:
6 * https://www.analog.com/media/en/technical-documentation/data-sheets/2309fd.pdf
8 * Copyright (c) 2023, Liam Beguin <liambeguin@gmail.com>
9 */
10 #include <linux/bitfield.h>
11 #include <linux/i2c.h>
12 #include <linux/iio/iio.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/mutex.h>
16 #include <linux/regulator/consumer.h>
18 #define LTC2309_ADC_RESOLUTION 12
19 #define LTC2309_INTERNAL_REF_MV 4096
21 #define LTC2309_DIN_CH_MASK GENMASK(7, 4)
22 #define LTC2309_DIN_SDN BIT(7)
23 #define LTC2309_DIN_OSN BIT(6)
24 #define LTC2309_DIN_S1 BIT(5)
25 #define LTC2309_DIN_S0 BIT(4)
26 #define LTC2309_DIN_UNI BIT(3)
27 #define LTC2309_DIN_SLEEP BIT(2)
29 /**
30 * struct ltc2309 - internal device data structure
31 * @dev: Device reference
32 * @client: I2C reference
33 * @lock: Lock to serialize data access
34 * @vref_mv: Internal voltage reference
36 struct ltc2309 {
37 struct device *dev;
38 struct i2c_client *client;
39 struct mutex lock; /* serialize data access */
40 int vref_mv;
43 /* Order matches expected channel address, See datasheet Table 1. */
44 enum ltc2309_channels {
45 LTC2309_CH0_CH1 = 0,
46 LTC2309_CH2_CH3,
47 LTC2309_CH4_CH5,
48 LTC2309_CH6_CH7,
49 LTC2309_CH1_CH0,
50 LTC2309_CH3_CH2,
51 LTC2309_CH5_CH4,
52 LTC2309_CH7_CH6,
53 LTC2309_CH0,
54 LTC2309_CH2,
55 LTC2309_CH4,
56 LTC2309_CH6,
57 LTC2309_CH1,
58 LTC2309_CH3,
59 LTC2309_CH5,
60 LTC2309_CH7,
63 #define LTC2309_CHAN(_chan, _addr) { \
64 .type = IIO_VOLTAGE, \
65 .indexed = 1, \
66 .address = _addr, \
67 .channel = _chan, \
68 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
69 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
72 #define LTC2309_DIFF_CHAN(_chan, _chan2, _addr) { \
73 .type = IIO_VOLTAGE, \
74 .differential = 1, \
75 .indexed = 1, \
76 .address = _addr, \
77 .channel = _chan, \
78 .channel2 = _chan2, \
79 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
80 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
83 static const struct iio_chan_spec ltc2309_channels[] = {
84 LTC2309_CHAN(0, LTC2309_CH0),
85 LTC2309_CHAN(1, LTC2309_CH1),
86 LTC2309_CHAN(2, LTC2309_CH2),
87 LTC2309_CHAN(3, LTC2309_CH3),
88 LTC2309_CHAN(4, LTC2309_CH4),
89 LTC2309_CHAN(5, LTC2309_CH5),
90 LTC2309_CHAN(6, LTC2309_CH6),
91 LTC2309_CHAN(7, LTC2309_CH7),
92 LTC2309_DIFF_CHAN(0, 1, LTC2309_CH0_CH1),
93 LTC2309_DIFF_CHAN(2, 3, LTC2309_CH2_CH3),
94 LTC2309_DIFF_CHAN(4, 5, LTC2309_CH4_CH5),
95 LTC2309_DIFF_CHAN(6, 7, LTC2309_CH6_CH7),
96 LTC2309_DIFF_CHAN(1, 0, LTC2309_CH1_CH0),
97 LTC2309_DIFF_CHAN(3, 2, LTC2309_CH3_CH2),
98 LTC2309_DIFF_CHAN(5, 4, LTC2309_CH5_CH4),
99 LTC2309_DIFF_CHAN(7, 6, LTC2309_CH7_CH6),
102 static int ltc2309_read_raw_channel(struct ltc2309 *ltc2309,
103 unsigned long address, int *val)
105 int ret;
106 __be16 buf;
107 u8 din;
109 din = FIELD_PREP(LTC2309_DIN_CH_MASK, address & 0x0f) |
110 FIELD_PREP(LTC2309_DIN_UNI, 1) |
111 FIELD_PREP(LTC2309_DIN_SLEEP, 0);
113 ret = i2c_smbus_write_byte(ltc2309->client, din);
114 if (ret < 0) {
115 dev_err(ltc2309->dev, "i2c command failed: %pe\n",
116 ERR_PTR(ret));
117 return ret;
120 ret = i2c_master_recv(ltc2309->client, (char *)&buf, 2);
121 if (ret < 0) {
122 dev_err(ltc2309->dev, "i2c read failed: %pe\n", ERR_PTR(ret));
123 return ret;
126 *val = be16_to_cpu(buf) >> 4;
128 return ret;
131 static int ltc2309_read_raw(struct iio_dev *indio_dev,
132 struct iio_chan_spec const *chan, int *val,
133 int *val2, long mask)
135 struct ltc2309 *ltc2309 = iio_priv(indio_dev);
136 int ret;
138 switch (mask) {
139 case IIO_CHAN_INFO_RAW:
140 mutex_lock(&ltc2309->lock);
141 ret = ltc2309_read_raw_channel(ltc2309, chan->address, val);
142 mutex_unlock(&ltc2309->lock);
143 if (ret < 0)
144 return -EINVAL;
145 return IIO_VAL_INT;
146 case IIO_CHAN_INFO_SCALE:
147 *val = ltc2309->vref_mv;
148 *val2 = LTC2309_ADC_RESOLUTION;
149 return IIO_VAL_FRACTIONAL_LOG2;
150 default:
151 return -EINVAL;
155 static const struct iio_info ltc2309_info = {
156 .read_raw = ltc2309_read_raw,
159 static int ltc2309_probe(struct i2c_client *client)
161 struct iio_dev *indio_dev;
162 struct ltc2309 *ltc2309;
163 int ret;
165 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*ltc2309));
166 if (!indio_dev)
167 return -ENOMEM;
169 ltc2309 = iio_priv(indio_dev);
170 ltc2309->dev = &indio_dev->dev;
171 ltc2309->client = client;
173 indio_dev->name = "ltc2309";
174 indio_dev->modes = INDIO_DIRECT_MODE;
175 indio_dev->channels = ltc2309_channels;
176 indio_dev->num_channels = ARRAY_SIZE(ltc2309_channels);
177 indio_dev->info = &ltc2309_info;
179 ret = devm_regulator_get_enable_read_voltage(&client->dev, "vref");
180 if (ret < 0 && ret != -ENODEV)
181 return dev_err_probe(ltc2309->dev, ret,
182 "failed to get vref voltage\n");
184 ltc2309->vref_mv = ret == -ENODEV ? LTC2309_INTERNAL_REF_MV : ret / 1000;
186 mutex_init(&ltc2309->lock);
188 return devm_iio_device_register(&client->dev, indio_dev);
191 static const struct of_device_id ltc2309_of_match[] = {
192 { .compatible = "lltc,ltc2309" },
195 MODULE_DEVICE_TABLE(of, ltc2309_of_match);
197 static const struct i2c_device_id ltc2309_id[] = {
198 { "ltc2309" },
201 MODULE_DEVICE_TABLE(i2c, ltc2309_id);
203 static struct i2c_driver ltc2309_driver = {
204 .driver = {
205 .name = "ltc2309",
206 .of_match_table = ltc2309_of_match,
208 .probe = ltc2309_probe,
209 .id_table = ltc2309_id,
211 module_i2c_driver(ltc2309_driver);
213 MODULE_AUTHOR("Liam Beguin <liambeguin@gmail.com>");
214 MODULE_DESCRIPTION("Linear Technology LTC2309 ADC");
215 MODULE_LICENSE("GPL v2");