diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-12-26 17:03:33 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-12-26 17:03:33 -0800 |
commit | 35ea984daccc60e6b9dd90074bb2f4f6b57e6309 (patch) | |
tree | cb6c0642539e6ab7e236949fc20cb0340ab09e19 /drivers/iio/proximity | |
parent | e59ac747946693b1356d576f843ce8ac1e283927 (diff) | |
parent | c34c18195d30aa3b95f5ae1b4349875c45fdb8e4 (diff) |
Merge tag 'iio-for-4.5b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next
Jonathan writes:
Second set of IIO new drivers, functionality and cleanups for the 4.5 cycle.
The big one here is the configfs support which has been a long time in the
works but should allow for cleaner ways to do instantiation of those elements
of IIO that aren't directly connected to specific hardware. Lots of cool new
stuff we can use this for in the works!
New core stuff (basically all configfs support related)
* Configfs support
- Core support (was waiting for a configfs patch that went in around 4.4rc2)
- A little fixlet to add a configfs.h to contain a reference to the
configfs_subsystem structure.
* Some infrastructure to simplify handling of software based triggers
(i.e. ones with no actual hardware associated with them)
* A high resolution timer based trigger. This has been around for years
but until the configfs support was ready we didn't have a sensible way
of instantiating instances of it (the method used for the sysfs_trigger
has never been really satisfactory)
New Device Support
* AMS iAQ Volatile Organic Compounds sensor support.
* Freescale imx7d ADC driver
* Maxim MAX30100 oximeter driver (note that for these devices most of the
smart stuff will be in userspace - effectively they are just light sensors
with some interesting led synchronization as far as the kernel is concerned).
* Microchip mcp3421 support added to the mcp3422 driver.
* TI adc124s021 support added to the adc128s052 driver.
* TI ina219, inda226 power monitors. Note that there is an existing hwmon driver
for these parts, the usecase is somewhat different so it is unclear at this
point if the hwmon driver will eventually be replaced by a bridge from
this driver. In the meantime the Kconfig dependencies should prevent both
from being built.
New driver functionality
* us8152d power management support.
Cleanups, fixups
* Use list_for_each_entry_safe instead of list_for_each_safe with the entry
bit coded longhand.
* Select IRQ_WORK for IIO_DUMMY_EVGEN. This is a fix that somehow got lost
when the driver was moved so lets do it again.
* st-accel - drop an unused define.
* vz89x, lidar - optimize i2c transactions by using a single i2c tranfers
instead of multiple calls where supported (fall back to smbus calls as
before if not).
* Use dev_get_platdata() in staging drivers: tsl2x7x, adcs and frequency
drivers instead of direct access to the structure element.
Diffstat (limited to 'drivers/iio/proximity')
-rw-r--r-- | drivers/iio/proximity/pulsedlight-lidar-lite-v2.c | 95 |
1 files changed, 70 insertions, 25 deletions
diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index 29ac262f591b..93e29fb67fa0 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -36,8 +36,10 @@ #define LIDAR_REG_STATUS_INVALID BIT(3) #define LIDAR_REG_STATUS_READY BIT(0) -#define LIDAR_REG_DATA_HBYTE 0x0f -#define LIDAR_REG_DATA_LBYTE 0x10 +#define LIDAR_REG_DATA_HBYTE 0x0f +#define LIDAR_REG_DATA_LBYTE 0x10 +#define LIDAR_REG_DATA_WORD_READ BIT(7) + #define LIDAR_REG_PWR_CONTROL 0x65 #define LIDAR_DRV_NAME "lidar" @@ -46,6 +48,9 @@ struct lidar_data { struct iio_dev *indio_dev; struct i2c_client *client; + int (*xfer)(struct lidar_data *data, u8 reg, u8 *val, int len); + int i2c_enabled; + u16 buffer[8]; /* 2 byte distance + 8 byte timestamp */ }; @@ -64,7 +69,28 @@ static const struct iio_chan_spec lidar_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(1), }; -static int lidar_read_byte(struct lidar_data *data, int reg) +static int lidar_i2c_xfer(struct lidar_data *data, u8 reg, u8 *val, int len) +{ + struct i2c_client *client = data->client; + struct i2c_msg msg[2]; + int ret; + + msg[0].addr = client->addr; + msg[0].flags = client->flags | I2C_M_STOP; + msg[0].len = 1; + msg[0].buf = (char *) ® + + msg[1].addr = client->addr; + msg[1].flags = client->flags | I2C_M_RD; + msg[1].len = len; + msg[1].buf = (char *) val; + + ret = i2c_transfer(client->adapter, msg, 2); + + return (ret == 2) ? 0 : ret; +} + +static int lidar_smbus_xfer(struct lidar_data *data, u8 reg, u8 *val, int len) { struct i2c_client *client = data->client; int ret; @@ -74,17 +100,35 @@ static int lidar_read_byte(struct lidar_data *data, int reg) * so in turn i2c_smbus_read_byte_data cannot be used */ - ret = i2c_smbus_write_byte(client, reg); - if (ret < 0) { - dev_err(&client->dev, "cannot write addr value"); - return ret; + while (len--) { + ret = i2c_smbus_write_byte(client, reg++); + if (ret < 0) { + dev_err(&client->dev, "cannot write addr value"); + return ret; + } + + ret = i2c_smbus_read_byte(client); + if (ret < 0) { + dev_err(&client->dev, "cannot read data value"); + return ret; + } + + *(val++) = ret; } - ret = i2c_smbus_read_byte(client); + return 0; +} + +static int lidar_read_byte(struct lidar_data *data, u8 reg) +{ + int ret; + u8 val; + + ret = data->xfer(data, reg, &val, 1); if (ret < 0) - dev_err(&client->dev, "cannot read data value"); + return ret; - return ret; + return val; } static inline int lidar_write_control(struct lidar_data *data, int val) @@ -100,22 +144,14 @@ static inline int lidar_write_power(struct lidar_data *data, int val) static int lidar_read_measurement(struct lidar_data *data, u16 *reg) { - int ret; - int val; - - ret = lidar_read_byte(data, LIDAR_REG_DATA_HBYTE); - if (ret < 0) - return ret; - val = ret << 8; + int ret = data->xfer(data, LIDAR_REG_DATA_HBYTE | + (data->i2c_enabled ? LIDAR_REG_DATA_WORD_READ : 0), + (u8 *) reg, 2); - ret = lidar_read_byte(data, LIDAR_REG_DATA_LBYTE); - if (ret < 0) - return ret; + if (!ret) + *reg = be16_to_cpu(*reg); - val |= ret; - *reg = val; - - return 0; + return ret; } static int lidar_get_measurement(struct lidar_data *data, u16 *reg) @@ -233,6 +269,16 @@ static int lidar_probe(struct i2c_client *client, indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; + data = iio_priv(indio_dev); + + if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + data->xfer = lidar_i2c_xfer; + data->i2c_enabled = 1; + } else if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE)) + data->xfer = lidar_smbus_xfer; + else + return -ENOTSUPP; indio_dev->info = &lidar_info; indio_dev->name = LIDAR_DRV_NAME; @@ -240,7 +286,6 @@ static int lidar_probe(struct i2c_client *client, indio_dev->num_channels = ARRAY_SIZE(lidar_channels); indio_dev->modes = INDIO_DIRECT_MODE; - data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); data->client = client; |