diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2020-05-15 17:03:28 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2020-05-15 17:03:28 +0300 |
commit | cef077e6aa4c7dbe2f23e1201cf705f9540ec467 (patch) | |
tree | d955418799ae8d491a648e07a44425bb06d957bb /drivers/iio/chemical/ccs811.c | |
parent | c336c022503d1be719ca06f2526c211709e3d2d3 (diff) | |
parent | 6b46ddb51eab245c64b6b9c55c189e45967d213f (diff) | |
download | linux-cef077e6aa4c7dbe2f23e1201cf705f9540ec467.tar.xz |
Merge tag 'iio-for-5.8b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next
Jonathan writes:
Second set of new device support, cleanups and features for IIO in the 5.8 cycle
Usual mixed back but with a few subsystem wide or device type
wide cleanups.
New device support
* adis16475
- New driver supporting adis16470, adis16475, adis16477, adis16465,
adis16467, adis16500, adis16505 and adis16507.
Includes some rework of the adis library to simplify using it
for this new driver.
* ak8974
- Add support for Alps hscdt008a. ID only. Related patches add support
for scale.
* atlas-sensor
- Add support for RTD-SM OEM temperature sensor.
* cm32181
- Add support for CM3218 including support for SMBUS alert via
ACPI resources.
* ltc2632
- Add support for ltc2634-12/10/8 DACS including handling per
device type numbers of channels.
Major Features
* cm32181
- ACPI bindings including parsing CPM0 and CPM1 custom ACPI tables.
Includes minor tidy ups and fixes.
* vcnl4000
- Add event support
- Add buffered data capture support
- Add control of sampling frequency
Cleanups and minor fixes.
* core
- Trivial rework of iio_device_alloc to use an early return and
improve readability.
- Precursors to addition of multiple buffer support. So far
minor refactoring.
* subsystem wide
- Use get_unaligned_be24 slightly improve readability over open
coding it.
* adis drivers
- Use iio_get_debugfs_dentry access function.
* bh1780, cm32181, cm3232, gp2ap02a00f, opt3001, st_uvis25, vl6180,
dmard06, kxsd9
- Drop use of of_match_ptr to allow ACPI based probing via PRP0001.
Part of clear out of this to avoid cut and paste into new drivers.
* ad5592r, ad5593r
- Fix typos
* ad5933
- Use managed interfaces to automate error handling and remove.
* ak8974
- Fix wrong number of 'real bits' for buffered data.
- Refactor to pull measurement code out as separate function.
bmp280
- Fix lack of clamp on range during data capture.
* at91-sama5d2_adc
- Handle unfinished conversions correctly.
- Allow use of triggers other than it's own.
- Reorganize buffer setup and tear down as part of long running
subsystem wide rework.
* ccs811
- Add DT binding docs and match table.
- Support external reset and wakeup pins.
* hid-sensors
- Reorganize buffer setup and tear down as part of long running
subsystem wide rework.
* ltr501
- Constify some structs.
* vcnl4000
- Fix an endian issue by using explicit byte swapped i2c accessors.
* tag 'iio-for-5.8b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (74 commits)
iio: light: ltr501: Constify structs
staging: iio: ad5933: attach life-cycle of kfifo buffer to parent device and use managed calls throughout
iio: bmp280: fix compensation of humidity
iio: light: cm32181: Fix integartion time typo
iio: light: cm32181: Add support for parsing CPM0 and CPM1 ACPI tables
iio: light: cm32181: Make lux_per_bit and lux_per_bit_base_it runtime settings
iio: light: cm32181: Use units of 1/100000th for calibscale and lux_per_bit
iio: light: cm32181: Change reg_init to use a bitmap of which registers to init
iio: light: cm32181: Handle CM3218 ACPI devices with 2 I2C resources
iio: light: cm32181: Clean up the probe function a bit
iio: light: cm32181: Add support for the CM3218
iio: light: cm32181: Add some extra register defines
iio: light: cm32181: Add support for ACPI enumeration
iio: light: cm32181: Switch to new style i2c-driver probe function
iio: hid-sensors: move triggered buffer setup into hid_sensor_setup_trigger
iio: vcnl4000: Add buffer support for VCNL4010/20.
iio: vcnl4000: Add sampling frequency support for VCNL4010/20.
iio: vcnl4000: Add event support for VCNL4010/20.
iio: vcnl4000: Factorize data reading and writing.
iio: vcnl4000: Fix i2c swapped word reading.
...
Diffstat (limited to 'drivers/iio/chemical/ccs811.c')
-rw-r--r-- | drivers/iio/chemical/ccs811.c | 112 |
1 files changed, 101 insertions, 11 deletions
diff --git a/drivers/iio/chemical/ccs811.c b/drivers/iio/chemical/ccs811.c index 2ebdfc35bcda..3ecd633f9ed3 100644 --- a/drivers/iio/chemical/ccs811.c +++ b/drivers/iio/chemical/ccs811.c @@ -16,6 +16,7 @@ */ #include <linux/delay.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> @@ -36,6 +37,7 @@ #define CCS811_ERR 0xE0 /* Used to transition from boot to application mode */ #define CCS811_APP_START 0xF4 +#define CCS811_SW_RESET 0xFF /* Status register flags */ #define CCS811_STATUS_ERROR BIT(0) @@ -74,6 +76,7 @@ struct ccs811_data { struct mutex lock; /* Protect readings */ struct ccs811_reading buffer; struct iio_trigger *drdy_trig; + struct gpio_desc *wakeup_gpio; bool drdy_trig_on; }; @@ -166,10 +169,25 @@ static int ccs811_setup(struct i2c_client *client) CCS811_MODE_IAQ_1SEC); } +static void ccs811_set_wakeup(struct ccs811_data *data, bool enable) +{ + if (!data->wakeup_gpio) + return; + + gpiod_set_value(data->wakeup_gpio, enable); + + if (enable) + usleep_range(50, 60); + else + usleep_range(20, 30); +} + static int ccs811_get_measurement(struct ccs811_data *data) { int ret, tries = 11; + ccs811_set_wakeup(data, true); + /* Maximum waiting time: 1s, as measurements are made every second */ while (tries-- > 0) { ret = i2c_smbus_read_byte_data(data->client, CCS811_STATUS); @@ -183,9 +201,12 @@ static int ccs811_get_measurement(struct ccs811_data *data) if (!(ret & CCS811_STATUS_DATA_READY)) return -EIO; - return i2c_smbus_read_i2c_block_data(data->client, + ret = i2c_smbus_read_i2c_block_data(data->client, CCS811_ALG_RESULT_DATA, 8, (char *)&data->buffer); + ccs811_set_wakeup(data, false); + + return ret; } static int ccs811_read_raw(struct iio_dev *indio_dev, @@ -336,6 +357,45 @@ static irqreturn_t ccs811_data_rdy_trigger_poll(int irq, void *private) return IRQ_HANDLED; } +static int ccs811_reset(struct i2c_client *client) +{ + struct gpio_desc *reset_gpio; + int ret; + + reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(reset_gpio)) + return PTR_ERR(reset_gpio); + + /* Try to reset using nRESET pin if available else do SW reset */ + if (reset_gpio) { + gpiod_set_value(reset_gpio, 1); + usleep_range(20, 30); + gpiod_set_value(reset_gpio, 0); + } else { + /* + * As per the datasheet, this sequence of values needs to be + * written to the SW_RESET register for triggering the soft + * reset in the device and placing it in boot mode. + */ + static const u8 reset_seq[] = { + 0x11, 0xE5, 0x72, 0x8A, + }; + + ret = i2c_smbus_write_i2c_block_data(client, CCS811_SW_RESET, + sizeof(reset_seq), reset_seq); + if (ret < 0) { + dev_err(&client->dev, "Failed to reset sensor\n"); + return ret; + } + } + + /* tSTART delay required after reset */ + usleep_range(1000, 2000); + + return 0; +} + static int ccs811_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -348,36 +408,59 @@ static int ccs811_probe(struct i2c_client *client, | I2C_FUNC_SMBUS_READ_I2C_BLOCK)) return -EOPNOTSUPP; + 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; + + data->wakeup_gpio = devm_gpiod_get_optional(&client->dev, "wakeup", + GPIOD_OUT_HIGH); + if (IS_ERR(data->wakeup_gpio)) + return PTR_ERR(data->wakeup_gpio); + + ccs811_set_wakeup(data, true); + + ret = ccs811_reset(client); + if (ret) { + ccs811_set_wakeup(data, false); + return ret; + } + /* Check hardware id (should be 0x81 for this family of devices) */ ret = i2c_smbus_read_byte_data(client, CCS811_HW_ID); - if (ret < 0) + if (ret < 0) { + ccs811_set_wakeup(data, false); return ret; + } if (ret != CCS811_HW_ID_VALUE) { dev_err(&client->dev, "hardware id doesn't match CCS81x\n"); + ccs811_set_wakeup(data, false); return -ENODEV; } ret = i2c_smbus_read_byte_data(client, CCS811_HW_VERSION); - if (ret < 0) + if (ret < 0) { + ccs811_set_wakeup(data, false); return ret; + } if ((ret & CCS811_HW_VERSION_MASK) != CCS811_HW_VERSION_VALUE) { dev_err(&client->dev, "no CCS811 sensor\n"); + ccs811_set_wakeup(data, false); return -ENODEV; } - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); - if (!indio_dev) - return -ENOMEM; - ret = ccs811_setup(client); - if (ret < 0) + if (ret < 0) { + ccs811_set_wakeup(data, false); return ret; + } - data = iio_priv(indio_dev); - i2c_set_clientdata(client, indio_dev); - data->client = client; + ccs811_set_wakeup(data, false); mutex_init(&data->lock); @@ -466,9 +549,16 @@ static const struct i2c_device_id ccs811_id[] = { }; MODULE_DEVICE_TABLE(i2c, ccs811_id); +static const struct of_device_id ccs811_dt_ids[] = { + { .compatible = "ams,ccs811" }, + { } +}; +MODULE_DEVICE_TABLE(of, ccs811_dt_ids); + static struct i2c_driver ccs811_driver = { .driver = { .name = "ccs811", + .of_match_table = ccs811_dt_ids, }, .probe = ccs811_probe, .remove = ccs811_remove, |