1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * mb1232.c - Support for MaxBotix I2CXL-MaxSonar-EZ series ultrasonic |
4 | * ranger with i2c interface |
5 | * actually tested with mb1232 type |
6 | * |
7 | * Copyright (c) 2019 Andreas Klinger <ak@it-klinger.de> |
8 | * |
9 | * For details about the device see: |
10 | * https://www.maxbotix.com/documents/I2CXL-MaxSonar-EZ_Datasheet.pdf |
11 | */ |
12 | |
13 | #include <linux/bitops.h> |
14 | #include <linux/err.h> |
15 | #include <linux/i2c.h> |
16 | #include <linux/delay.h> |
17 | #include <linux/mod_devicetable.h> |
18 | #include <linux/module.h> |
19 | #include <linux/property.h> |
20 | |
21 | #include <linux/iio/iio.h> |
22 | #include <linux/iio/sysfs.h> |
23 | #include <linux/iio/buffer.h> |
24 | #include <linux/iio/trigger_consumer.h> |
25 | #include <linux/iio/triggered_buffer.h> |
26 | |
27 | /* registers of MaxSonar device */ |
28 | #define MB1232_RANGE_COMMAND 0x51 /* Command for reading range */ |
29 | #define MB1232_ADDR_UNLOCK_1 0xAA /* Command 1 for changing address */ |
30 | #define MB1232_ADDR_UNLOCK_2 0xA5 /* Command 2 for changing address */ |
31 | |
32 | struct mb1232_data { |
33 | struct i2c_client *client; |
34 | |
35 | struct mutex lock; |
36 | |
37 | /* |
38 | * optionally a gpio can be used to announce when ranging has |
39 | * finished |
40 | * since we are just using the falling trigger of it we request |
41 | * only the interrupt for announcing when data is ready to be read |
42 | */ |
43 | struct completion ranging; |
44 | int irqnr; |
45 | /* Ensure correct alignment of data to push to IIO buffer */ |
46 | struct { |
47 | s16 distance; |
48 | s64 ts __aligned(8); |
49 | } scan; |
50 | }; |
51 | |
52 | static irqreturn_t mb1232_handle_irq(int irq, void *dev_id) |
53 | { |
54 | struct iio_dev *indio_dev = dev_id; |
55 | struct mb1232_data *data = iio_priv(indio_dev); |
56 | |
57 | complete(&data->ranging); |
58 | |
59 | return IRQ_HANDLED; |
60 | } |
61 | |
62 | static s16 mb1232_read_distance(struct mb1232_data *data) |
63 | { |
64 | struct i2c_client *client = data->client; |
65 | int ret; |
66 | s16 distance; |
67 | __be16 buf; |
68 | |
69 | mutex_lock(&data->lock); |
70 | |
71 | reinit_completion(x: &data->ranging); |
72 | |
73 | ret = i2c_smbus_write_byte(client, MB1232_RANGE_COMMAND); |
74 | if (ret < 0) { |
75 | dev_err(&client->dev, "write command - err: %d\n" , ret); |
76 | goto error_unlock; |
77 | } |
78 | |
79 | if (data->irqnr > 0) { |
80 | /* it cannot take more than 100 ms */ |
81 | ret = wait_for_completion_killable_timeout(x: &data->ranging, |
82 | HZ/10); |
83 | if (ret < 0) |
84 | goto error_unlock; |
85 | else if (ret == 0) { |
86 | ret = -ETIMEDOUT; |
87 | goto error_unlock; |
88 | } |
89 | } else { |
90 | /* use simple sleep if announce irq is not connected */ |
91 | msleep(msecs: 15); |
92 | } |
93 | |
94 | ret = i2c_master_recv(client, buf: (char *)&buf, count: sizeof(buf)); |
95 | if (ret < 0) { |
96 | dev_err(&client->dev, "i2c_master_recv: ret=%d\n" , ret); |
97 | goto error_unlock; |
98 | } |
99 | |
100 | distance = __be16_to_cpu(buf); |
101 | /* check for not returning misleading error codes */ |
102 | if (distance < 0) { |
103 | dev_err(&client->dev, "distance=%d\n" , distance); |
104 | ret = -EINVAL; |
105 | goto error_unlock; |
106 | } |
107 | |
108 | mutex_unlock(lock: &data->lock); |
109 | |
110 | return distance; |
111 | |
112 | error_unlock: |
113 | mutex_unlock(lock: &data->lock); |
114 | |
115 | return ret; |
116 | } |
117 | |
118 | static irqreturn_t mb1232_trigger_handler(int irq, void *p) |
119 | { |
120 | struct iio_poll_func *pf = p; |
121 | struct iio_dev *indio_dev = pf->indio_dev; |
122 | struct mb1232_data *data = iio_priv(indio_dev); |
123 | |
124 | data->scan.distance = mb1232_read_distance(data); |
125 | if (data->scan.distance < 0) |
126 | goto err; |
127 | |
128 | iio_push_to_buffers_with_timestamp(indio_dev, data: &data->scan, |
129 | timestamp: pf->timestamp); |
130 | |
131 | err: |
132 | iio_trigger_notify_done(trig: indio_dev->trig); |
133 | return IRQ_HANDLED; |
134 | } |
135 | |
136 | static int mb1232_read_raw(struct iio_dev *indio_dev, |
137 | struct iio_chan_spec const *channel, int *val, |
138 | int *val2, long mask) |
139 | { |
140 | struct mb1232_data *data = iio_priv(indio_dev); |
141 | int ret; |
142 | |
143 | if (channel->type != IIO_DISTANCE) |
144 | return -EINVAL; |
145 | |
146 | switch (mask) { |
147 | case IIO_CHAN_INFO_RAW: |
148 | ret = mb1232_read_distance(data); |
149 | if (ret < 0) |
150 | return ret; |
151 | *val = ret; |
152 | return IIO_VAL_INT; |
153 | case IIO_CHAN_INFO_SCALE: |
154 | /* 1 LSB is 1 cm */ |
155 | *val = 0; |
156 | *val2 = 10000; |
157 | return IIO_VAL_INT_PLUS_MICRO; |
158 | default: |
159 | return -EINVAL; |
160 | } |
161 | } |
162 | |
163 | static const struct iio_chan_spec mb1232_channels[] = { |
164 | { |
165 | .type = IIO_DISTANCE, |
166 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
167 | BIT(IIO_CHAN_INFO_SCALE), |
168 | .scan_index = 0, |
169 | .scan_type = { |
170 | .sign = 's', |
171 | .realbits = 16, |
172 | .storagebits = 16, |
173 | .endianness = IIO_CPU, |
174 | }, |
175 | }, |
176 | IIO_CHAN_SOFT_TIMESTAMP(1), |
177 | }; |
178 | |
179 | static const struct iio_info mb1232_info = { |
180 | .read_raw = mb1232_read_raw, |
181 | }; |
182 | |
183 | static int mb1232_probe(struct i2c_client *client) |
184 | { |
185 | const struct i2c_device_id *id = i2c_client_get_device_id(client); |
186 | struct iio_dev *indio_dev; |
187 | struct mb1232_data *data; |
188 | int ret; |
189 | struct device *dev = &client->dev; |
190 | |
191 | if (!i2c_check_functionality(adap: client->adapter, |
192 | I2C_FUNC_SMBUS_READ_BYTE | |
193 | I2C_FUNC_SMBUS_WRITE_BYTE)) |
194 | return -ENODEV; |
195 | |
196 | indio_dev = devm_iio_device_alloc(parent: dev, sizeof_priv: sizeof(*data)); |
197 | if (!indio_dev) |
198 | return -ENOMEM; |
199 | |
200 | data = iio_priv(indio_dev); |
201 | i2c_set_clientdata(client, data: indio_dev); |
202 | data->client = client; |
203 | |
204 | indio_dev->info = &mb1232_info; |
205 | indio_dev->name = id->name; |
206 | indio_dev->modes = INDIO_DIRECT_MODE; |
207 | indio_dev->channels = mb1232_channels; |
208 | indio_dev->num_channels = ARRAY_SIZE(mb1232_channels); |
209 | |
210 | mutex_init(&data->lock); |
211 | |
212 | init_completion(x: &data->ranging); |
213 | |
214 | data->irqnr = fwnode_irq_get(dev_fwnode(&client->dev), index: 0); |
215 | if (data->irqnr > 0) { |
216 | ret = devm_request_irq(dev, irq: data->irqnr, handler: mb1232_handle_irq, |
217 | IRQF_TRIGGER_FALLING, devname: id->name, dev_id: indio_dev); |
218 | if (ret < 0) { |
219 | dev_err(dev, "request_irq: %d\n" , ret); |
220 | return ret; |
221 | } |
222 | } |
223 | |
224 | ret = devm_iio_triggered_buffer_setup(dev, indio_dev, |
225 | iio_pollfunc_store_time, mb1232_trigger_handler, NULL); |
226 | if (ret < 0) { |
227 | dev_err(dev, "setup of iio triggered buffer failed\n" ); |
228 | return ret; |
229 | } |
230 | |
231 | return devm_iio_device_register(dev, indio_dev); |
232 | } |
233 | |
234 | static const struct of_device_id of_mb1232_match[] = { |
235 | { .compatible = "maxbotix,mb1202" , }, |
236 | { .compatible = "maxbotix,mb1212" , }, |
237 | { .compatible = "maxbotix,mb1222" , }, |
238 | { .compatible = "maxbotix,mb1232" , }, |
239 | { .compatible = "maxbotix,mb1242" , }, |
240 | { .compatible = "maxbotix,mb7040" , }, |
241 | { .compatible = "maxbotix,mb7137" , }, |
242 | {}, |
243 | }; |
244 | |
245 | MODULE_DEVICE_TABLE(of, of_mb1232_match); |
246 | |
247 | static const struct i2c_device_id mb1232_id[] = { |
248 | { "maxbotix-mb1202" , }, |
249 | { "maxbotix-mb1212" , }, |
250 | { "maxbotix-mb1222" , }, |
251 | { "maxbotix-mb1232" , }, |
252 | { "maxbotix-mb1242" , }, |
253 | { "maxbotix-mb7040" , }, |
254 | { "maxbotix-mb7137" , }, |
255 | { } |
256 | }; |
257 | MODULE_DEVICE_TABLE(i2c, mb1232_id); |
258 | |
259 | static struct i2c_driver mb1232_driver = { |
260 | .driver = { |
261 | .name = "maxbotix-mb1232" , |
262 | .of_match_table = of_mb1232_match, |
263 | }, |
264 | .probe = mb1232_probe, |
265 | .id_table = mb1232_id, |
266 | }; |
267 | module_i2c_driver(mb1232_driver); |
268 | |
269 | MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>" ); |
270 | MODULE_DESCRIPTION("Maxbotix I2CXL-MaxSonar i2c ultrasonic ranger driver" ); |
271 | MODULE_LICENSE("GPL" ); |
272 | |