Commit | Line | Data |
---|---|---|
fda8d26e | 1 | // SPDX-License-Identifier: GPL-2.0-only |
bc82222f MH |
2 | /* |
3 | * ltc2497.c - Driver for Analog Devices/Linear Technology LTC2497 ADC | |
4 | * | |
5 | * Copyright (C) 2017 Analog Devices Inc. | |
6 | * | |
bc82222f MH |
7 | * Datasheet: http://cds.linear.com/docs/en/datasheet/2497fd.pdf |
8 | */ | |
9 | ||
bc82222f MH |
10 | #include <linux/i2c.h> |
11 | #include <linux/iio/iio.h> | |
b995a732 | 12 | #include <linux/iio/driver.h> |
bc82222f | 13 | #include <linux/module.h> |
0a9a500a | 14 | #include <linux/mod_devicetable.h> |
2187cfeb CR |
15 | #include <linux/property.h> |
16 | ||
5f60d5f6 | 17 | #include <linux/unaligned.h> |
bc82222f | 18 | |
69548b7c | 19 | #include "ltc2497.h" |
bc82222f | 20 | |
2187cfeb CR |
21 | enum ltc2497_chip_type { |
22 | TYPE_LTC2497, | |
23 | TYPE_LTC2499, | |
24 | }; | |
25 | ||
69548b7c UKK |
26 | struct ltc2497_driverdata { |
27 | /* this must be the first member */ | |
28 | struct ltc2497core_driverdata common_ddata; | |
bc82222f | 29 | struct i2c_client *client; |
2187cfeb | 30 | u32 recv_size; |
bc82222f | 31 | /* |
6ebf401d | 32 | * DMA (thus cache coherency maintenance) may require the |
bc82222f MH |
33 | * transfer buffers to live in their own cache lines. |
34 | */ | |
2187cfeb CR |
35 | union { |
36 | __be32 d32; | |
37 | u8 d8[3]; | |
38 | } data __aligned(IIO_DMA_MINALIGN); | |
bc82222f MH |
39 | }; |
40 | ||
69548b7c UKK |
41 | static int ltc2497_result_and_measure(struct ltc2497core_driverdata *ddata, |
42 | u8 address, int *val) | |
bc82222f | 43 | { |
69548b7c UKK |
44 | struct ltc2497_driverdata *st = |
45 | container_of(ddata, struct ltc2497_driverdata, common_ddata); | |
bc82222f MH |
46 | int ret; |
47 | ||
69548b7c | 48 | if (val) { |
2187cfeb CR |
49 | if (st->recv_size == 3) |
50 | ret = i2c_master_recv(st->client, (char *)&st->data.d8, | |
51 | st->recv_size); | |
52 | else | |
53 | ret = i2c_master_recv(st->client, (char *)&st->data.d32, | |
54 | st->recv_size); | |
69548b7c UKK |
55 | if (ret < 0) { |
56 | dev_err(&st->client->dev, "i2c_master_recv failed\n"); | |
bc82222f | 57 | return ret; |
69548b7c | 58 | } |
bc82222f | 59 | |
2187cfeb CR |
60 | /* |
61 | * The data format is 16/24 bit 2s complement, but with an upper sign bit on the | |
62 | * resolution + 1 position, which is set for positive values only. Given this | |
63 | * bit's value, subtracting BIT(resolution + 1) from the ADC's result is | |
64 | * equivalent to a sign extension. | |
65 | */ | |
66 | if (st->recv_size == 3) { | |
6327a930 | 67 | *val = (get_unaligned_be24(st->data.d8) >> 6) |
2187cfeb CR |
68 | - BIT(ddata->chip_info->resolution + 1); |
69 | } else { | |
6327a930 | 70 | *val = (be32_to_cpu(st->data.d32) >> 6) |
2187cfeb CR |
71 | - BIT(ddata->chip_info->resolution + 1); |
72 | } | |
7f4f1096 UKK |
73 | |
74 | /* | |
75 | * The part started a new conversion at the end of the above i2c | |
76 | * transfer, so if the address didn't change since the last call | |
77 | * everything is fine and we can return early. | |
78 | * If not (which should only happen when some sort of bulk | |
79 | * conversion is implemented) we have to program the new | |
80 | * address. Note that this probably fails as the conversion that | |
81 | * was triggered above is like not complete yet and the two | |
82 | * operations have to be done in a single transfer. | |
83 | */ | |
84 | if (ddata->addr_prev == address) | |
85 | return 0; | |
bc82222f | 86 | } |
bc82222f | 87 | |
69548b7c UKK |
88 | ret = i2c_smbus_write_byte(st->client, |
89 | LTC2497_ENABLE | address); | |
90 | if (ret) | |
91 | dev_err(&st->client->dev, "i2c transfer failed: %pe\n", | |
92 | ERR_PTR(ret)); | |
93 | return ret; | |
bc82222f MH |
94 | } |
95 | ||
3a798444 | 96 | static int ltc2497_probe(struct i2c_client *client) |
bc82222f | 97 | { |
2187cfeb | 98 | const struct ltc2497_chip_info *chip_info; |
bc82222f | 99 | struct iio_dev *indio_dev; |
69548b7c UKK |
100 | struct ltc2497_driverdata *st; |
101 | struct device *dev = &client->dev; | |
2187cfeb | 102 | u32 resolution; |
bc82222f MH |
103 | |
104 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | | |
105 | I2C_FUNC_SMBUS_WRITE_BYTE)) | |
106 | return -EOPNOTSUPP; | |
107 | ||
69548b7c | 108 | indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); |
bc82222f MH |
109 | if (!indio_dev) |
110 | return -ENOMEM; | |
111 | ||
112 | st = iio_priv(indio_dev); | |
113 | i2c_set_clientdata(client, indio_dev); | |
114 | st->client = client; | |
69548b7c | 115 | st->common_ddata.result_and_measure = ltc2497_result_and_measure; |
bc82222f | 116 | |
6c70012d | 117 | chip_info = i2c_get_match_data(client); |
2187cfeb CR |
118 | st->common_ddata.chip_info = chip_info; |
119 | ||
120 | resolution = chip_info->resolution; | |
2187cfeb CR |
121 | st->recv_size = BITS_TO_BYTES(resolution) + 1; |
122 | ||
69548b7c | 123 | return ltc2497core_probe(dev, indio_dev); |
bc82222f MH |
124 | } |
125 | ||
ed5c2f5f | 126 | static void ltc2497_remove(struct i2c_client *client) |
bc82222f MH |
127 | { |
128 | struct iio_dev *indio_dev = i2c_get_clientdata(client); | |
bc82222f | 129 | |
69548b7c | 130 | ltc2497core_remove(indio_dev); |
bc82222f MH |
131 | } |
132 | ||
2187cfeb CR |
133 | static const struct ltc2497_chip_info ltc2497_info[] = { |
134 | [TYPE_LTC2497] = { | |
135 | .resolution = 16, | |
1695c52a | 136 | .name = NULL, |
2187cfeb CR |
137 | }, |
138 | [TYPE_LTC2499] = { | |
139 | .resolution = 24, | |
1695c52a | 140 | .name = "ltc2499", |
2187cfeb CR |
141 | }, |
142 | }; | |
143 | ||
bc82222f | 144 | static const struct i2c_device_id ltc2497_id[] = { |
2187cfeb CR |
145 | { "ltc2497", (kernel_ulong_t)<c2497_info[TYPE_LTC2497] }, |
146 | { "ltc2499", (kernel_ulong_t)<c2497_info[TYPE_LTC2499] }, | |
bc82222f MH |
147 | { } |
148 | }; | |
149 | MODULE_DEVICE_TABLE(i2c, ltc2497_id); | |
150 | ||
151 | static const struct of_device_id ltc2497_of_match[] = { | |
2187cfeb CR |
152 | { .compatible = "lltc,ltc2497", .data = <c2497_info[TYPE_LTC2497] }, |
153 | { .compatible = "lltc,ltc2499", .data = <c2497_info[TYPE_LTC2499] }, | |
09e3bdfe | 154 | { } |
bc82222f MH |
155 | }; |
156 | MODULE_DEVICE_TABLE(of, ltc2497_of_match); | |
157 | ||
158 | static struct i2c_driver ltc2497_driver = { | |
159 | .driver = { | |
160 | .name = "ltc2497", | |
0a9a500a | 161 | .of_match_table = ltc2497_of_match, |
bc82222f | 162 | }, |
7cf15f42 | 163 | .probe = ltc2497_probe, |
bc82222f MH |
164 | .remove = ltc2497_remove, |
165 | .id_table = ltc2497_id, | |
166 | }; | |
167 | module_i2c_driver(ltc2497_driver); | |
168 | ||
169 | MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); | |
170 | MODULE_DESCRIPTION("Linear Technology LTC2497 ADC driver"); | |
171 | MODULE_LICENSE("GPL v2"); |