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