diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig index 2ca3b0bc5eba..947cf7a36e75 100644 --- a/drivers/iio/proximity/Kconfig +++ b/drivers/iio/proximity/Kconfig @@ -96,6 +96,20 @@ config PING To compile this driver as a module, choose M here: the module will be called ping. +config RCWL96XX + tristate "RCWL96XX ultrasonic distance sensor" + depends on I2C + help + Say Y yo build a driver for the RCWL96XX distance sensor chip + with I2C module. + + The driver drives the following modules: + - RCWL-1005 + - RCWL-1605 + + To compile this driver as a module, choose M here: the + module will be called rcwl96xx. + config RFD77402 tristate "RFD77402 ToF sensor" depends on I2C diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile index f36598380446..a6abe1b7ccc9 100644 --- a/drivers/iio/proximity/Makefile +++ b/drivers/iio/proximity/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_ISL29501) += isl29501.o obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o obj-$(CONFIG_MB1232) += mb1232.o obj-$(CONFIG_PING) += ping.o +obj-$(CONFIG_RCWL96XX) += rcwl96xx.o obj-$(CONFIG_RFD77402) += rfd77402.o obj-$(CONFIG_SRF04) += srf04.o obj-$(CONFIG_SRF08) += srf08.o diff --git a/drivers/iio/proximity/rcwl96xx.c b/drivers/iio/proximity/rcwl96xx.c new file mode 100644 index 000000000000..1e8b2a60adfe --- /dev/null +++ b/drivers/iio/proximity/rcwl96xx.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * RCWL96xx: ultrasonic distance sensor (i2c) + * Support for RCWL96XX chips that drive RCWL-1005, RCWL-1605 modules. + * + * Copyright (C) 2024 William Goodspeed + */ + +#include +#include +#include + +#include +#include + +#define RCWL96XX_I2C_TRIG_CMD 0x01 + +struct rcwl96xx_data { + struct i2c_client *client; + struct mutex lock; +}; + +static int rcwl96xx_read(struct rcwl96xx_data *data) +{ + u8 raw[3] = { 0 }, cmd[1] = { RCWL96XX_I2C_TRIG_CMD }; + int ret, distance_mm; + + /* lock against concurrent reading calls */ + mutex_lock(&data->lock); + + ret = i2c_master_send(data->client, cmd, 1); + if (ret < 0) { + mutex_unlock(&data->lock); + return ret; + } + + /* Maximum delay for measurement: 100mS */ + msleep(100); + + ret = i2c_master_recv(data->client, raw, 3); + if (ret < 0) { + mutex_unlock(&data->lock); + return ret; + } else if (ret < 3) { + mutex_unlock(&data->lock); + return -ENODATA; + } + + mutex_unlock(&data->lock); + + /* Distance (mm) = ((BYTE_H << 16) + (BYTE_M << 8) + BYTE_L)/1000 */ + distance_mm = ((raw[0] << 16) + (raw[1] << 8) + raw[2])/1000; + + return distance_mm; +} + +static int rcwl96xx_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, + int *val, + int *val2, + long info) +{ + struct rcwl96xx_data *data = iio_priv(indio_dev); + int ret; + + if (channel->type != IIO_DISTANCE) + return -EINVAL; + + switch (info) { + case IIO_CHAN_INFO_RAW: + ret = rcwl96xx_read(data); + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = 1000; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static const struct iio_info rcwl96xx_info = { + .read_raw = rcwl96xx_read_raw, +}; + +static const struct iio_chan_spec rcwl96xx_chan_spec[] = { + { + .type = IIO_DISTANCE, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + }, +}; + +static int rcwl96xx_probe(struct i2c_client *client) +{ + struct rcwl96xx_data *data; + struct iio_dev *indio_dev; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + + mutex_init(&data->lock); + + indio_dev->info = &rcwl96xx_info; + indio_dev->channels = rcwl96xx_chan_spec; + indio_dev->num_channels = ARRAY_SIZE(rcwl96xx_chan_spec); + indio_dev->name = "rcwl96xx"; + indio_dev->modes = INDIO_DIRECT_MODE; + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static const struct of_device_id rcwl96xx_of_match[] = { + { + .compatible = "mangze,rcwl96xx", + }, + {} +}; +MODULE_DEVICE_TABLE(of, rcwl96xx_of_match); + +static struct i2c_driver rcwl96xx_driver = { + .driver = { + .name = "rcwl96xx", + .of_match_table = rcwl96xx_of_match, + }, + .probe = rcwl96xx_probe, +}; +module_i2c_driver(rcwl96xx_driver); + +MODULE_AUTHOR("William Goodspeed "); +MODULE_DESCRIPTION("Mangze RCWL96XX ultrasonic distance sensor driver"); +MODULE_LICENSE("GPL");