diff options
Diffstat (limited to 'drivers/iio/proximity/srf08.c')
-rw-r--r-- | drivers/iio/proximity/srf08.c | 227 |
1 files changed, 197 insertions, 30 deletions
diff --git a/drivers/iio/proximity/srf08.c b/drivers/iio/proximity/srf08.c index 49316cbf7c60..9380d545aab1 100644 --- a/drivers/iio/proximity/srf08.c +++ b/drivers/iio/proximity/srf08.c @@ -1,14 +1,18 @@ /* - * srf08.c - Support for Devantech SRF08 ultrasonic ranger + * srf08.c - Support for Devantech SRFxx ultrasonic ranger + * with i2c interface + * actually supported are srf02, srf08, srf10 * - * Copyright (c) 2016 Andreas Klinger <ak@it-klinger.de> + * Copyright (c) 2016, 2017 Andreas Klinger <ak@it-klinger.de> * * This file is subject to the terms and conditions of version 2 of - * the GNU General Public License. See the file COPYING in the main + * the GNU General Public License. See the file COPYING in the main * directory of this archive for more details. * * For details about the device see: * http://www.robot-electronics.co.uk/htm/srf08tech.html + * http://www.robot-electronics.co.uk/htm/srf10tech.htm + * http://www.robot-electronics.co.uk/htm/srf02tech.htm */ #include <linux/err.h> @@ -18,6 +22,9 @@ #include <linux/bitops.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> /* registers of SRF08 device */ #define SRF08_WRITE_COMMAND 0x00 /* Command Register */ @@ -30,14 +37,46 @@ #define SRF08_CMD_RANGING_CM 0x51 /* Ranging Mode - Result in cm */ -#define SRF08_DEFAULT_GAIN 1025 /* default analogue value of Gain */ -#define SRF08_DEFAULT_RANGE 6020 /* default value of Range in mm */ +enum srf08_sensor_type { + SRF02, + SRF08, + SRF10, + SRF_MAX_TYPE +}; + +struct srf08_chip_info { + const int *sensitivity_avail; + int num_sensitivity_avail; + int sensitivity_default; + + /* default value of Range in mm */ + int range_default; +}; struct srf08_data { struct i2c_client *client; - int sensitivity; /* Gain */ - int range_mm; /* max. Range in mm */ + + /* + * Gain in the datasheet is called sensitivity here to distinct it + * from the gain used with amplifiers of adc's + */ + int sensitivity; + + /* max. Range in mm */ + int range_mm; struct mutex lock; + + /* + * triggered buffer + * 1x16-bit channel + 3x16 padding + 4x16 timestamp + */ + s16 buffer[8]; + + /* Sensor-Type */ + enum srf08_sensor_type sensor_type; + + /* Chip-specific information */ + const struct srf08_chip_info *chip_info; }; /* @@ -47,11 +86,42 @@ struct srf08_data { * But with ADC's this term is already used differently and that's why it * is called "Sensitivity" here. */ -static const int srf08_sensitivity[] = { +static const struct srf08_chip_info srf02_chip_info = { + .sensitivity_avail = NULL, + .num_sensitivity_avail = 0, + .sensitivity_default = 0, + + .range_default = 0, +}; + +static const int srf08_sensitivity_avail[] = { 94, 97, 100, 103, 107, 110, 114, 118, 123, 128, 133, 139, 145, 152, 159, 168, 177, 187, 199, 212, 227, 245, 265, 288, - 317, 352, 395, 450, 524, 626, 777, 1025 }; + 317, 352, 395, 450, 524, 626, 777, 1025 + }; + +static const struct srf08_chip_info srf08_chip_info = { + .sensitivity_avail = srf08_sensitivity_avail, + .num_sensitivity_avail = ARRAY_SIZE(srf08_sensitivity_avail), + .sensitivity_default = 1025, + + .range_default = 6020, +}; + +static const int srf10_sensitivity_avail[] = { + 40, 40, 50, 60, 70, 80, 100, 120, + 140, 200, 250, 300, 350, 400, 500, 600, + 700, + }; + +static const struct srf08_chip_info srf10_chip_info = { + .sensitivity_avail = srf10_sensitivity_avail, + .num_sensitivity_avail = ARRAY_SIZE(srf10_sensitivity_avail), + .sensitivity_default = 700, + + .range_default = 6020, +}; static int srf08_read_ranging(struct srf08_data *data) { @@ -110,6 +180,29 @@ static int srf08_read_ranging(struct srf08_data *data) return ret; } +static irqreturn_t srf08_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct srf08_data *data = iio_priv(indio_dev); + s16 sensor_data; + + sensor_data = srf08_read_ranging(data); + if (sensor_data < 0) + goto err; + + mutex_lock(&data->lock); + + data->buffer[0] = sensor_data; + iio_push_to_buffers_with_timestamp(indio_dev, + data->buffer, pf->timestamp); + + mutex_unlock(&data->lock); +err: + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + static int srf08_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *channel, int *val, int *val2, long mask) @@ -225,9 +318,13 @@ static ssize_t srf08_show_sensitivity_available(struct device *dev, struct device_attribute *attr, char *buf) { int i, len = 0; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct srf08_data *data = iio_priv(indio_dev); - for (i = 0; i < ARRAY_SIZE(srf08_sensitivity); i++) - len += sprintf(buf + len, "%d ", srf08_sensitivity[i]); + for (i = 0; i < data->chip_info->num_sensitivity_avail; i++) + if (data->chip_info->sensitivity_avail[i]) + len += sprintf(buf + len, "%d ", + data->chip_info->sensitivity_avail[i]); len += sprintf(buf + len, "\n"); @@ -256,19 +353,21 @@ static ssize_t srf08_write_sensitivity(struct srf08_data *data, int ret, i; u8 regval; - for (i = 0; i < ARRAY_SIZE(srf08_sensitivity); i++) - if (val == srf08_sensitivity[i]) { + if (!val) + return -EINVAL; + + for (i = 0; i < data->chip_info->num_sensitivity_avail; i++) + if (val && (val == data->chip_info->sensitivity_avail[i])) { regval = i; break; } - if (i >= ARRAY_SIZE(srf08_sensitivity)) + if (i >= data->chip_info->num_sensitivity_avail) return -EINVAL; mutex_lock(&data->lock); - ret = i2c_smbus_write_byte_data(client, - SRF08_WRITE_MAX_GAIN, regval); + ret = i2c_smbus_write_byte_data(client, SRF08_WRITE_MAX_GAIN, regval); if (ret < 0) { dev_err(&client->dev, "write_sensitivity - err: %d\n", ret); mutex_unlock(&data->lock); @@ -323,7 +422,15 @@ static const struct iio_chan_spec srf08_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + .scan_index = 0, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU, + }, }, + IIO_CHAN_SOFT_TIMESTAMP(1), }; static const struct iio_info srf08_info = { @@ -332,6 +439,15 @@ static const struct iio_info srf08_info = { .driver_module = THIS_MODULE, }; +/* + * srf02 don't have an adjustable range or sensitivity, + * so we don't need attributes at all + */ +static const struct iio_info srf02_info = { + .read_raw = srf08_read_raw, + .driver_module = THIS_MODULE, +}; + static int srf08_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -352,34 +468,84 @@ static int srf08_probe(struct i2c_client *client, data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); data->client = client; + data->sensor_type = (enum srf08_sensor_type)id->driver_data; + + switch (data->sensor_type) { + case SRF02: + data->chip_info = &srf02_chip_info; + indio_dev->info = &srf02_info; + break; + case SRF08: + data->chip_info = &srf08_chip_info; + indio_dev->info = &srf08_info; + break; + case SRF10: + data->chip_info = &srf10_chip_info; + indio_dev->info = &srf08_info; + break; + default: + return -EINVAL; + } - indio_dev->name = "srf08"; + indio_dev->name = id->name; indio_dev->dev.parent = &client->dev; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->info = &srf08_info; indio_dev->channels = srf08_channels; indio_dev->num_channels = ARRAY_SIZE(srf08_channels); mutex_init(&data->lock); - /* - * set default values of device here - * these register values cannot be read from the hardware - * therefore set driver specific default values - */ - ret = srf08_write_range_mm(data, SRF08_DEFAULT_RANGE); - if (ret < 0) + ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, + iio_pollfunc_store_time, srf08_trigger_handler, NULL); + if (ret < 0) { + dev_err(&client->dev, "setup of iio triggered buffer failed\n"); return ret; + } - ret = srf08_write_sensitivity(data, SRF08_DEFAULT_GAIN); - if (ret < 0) - return ret; + if (data->chip_info->range_default) { + /* + * set default range of device in mm here + * these register values cannot be read from the hardware + * therefore set driver specific default values + * + * srf02 don't have a default value so it'll be omitted + */ + ret = srf08_write_range_mm(data, + data->chip_info->range_default); + if (ret < 0) + return ret; + } + + if (data->chip_info->sensitivity_default) { + /* + * set default sensitivity of device here + * these register values cannot be read from the hardware + * therefore set driver specific default values + * + * srf02 don't have a default value so it'll be omitted + */ + ret = srf08_write_sensitivity(data, + data->chip_info->sensitivity_default); + if (ret < 0) + return ret; + } return devm_iio_device_register(&client->dev, indio_dev); } +static const struct of_device_id of_srf08_match[] = { + { .compatible = "devantech,srf02", (void *)SRF02}, + { .compatible = "devantech,srf08", (void *)SRF08}, + { .compatible = "devantech,srf10", (void *)SRF10}, + {}, +}; + +MODULE_DEVICE_TABLE(of, of_srf08_match); + static const struct i2c_device_id srf08_id[] = { - { "srf08", 0 }, + { "srf02", SRF02 }, + { "srf08", SRF08 }, + { "srf10", SRF10 }, { } }; MODULE_DEVICE_TABLE(i2c, srf08_id); @@ -387,6 +553,7 @@ MODULE_DEVICE_TABLE(i2c, srf08_id); static struct i2c_driver srf08_driver = { .driver = { .name = "srf08", + .of_match_table = of_srf08_match, }, .probe = srf08_probe, .id_table = srf08_id, @@ -394,5 +561,5 @@ static struct i2c_driver srf08_driver = { module_i2c_driver(srf08_driver); MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>"); -MODULE_DESCRIPTION("Devantech SRF08 ultrasonic ranger driver"); +MODULE_DESCRIPTION("Devantech SRF02/SRF08/SRF10 i2c ultrasonic ranger driver"); MODULE_LICENSE("GPL"); |