diff options
Diffstat (limited to 'drivers/iio')
61 files changed, 4717 insertions, 759 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 1e120fa1e156..12addf272a61 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -77,4 +77,16 @@ config MMA8452 To compile this driver as a module, choose M here: the module will be called mma8452. +config KXCJK1013 + tristate "Kionix 3-Axis Accelerometer Driver" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say Y here if you want to build a driver for the Kionix KXCJK-1013 + triaxial acceleration sensor. + + To compile this driver as a module, choose M here: the module will + be called kxcjk-1013. + endmenu diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index dc0e379c2592..6578ca1a8e09 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -5,6 +5,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_BMA180) += bma180.o obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o +obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o obj-$(CONFIG_KXSD9) += kxsd9.o obj-$(CONFIG_MMA8452) += mma8452.o diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c new file mode 100644 index 000000000000..7941cf2d31ee --- /dev/null +++ b/drivers/iio/accel/kxcjk-1013.c @@ -0,0 +1,764 @@ +/* + * KXCJK-1013 3-axis accelerometer driver + * Copyright (c) 2014, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/bitops.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/acpi.h> +#include <linux/gpio/consumer.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/iio/accel/kxcjk_1013.h> + +#define KXCJK1013_DRV_NAME "kxcjk1013" +#define KXCJK1013_IRQ_NAME "kxcjk1013_event" + +#define KXCJK1013_REG_XOUT_L 0x06 +/* + * From low byte X axis register, all the other addresses of Y and Z can be + * obtained by just applying axis offset. The following axis defines are just + * provide clarity, but not used. + */ +#define KXCJK1013_REG_XOUT_H 0x07 +#define KXCJK1013_REG_YOUT_L 0x08 +#define KXCJK1013_REG_YOUT_H 0x09 +#define KXCJK1013_REG_ZOUT_L 0x0A +#define KXCJK1013_REG_ZOUT_H 0x0B + +#define KXCJK1013_REG_DCST_RESP 0x0C +#define KXCJK1013_REG_WHO_AM_I 0x0F +#define KXCJK1013_REG_INT_SRC1 0x16 +#define KXCJK1013_REG_INT_SRC2 0x17 +#define KXCJK1013_REG_STATUS_REG 0x18 +#define KXCJK1013_REG_INT_REL 0x1A +#define KXCJK1013_REG_CTRL1 0x1B +#define KXCJK1013_REG_CTRL2 0x1D +#define KXCJK1013_REG_INT_CTRL1 0x1E +#define KXCJK1013_REG_INT_CTRL2 0x1F +#define KXCJK1013_REG_DATA_CTRL 0x21 +#define KXCJK1013_REG_WAKE_TIMER 0x29 +#define KXCJK1013_REG_SELF_TEST 0x3A +#define KXCJK1013_REG_WAKE_THRES 0x6A + +#define KXCJK1013_REG_CTRL1_BIT_PC1 BIT(7) +#define KXCJK1013_REG_CTRL1_BIT_RES BIT(6) +#define KXCJK1013_REG_CTRL1_BIT_DRDY BIT(5) +#define KXCJK1013_REG_CTRL1_BIT_GSEL1 BIT(4) +#define KXCJK1013_REG_CTRL1_BIT_GSEL0 BIT(3) +#define KXCJK1013_REG_CTRL1_BIT_WUFE BIT(1) +#define KXCJK1013_REG_INT_REG1_BIT_IEA BIT(4) +#define KXCJK1013_REG_INT_REG1_BIT_IEN BIT(5) + +#define KXCJK1013_DATA_MASK_12_BIT 0x0FFF +#define KXCJK1013_MAX_STARTUP_TIME_US 100000 + +struct kxcjk1013_data { + struct i2c_client *client; + struct iio_trigger *trig; + bool trig_mode; + struct mutex mutex; + s16 buffer[8]; + int power_state; + u8 odr_bits; + bool active_high_intr; +}; + +enum kxcjk1013_axis { + AXIS_X, + AXIS_Y, + AXIS_Z, +}; + +enum kxcjk1013_mode { + STANDBY, + OPERATION, +}; + +static const struct { + int val; + int val2; + int odr_bits; +} samp_freq_table[] = { {0, 781000, 0x08}, {1, 563000, 0x09}, + {3, 125000, 0x0A}, {6, 250000, 0x0B}, {12, 500000, 0}, + {25, 0, 0x01}, {50, 0, 0x02}, {100, 0, 0x03}, + {200, 0, 0x04}, {400, 0, 0x05}, {800, 0, 0x06}, + {1600, 0, 0x07} }; + +/* Refer to section 4 of the specification */ +static const struct { + int odr_bits; + int usec; +} odr_start_up_times[] = { {0x08, 100000}, {0x09, 100000}, {0x0A, 100000}, + {0x0B, 100000}, { 0, 80000}, {0x01, 41000}, + {0x02, 21000}, {0x03, 11000}, {0x04, 6400}, + {0x05, 3900}, {0x06, 2700}, {0x07, 2100} }; + +static int kxcjk1013_set_mode(struct kxcjk1013_data *data, + enum kxcjk1013_mode mode) +{ + int ret; + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); + return ret; + } + + if (mode == STANDBY) + ret &= ~KXCJK1013_REG_CTRL1_BIT_PC1; + else + ret |= KXCJK1013_REG_CTRL1_BIT_PC1; + + ret = i2c_smbus_write_byte_data(data->client, + KXCJK1013_REG_CTRL1, ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); + return ret; + } + + return 0; +} + +static int kxcjk1013_chip_init(struct kxcjk1013_data *data) +{ + int ret; + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_WHO_AM_I); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading who_am_i\n"); + return ret; + } + + dev_dbg(&data->client->dev, "KXCJK1013 Chip Id %x\n", ret); + + ret = kxcjk1013_set_mode(data, STANDBY); + if (ret < 0) + return ret; + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); + return ret; + } + + /* Setting range to 4G */ + ret |= KXCJK1013_REG_CTRL1_BIT_GSEL0; + ret &= ~KXCJK1013_REG_CTRL1_BIT_GSEL1; + + /* Set 12 bit mode */ + ret |= KXCJK1013_REG_CTRL1_BIT_RES; + + ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_CTRL1, + ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_ctrl\n"); + return ret; + } + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_DATA_CTRL); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_data_ctrl\n"); + return ret; + } + + data->odr_bits = ret; + + /* Set up INT polarity */ + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n"); + return ret; + } + + if (data->active_high_intr) + ret |= KXCJK1013_REG_INT_REG1_BIT_IEA; + else + ret &= ~KXCJK1013_REG_INT_REG1_BIT_IEA; + + ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1, + ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n"); + return ret; + } + + return 0; +} + +static int kxcjk1013_chip_setup_interrupt(struct kxcjk1013_data *data, + bool status) +{ + int ret; + + /* This is requirement by spec to change state to STANDBY */ + ret = kxcjk1013_set_mode(data, STANDBY); + if (ret < 0) + return ret; + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n"); + return ret; + } + + if (status) + ret |= KXCJK1013_REG_INT_REG1_BIT_IEN; + else + ret &= ~KXCJK1013_REG_INT_REG1_BIT_IEN; + + ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1, + ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n"); + return ret; + } + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); + return ret; + } + + if (status) + ret |= KXCJK1013_REG_CTRL1_BIT_DRDY; + else + ret &= ~KXCJK1013_REG_CTRL1_BIT_DRDY; + + ret = i2c_smbus_write_byte_data(data->client, + KXCJK1013_REG_CTRL1, ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); + return ret; + } + + return ret; +} + +static int kxcjk1013_convert_freq_to_bit(int val, int val2) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(samp_freq_table); ++i) { + if (samp_freq_table[i].val == val && + samp_freq_table[i].val2 == val2) { + return samp_freq_table[i].odr_bits; + } + } + + return -EINVAL; +} + +static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) +{ + int ret; + int odr_bits; + + odr_bits = kxcjk1013_convert_freq_to_bit(val, val2); + if (odr_bits < 0) + return odr_bits; + + /* To change ODR, the chip must be set to STANDBY as per spec */ + ret = kxcjk1013_set_mode(data, STANDBY); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_DATA_CTRL, + odr_bits); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing data_ctrl\n"); + return ret; + } + + data->odr_bits = odr_bits; + + /* Check, if the ODR is changed after data enable */ + if (data->power_state) { + /* Set the state back to operation */ + ret = kxcjk1013_set_mode(data, OPERATION); + if (ret < 0) + return ret; + } + + return 0; +} + +static int kxcjk1013_get_odr(struct kxcjk1013_data *data, int *val, int *val2) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(samp_freq_table); ++i) { + if (samp_freq_table[i].odr_bits == data->odr_bits) { + *val = samp_freq_table[i].val; + *val2 = samp_freq_table[i].val2; + return IIO_VAL_INT_PLUS_MICRO; + } + } + + return -EINVAL; +} + +static int kxcjk1013_get_acc_reg(struct kxcjk1013_data *data, int axis) +{ + u8 reg = KXCJK1013_REG_XOUT_L + axis * 2; + int ret; + + ret = i2c_smbus_read_word_data(data->client, reg); + if (ret < 0) { + dev_err(&data->client->dev, + "failed to read accel_%c registers\n", 'x' + axis); + return ret; + } + + return ret; +} + +static int kxcjk1013_get_startup_times(struct kxcjk1013_data *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(odr_start_up_times); ++i) { + if (odr_start_up_times[i].odr_bits == data->odr_bits) + return odr_start_up_times[i].usec; + } + + return KXCJK1013_MAX_STARTUP_TIME_US; +} + +static int kxcjk1013_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct kxcjk1013_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&data->mutex); + if (iio_buffer_enabled(indio_dev)) + ret = -EBUSY; + else { + int sleep_val; + + ret = kxcjk1013_set_mode(data, OPERATION); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + ++data->power_state; + sleep_val = kxcjk1013_get_startup_times(data); + if (sleep_val < 20000) + usleep_range(sleep_val, 20000); + else + msleep_interruptible(sleep_val/1000); + ret = kxcjk1013_get_acc_reg(data, chan->scan_index); + if (--data->power_state == 0) + kxcjk1013_set_mode(data, STANDBY); + } + mutex_unlock(&data->mutex); + + if (ret < 0) + return ret; + + *val = sign_extend32(ret >> 4, 11); + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = 19163; /* range +-4g (4/2047*9.806650) */ + return IIO_VAL_INT_PLUS_MICRO; + + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&data->mutex); + ret = kxcjk1013_get_odr(data, val, val2); + mutex_unlock(&data->mutex); + return ret; + + default: + return -EINVAL; + } +} + +static int kxcjk1013_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct kxcjk1013_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&data->mutex); + ret = kxcjk1013_set_odr(data, val, val2); + mutex_unlock(&data->mutex); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int kxcjk1013_validate_trigger(struct iio_dev *indio_dev, + struct iio_trigger *trig) +{ + struct kxcjk1013_data *data = iio_priv(indio_dev); + + if (data->trig != trig) + return -EINVAL; + + return 0; +} + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( + "0.781000 1.563000 3.125000 6.250000 12.500000 25 50 100 200 400 800 1600"); + +static struct attribute *kxcjk1013_attributes[] = { + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group kxcjk1013_attrs_group = { + .attrs = kxcjk1013_attributes, +}; + +#define KXCJK1013_CHANNEL(_axis) { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = AXIS_##_axis, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 12, \ + .storagebits = 16, \ + .shift = 4, \ + .endianness = IIO_CPU, \ + }, \ +} + +static const struct iio_chan_spec kxcjk1013_channels[] = { + KXCJK1013_CHANNEL(X), + KXCJK1013_CHANNEL(Y), + KXCJK1013_CHANNEL(Z), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static const struct iio_info kxcjk1013_info = { + .attrs = &kxcjk1013_attrs_group, + .read_raw = kxcjk1013_read_raw, + .write_raw = kxcjk1013_write_raw, + .validate_trigger = kxcjk1013_validate_trigger, + .driver_module = THIS_MODULE, +}; + +static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct kxcjk1013_data *data = iio_priv(indio_dev); + int bit, ret, i = 0; + + mutex_lock(&data->mutex); + + for_each_set_bit(bit, indio_dev->buffer->scan_mask, + indio_dev->masklength) { + ret = kxcjk1013_get_acc_reg(data, bit); + if (ret < 0) { + mutex_unlock(&data->mutex); + goto err; + } + data->buffer[i++] = ret; + } + mutex_unlock(&data->mutex); + + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + pf->timestamp); +err: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int kxcjk1013_trig_try_reen(struct iio_trigger *trig) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct kxcjk1013_data *data = iio_priv(indio_dev); + int ret; + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_REL); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_rel\n"); + return ret; + } + + return 0; +} + +static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct kxcjk1013_data *data = iio_priv(indio_dev); + + mutex_lock(&data->mutex); + if (state) { + kxcjk1013_chip_setup_interrupt(data, true); + kxcjk1013_set_mode(data, OPERATION); + ++data->power_state; + } else { + if (--data->power_state) { + mutex_unlock(&data->mutex); + return 0; + } + kxcjk1013_chip_setup_interrupt(data, false); + kxcjk1013_set_mode(data, STANDBY); + } + mutex_unlock(&data->mutex); + + return 0; +} + +static const struct iio_trigger_ops kxcjk1013_trigger_ops = { + .set_trigger_state = kxcjk1013_data_rdy_trigger_set_state, + .try_reenable = kxcjk1013_trig_try_reen, + .owner = THIS_MODULE, +}; + +static int kxcjk1013_acpi_gpio_probe(struct i2c_client *client, + struct kxcjk1013_data *data) +{ + const struct acpi_device_id *id; + struct device *dev; + struct gpio_desc *gpio; + int ret; + + if (!client) + return -EINVAL; + + dev = &client->dev; + if (!ACPI_HANDLE(dev)) + return -ENODEV; + + id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!id) + return -ENODEV; + + /* data ready gpio interrupt pin */ + gpio = devm_gpiod_get_index(dev, "kxcjk1013_int", 0); + if (IS_ERR(gpio)) { + dev_err(dev, "acpi gpio get index failed\n"); + return PTR_ERR(gpio); + } + + ret = gpiod_direction_input(gpio); + if (ret) + return ret; + + ret = gpiod_to_irq(gpio); + + dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); + + return ret; +} + +static int kxcjk1013_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct kxcjk1013_data *data; + struct iio_dev *indio_dev; + struct iio_trigger *trig = NULL; + struct kxcjk_1013_platform_data *pdata; + int ret; + + 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; + + pdata = dev_get_platdata(&client->dev); + if (pdata) + data->active_high_intr = pdata->active_high_intr; + else + data->active_high_intr = true; /* default polarity */ + + ret = kxcjk1013_chip_init(data); + if (ret < 0) + return ret; + + mutex_init(&data->mutex); + + indio_dev->dev.parent = &client->dev; + indio_dev->channels = kxcjk1013_channels; + indio_dev->num_channels = ARRAY_SIZE(kxcjk1013_channels); + indio_dev->name = KXCJK1013_DRV_NAME; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &kxcjk1013_info; + + if (client->irq < 0) + client->irq = kxcjk1013_acpi_gpio_probe(client, data); + + if (client->irq >= 0) { + trig = iio_trigger_alloc("%s-dev%d", indio_dev->name, + indio_dev->id); + if (!trig) + return -ENOMEM; + + data->trig_mode = true; + + ret = devm_request_irq(&client->dev, client->irq, + iio_trigger_generic_data_rdy_poll, + IRQF_TRIGGER_RISING, + KXCJK1013_IRQ_NAME, + trig); + if (ret) { + dev_err(&client->dev, "unable to request IRQ\n"); + goto err_trigger_free; + } + + trig->dev.parent = &client->dev; + trig->ops = &kxcjk1013_trigger_ops; + iio_trigger_set_drvdata(trig, indio_dev); + data->trig = trig; + indio_dev->trig = trig; + iio_trigger_get(indio_dev->trig); + + ret = iio_trigger_register(trig); + if (ret) + goto err_trigger_free; + + ret = iio_triggered_buffer_setup(indio_dev, + &iio_pollfunc_store_time, + kxcjk1013_trigger_handler, + NULL); + if (ret < 0) { + dev_err(&client->dev, + "iio triggered buffer setup failed\n"); + goto err_trigger_unregister; + } + } + + ret = devm_iio_device_register(&client->dev, indio_dev); + if (ret < 0) { + dev_err(&client->dev, "unable to register iio device\n"); + goto err_buffer_cleanup; + } + + return 0; + +err_buffer_cleanup: + if (data->trig_mode) + iio_triggered_buffer_cleanup(indio_dev); +err_trigger_unregister: + if (data->trig_mode) + iio_trigger_unregister(trig); +err_trigger_free: + if (data->trig_mode) + iio_trigger_free(trig); + + return ret; +} + +static int kxcjk1013_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct kxcjk1013_data *data = iio_priv(indio_dev); + + if (data->trig_mode) { + iio_triggered_buffer_cleanup(indio_dev); + iio_trigger_unregister(data->trig); + iio_trigger_free(data->trig); + } + + mutex_lock(&data->mutex); + kxcjk1013_set_mode(data, STANDBY); + mutex_unlock(&data->mutex); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int kxcjk1013_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct kxcjk1013_data *data = iio_priv(indio_dev); + + mutex_lock(&data->mutex); + kxcjk1013_set_mode(data, STANDBY); + mutex_unlock(&data->mutex); + + return 0; +} + +static int kxcjk1013_resume(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct kxcjk1013_data *data = iio_priv(indio_dev); + + mutex_lock(&data->mutex); + + if (data->power_state) + kxcjk1013_set_mode(data, OPERATION); + + mutex_unlock(&data->mutex); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(kxcjk1013_pm_ops, kxcjk1013_suspend, kxcjk1013_resume); +#define KXCJK1013_PM_OPS (&kxcjk1013_pm_ops) +#else +#define KXCJK1013_PM_OPS NULL +#endif + +static const struct acpi_device_id kx_acpi_match[] = { + {"KXCJ1013", 0}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, kx_acpi_match); + +static const struct i2c_device_id kxcjk1013_id[] = { + {"kxcjk1013", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, kxcjk1013_id); + +static struct i2c_driver kxcjk1013_driver = { + .driver = { + .name = KXCJK1013_DRV_NAME, + .acpi_match_table = ACPI_PTR(kx_acpi_match), + .pm = KXCJK1013_PM_OPS, + }, + .probe = kxcjk1013_probe, + .remove = kxcjk1013_remove, + .id_table = kxcjk1013_id, +}; +module_i2c_driver(kxcjk1013_driver); + +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("KXCJK1013 accelerometer driver"); diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 2a5fa9a436e5..3c12d4966376 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -429,9 +429,15 @@ static const struct i2c_device_id mma8452_id[] = { }; MODULE_DEVICE_TABLE(i2c, mma8452_id); +static const struct of_device_id mma8452_dt_ids[] = { + { .compatible = "fsl,mma8452" }, + { } +}; + static struct i2c_driver mma8452_driver = { .driver = { .name = "mma8452", + .of_match_table = of_match_ptr(mma8452_dt_ids), .pm = MMA8452_PM_OPS, }, .probe = mma8452_probe, diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index a2abf7c2ce3b..087864854c61 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -393,6 +393,9 @@ static int st_accel_read_raw(struct iio_dev *indio_dev, *val = 0; *val2 = adata->current_fullscale->gain; return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = adata->odr; + return IIO_VAL_INT; default: return -EINVAL; } @@ -410,6 +413,13 @@ static int st_accel_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: err = st_sensors_set_fullscale_by_gain(indio_dev, val2); break; + case IIO_CHAN_INFO_SAMP_FREQ: + if (val2) + return -EINVAL; + mutex_lock(&indio_dev->mlock); + err = st_sensors_set_odr(indio_dev, val); + mutex_unlock(&indio_dev->mlock); + return err; default: return -EINVAL; } @@ -417,14 +427,12 @@ static int st_accel_write_raw(struct iio_dev *indio_dev, return err; } -static ST_SENSOR_DEV_ATTR_SAMP_FREQ(); static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL(); static ST_SENSORS_DEV_ATTR_SCALE_AVAIL(in_accel_scale_available); static struct attribute *st_accel_attributes[] = { &iio_dev_attr_sampling_frequency_available.dev_attr.attr, &iio_dev_attr_in_accel_scale_available.dev_attr.attr, - &iio_dev_attr_sampling_frequency.dev_attr.attr, NULL, }; diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index d7bedbdfc81d..7164aeff3ab1 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -18,6 +18,55 @@ #include <linux/iio/common/st_sensors_i2c.h> #include "st_accel.h" +#ifdef CONFIG_OF +static const struct of_device_id st_accel_of_match[] = { + { + .compatible = "st,lsm303dlh-accel", + .data = LSM303DLH_ACCEL_DEV_NAME, + }, + { + .compatible = "st,lsm303dlhc-accel", + .data = LSM303DLHC_ACCEL_DEV_NAME, + }, + { + .compatible = "st,lis3dh-accel", + .data = LIS3DH_ACCEL_DEV_NAME, + }, + { + .compatible = "st,lsm330d-accel", + .data = LSM330D_ACCEL_DEV_NAME, + }, + { + .compatible = "st,lsm330dl-accel", + .data = LSM330DL_ACCEL_DEV_NAME, + }, + { + .compatible = "st,lsm330dlc-accel", + .data = LSM330DLC_ACCEL_DEV_NAME, + }, + { + .compatible = "st,lis331dlh-accel", + .data = LIS331DLH_ACCEL_DEV_NAME, + }, + { + .compatible = "st,lsm303dl-accel", + .data = LSM303DL_ACCEL_DEV_NAME, + }, + { + .compatible = "st,lsm303dlm-accel", + .data = LSM303DLM_ACCEL_DEV_NAME, + }, + { + .compatible = "st,lsm330-accel", + .data = LSM330_ACCEL_DEV_NAME, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, st_accel_of_match); +#else +#define st_accel_of_match NULL +#endif + static int st_accel_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -31,6 +80,7 @@ static int st_accel_i2c_probe(struct i2c_client *client, adata = iio_priv(indio_dev); adata->dev = &client->dev; + st_sensors_of_i2c_probe(client, st_accel_of_match); st_sensors_i2c_configure(indio_dev, client, adata); @@ -67,6 +117,7 @@ static struct i2c_driver st_accel_driver = { .driver = { .owner = THIS_MODULE, .name = "st-accel-i2c", + .of_match_table = of_match_ptr(st_accel_of_match), }, .probe = st_accel_i2c_probe, .remove = st_accel_i2c_remove, diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index a80d23628f14..11b048a59fde 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -20,6 +20,16 @@ config AD7266 Say yes here to build support for Analog Devices AD7265 and AD7266 ADCs. +config AD7291 + tristate "Analog Devices AD7291 ADC driver" + depends on I2C + help + Say yes here to build support for Analog Devices AD7291 + 8 Channel ADC with temperature sensor. + + To compile this driver as a module, choose M here: the + module will be called ad7291. + config AD7298 tristate "Analog Devices AD7298 ADC driver" depends on SPI @@ -131,6 +141,15 @@ config LP8788_ADC help Say yes here to build support for TI LP8788 ADC. +config MAX1027 + tristate "Maxim max1027 ADC driver" + depends on SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for Maxim SPI ADC models + max1027, max1029 and max1031. + config MAX1363 tristate "Maxim max1363 ADC driver" depends on I2C diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 9d60f2deaaaf..ad81b512aa3d 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -5,6 +5,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o obj-$(CONFIG_AD7266) += ad7266.o +obj-$(CONFIG_AD7291) += ad7291.o obj-$(CONFIG_AD7298) += ad7298.o obj-$(CONFIG_AD7923) += ad7923.o obj-$(CONFIG_AD7476) += ad7476.o @@ -15,6 +16,7 @@ obj-$(CONFIG_AD799X) += ad799x.o obj-$(CONFIG_AT91_ADC) += at91_adc.o obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o +obj-$(CONFIG_MAX1027) += max1027.o obj-$(CONFIG_MAX1363) += max1363.o obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o diff --git a/drivers/iio/adc/ad7291.c b/drivers/iio/adc/ad7291.c new file mode 100644 index 000000000000..c0eabf156702 --- /dev/null +++ b/drivers/iio/adc/ad7291.c @@ -0,0 +1,585 @@ +/* + * AD7291 8-Channel, I2C, 12-Bit SAR ADC with Temperature Sensor + * + * Copyright 2010-2011 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/sysfs.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/events.h> + +#include <linux/platform_data/ad7291.h> + +/* + * Simplified handling + * + * If no events enabled - single polled channel read + * If event enabled direct reads disable unless channel + * is in the read mask. + * + * The noise-delayed bit as per datasheet suggestion is always enabled. + */ + +/* + * AD7291 registers definition + */ +#define AD7291_COMMAND 0x00 +#define AD7291_VOLTAGE 0x01 +#define AD7291_T_SENSE 0x02 +#define AD7291_T_AVERAGE 0x03 +#define AD7291_DATA_HIGH(x) ((x) * 3 + 0x4) +#define AD7291_DATA_LOW(x) ((x) * 3 + 0x5) +#define AD7291_HYST(x) ((x) * 3 + 0x6) +#define AD7291_VOLTAGE_ALERT_STATUS 0x1F +#define AD7291_T_ALERT_STATUS 0x20 + +#define AD7291_BITS 12 +#define AD7291_VOLTAGE_LIMIT_COUNT 8 + + +/* + * AD7291 command + */ +#define AD7291_AUTOCYCLE BIT(0) +#define AD7291_RESET BIT(1) +#define AD7291_ALERT_CLEAR BIT(2) +#define AD7291_ALERT_POLARITY BIT(3) +#define AD7291_EXT_REF BIT(4) +#define AD7291_NOISE_DELAY BIT(5) +#define AD7291_T_SENSE_MASK BIT(7) +#define AD7291_VOLTAGE_MASK GENMASK(15, 8) +#define AD7291_VOLTAGE_OFFSET 8 + +/* + * AD7291 value masks + */ +#define AD7291_VALUE_MASK GENMASK(11, 0) + +/* + * AD7291 alert register bits + */ +#define AD7291_T_LOW BIT(0) +#define AD7291_T_HIGH BIT(1) +#define AD7291_T_AVG_LOW BIT(2) +#define AD7291_T_AVG_HIGH BIT(3) +#define AD7291_V_LOW(x) BIT((x) * 2) +#define AD7291_V_HIGH(x) BIT((x) * 2 + 1) + + +struct ad7291_chip_info { + struct i2c_client *client; + struct regulator *reg; + u16 command; + u16 c_mask; /* Active voltage channels for events */ + struct mutex state_lock; +}; + +static int ad7291_i2c_read(struct ad7291_chip_info *chip, u8 reg, u16 *data) +{ + struct i2c_client *client = chip->client; + int ret = 0; + + ret = i2c_smbus_read_word_swapped(client, reg); + if (ret < 0) { + dev_err(&client->dev, "I2C read error\n"); + return ret; + } + + *data = ret; + + return 0; +} + +static int ad7291_i2c_write(struct ad7291_chip_info *chip, u8 reg, u16 data) +{ + return i2c_smbus_write_word_swapped(chip->client, reg, data); +} + +static irqreturn_t ad7291_event_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct ad7291_chip_info *chip = iio_priv(private); + u16 t_status, v_status; + u16 command; + int i; + s64 timestamp = iio_get_time_ns(); + + if (ad7291_i2c_read(chip, AD7291_T_ALERT_STATUS, &t_status)) + return IRQ_HANDLED; + + if (ad7291_i2c_read(chip, AD7291_VOLTAGE_ALERT_STATUS, &v_status)) + return IRQ_HANDLED; + + if (!(t_status || v_status)) + return IRQ_HANDLED; + + command = chip->command | AD7291_ALERT_CLEAR; + ad7291_i2c_write(chip, AD7291_COMMAND, command); + + command = chip->command & ~AD7291_ALERT_CLEAR; + ad7291_i2c_write(chip, AD7291_COMMAND, command); + + /* For now treat t_sense and t_sense_average the same */ + if ((t_status & AD7291_T_LOW) || (t_status & AD7291_T_AVG_LOW)) + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_TEMP, + 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + timestamp); + if ((t_status & AD7291_T_HIGH) || (t_status & AD7291_T_AVG_HIGH)) + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_TEMP, + 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + timestamp); + + for (i = 0; i < AD7291_VOLTAGE_LIMIT_COUNT; i++) { + if (v_status & AD7291_V_LOW(i)) + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + i, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + timestamp); + if (v_status & AD7291_V_HIGH(i)) + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + i, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + timestamp); + } + + return IRQ_HANDLED; +} + +static unsigned int ad7291_threshold_reg(const struct iio_chan_spec *chan, + enum iio_event_direction dir, + enum iio_event_info info) +{ + unsigned int offset; + + switch (chan->type) { + case IIO_VOLTAGE: + offset = chan->channel; + break; + case IIO_TEMP: + offset = AD7291_VOLTAGE_OFFSET; + break; + default: + return 0; + } + + switch (info) { + case IIO_EV_INFO_VALUE: + if (dir == IIO_EV_DIR_FALLING) + return AD7291_DATA_HIGH(offset); + else + return AD7291_DATA_LOW(offset); + case IIO_EV_INFO_HYSTERESIS: + return AD7291_HYST(offset); + default: + break; + } + return 0; +} + +static int ad7291_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct ad7291_chip_info *chip = iio_priv(indio_dev); + int ret; + u16 uval; + + ret = ad7291_i2c_read(chip, ad7291_threshold_reg(chan, dir, info), + &uval); + if (ret < 0) + return ret; + + if (info == IIO_EV_INFO_HYSTERESIS || chan->type == IIO_VOLTAGE) + *val = uval & AD7291_VALUE_MASK; + + else + *val = sign_extend32(uval, 11); + + return IIO_VAL_INT; +} + +static int ad7291_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct ad7291_chip_info *chip = iio_priv(indio_dev); + + if (info == IIO_EV_INFO_HYSTERESIS || chan->type == IIO_VOLTAGE) { + if (val > AD7291_VALUE_MASK || val < 0) + return -EINVAL; + } else { + if (val > 2047 || val < -2048) + return -EINVAL; + } + + return ad7291_i2c_write(chip, ad7291_threshold_reg(chan, dir, info), + val); +} + +static int ad7291_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct ad7291_chip_info *chip = iio_priv(indio_dev); + /* + * To be enabled the channel must simply be on. If any are enabled + * we are in continuous sampling mode + */ + + switch (chan->type) { + case IIO_VOLTAGE: + return !!(chip->c_mask & BIT(15 - chan->channel)); + case IIO_TEMP: + /* always on */ + return 1; + default: + return -EINVAL; + } + +} + +static int ad7291_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int state) +{ + int ret = 0; + struct ad7291_chip_info *chip = iio_priv(indio_dev); + unsigned int mask; + u16 regval; + + mutex_lock(&chip->state_lock); + regval = chip->command; + /* + * To be enabled the channel must simply be on. If any are enabled + * use continuous sampling mode. + * Possible to disable temp as well but that makes single read tricky. + */ + + mask = BIT(15 - chan->channel); + + switch (chan->type) { + case IIO_VOLTAGE: + if ((!state) && (chip->c_mask & mask)) + chip->c_mask &= ~mask; + else if (state && (!(chip->c_mask & mask))) + chip->c_mask |= mask; + else + break; + + regval &= ~AD7291_AUTOCYCLE; + regval |= chip->c_mask; + if (chip->c_mask) /* Enable autocycle? */ + regval |= AD7291_AUTOCYCLE; + + ret = ad7291_i2c_write(chip, AD7291_COMMAND, regval); + if (ret < 0) + goto error_ret; + + chip->command = regval; + break; + default: + ret = -EINVAL; + } + +error_ret: + mutex_unlock(&chip->state_lock); + return ret; +} + +static int ad7291_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + int ret; + struct ad7291_chip_info *chip = iio_priv(indio_dev); + u16 regval; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_VOLTAGE: + mutex_lock(&chip->state_lock); + /* If in autocycle mode drop through */ + if (chip->command & AD7291_AUTOCYCLE) { + mutex_unlock(&chip->state_lock); + return -EBUSY; + } + /* Enable this channel alone */ + regval = chip->command & (~AD7291_VOLTAGE_MASK); + regval |= BIT(15 - chan->channel); + ret = ad7291_i2c_write(chip, AD7291_COMMAND, regval); + if (ret < 0) { + mutex_unlock(&chip->state_lock); + return ret; + } + /* Read voltage */ + ret = i2c_smbus_read_word_swapped(chip->client, + AD7291_VOLTAGE); + if (ret < 0) { + mutex_unlock(&chip->state_lock); + return ret; + } + *val = ret & AD7291_VALUE_MASK; + mutex_unlock(&chip->state_lock); + return IIO_VAL_INT; + case IIO_TEMP: + /* Assumes tsense bit of command register always set */ + ret = i2c_smbus_read_word_swapped(chip->client, + AD7291_T_SENSE); + if (ret < 0) + return ret; + *val = sign_extend32(ret, 11); + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_AVERAGE_RAW: + ret = i2c_smbus_read_word_swapped(chip->client, + AD7291_T_AVERAGE); + if (ret < 0) + return ret; + *val = sign_extend32(ret, 11); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_VOLTAGE: + if (chip->reg) { + int vref; + + vref = regulator_get_voltage(chip->reg); + if (vref < 0) + return vref; + *val = vref / 1000; + } else { + *val = 2500; + } + *val2 = AD7291_BITS; + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_TEMP: + /* + * One LSB of the ADC corresponds to 0.25 deg C. + * The temperature reading is in 12-bit twos + * complement format + */ + *val = 250; + return IIO_VAL_INT; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static const struct iio_event_spec ad7291_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_separate = BIT(IIO_EV_INFO_HYSTERESIS), + }, +}; + +#define AD7291_VOLTAGE_CHAN(_chan) \ +{ \ + .type = IIO_VOLTAGE, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .indexed = 1, \ + .channel = _chan, \ + .event_spec = ad7291_events, \ + .num_event_specs = ARRAY_SIZE(ad7291_events), \ +} + +static const struct iio_chan_spec ad7291_channels[] = { + AD7291_VOLTAGE_CHAN(0), + AD7291_VOLTAGE_CHAN(1), + AD7291_VOLTAGE_CHAN(2), + AD7291_VOLTAGE_CHAN(3), + AD7291_VOLTAGE_CHAN(4), + AD7291_VOLTAGE_CHAN(5), + AD7291_VOLTAGE_CHAN(6), + AD7291_VOLTAGE_CHAN(7), + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_AVERAGE_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .indexed = 1, + .channel = 0, + .event_spec = ad7291_events, + .num_event_specs = ARRAY_SIZE(ad7291_events), + } +}; + +static const struct iio_info ad7291_info = { + .read_raw = &ad7291_read_raw, + .read_event_config = &ad7291_read_event_config, + .write_event_config = &ad7291_write_event_config, + .read_event_value = &ad7291_read_event_value, + .write_event_value = &ad7291_write_event_value, + .driver_module = THIS_MODULE, +}; + +static int ad7291_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ad7291_platform_data *pdata = client->dev.platform_data; + struct ad7291_chip_info *chip; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip)); + if (!indio_dev) + return -ENOMEM; + chip = iio_priv(indio_dev); + + if (pdata && pdata->use_external_ref) { + chip->reg = devm_regulator_get(&client->dev, "vref"); + if (IS_ERR(chip->reg)) + return PTR_ERR(chip->reg); + + ret = regulator_enable(chip->reg); + if (ret) + return ret; + } + + mutex_init(&chip->state_lock); + /* this is only used for device removal purposes */ + i2c_set_clientdata(client, indio_dev); + + chip->client = client; + + chip->command = AD7291_NOISE_DELAY | + AD7291_T_SENSE_MASK | /* Tsense always enabled */ + AD7291_ALERT_POLARITY; /* set irq polarity low level */ + + if (pdata && pdata->use_external_ref) + chip->command |= AD7291_EXT_REF; + + indio_dev->name = id->name; + indio_dev->channels = ad7291_channels; + indio_dev->num_channels = ARRAY_SIZE(ad7291_channels); + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &ad7291_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = ad7291_i2c_write(chip, AD7291_COMMAND, AD7291_RESET); + if (ret) { + ret = -EIO; + goto error_disable_reg; + } + + ret = ad7291_i2c_write(chip, AD7291_COMMAND, chip->command); + if (ret) { + ret = -EIO; + goto error_disable_reg; + } + + if (client->irq > 0) { + ret = request_threaded_irq(client->irq, + NULL, + &ad7291_event_handler, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + id->name, + indio_dev); + if (ret) + goto error_disable_reg; + } + + ret = iio_device_register(indio_dev); + if (ret) + goto error_unreg_irq; + + return 0; + +error_unreg_irq: + if (client->irq) + free_irq(client->irq, indio_dev); +error_disable_reg: + if (chip->reg) + regulator_disable(chip->reg); + + return ret; +} + +static int ad7291_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct ad7291_chip_info *chip = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + if (client->irq) + free_irq(client->irq, indio_dev); + + if (chip->reg) + regulator_disable(chip->reg); + + return 0; +} + +static const struct i2c_device_id ad7291_id[] = { + { "ad7291", 0 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ad7291_id); + +static struct i2c_driver ad7291_driver = { + .driver = { + .name = KBUILD_MODNAME, + }, + .probe = ad7291_probe, + .remove = ad7291_remove, + .id_table = ad7291_id, +}; +module_i2c_driver(ad7291_driver); + +MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>"); +MODULE_DESCRIPTION("Analog Devices AD7291 ADC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c index 2a3b65c74af9..4a8c0a2f49b6 100644 --- a/drivers/iio/adc/ad7298.c +++ b/drivers/iio/adc/ad7298.c @@ -16,6 +16,7 @@ #include <linux/delay.h> #include <linux/module.h> #include <linux/interrupt.h> +#include <linux/bitops.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -25,23 +26,19 @@ #include <linux/platform_data/ad7298.h> -#define AD7298_WRITE (1 << 15) /* write to the control register */ -#define AD7298_REPEAT (1 << 14) /* repeated conversion enable */ -#define AD7298_CH(x) (1 << (13 - (x))) /* channel select */ -#define AD7298_TSENSE (1 << 5) /* temperature conversion enable */ -#define AD7298_EXTREF (1 << 2) /* external reference enable */ -#define AD7298_TAVG (1 << 1) /* temperature sensor averaging enable */ -#define AD7298_PDD (1 << 0) /* partial power down enable */ +#define AD7298_WRITE BIT(15) /* write to the control register */ +#define AD7298_REPEAT BIT(14) /* repeated conversion enable */ +#define AD7298_CH(x) BIT(13 - (x)) /* channel select */ +#define AD7298_TSENSE BIT(5) /* temperature conversion enable */ +#define AD7298_EXTREF BIT(2) /* external reference enable */ +#define AD7298_TAVG BIT(1) /* temperature sensor averaging enable */ +#define AD7298_PDD BIT(0) /* partial power down enable */ #define AD7298_MAX_CHAN 8 -#define AD7298_BITS 12 -#define AD7298_STORAGE_BITS 16 #define AD7298_INTREF_mV 2500 #define AD7298_CH_TEMP 9 -#define RES_MASK(bits) ((1 << (bits)) - 1) - struct ad7298_state { struct spi_device *spi; struct regulator *reg; @@ -257,7 +254,7 @@ static int ad7298_read_raw(struct iio_dev *indio_dev, return ret; if (chan->address != AD7298_CH_TEMP) - *val = ret & RES_MASK(AD7298_BITS); + *val = ret & GENMASK(chan->scan_type.realbits - 1, 0); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index d141d452c3d1..ce400ec176f1 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -14,6 +14,7 @@ #include <linux/regulator/consumer.h> #include <linux/err.h> #include <linux/module.h> +#include <linux/bitops.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -21,8 +22,6 @@ #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> -#define RES_MASK(bits) ((1 << (bits)) - 1) - struct ad7476_state; struct ad7476_chip_info { @@ -117,7 +116,7 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; *val = (ret >> st->chip_info->channel[0].scan_type.shift) & - RES_MASK(st->chip_info->channel[0].scan_type.realbits); + GENMASK(st->chip_info->channel[0].scan_type.realbits - 1, 0); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: if (!st->chip_info->int_vref_uv) { diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c index 749a6cadab8b..2fd012ee99f5 100644 --- a/drivers/iio/adc/ad7887.c +++ b/drivers/iio/adc/ad7887.c @@ -15,6 +15,7 @@ #include <linux/err.h> #include <linux/module.h> #include <linux/interrupt.h> +#include <linux/bitops.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -25,14 +26,14 @@ #include <linux/platform_data/ad7887.h> -#define AD7887_REF_DIS (1 << 5) /* on-chip reference disable */ -#define AD7887_DUAL (1 << 4) /* dual-channel mode */ -#define AD7887_CH_AIN1 (1 << 3) /* convert on channel 1, DUAL=1 */ -#define AD7887_CH_AIN0 (0 << 3) /* convert on channel 0, DUAL=0,1 */ -#define AD7887_PM_MODE1 (0) /* CS based shutdown */ -#define AD7887_PM_MODE2 (1) /* full on */ -#define AD7887_PM_MODE3 (2) /* auto shutdown after conversion */ -#define AD7887_PM_MODE4 (3) /* standby mode */ +#define AD7887_REF_DIS BIT(5) /* on-chip reference disable */ +#define AD7887_DUAL BIT(4) /* dual-channel mode */ +#define AD7887_CH_AIN1 BIT(3) /* convert on channel 1, DUAL=1 */ +#define AD7887_CH_AIN0 0 /* convert on channel 0, DUAL=0,1 */ +#define AD7887_PM_MODE1 0 /* CS based shutdown */ +#define AD7887_PM_MODE2 1 /* full on */ +#define AD7887_PM_MODE3 2 /* auto shutdown after conversion */ +#define AD7887_PM_MODE4 3 /* standby mode */ enum ad7887_channels { AD7887_CH0, @@ -40,8 +41,6 @@ enum ad7887_channels { AD7887_CH1, }; -#define RES_MASK(bits) ((1 << (bits)) - 1) - /** * struct ad7887_chip_info - chip specifc information * @int_vref_mv: the internal reference voltage @@ -167,7 +166,7 @@ static int ad7887_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; *val = ret >> chan->scan_type.shift; - *val &= RES_MASK(chan->scan_type.realbits); + *val &= GENMASK(chan->scan_type.realbits - 1, 0); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: if (st->reg) { diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index 6eba301ee03d..e37412da15f5 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -32,6 +32,7 @@ #include <linux/types.h> #include <linux/err.h> #include <linux/module.h> +#include <linux/bitops.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -41,7 +42,7 @@ #include <linux/iio/triggered_buffer.h> #define AD799X_CHANNEL_SHIFT 4 -#define AD799X_STORAGEBITS 16 + /* * AD7991, AD7995 and AD7999 defines */ @@ -55,10 +56,10 @@ * AD7992, AD7993, AD7994, AD7997 and AD7998 defines */ -#define AD7998_FLTR 0x08 -#define AD7998_ALERT_EN 0x04 -#define AD7998_BUSY_ALERT 0x02 -#define AD7998_BUSY_ALERT_POL 0x01 +#define AD7998_FLTR BIT(3) +#define AD7998_ALERT_EN BIT(2) +#define AD7998_BUSY_ALERT BIT(1) +#define AD7998_BUSY_ALERT_POL BIT(0) #define AD7998_CONV_RES_REG 0x0 #define AD7998_ALERT_STAT_REG 0x1 @@ -69,7 +70,7 @@ #define AD7998_DATAHIGH_REG(x) ((x) * 3 + 0x5) #define AD7998_HYST_REG(x) ((x) * 3 + 0x6) -#define AD7998_CYC_MASK 0x7 +#define AD7998_CYC_MASK GENMASK(2, 0) #define AD7998_CYC_DIS 0x0 #define AD7998_CYC_TCONF_32 0x1 #define AD7998_CYC_TCONF_64 0x2 @@ -85,10 +86,8 @@ * AD7997 and AD7997 defines */ -#define AD7997_8_READ_SINGLE 0x80 -#define AD7997_8_READ_SEQUENCE 0x70 -/* TODO: move this into a common header */ -#define RES_MASK(bits) ((1 << (bits)) - 1) +#define AD7997_8_READ_SINGLE BIT(7) +#define AD7997_8_READ_SEQUENCE (BIT(6) | BIT(5) | BIT(4)) enum { ad7991, @@ -102,23 +101,32 @@ enum { }; /** - * struct ad799x_chip_info - chip specific information + * struct ad799x_chip_config - chip specific information * @channel: channel specification - * @num_channels: number of channels - * @monitor_mode: whether the chip supports monitor interrupts * @default_config: device default configuration - * @event_attrs: pointer to the monitor event attribute group + * @info: pointer to iio_info struct */ -struct ad799x_chip_info { - struct iio_chan_spec channel[9]; - int num_channels; +struct ad799x_chip_config { + const struct iio_chan_spec channel[9]; u16 default_config; const struct iio_info *info; }; +/** + * struct ad799x_chip_info - chip specific information + * @num_channels: number of channels + * @noirq_config: device configuration w/o IRQ + * @irq_config: device configuration w/IRQ + */ +struct ad799x_chip_info { + int num_channels; + const struct ad799x_chip_config noirq_config; + const struct ad799x_chip_config irq_config; +}; + struct ad799x_state { struct i2c_client *client; - const struct ad799x_chip_info *chip_info; + const struct ad799x_chip_config *chip_config; struct regulator *reg; struct regulator *vref; unsigned id; @@ -128,6 +136,30 @@ struct ad799x_state { unsigned int transfer_size; }; +static int ad799x_write_config(struct ad799x_state *st, u16 val) +{ + switch (st->id) { + case ad7997: + case ad7998: + return i2c_smbus_write_word_swapped(st->client, AD7998_CONF_REG, + val); + default: + return i2c_smbus_write_byte_data(st->client, AD7998_CONF_REG, + val); + } +} + +static int ad799x_read_config(struct ad799x_state *st) +{ + switch (st->id) { + case ad7997: + case ad7998: + return i2c_smbus_read_word_swapped(st->client, AD7998_CONF_REG); + default: + return i2c_smbus_read_byte_data(st->client, AD7998_CONF_REG); + } +} + /** * ad799x_trigger_handler() bh of trigger launched polling to ring buffer * @@ -176,66 +208,7 @@ out: return IRQ_HANDLED; } -/* - * ad799x register access by I2C - */ -static int ad799x_i2c_read16(struct ad799x_state *st, u8 reg, u16 *data) -{ - struct i2c_client *client = st->client; - int ret = 0; - - ret = i2c_smbus_read_word_swapped(client, reg); - if (ret < 0) { - dev_err(&client->dev, "I2C read error\n"); - return ret; - } - - *data = (u16)ret; - - return 0; -} - -static int ad799x_i2c_read8(struct ad799x_state *st, u8 reg, u8 *data) -{ - struct i2c_client *client = st->client; - int ret = 0; - - ret = i2c_smbus_read_byte_data(client, reg); - if (ret < 0) { - dev_err(&client->dev, "I2C read error\n"); - return ret; - } - - *data = (u8)ret; - - return 0; -} - -static int ad799x_i2c_write16(struct ad799x_state *st, u8 reg, u16 data) -{ - struct i2c_client *client = st->client; - int ret = 0; - - ret = i2c_smbus_write_word_swapped(client, reg, data); - if (ret < 0) - dev_err(&client->dev, "I2C write error\n"); - - return ret; -} - -static int ad799x_i2c_write8(struct ad799x_state *st, u8 reg, u8 data) -{ - struct i2c_client *client = st->client; - int ret = 0; - - ret = i2c_smbus_write_byte_data(client, reg, data); - if (ret < 0) - dev_err(&client->dev, "I2C write error\n"); - - return ret; -} - -static int ad7997_8_update_scan_mode(struct iio_dev *indio_dev, +static int ad799x_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask) { struct ad799x_state *st = iio_priv(indio_dev); @@ -248,33 +221,33 @@ static int ad7997_8_update_scan_mode(struct iio_dev *indio_dev, st->transfer_size = bitmap_weight(scan_mask, indio_dev->masklength) * 2; switch (st->id) { + case ad7992: + case ad7993: + case ad7994: case ad7997: case ad7998: - return ad799x_i2c_write16(st, AD7998_CONF_REG, - st->config | (*scan_mask << AD799X_CHANNEL_SHIFT)); + st->config &= ~(GENMASK(7, 0) << AD799X_CHANNEL_SHIFT); + st->config |= (*scan_mask << AD799X_CHANNEL_SHIFT); + return ad799x_write_config(st, st->config); default: - break; + return 0; } - - return 0; } static int ad799x_scan_direct(struct ad799x_state *st, unsigned ch) { - u16 rxbuf; u8 cmd; - int ret; switch (st->id) { case ad7991: case ad7995: case ad7999: - cmd = st->config | ((1 << ch) << AD799X_CHANNEL_SHIFT); + cmd = st->config | (BIT(ch) << AD799X_CHANNEL_SHIFT); break; case ad7992: case ad7993: case ad7994: - cmd = (1 << ch) << AD799X_CHANNEL_SHIFT; + cmd = BIT(ch) << AD799X_CHANNEL_SHIFT; break; case ad7997: case ad7998: @@ -284,11 +257,7 @@ static int ad799x_scan_direct(struct ad799x_state *st, unsigned ch) return -EINVAL; } - ret = ad799x_i2c_read16(st, cmd, &rxbuf); - if (ret < 0) - return ret; - - return rxbuf; + return i2c_smbus_read_word_swapped(st->client, cmd); } static int ad799x_read_raw(struct iio_dev *indio_dev, @@ -312,7 +281,7 @@ static int ad799x_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; *val = (ret >> chan->scan_type.shift) & - RES_MASK(chan->scan_type.realbits); + GENMASK(chan->scan_type.realbits - 1, 0); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: ret = regulator_get_voltage(st->vref); @@ -333,6 +302,7 @@ static const unsigned int ad7998_frequencies[] = { [AD7998_CYC_TCONF_1024] = 488, [AD7998_CYC_TCONF_2048] = 244, }; + static ssize_t ad799x_read_frequency(struct device *dev, struct device_attribute *attr, char *buf) @@ -340,15 +310,11 @@ static ssize_t ad799x_read_frequency(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad799x_state *st = iio_priv(indio_dev); - int ret; - u8 val; - ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &val); - if (ret) + int ret = i2c_smbus_read_byte_data(st->client, AD7998_CYCLE_TMR_REG); + if (ret < 0) return ret; - val &= AD7998_CYC_MASK; - - return sprintf(buf, "%u\n", ad7998_frequencies[val]); + return sprintf(buf, "%u\n", ad7998_frequencies[ret & AD7998_CYC_MASK]); } static ssize_t ad799x_write_frequency(struct device *dev, @@ -361,18 +327,17 @@ static ssize_t ad799x_write_frequency(struct device *dev, long val; int ret, i; - u8 t; ret = kstrtol(buf, 10, &val); if (ret) return ret; mutex_lock(&indio_dev->mlock); - ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &t); - if (ret) + ret = i2c_smbus_read_byte_data(st->client, AD7998_CYCLE_TMR_REG); + if (ret < 0) goto error_ret_mutex; /* Wipe the bits clean */ - t &= ~AD7998_CYC_MASK; + ret &= ~AD7998_CYC_MASK; for (i = 0; i < ARRAY_SIZE(ad7998_frequencies); i++) if (val == ad7998_frequencies[i]) @@ -381,13 +346,17 @@ static ssize_t ad799x_write_frequency(struct device *dev, ret = -EINVAL; goto error_ret_mutex; } - t |= i; - ret = ad799x_i2c_write8(st, AD7998_CYCLE_TMR_REG, t); + + ret = i2c_smbus_write_byte_data(st->client, AD7998_CYCLE_TMR_REG, + ret | i); + if (ret < 0) + goto error_ret_mutex; + ret = len; error_ret_mutex: mutex_unlock(&indio_dev->mlock); - return ret ? ret : len; + return ret; } static int ad799x_read_event_config(struct iio_dev *indio_dev, @@ -395,7 +364,48 @@ static int ad799x_read_event_config(struct iio_dev *indio_dev, enum iio_event_type type, enum iio_event_direction dir) { - return 1; + struct ad799x_state *st = iio_priv(indio_dev); + + if (!(st->config & AD7998_ALERT_EN)) + return 0; + + if ((st->config >> AD799X_CHANNEL_SHIFT) & BIT(chan->scan_index)) + return 1; + + return 0; +} + +static int ad799x_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int state) +{ + struct ad799x_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&indio_dev->mlock); + if (iio_buffer_enabled(indio_dev)) { + ret = -EBUSY; + goto done; + } + + if (state) + st->config |= BIT(chan->scan_index) << AD799X_CHANNEL_SHIFT; + else + st->config &= ~(BIT(chan->scan_index) << AD799X_CHANNEL_SHIFT); + + if (st->config >> AD799X_CHANNEL_SHIFT) + st->config |= AD7998_ALERT_EN; + else + st->config &= ~AD7998_ALERT_EN; + + ret = ad799x_write_config(st, st->config); + +done: + mutex_unlock(&indio_dev->mlock); + + return ret; } static unsigned int ad799x_threshold_reg(const struct iio_chan_spec *chan, @@ -427,11 +437,12 @@ static int ad799x_write_event_value(struct iio_dev *indio_dev, int ret; struct ad799x_state *st = iio_priv(indio_dev); - if (val < 0 || val > RES_MASK(chan->scan_type.realbits)) + if (val < 0 || val > GENMASK(chan->scan_type.realbits - 1, 0)) return -EINVAL; mutex_lock(&indio_dev->mlock); - ret = ad799x_i2c_write16(st, ad799x_threshold_reg(chan, dir, info), + ret = i2c_smbus_write_word_swapped(st->client, + ad799x_threshold_reg(chan, dir, info), val << chan->scan_type.shift); mutex_unlock(&indio_dev->mlock); @@ -447,16 +458,15 @@ static int ad799x_read_event_value(struct iio_dev *indio_dev, { int ret; struct ad799x_state *st = iio_priv(indio_dev); - u16 valin; mutex_lock(&indio_dev->mlock); - ret = ad799x_i2c_read16(st, ad799x_threshold_reg(chan, dir, info), - &valin); + ret = i2c_smbus_read_word_swapped(st->client, + ad799x_threshold_reg(chan, dir, info)); mutex_unlock(&indio_dev->mlock); if (ret < 0) return ret; - *val = (valin >> chan->scan_type.shift) & - RES_MASK(chan->scan_type.realbits); + *val = (ret >> chan->scan_type.shift) & + GENMASK(chan->scan_type.realbits - 1 , 0); return IIO_VAL_INT; } @@ -465,20 +475,18 @@ static irqreturn_t ad799x_event_handler(int irq, void *private) { struct iio_dev *indio_dev = private; struct ad799x_state *st = iio_priv(private); - u8 status; int i, ret; - ret = ad799x_i2c_read8(st, AD7998_ALERT_STAT_REG, &status); - if (ret) + ret = i2c_smbus_read_byte_data(st->client, AD7998_ALERT_STAT_REG); + if (ret <= 0) goto done; - if (!status) + if (i2c_smbus_write_byte_data(st->client, AD7998_ALERT_STAT_REG, + AD7998_ALERT_STAT_CLEAR) < 0) goto done; - ad799x_i2c_write8(st, AD7998_ALERT_STAT_REG, AD7998_ALERT_STAT_CLEAR); - for (i = 0; i < 8; i++) { - if (status & (1 << i)) + if (ret & BIT(i)) iio_push_event(indio_dev, i & 0x1 ? IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, @@ -517,14 +525,21 @@ static const struct iio_info ad7991_info = { .driver_module = THIS_MODULE, }; -static const struct iio_info ad7993_4_7_8_info = { +static const struct iio_info ad7993_4_7_8_noirq_info = { + .read_raw = &ad799x_read_raw, + .driver_module = THIS_MODULE, + .update_scan_mode = ad799x_update_scan_mode, +}; + +static const struct iio_info ad7993_4_7_8_irq_info = { .read_raw = &ad799x_read_raw, .event_attrs = &ad799x_event_attrs_group, .read_event_config = &ad799x_read_event_config, + .write_event_config = &ad799x_write_event_config, .read_event_value = &ad799x_read_event_value, .write_event_value = &ad799x_write_event_value, .driver_module = THIS_MODULE, - .update_scan_mode = ad7997_8_update_scan_mode, + .update_scan_mode = ad799x_update_scan_mode, }; static const struct iio_event_spec ad799x_events[] = { @@ -572,103 +587,175 @@ static const struct iio_event_spec ad799x_events[] = { static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { [ad7991] = { - .channel = { - AD799X_CHANNEL(0, 12), - AD799X_CHANNEL(1, 12), - AD799X_CHANNEL(2, 12), - AD799X_CHANNEL(3, 12), - IIO_CHAN_SOFT_TIMESTAMP(4), - }, .num_channels = 5, - .info = &ad7991_info, + .noirq_config = { + .channel = { + AD799X_CHANNEL(0, 12), + AD799X_CHANNEL(1, 12), + AD799X_CHANNEL(2, 12), + AD799X_CHANNEL(3, 12), + IIO_CHAN_SOFT_TIMESTAMP(4), + }, + .info = &ad7991_info, + }, }, [ad7995] = { - .channel = { - AD799X_CHANNEL(0, 10), - AD799X_CHANNEL(1, 10), - AD799X_CHANNEL(2, 10), - AD799X_CHANNEL(3, 10), - IIO_CHAN_SOFT_TIMESTAMP(4), - }, .num_channels = 5, - .info = &ad7991_info, + .noirq_config = { + .channel = { + AD799X_CHANNEL(0, 10), + AD799X_CHANNEL(1, 10), + AD799X_CHANNEL(2, 10), + AD799X_CHANNEL(3, 10), + IIO_CHAN_SOFT_TIMESTAMP(4), + }, + .info = &ad7991_info, + }, }, [ad7999] = { - .channel = { - AD799X_CHANNEL(0, 8), - AD799X_CHANNEL(1, 8), - AD799X_CHANNEL(2, 8), - AD799X_CHANNEL(3, 8), - IIO_CHAN_SOFT_TIMESTAMP(4), - }, .num_channels = 5, - .info = &ad7991_info, + .noirq_config = { + .channel = { + AD799X_CHANNEL(0, 8), + AD799X_CHANNEL(1, 8), + AD799X_CHANNEL(2, 8), + AD799X_CHANNEL(3, 8), + IIO_CHAN_SOFT_TIMESTAMP(4), + }, + .info = &ad7991_info, + }, }, [ad7992] = { - .channel = { - AD799X_CHANNEL_WITH_EVENTS(0, 12), - AD799X_CHANNEL_WITH_EVENTS(1, 12), - IIO_CHAN_SOFT_TIMESTAMP(3), - }, .num_channels = 3, - .default_config = AD7998_ALERT_EN, - .info = &ad7993_4_7_8_info, + .noirq_config = { + .channel = { + AD799X_CHANNEL(0, 12), + AD799X_CHANNEL(1, 12), + IIO_CHAN_SOFT_TIMESTAMP(3), + }, + .info = &ad7993_4_7_8_noirq_info, + }, + .irq_config = { + .channel = { + AD799X_CHANNEL_WITH_EVENTS(0, 12), + AD799X_CHANNEL_WITH_EVENTS(1, 12), + IIO_CHAN_SOFT_TIMESTAMP(3), + }, + .default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT, + .info = &ad7993_4_7_8_irq_info, + }, }, [ad7993] = { - .channel = { - AD799X_CHANNEL_WITH_EVENTS(0, 10), - AD799X_CHANNEL_WITH_EVENTS(1, 10), - AD799X_CHANNEL_WITH_EVENTS(2, 10), - AD799X_CHANNEL_WITH_EVENTS(3, 10), - IIO_CHAN_SOFT_TIMESTAMP(4), - }, .num_channels = 5, - .default_config = AD7998_ALERT_EN, - .info = &ad7993_4_7_8_info, + .noirq_config = { + .channel = { + AD799X_CHANNEL(0, 10), + AD799X_CHANNEL(1, 10), + AD799X_CHANNEL(2, 10), + AD799X_CHANNEL(3, 10), + IIO_CHAN_SOFT_TIMESTAMP(4), + }, + .info = &ad7993_4_7_8_noirq_info, + }, + .irq_config = { + .channel = { + AD799X_CHANNEL_WITH_EVENTS(0, 10), + AD799X_CHANNEL_WITH_EVENTS(1, 10), + AD799X_CHANNEL_WITH_EVENTS(2, 10), + AD799X_CHANNEL_WITH_EVENTS(3, 10), + IIO_CHAN_SOFT_TIMESTAMP(4), + }, + .default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT, + .info = &ad7993_4_7_8_irq_info, + }, }, [ad7994] = { - .channel = { - AD799X_CHANNEL_WITH_EVENTS(0, 12), - AD799X_CHANNEL_WITH_EVENTS(1, 12), - AD799X_CHANNEL_WITH_EVENTS(2, 12), - AD799X_CHANNEL_WITH_EVENTS(3, 12), - IIO_CHAN_SOFT_TIMESTAMP(4), - }, .num_channels = 5, - .default_config = AD7998_ALERT_EN, - .info = &ad7993_4_7_8_info, + .noirq_config = { + .channel = { + AD799X_CHANNEL(0, 12), + AD799X_CHANNEL(1, 12), + AD799X_CHANNEL(2, 12), + AD799X_CHANNEL(3, 12), + IIO_CHAN_SOFT_TIMESTAMP(4), + }, + .info = &ad7993_4_7_8_noirq_info, + }, + .irq_config = { + .channel = { + AD799X_CHANNEL_WITH_EVENTS(0, 12), + AD799X_CHANNEL_WITH_EVENTS(1, 12), + AD799X_CHANNEL_WITH_EVENTS(2, 12), + AD799X_CHANNEL_WITH_EVENTS(3, 12), + IIO_CHAN_SOFT_TIMESTAMP(4), + }, + .default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT, + .info = &ad7993_4_7_8_irq_info, + }, }, [ad7997] = { - .channel = { - AD799X_CHANNEL_WITH_EVENTS(0, 10), - AD799X_CHANNEL_WITH_EVENTS(1, 10), - AD799X_CHANNEL_WITH_EVENTS(2, 10), - AD799X_CHANNEL_WITH_EVENTS(3, 10), - AD799X_CHANNEL(4, 10), - AD799X_CHANNEL(5, 10), - AD799X_CHANNEL(6, 10), - AD799X_CHANNEL(7, 10), - IIO_CHAN_SOFT_TIMESTAMP(8), - }, .num_channels = 9, - .default_config = AD7998_ALERT_EN, - .info = &ad7993_4_7_8_info, + .noirq_config = { + .channel = { + AD799X_CHANNEL(0, 10), + AD799X_CHANNEL(1, 10), + AD799X_CHANNEL(2, 10), + AD799X_CHANNEL(3, 10), + AD799X_CHANNEL(4, 10), + AD799X_CHANNEL(5, 10), + AD799X_CHANNEL(6, 10), + AD799X_CHANNEL(7, 10), + IIO_CHAN_SOFT_TIMESTAMP(8), + }, + .info = &ad7993_4_7_8_noirq_info, + }, + .irq_config = { + .channel = { + AD799X_CHANNEL_WITH_EVENTS(0, 10), + AD799X_CHANNEL_WITH_EVENTS(1, 10), + AD799X_CHANNEL_WITH_EVENTS(2, 10), + AD799X_CHANNEL_WITH_EVENTS(3, 10), + AD799X_CHANNEL(4, 10), + AD799X_CHANNEL(5, 10), + AD799X_CHANNEL(6, 10), + AD799X_CHANNEL(7, 10), + IIO_CHAN_SOFT_TIMESTAMP(8), + }, + .default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT, + .info = &ad7993_4_7_8_irq_info, + }, }, [ad7998] = { - .channel = { - AD799X_CHANNEL_WITH_EVENTS(0, 12), - AD799X_CHANNEL_WITH_EVENTS(1, 12), - AD799X_CHANNEL_WITH_EVENTS(2, 12), - AD799X_CHANNEL_WITH_EVENTS(3, 12), - AD799X_CHANNEL(4, 12), - AD799X_CHANNEL(5, 12), - AD799X_CHANNEL(6, 12), - AD799X_CHANNEL(7, 12), - IIO_CHAN_SOFT_TIMESTAMP(8), - }, .num_channels = 9, - .default_config = AD7998_ALERT_EN, - .info = &ad7993_4_7_8_info, + .noirq_config = { + .channel = { + AD799X_CHANNEL(0, 12), + AD799X_CHANNEL(1, 12), + AD799X_CHANNEL(2, 12), + AD799X_CHANNEL(3, 12), + AD799X_CHANNEL(4, 12), + AD799X_CHANNEL(5, 12), + AD799X_CHANNEL(6, 12), + AD799X_CHANNEL(7, 12), + IIO_CHAN_SOFT_TIMESTAMP(8), + }, + .info = &ad7993_4_7_8_noirq_info, + }, + .irq_config = { + .channel = { + AD799X_CHANNEL_WITH_EVENTS(0, 12), + AD799X_CHANNEL_WITH_EVENTS(1, 12), + AD799X_CHANNEL_WITH_EVENTS(2, 12), + AD799X_CHANNEL_WITH_EVENTS(3, 12), + AD799X_CHANNEL(4, 12), + AD799X_CHANNEL(5, 12), + AD799X_CHANNEL(6, 12), + AD799X_CHANNEL(7, 12), + IIO_CHAN_SOFT_TIMESTAMP(8), + }, + .default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT, + .info = &ad7993_4_7_8_irq_info, + }, }, }; @@ -678,6 +765,8 @@ static int ad799x_probe(struct i2c_client *client, int ret; struct ad799x_state *st; struct iio_dev *indio_dev; + const struct ad799x_chip_info *chip_info = + &ad799x_chip_info_tbl[id->driver_data]; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); if (indio_dev == NULL) @@ -688,8 +777,10 @@ static int ad799x_probe(struct i2c_client *client, i2c_set_clientdata(client, indio_dev); st->id = id->driver_data; - st->chip_info = &ad799x_chip_info_tbl[st->id]; - st->config = st->chip_info->default_config; + if (client->irq > 0 && chip_info->irq_config.info) + st->chip_config = &chip_info->irq_config; + else + st->chip_config = &chip_info->noirq_config; /* TODO: Add pdata options for filtering and bit delay */ @@ -712,11 +803,19 @@ static int ad799x_probe(struct i2c_client *client, indio_dev->dev.parent = &client->dev; indio_dev->name = id->name; - indio_dev->info = st->chip_info->info; + indio_dev->info = st->chip_config->info; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = st->chip_info->channel; - indio_dev->num_channels = st->chip_info->num_channels; + indio_dev->channels = st->chip_config->channel; + indio_dev->num_channels = chip_info->num_channels; + + ret = ad799x_write_config(st, st->chip_config->default_config); + if (ret < 0) + goto error_disable_reg; + ret = ad799x_read_config(st); + if (ret < 0) + goto error_disable_reg; + st->config = ret; ret = iio_triggered_buffer_setup(indio_dev, NULL, &ad799x_trigger_handler, NULL); diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index 9a4e0e32a771..c55b81f7f970 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -410,7 +410,7 @@ static irqreturn_t ad_sd_data_rdy_trig_poll(int irq, void *private) complete(&sigma_delta->completion); disable_irq_nosync(irq); sigma_delta->irq_dis = true; - iio_trigger_poll(sigma_delta->trig, iio_get_time_ns()); + iio_trigger_poll(sigma_delta->trig); return IRQ_HANDLED; } diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 2b6a9ce9927c..772e869c280e 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -272,7 +272,7 @@ void handle_adc_eoc_trigger(int irq, struct iio_dev *idev) if (iio_buffer_enabled(idev)) { disable_irq_nosync(irq); - iio_trigger_poll(idev->trig, iio_get_time_ns()); + iio_trigger_poll(idev->trig); } else { st->last_value = at91_adc_readl(st, AT91_ADC_LCDR); st->done = true; diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index 010578f1d762..fc9dfc23ecb7 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -24,6 +24,7 @@ #include <linux/platform_device.h> #include <linux/interrupt.h> #include <linux/delay.h> +#include <linux/errno.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/io.h> @@ -39,11 +40,6 @@ #include <linux/iio/machine.h> #include <linux/iio/driver.h> -enum adc_version { - ADC_V1, - ADC_V2 -}; - /* EXYNOS4412/5250 ADC_V1 registers definitions */ #define ADC_V1_CON(x) ((x) + 0x00) #define ADC_V1_DLY(x) ((x) + 0x08) @@ -75,8 +71,9 @@ enum adc_version { #define ADC_V2_CON2_ACH_SEL(x) (((x) & 0xF) << 0) #define ADC_V2_CON2_ACH_MASK 0xF -#define MAX_ADC_V2_CHANNELS 10 -#define MAX_ADC_V1_CHANNELS 8 +#define MAX_ADC_V2_CHANNELS 10 +#define MAX_ADC_V1_CHANNELS 8 +#define MAX_EXYNOS3250_ADC_CHANNELS 2 /* Bit definitions common for ADC_V1 and ADC_V2 */ #define ADC_CON_EN_START (1u << 0) @@ -85,9 +82,12 @@ enum adc_version { #define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100)) struct exynos_adc { + struct exynos_adc_data *data; + struct device *dev; void __iomem *regs; void __iomem *enable_reg; struct clk *clk; + struct clk *sclk; unsigned int irq; struct regulator *vdd; @@ -97,43 +97,213 @@ struct exynos_adc { unsigned int version; }; -static const struct of_device_id exynos_adc_match[] = { - { .compatible = "samsung,exynos-adc-v1", .data = (void *)ADC_V1 }, - { .compatible = "samsung,exynos-adc-v2", .data = (void *)ADC_V2 }, - {}, +struct exynos_adc_data { + int num_channels; + bool needs_sclk; + + void (*init_hw)(struct exynos_adc *info); + void (*exit_hw)(struct exynos_adc *info); + void (*clear_irq)(struct exynos_adc *info); + void (*start_conv)(struct exynos_adc *info, unsigned long addr); }; -MODULE_DEVICE_TABLE(of, exynos_adc_match); -static inline unsigned int exynos_adc_get_version(struct platform_device *pdev) +static void exynos_adc_unprepare_clk(struct exynos_adc *info) { - const struct of_device_id *match; + if (info->data->needs_sclk) + clk_unprepare(info->sclk); + clk_unprepare(info->clk); +} - match = of_match_node(exynos_adc_match, pdev->dev.of_node); - return (unsigned int)match->data; +static int exynos_adc_prepare_clk(struct exynos_adc *info) +{ + int ret; + + ret = clk_prepare(info->clk); + if (ret) { + dev_err(info->dev, "failed preparing adc clock: %d\n", ret); + return ret; + } + + if (info->data->needs_sclk) { + ret = clk_prepare(info->sclk); + if (ret) { + clk_unprepare(info->clk); + dev_err(info->dev, + "failed preparing sclk_adc clock: %d\n", ret); + return ret; + } + } + + return 0; +} + +static void exynos_adc_disable_clk(struct exynos_adc *info) +{ + if (info->data->needs_sclk) + clk_disable(info->sclk); + clk_disable(info->clk); +} + +static int exynos_adc_enable_clk(struct exynos_adc *info) +{ + int ret; + + ret = clk_enable(info->clk); + if (ret) { + dev_err(info->dev, "failed enabling adc clock: %d\n", ret); + return ret; + } + + if (info->data->needs_sclk) { + ret = clk_enable(info->sclk); + if (ret) { + clk_disable(info->clk); + dev_err(info->dev, + "failed enabling sclk_adc clock: %d\n", ret); + return ret; + } + } + + return 0; +} + +static void exynos_adc_v1_init_hw(struct exynos_adc *info) +{ + u32 con1; + + writel(1, info->enable_reg); + + /* set default prescaler values and Enable prescaler */ + con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN; + + /* Enable 12-bit ADC resolution */ + con1 |= ADC_V1_CON_RES; + writel(con1, ADC_V1_CON(info->regs)); +} + +static void exynos_adc_v1_exit_hw(struct exynos_adc *info) +{ + u32 con; + + writel(0, info->enable_reg); + + con = readl(ADC_V1_CON(info->regs)); + con |= ADC_V1_CON_STANDBY; + writel(con, ADC_V1_CON(info->regs)); +} + +static void exynos_adc_v1_clear_irq(struct exynos_adc *info) +{ + writel(1, ADC_V1_INTCLR(info->regs)); +} + +static void exynos_adc_v1_start_conv(struct exynos_adc *info, + unsigned long addr) +{ + u32 con1; + + writel(addr, ADC_V1_MUX(info->regs)); + + con1 = readl(ADC_V1_CON(info->regs)); + writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs)); +} + +static const struct exynos_adc_data exynos_adc_v1_data = { + .num_channels = MAX_ADC_V1_CHANNELS, + + .init_hw = exynos_adc_v1_init_hw, + .exit_hw = exynos_adc_v1_exit_hw, + .clear_irq = exynos_adc_v1_clear_irq, + .start_conv = exynos_adc_v1_start_conv, +}; + +static void exynos_adc_v2_init_hw(struct exynos_adc *info) +{ + u32 con1, con2; + + writel(1, info->enable_reg); + + con1 = ADC_V2_CON1_SOFT_RESET; + writel(con1, ADC_V2_CON1(info->regs)); + + con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL | + ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0); + writel(con2, ADC_V2_CON2(info->regs)); + + /* Enable interrupts */ + writel(1, ADC_V2_INT_EN(info->regs)); +} + +static void exynos_adc_v2_exit_hw(struct exynos_adc *info) +{ + u32 con; + + writel(0, info->enable_reg); + + con = readl(ADC_V2_CON1(info->regs)); + con &= ~ADC_CON_EN_START; + writel(con, ADC_V2_CON1(info->regs)); } -static void exynos_adc_hw_init(struct exynos_adc *info) +static void exynos_adc_v2_clear_irq(struct exynos_adc *info) +{ + writel(1, ADC_V2_INT_ST(info->regs)); +} + +static void exynos_adc_v2_start_conv(struct exynos_adc *info, + unsigned long addr) { u32 con1, con2; - if (info->version == ADC_V2) { - con1 = ADC_V2_CON1_SOFT_RESET; - writel(con1, ADC_V2_CON1(info->regs)); + con2 = readl(ADC_V2_CON2(info->regs)); + con2 &= ~ADC_V2_CON2_ACH_MASK; + con2 |= ADC_V2_CON2_ACH_SEL(addr); + writel(con2, ADC_V2_CON2(info->regs)); - con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL | - ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0); - writel(con2, ADC_V2_CON2(info->regs)); + con1 = readl(ADC_V2_CON1(info->regs)); + writel(con1 | ADC_CON_EN_START, ADC_V2_CON1(info->regs)); +} - /* Enable interrupts */ - writel(1, ADC_V2_INT_EN(info->regs)); - } else { - /* set default prescaler values and Enable prescaler */ - con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN; +static const struct exynos_adc_data exynos_adc_v2_data = { + .num_channels = MAX_ADC_V2_CHANNELS, - /* Enable 12-bit ADC resolution */ - con1 |= ADC_V1_CON_RES; - writel(con1, ADC_V1_CON(info->regs)); - } + .init_hw = exynos_adc_v2_init_hw, + .exit_hw = exynos_adc_v2_exit_hw, + .clear_irq = exynos_adc_v2_clear_irq, + .start_conv = exynos_adc_v2_start_conv, +}; + +static const struct exynos_adc_data exynos3250_adc_data = { + .num_channels = MAX_EXYNOS3250_ADC_CHANNELS, + .needs_sclk = true, + + .init_hw = exynos_adc_v2_init_hw, + .exit_hw = exynos_adc_v2_exit_hw, + .clear_irq = exynos_adc_v2_clear_irq, + .start_conv = exynos_adc_v2_start_conv, +}; + +static const struct of_device_id exynos_adc_match[] = { + { + .compatible = "samsung,exynos-adc-v1", + .data = &exynos_adc_v1_data, + }, { + .compatible = "samsung,exynos-adc-v2", + .data = &exynos_adc_v2_data, + }, { + .compatible = "samsung,exynos3250-adc", + .data = &exynos3250_adc_data, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, exynos_adc_match); + +static struct exynos_adc_data *exynos_adc_get_data(struct platform_device *pdev) +{ + const struct of_device_id *match; + + match = of_match_node(exynos_adc_match, pdev->dev.of_node); + return (struct exynos_adc_data *)match->data; } static int exynos_read_raw(struct iio_dev *indio_dev, @@ -144,7 +314,6 @@ static int exynos_read_raw(struct iio_dev *indio_dev, { struct exynos_adc *info = iio_priv(indio_dev); unsigned long timeout; - u32 con1, con2; int ret; if (mask != IIO_CHAN_INFO_RAW) @@ -154,28 +323,15 @@ static int exynos_read_raw(struct iio_dev *indio_dev, reinit_completion(&info->completion); /* Select the channel to be used and Trigger conversion */ - if (info->version == ADC_V2) { - con2 = readl(ADC_V2_CON2(info->regs)); - con2 &= ~ADC_V2_CON2_ACH_MASK; - con2 |= ADC_V2_CON2_ACH_SEL(chan->address); - writel(con2, ADC_V2_CON2(info->regs)); - - con1 = readl(ADC_V2_CON1(info->regs)); - writel(con1 | ADC_CON_EN_START, - ADC_V2_CON1(info->regs)); - } else { - writel(chan->address, ADC_V1_MUX(info->regs)); - - con1 = readl(ADC_V1_CON(info->regs)); - writel(con1 | ADC_CON_EN_START, - ADC_V1_CON(info->regs)); - } + if (info->data->start_conv) + info->data->start_conv(info, chan->address); timeout = wait_for_completion_timeout (&info->completion, EXYNOS_ADC_TIMEOUT); if (timeout == 0) { dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n"); - exynos_adc_hw_init(info); + if (info->data->init_hw) + info->data->init_hw(info); ret = -ETIMEDOUT; } else { *val = info->value; @@ -193,13 +349,11 @@ static irqreturn_t exynos_adc_isr(int irq, void *dev_id) struct exynos_adc *info = (struct exynos_adc *)dev_id; /* Read value */ - info->value = readl(ADC_V1_DATX(info->regs)) & - ADC_DATX_MASK; + info->value = readl(ADC_V1_DATX(info->regs)) & ADC_DATX_MASK; + /* clear irq */ - if (info->version == ADC_V2) - writel(1, ADC_V2_INT_ST(info->regs)); - else - writel(1, ADC_V1_INTCLR(info->regs)); + if (info->data->clear_irq) + info->data->clear_irq(info); complete(&info->completion); @@ -277,6 +431,12 @@ static int exynos_adc_probe(struct platform_device *pdev) info = iio_priv(indio_dev); + info->data = exynos_adc_get_data(pdev); + if (!info->data) { + dev_err(&pdev->dev, "failed getting exynos_adc_data\n"); + return -EINVAL; + } + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); info->regs = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(info->regs)) @@ -294,6 +454,7 @@ static int exynos_adc_probe(struct platform_device *pdev) } info->irq = irq; + info->dev = &pdev->dev; init_completion(&info->completion); @@ -304,6 +465,16 @@ static int exynos_adc_probe(struct platform_device *pdev) return PTR_ERR(info->clk); } + if (info->data->needs_sclk) { + info->sclk = devm_clk_get(&pdev->dev, "sclk"); + if (IS_ERR(info->sclk)) { + dev_err(&pdev->dev, + "failed getting sclk clock, err = %ld\n", + PTR_ERR(info->sclk)); + return PTR_ERR(info->sclk); + } + } + info->vdd = devm_regulator_get(&pdev->dev, "vdd"); if (IS_ERR(info->vdd)) { dev_err(&pdev->dev, "failed getting regulator, err = %ld\n", @@ -315,13 +486,13 @@ static int exynos_adc_probe(struct platform_device *pdev) if (ret) return ret; - ret = clk_prepare_enable(info->clk); + ret = exynos_adc_prepare_clk(info); if (ret) goto err_disable_reg; - writel(1, info->enable_reg); - - info->version = exynos_adc_get_version(pdev); + ret = exynos_adc_enable_clk(info); + if (ret) + goto err_unprepare_clk; platform_set_drvdata(pdev, indio_dev); @@ -331,11 +502,7 @@ static int exynos_adc_probe(struct platform_device *pdev) indio_dev->info = &exynos_adc_iio_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = exynos_adc_iio_channels; - - if (info->version == ADC_V1) - indio_dev->num_channels = MAX_ADC_V1_CHANNELS; - else - indio_dev->num_channels = MAX_ADC_V2_CHANNELS; + indio_dev->num_channels = info->data->num_channels; ret = request_irq(info->irq, exynos_adc_isr, 0, dev_name(&pdev->dev), info); @@ -349,7 +516,8 @@ static int exynos_adc_probe(struct platform_device *pdev) if (ret) goto err_irq; - exynos_adc_hw_init(info); + if (info->data->init_hw) + info->data->init_hw(info); ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev); if (ret < 0) { @@ -366,8 +534,11 @@ err_of_populate: err_irq: free_irq(info->irq, info); err_disable_clk: - writel(0, info->enable_reg); - clk_disable_unprepare(info->clk); + if (info->data->exit_hw) + info->data->exit_hw(info); + exynos_adc_disable_clk(info); +err_unprepare_clk: + exynos_adc_unprepare_clk(info); err_disable_reg: regulator_disable(info->vdd); return ret; @@ -382,8 +553,10 @@ static int exynos_adc_remove(struct platform_device *pdev) exynos_adc_remove_devices); iio_device_unregister(indio_dev); free_irq(info->irq, info); - writel(0, info->enable_reg); - clk_disable_unprepare(info->clk); + if (info->data->exit_hw) + info->data->exit_hw(info); + exynos_adc_disable_clk(info); + exynos_adc_unprepare_clk(info); regulator_disable(info->vdd); return 0; @@ -394,20 +567,10 @@ static int exynos_adc_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct exynos_adc *info = iio_priv(indio_dev); - u32 con; - if (info->version == ADC_V2) { - con = readl(ADC_V2_CON1(info->regs)); - con &= ~ADC_CON_EN_START; - writel(con, ADC_V2_CON1(info->regs)); - } else { - con = readl(ADC_V1_CON(info->regs)); - con |= ADC_V1_CON_STANDBY; - writel(con, ADC_V1_CON(info->regs)); - } - - writel(0, info->enable_reg); - clk_disable_unprepare(info->clk); + if (info->data->exit_hw) + info->data->exit_hw(info); + exynos_adc_disable_clk(info); regulator_disable(info->vdd); return 0; @@ -423,12 +586,12 @@ static int exynos_adc_resume(struct device *dev) if (ret) return ret; - ret = clk_prepare_enable(info->clk); + ret = exynos_adc_enable_clk(info); if (ret) return ret; - writel(1, info->enable_reg); - exynos_adc_hw_init(info); + if (info->data->init_hw) + info->data->init_hw(info); return 0; } diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c new file mode 100644 index 000000000000..87ee1c7d0b54 --- /dev/null +++ b/drivers/iio/adc/max1027.c @@ -0,0 +1,521 @@ + /* + * iio/adc/max1027.c + * Copyright (C) 2014 Philippe Reynes + * + * based on linux/drivers/iio/ad7923.c + * Copyright 2011 Analog Devices Inc (from AD7923 Driver) + * Copyright 2012 CS Systemes d'Information + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * max1027.c + * + * Partial support for max1027 and similar chips. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/spi/spi.h> +#include <linux/delay.h> + +#include <linux/iio/iio.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#define MAX1027_CONV_REG BIT(7) +#define MAX1027_SETUP_REG BIT(6) +#define MAX1027_AVG_REG BIT(5) +#define MAX1027_RST_REG BIT(4) + +/* conversion register */ +#define MAX1027_TEMP BIT(0) +#define MAX1027_SCAN_0_N (0x00 << 1) +#define MAX1027_SCAN_N_M (0x01 << 1) +#define MAX1027_SCAN_N (0x02 << 1) +#define MAX1027_NOSCAN (0x03 << 1) +#define MAX1027_CHAN(n) ((n) << 3) + +/* setup register */ +#define MAX1027_UNIPOLAR 0x02 +#define MAX1027_BIPOLAR 0x03 +#define MAX1027_REF_MODE0 (0x00 << 2) +#define MAX1027_REF_MODE1 (0x01 << 2) +#define MAX1027_REF_MODE2 (0x02 << 2) +#define MAX1027_REF_MODE3 (0x03 << 2) +#define MAX1027_CKS_MODE0 (0x00 << 4) +#define MAX1027_CKS_MODE1 (0x01 << 4) +#define MAX1027_CKS_MODE2 (0x02 << 4) +#define MAX1027_CKS_MODE3 (0x03 << 4) + +/* averaging register */ +#define MAX1027_NSCAN_4 0x00 +#define MAX1027_NSCAN_8 0x01 +#define MAX1027_NSCAN_12 0x02 +#define MAX1027_NSCAN_16 0x03 +#define MAX1027_NAVG_4 (0x00 << 2) +#define MAX1027_NAVG_8 (0x01 << 2) +#define MAX1027_NAVG_16 (0x02 << 2) +#define MAX1027_NAVG_32 (0x03 << 2) +#define MAX1027_AVG_EN BIT(4) + +enum max1027_id { + max1027, + max1029, + max1031, +}; + +static const struct spi_device_id max1027_id[] = { + {"max1027", max1027}, + {"max1029", max1029}, + {"max1031", max1031}, + {} +}; +MODULE_DEVICE_TABLE(spi, max1027_id); + +#ifdef CONFIG_OF +static const struct of_device_id max1027_adc_dt_ids[] = { + { .compatible = "maxim,max1027" }, + { .compatible = "maxim,max1029" }, + { .compatible = "maxim,max1031" }, + {}, +}; +MODULE_DEVICE_TABLE(of, max1027_adc_dt_ids); +#endif + +#define MAX1027_V_CHAN(index) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = index, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = index + 1, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 10, \ + .storagebits = 16, \ + .shift = 2, \ + .endianness = IIO_BE, \ + }, \ + } + +#define MAX1027_T_CHAN \ + { \ + .type = IIO_TEMP, \ + .channel = 0, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = 0, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 12, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ + } + +static const struct iio_chan_spec max1027_channels[] = { + MAX1027_T_CHAN, + MAX1027_V_CHAN(0), + MAX1027_V_CHAN(1), + MAX1027_V_CHAN(2), + MAX1027_V_CHAN(3), + MAX1027_V_CHAN(4), + MAX1027_V_CHAN(5), + MAX1027_V_CHAN(6), + MAX1027_V_CHAN(7) +}; + +static const struct iio_chan_spec max1029_channels[] = { + MAX1027_T_CHAN, + MAX1027_V_CHAN(0), + MAX1027_V_CHAN(1), + MAX1027_V_CHAN(2), + MAX1027_V_CHAN(3), + MAX1027_V_CHAN(4), + MAX1027_V_CHAN(5), + MAX1027_V_CHAN(6), + MAX1027_V_CHAN(7), + MAX1027_V_CHAN(8), + MAX1027_V_CHAN(9), + MAX1027_V_CHAN(10), + MAX1027_V_CHAN(11) +}; + +static const struct iio_chan_spec max1031_channels[] = { + MAX1027_T_CHAN, + MAX1027_V_CHAN(0), + MAX1027_V_CHAN(1), + MAX1027_V_CHAN(2), + MAX1027_V_CHAN(3), + MAX1027_V_CHAN(4), + MAX1027_V_CHAN(5), + MAX1027_V_CHAN(6), + MAX1027_V_CHAN(7), + MAX1027_V_CHAN(8), + MAX1027_V_CHAN(9), + MAX1027_V_CHAN(10), + MAX1027_V_CHAN(11), + MAX1027_V_CHAN(12), + MAX1027_V_CHAN(13), + MAX1027_V_CHAN(14), + MAX1027_V_CHAN(15) +}; + +static const unsigned long max1027_available_scan_masks[] = { + 0x000001ff, + 0x00000000, +}; + +static const unsigned long max1029_available_scan_masks[] = { + 0x00001fff, + 0x00000000, +}; + +static const unsigned long max1031_available_scan_masks[] = { + 0x0001ffff, + 0x00000000, +}; + +struct max1027_chip_info { + const struct iio_chan_spec *channels; + unsigned int num_channels; + const unsigned long *available_scan_masks; +}; + +static const struct max1027_chip_info max1027_chip_info_tbl[] = { + [max1027] = { + .channels = max1027_channels, + .num_channels = ARRAY_SIZE(max1027_channels), + .available_scan_masks = max1027_available_scan_masks, + }, + [max1029] = { + .channels = max1029_channels, + .num_channels = ARRAY_SIZE(max1029_channels), + .available_scan_masks = max1029_available_scan_masks, + }, + [max1031] = { + .channels = max1031_channels, + .num_channels = ARRAY_SIZE(max1031_channels), + .available_scan_masks = max1031_available_scan_masks, + }, +}; + +struct max1027_state { + const struct max1027_chip_info *info; + struct spi_device *spi; + struct iio_trigger *trig; + __be16 *buffer; + struct mutex lock; + + u8 reg ____cacheline_aligned; +}; + +static int max1027_read_single_value(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val) +{ + int ret; + struct max1027_state *st = iio_priv(indio_dev); + + if (iio_buffer_enabled(indio_dev)) { + dev_warn(&indio_dev->dev, "trigger mode already enabled"); + return -EBUSY; + } + + /* Start acquisition on conversion register write */ + st->reg = MAX1027_SETUP_REG | MAX1027_REF_MODE2 | MAX1027_CKS_MODE2; + ret = spi_write(st->spi, &st->reg, 1); + if (ret < 0) { + dev_err(&indio_dev->dev, + "Failed to configure setup register\n"); + return ret; + } + + /* Configure conversion register with the requested chan */ + st->reg = MAX1027_CONV_REG | MAX1027_CHAN(chan->channel) | + MAX1027_NOSCAN | !!(chan->type == IIO_TEMP); + ret = spi_write(st->spi, &st->reg, 1); + if (ret < 0) { + dev_err(&indio_dev->dev, + "Failed to configure conversion register\n"); + return ret; + } + + /* + * For an unknown reason, when we use the mode "10" (write + * conversion register), the interrupt doesn't occur every time. + * So we just wait 1 ms. + */ + mdelay(1); + + /* Read result */ + ret = spi_read(st->spi, st->buffer, (chan->type == IIO_TEMP) ? 4 : 2); + if (ret < 0) + return ret; + + *val = be16_to_cpu(st->buffer[0]); + + return IIO_VAL_INT; +} + +static int max1027_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + int ret = 0; + struct max1027_state *st = iio_priv(indio_dev); + + mutex_lock(&st->lock); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = max1027_read_single_value(indio_dev, chan, val); + break; + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_TEMP: + *val = 1; + *val2 = 8; + ret = IIO_VAL_FRACTIONAL; + break; + case IIO_VOLTAGE: + *val = 2500; + *val2 = 10; + ret = IIO_VAL_FRACTIONAL_LOG2; + break; + default: + ret = -EINVAL; + break; + } + break; + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&st->lock); + + return ret; +} + +static int max1027_debugfs_reg_access(struct iio_dev *indio_dev, + unsigned reg, unsigned writeval, + unsigned *readval) +{ + struct max1027_state *st = iio_priv(indio_dev); + u8 *val = (u8 *)st->buffer; + + if (readval != NULL) + return -EINVAL; + + *val = (u8)writeval; + return spi_write(st->spi, val, 1); +} + +static int max1027_validate_trigger(struct iio_dev *indio_dev, + struct iio_trigger *trig) +{ + struct max1027_state *st = iio_priv(indio_dev); + + if (st->trig != trig) + return -EINVAL; + + return 0; +} + +static int max1027_set_trigger_state(struct iio_trigger *trig, bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct max1027_state *st = iio_priv(indio_dev); + int ret; + + if (state) { + /* Start acquisition on cnvst */ + st->reg = MAX1027_SETUP_REG | MAX1027_CKS_MODE0 | + MAX1027_REF_MODE2; + ret = spi_write(st->spi, &st->reg, 1); + if (ret < 0) + return ret; + + /* Scan from 0 to max */ + st->reg = MAX1027_CONV_REG | MAX1027_CHAN(0) | + MAX1027_SCAN_N_M | MAX1027_TEMP; + ret = spi_write(st->spi, &st->reg, 1); + if (ret < 0) + return ret; + } else { + /* Start acquisition on conversion register write */ + st->reg = MAX1027_SETUP_REG | MAX1027_CKS_MODE2 | + MAX1027_REF_MODE2; + ret = spi_write(st->spi, &st->reg, 1); + if (ret < 0) + return ret; + } + + return 0; +} + +static int max1027_validate_device(struct iio_trigger *trig, + struct iio_dev *indio_dev) +{ + struct iio_dev *indio = iio_trigger_get_drvdata(trig); + + if (indio != indio_dev) + return -EINVAL; + + return 0; +} + +static irqreturn_t max1027_trigger_handler(int irq, void *private) +{ + struct iio_poll_func *pf = (struct iio_poll_func *)private; + struct iio_dev *indio_dev = pf->indio_dev; + struct max1027_state *st = iio_priv(indio_dev); + + pr_debug("%s(irq=%d, private=0x%p)\n", __func__, irq, private); + + /* fill buffer with all channel */ + spi_read(st->spi, st->buffer, indio_dev->masklength * 2); + + iio_push_to_buffers(indio_dev, st->buffer); + + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static const struct iio_trigger_ops max1027_trigger_ops = { + .owner = THIS_MODULE, + .validate_device = &max1027_validate_device, + .set_trigger_state = &max1027_set_trigger_state, +}; + +static const struct iio_info max1027_info = { + .driver_module = THIS_MODULE, + .read_raw = &max1027_read_raw, + .validate_trigger = &max1027_validate_trigger, + .debugfs_reg_access = &max1027_debugfs_reg_access, +}; + +static int max1027_probe(struct spi_device *spi) +{ + int ret; + struct iio_dev *indio_dev; + struct max1027_state *st; + + pr_debug("%s: probe(spi = 0x%p)\n", __func__, spi); + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (indio_dev == NULL) { + pr_err("Can't allocate iio device\n"); + return -ENOMEM; + } + + spi_set_drvdata(spi, indio_dev); + + st = iio_priv(indio_dev); + st->spi = spi; + st->info = &max1027_chip_info_tbl[spi_get_device_id(spi)->driver_data]; + + mutex_init(&st->lock); + + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->dev.parent = &spi->dev; + indio_dev->info = &max1027_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = st->info->channels; + indio_dev->num_channels = st->info->num_channels; + indio_dev->available_scan_masks = st->info->available_scan_masks; + + st->buffer = devm_kmalloc(&indio_dev->dev, + indio_dev->num_channels * 2, + GFP_KERNEL); + if (st->buffer == NULL) { + dev_err(&indio_dev->dev, "Can't allocate bufffer\n"); + return -ENOMEM; + } + + ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + &max1027_trigger_handler, NULL); + if (ret < 0) { + dev_err(&indio_dev->dev, "Failed to setup buffer\n"); + return ret; + } + + st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-trigger", + indio_dev->name); + if (st->trig == NULL) { + ret = -ENOMEM; + dev_err(&indio_dev->dev, "Failed to allocate iio trigger\n"); + goto fail_trigger_alloc; + } + + st->trig->ops = &max1027_trigger_ops; + st->trig->dev.parent = &spi->dev; + iio_trigger_set_drvdata(st->trig, indio_dev); + iio_trigger_register(st->trig); + + ret = devm_request_threaded_irq(&spi->dev, spi->irq, + iio_trigger_generic_data_rdy_poll, + NULL, + IRQF_TRIGGER_FALLING, + spi->dev.driver->name, st->trig); + if (ret < 0) { + dev_err(&indio_dev->dev, "Failed to allocate IRQ.\n"); + goto fail_dev_register; + } + + /* Disable averaging */ + st->reg = MAX1027_AVG_REG; + ret = spi_write(st->spi, &st->reg, 1); + if (ret < 0) { + dev_err(&indio_dev->dev, "Failed to configure averaging register\n"); + goto fail_dev_register; + } + + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(&indio_dev->dev, "Failed to register iio device\n"); + goto fail_dev_register; + } + + return 0; + +fail_dev_register: +fail_trigger_alloc: + iio_triggered_buffer_cleanup(indio_dev); + + return ret; +} + +static int max1027_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + + pr_debug("%s: remove(spi = 0x%p)\n", __func__, spi); + + iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + + return 0; +} + +static struct spi_driver max1027_driver = { + .driver = { + .name = "max1027", + .owner = THIS_MODULE, + }, + .probe = max1027_probe, + .remove = max1027_remove, + .id_table = max1027_id, +}; +module_spi_driver(max1027_driver); + +MODULE_AUTHOR("Philippe Reynes <tremyfr@yahoo.fr>"); +MODULE_DESCRIPTION("MAX1027/MAX1029/MAX1031 ADC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index ab52be29141b..fd2745c62943 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -486,7 +486,7 @@ static irqreturn_t xadc_axi_interrupt_handler(int irq, void *devid) return IRQ_NONE; if ((status & XADC_AXI_INT_EOS) && xadc->trigger) - iio_trigger_poll(xadc->trigger, 0); + iio_trigger_poll(xadc->trigger); if (status & XADC_AXI_INT_ALARM_MASK) { /* diff --git a/drivers/iio/adc/xilinx-xadc-events.c b/drivers/iio/adc/xilinx-xadc-events.c index 3e7f0d7a80c3..edcf3aabd70d 100644 --- a/drivers/iio/adc/xilinx-xadc-events.c +++ b/drivers/iio/adc/xilinx-xadc-events.c @@ -31,17 +31,11 @@ static const struct iio_chan_spec *xadc_event_to_channel( static void xadc_handle_event(struct iio_dev *indio_dev, unsigned int event) { const struct iio_chan_spec *chan; - unsigned int offset; /* Temperature threshold error, we don't handle this yet */ if (event == 0) return; - if (event < 4) - offset = event; - else - offset = event + 4; - chan = xadc_event_to_channel(indio_dev, event); if (chan->type == IIO_TEMP) { diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index 403dd3d8986e..25b01e156d82 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -26,12 +26,12 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -struct { +static struct { u32 usage_id; int unit; /* 0 for default others from HID sensor spec */ int scale_val0; /* scale, whole number */ int scale_val1; /* scale, fraction in micros */ -} static unit_conversion[] = { +} unit_conversion[] = { {HID_USAGE_SENSOR_ACCEL_3D, 0, 9, 806650}, {HID_USAGE_SENSOR_ACCEL_3D, HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD, 1, 0}, @@ -343,6 +343,7 @@ int hid_sensor_format_scale(u32 usage_id, } EXPORT_SYMBOL(hid_sensor_format_scale); +static int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev, u32 usage_id, struct hid_sensor_common *st) diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index e8b932fed70e..8a4ec00a91a0 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -14,8 +14,8 @@ #include <linux/delay.h> #include <linux/iio/iio.h> #include <linux/regulator/consumer.h> +#include <linux/of.h> #include <asm/unaligned.h> - #include <linux/iio/common/st_sensors.h> @@ -265,14 +265,47 @@ static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev, return 0; } +#ifdef CONFIG_OF +static struct st_sensors_platform_data *st_sensors_of_probe(struct device *dev, + struct st_sensors_platform_data *defdata) +{ + struct st_sensors_platform_data *pdata; + struct device_node *np = dev->of_node; + u32 val; + + if (!np) + return NULL; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!of_property_read_u32(np, "st,drdy-int-pin", &val) && (val <= 2)) + pdata->drdy_int_pin = (u8) val; + else + pdata->drdy_int_pin = defdata ? defdata->drdy_int_pin : 1; + + return pdata; +} +#else +static struct st_sensors_platform_data *st_sensors_of_probe(struct device *dev, + struct st_sensors_platform_data *defdata) +{ + return NULL; +} +#endif + int st_sensors_init_sensor(struct iio_dev *indio_dev, struct st_sensors_platform_data *pdata) { struct st_sensor_data *sdata = iio_priv(indio_dev); + struct st_sensors_platform_data *of_pdata; int err = 0; mutex_init(&sdata->tb.buf_lock); + /* If OF/DT pdata exists, it will take precedence of anything else */ + of_pdata = st_sensors_of_probe(indio_dev->dev.parent, pdata); + if (of_pdata) + pdata = of_pdata; + if (pdata) err = st_sensors_set_drdy_int_pin(indio_dev, pdata); @@ -463,35 +496,6 @@ read_wai_error: } EXPORT_SYMBOL(st_sensors_check_device_support); -ssize_t st_sensors_sysfs_get_sampling_frequency(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct st_sensor_data *adata = iio_priv(dev_get_drvdata(dev)); - - return sprintf(buf, "%d\n", adata->odr); -} -EXPORT_SYMBOL(st_sensors_sysfs_get_sampling_frequency); - -ssize_t st_sensors_sysfs_set_sampling_frequency(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - int err; - unsigned int odr; - struct iio_dev *indio_dev = dev_get_drvdata(dev); - - err = kstrtoint(buf, 10, &odr); - if (err < 0) - goto conversion_error; - - mutex_lock(&indio_dev->mlock); - err = st_sensors_set_odr(indio_dev, odr); - mutex_unlock(&indio_dev->mlock); - -conversion_error: - return err < 0 ? err : size; -} -EXPORT_SYMBOL(st_sensors_sysfs_set_sampling_frequency); - ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/iio/common/st_sensors/st_sensors_i2c.c b/drivers/iio/common/st_sensors/st_sensors_i2c.c index 38af9440c103..bb6f3085f57b 100644 --- a/drivers/iio/common/st_sensors/st_sensors_i2c.c +++ b/drivers/iio/common/st_sensors/st_sensors_i2c.c @@ -12,6 +12,7 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/iio/iio.h> +#include <linux/of_device.h> #include <linux/iio/common/st_sensors_i2c.h> @@ -76,6 +77,35 @@ void st_sensors_i2c_configure(struct iio_dev *indio_dev, } EXPORT_SYMBOL(st_sensors_i2c_configure); +#ifdef CONFIG_OF +/** + * st_sensors_of_i2c_probe() - device tree probe for ST I2C sensors + * @client: the I2C client device for the sensor + * @match: the OF match table for the device, containing compatible strings + * but also a .data field with the corresponding internal kernel name + * used by this sensor. + * + * In effect this function matches a compatible string to an internal kernel + * name for a certain sensor device, so that the rest of the autodetection can + * rely on that name from this point on. I2C client devices will be renamed + * to match the internal kernel convention. + */ +void st_sensors_of_i2c_probe(struct i2c_client *client, + const struct of_device_id *match) +{ + const struct of_device_id *of_id; + + of_id = of_match_device(match, &client->dev); + if (!of_id) + return; + + /* The name from the OF match takes precedence if present */ + strncpy(client->name, of_id->data, sizeof(client->name)); + client->name[sizeof(client->name) - 1] = '\0'; +} +EXPORT_SYMBOL(st_sensors_of_i2c_probe); +#endif + MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); MODULE_DESCRIPTION("STMicroelectronics ST-sensors i2c driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index f378ca8033db..f278eff42a4c 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -163,4 +163,14 @@ config MCP4725 To compile this driver as a module, choose M here: the module will be called mcp4725. +config MCP4922 + tristate "MCP4902, MCP4912, MCP4922 DAC driver" + depends on SPI + help + Say yes here to build the driver for the Microchip MCP4902 + MCP4912, and MCP4922 DAC devices. + + To compile this driver as a module, choose M here: the module + will be called mcp4922. + endmenu diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index bb84ad64463f..10107640bb46 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_AD5686) += ad5686.o obj-$(CONFIG_AD7303) += ad7303.o obj-$(CONFIG_MAX517) += max517.o obj-$(CONFIG_MCP4725) += mcp4725.o +obj-$(CONFIG_MCP4922) += mcp4922.o diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index 1e6449346b50..581ec141de3d 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c @@ -15,17 +15,16 @@ #include <linux/sysfs.h> #include <linux/regulator/consumer.h> #include <linux/module.h> +#include <linux/bitops.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/events.h> #include <linux/iio/dac/ad5504.h> -#define AD5505_BITS 12 -#define AD5504_RES_MASK ((1 << (AD5505_BITS)) - 1) - -#define AD5504_CMD_READ (1 << 15) -#define AD5504_CMD_WRITE (0 << 15) +#define AD5504_RES_MASK GENMASK(11, 0) +#define AD5504_CMD_READ BIT(15) +#define AD5504_CMD_WRITE 0 #define AD5504_ADDR(addr) ((addr) << 12) /* Registers */ @@ -42,7 +41,7 @@ /** * struct ad5446_state - driver instance specific data - * @us: spi_device + * @spi: spi_device * @reg: supply regulator * @vref_mv: actual reference voltage used * @pwr_down_mask power down mask @@ -126,7 +125,6 @@ static int ad5504_write_raw(struct iio_dev *indio_dev, long mask) { struct ad5504_state *st = iio_priv(indio_dev); - int ret; switch (mask) { case IIO_CHAN_INFO_RAW: @@ -135,10 +133,8 @@ static int ad5504_write_raw(struct iio_dev *indio_dev, return ad5504_spi_write(st, chan->address, val); default: - ret = -EINVAL; + return -EINVAL; } - - return -EINVAL; } static const char * const ad5504_powerdown_modes[] = { diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c index e8199cce2aea..61bb9d4239ea 100644 --- a/drivers/iio/dac/ad5624r_spi.c +++ b/drivers/iio/dac/ad5624r_spi.c @@ -67,7 +67,6 @@ static int ad5624r_write_raw(struct iio_dev *indio_dev, long mask) { struct ad5624r_state *st = iio_priv(indio_dev); - int ret; switch (mask) { case IIO_CHAN_INFO_RAW: @@ -79,10 +78,8 @@ static int ad5624r_write_raw(struct iio_dev *indio_dev, chan->address, val, chan->scan_type.shift); default: - ret = -EINVAL; + return -EINVAL; } - - return -EINVAL; } static const char * const ad5624r_powerdown_modes[] = { diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 17aca4d9bd06..f57562aa396f 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -313,7 +313,7 @@ static int ad5686_probe(struct spi_device *spi) { struct ad5686_state *st; struct iio_dev *indio_dev; - int ret, regdone = 0, voltage_uv = 0; + int ret, voltage_uv = 0; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) @@ -355,7 +355,6 @@ static int ad5686_probe(struct spi_device *spi) indio_dev->channels = st->chip_info->channel; indio_dev->num_channels = AD5686_DAC_CHANNELS; - regdone = 1; ret = ad5686_spi_write(st, AD5686_CMD_INTERNAL_REFER_SETUP, 0, !!voltage_uv, 0); if (ret) diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index ae49afe2b380..5ba785f18589 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c @@ -16,17 +16,16 @@ #include <linux/sysfs.h> #include <linux/regulator/consumer.h> #include <linux/module.h> +#include <linux/bitops.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/dac/ad5791.h> -#define AD5791_RES_MASK(x) ((1 << (x)) - 1) -#define AD5791_DAC_MASK AD5791_RES_MASK(20) -#define AD5791_DAC_MSB (1 << 19) +#define AD5791_DAC_MASK GENMASK(19, 0) -#define AD5791_CMD_READ (1 << 23) -#define AD5791_CMD_WRITE (0 << 23) +#define AD5791_CMD_READ BIT(23) +#define AD5791_CMD_WRITE 0 #define AD5791_ADDR(addr) ((addr) << 20) /* Registers */ @@ -37,11 +36,11 @@ #define AD5791_ADDR_SW_CTRL 4 /* Control Register */ -#define AD5791_CTRL_RBUF (1 << 1) -#define AD5791_CTRL_OPGND (1 << 2) -#define AD5791_CTRL_DACTRI (1 << 3) -#define AD5791_CTRL_BIN2SC (1 << 4) -#define AD5791_CTRL_SDODIS (1 << 5) +#define AD5791_CTRL_RBUF BIT(1) +#define AD5791_CTRL_OPGND BIT(2) +#define AD5791_CTRL_DACTRI BIT(3) +#define AD5791_CTRL_BIN2SC BIT(4) +#define AD5791_CTRL_SDODIS BIT(5) #define AD5761_CTRL_LINCOMP(x) ((x) << 6) #define AD5791_LINCOMP_0_10 0 @@ -54,9 +53,9 @@ #define AD5780_LINCOMP_10_20 12 /* Software Control Register */ -#define AD5791_SWCTRL_LDAC (1 << 0) -#define AD5791_SWCTRL_CLR (1 << 1) -#define AD5791_SWCTRL_RESET (1 << 2) +#define AD5791_SWCTRL_LDAC BIT(0) +#define AD5791_SWCTRL_CLR BIT(1) +#define AD5791_SWCTRL_RESET BIT(2) #define AD5791_DAC_PWRDN_6K 0 #define AD5791_DAC_PWRDN_3STATE 1 @@ -72,7 +71,7 @@ struct ad5791_chip_info { /** * struct ad5791_state - driver instance specific data - * @us: spi_device + * @spi: spi_device * @reg_vdd: positive supply regulator * @reg_vss: negative supply regulator * @chip_info: chip model specific constants @@ -328,7 +327,7 @@ static int ad5791_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - val &= AD5791_RES_MASK(chan->scan_type.realbits); + val &= GENMASK(chan->scan_type.realbits - 1, 0); val <<= chan->scan_type.shift; return ad5791_spi_write(st, chan->address, val); diff --git a/drivers/iio/dac/mcp4922.c b/drivers/iio/dac/mcp4922.c new file mode 100644 index 000000000000..92cf4ca6981d --- /dev/null +++ b/drivers/iio/dac/mcp4922.c @@ -0,0 +1,216 @@ +/* + * mcp4922.c + * + * Driver for Microchip Digital to Analog Converters. + * Supports MCP4902, MCP4912, and MCP4922. + * + * Copyright (c) 2014 EMAC Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/spi/spi.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/regulator/consumer.h> +#include <linux/bitops.h> + +#define MCP4922_NUM_CHANNELS 2 + +enum mcp4922_supported_device_ids { + ID_MCP4902, + ID_MCP4912, + ID_MCP4922, +}; + +struct mcp4922_state { + struct spi_device *spi; + unsigned int value[MCP4922_NUM_CHANNELS]; + unsigned int vref_mv; + struct regulator *vref_reg; + u8 mosi[2] ____cacheline_aligned; +}; + +#define MCP4922_CHAN(chan, bits) { \ + .type = IIO_VOLTAGE, \ + .output = 1, \ + .indexed = 1, \ + .channel = chan, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = 12 - (bits), \ + }, \ +} + +static int mcp4922_spi_write(struct mcp4922_state *state, u8 addr, u32 val) +{ + state->mosi[1] = val & 0xff; + state->mosi[0] = (addr == 0) ? 0x00 : 0x80; + state->mosi[0] |= 0x30 | ((val >> 8) & 0x0f); + + return spi_write(state->spi, state->mosi, 2); +} + +static int mcp4922_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + struct mcp4922_state *state = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + *val = state->value[chan->channel]; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = state->vref_mv; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static int mcp4922_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct mcp4922_state *state = iio_priv(indio_dev); + + if (val2 != 0) + return -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (val > GENMASK(chan->scan_type.realbits-1, 0)) + return -EINVAL; + val <<= chan->scan_type.shift; + state->value[chan->channel] = val; + return mcp4922_spi_write(state, chan->channel, val); + default: + return -EINVAL; + } +} + +static const struct iio_chan_spec mcp4922_channels[3][MCP4922_NUM_CHANNELS] = { + [ID_MCP4902] = { MCP4922_CHAN(0, 8), MCP4922_CHAN(1, 8) }, + [ID_MCP4912] = { MCP4922_CHAN(0, 10), MCP4922_CHAN(1, 10) }, + [ID_MCP4922] = { MCP4922_CHAN(0, 12), MCP4922_CHAN(1, 12) }, +}; + +static const struct iio_info mcp4922_info = { + .read_raw = &mcp4922_read_raw, + .write_raw = &mcp4922_write_raw, + .driver_module = THIS_MODULE, +}; + +static int mcp4922_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct mcp4922_state *state; + const struct spi_device_id *id; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state)); + if (indio_dev == NULL) + return -ENOMEM; + + state = iio_priv(indio_dev); + state->spi = spi; + state->vref_reg = devm_regulator_get(&spi->dev, "vref"); + if (IS_ERR(state->vref_reg)) { + dev_err(&spi->dev, "Vref regulator not specified\n"); + return PTR_ERR(state->vref_reg); + } + + ret = regulator_enable(state->vref_reg); + if (ret) { + dev_err(&spi->dev, "Failed to enable vref regulator: %d\n", + ret); + return ret; + } + + ret = regulator_get_voltage(state->vref_reg); + if (ret < 0) { + dev_err(&spi->dev, "Failed to read vref regulator: %d\n", + ret); + goto error_disable_reg; + } + state->vref_mv = ret / 1000; + + spi_set_drvdata(spi, indio_dev); + id = spi_get_device_id(spi); + indio_dev->dev.parent = &spi->dev; + indio_dev->info = &mcp4922_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = mcp4922_channels[id->driver_data]; + indio_dev->num_channels = MCP4922_NUM_CHANNELS; + indio_dev->name = id->name; + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&spi->dev, "Failed to register iio device: %d\n", + ret); + goto error_disable_reg; + } + + return 0; + +error_disable_reg: + regulator_disable(state->vref_reg); + + return ret; +} + +static int mcp4922_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct mcp4922_state *state; + + iio_device_unregister(indio_dev); + state = iio_priv(indio_dev); + regulator_disable(state->vref_reg); + + return 0; +} + +static const struct spi_device_id mcp4922_id[] = { + {"mcp4902", ID_MCP4902}, + {"mcp4912", ID_MCP4912}, + {"mcp4922", ID_MCP4922}, + {} +}; +MODULE_DEVICE_TABLE(spi, mcp4922_id); + +static struct spi_driver mcp4922_driver = { + .driver = { + .name = "mcp4922", + .owner = THIS_MODULE, + }, + .probe = mcp4922_probe, + .remove = mcp4922_remove, + .id_table = mcp4922_id, +}; +module_spi_driver(mcp4922_driver); + +MODULE_AUTHOR("Michael Welling <mwelling@ieee.org>"); +MODULE_DESCRIPTION("Microchip MCP4902, MCP4912, MCP4922 DAC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c index 22b6fb80fa1a..75fe0edd3d0f 100644 --- a/drivers/iio/gyro/adis16260.c +++ b/drivers/iio/gyro/adis16260.c @@ -101,65 +101,6 @@ #define ADIS16260_SCAN_TEMP 3 #define ADIS16260_SCAN_ANGL 4 -static ssize_t adis16260_read_frequency(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct adis *adis = iio_priv(indio_dev); - int ret, len = 0; - u16 t; - int sps; - ret = adis_read_reg_16(adis, ADIS16260_SMPL_PRD, &t); - if (ret) - return ret; - - if (spi_get_device_id(adis->spi)->driver_data) /* If an adis16251 */ - sps = (t & ADIS16260_SMPL_PRD_TIME_BASE) ? 8 : 256; - else - sps = (t & ADIS16260_SMPL_PRD_TIME_BASE) ? 66 : 2048; - sps /= (t & ADIS16260_SMPL_PRD_DIV_MASK) + 1; - len = sprintf(buf, "%d\n", sps); - return len; -} - -static ssize_t adis16260_write_frequency(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct adis *adis = iio_priv(indio_dev); - unsigned int val; - int ret; - u8 t; - - ret = kstrtouint(buf, 10, &val); - if (ret) - return ret; - - mutex_lock(&indio_dev->mlock); - if (spi_get_device_id(adis->spi)->driver_data) - t = 256 / val; - else - t = 2048 / val; - - if (t > ADIS16260_SMPL_PRD_DIV_MASK) - t = ADIS16260_SMPL_PRD_DIV_MASK; - else if (t > 0) - t--; - - if (t >= 0x0A) - adis->spi->max_speed_hz = ADIS16260_SPI_SLOW; - else - adis->spi->max_speed_hz = ADIS16260_SPI_FAST; - ret = adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t); - - mutex_unlock(&indio_dev->mlock); - - return ret ? ret : len; -} - /* Power down the device */ static int adis16260_stop_device(struct iio_dev *indio_dev) { @@ -174,18 +115,19 @@ static int adis16260_stop_device(struct iio_dev *indio_dev) return ret; } -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, - adis16260_read_frequency, - adis16260_write_frequency); - static const struct iio_chan_spec adis16260_channels[] = { ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO, BIT(IIO_CHAN_INFO_CALIBBIAS) | - BIT(IIO_CHAN_INFO_CALIBSCALE), 14), - ADIS_INCLI_CHAN(X, ADIS16260_ANGL_OUT, ADIS16260_SCAN_ANGL, 0, 14), - ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP, 12), - ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY, 12), - ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC, 12), + BIT(IIO_CHAN_INFO_CALIBSCALE), + BIT(IIO_CHAN_INFO_SAMP_FREQ), 14), + ADIS_INCLI_CHAN(X, ADIS16260_ANGL_OUT, ADIS16260_SCAN_ANGL, 0, + BIT(IIO_CHAN_INFO_SAMP_FREQ), 14), + ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP, + BIT(IIO_CHAN_INFO_SAMP_FREQ), 12), + ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY, + BIT(IIO_CHAN_INFO_SAMP_FREQ), 12), + ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC, + BIT(IIO_CHAN_INFO_SAMP_FREQ), 12), IIO_CHAN_SOFT_TIMESTAMP(5), }; @@ -258,6 +200,20 @@ static int adis16260_read_raw(struct iio_dev *indio_dev, *val = val16; return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = adis_read_reg_16(adis, ADIS16260_SMPL_PRD, &val16); + if (ret) + return ret; + + if (spi_get_device_id(adis->spi)->driver_data) + /* If an adis16251 */ + *val = (val16 & ADIS16260_SMPL_PRD_TIME_BASE) ? + 8 : 256; + else + *val = (val16 & ADIS16260_SMPL_PRD_TIME_BASE) ? + 66 : 2048; + *val /= (val16 & ADIS16260_SMPL_PRD_DIV_MASK) + 1; + return IIO_VAL_INT; } return -EINVAL; } @@ -269,7 +225,9 @@ static int adis16260_write_raw(struct iio_dev *indio_dev, long mask) { struct adis *adis = iio_priv(indio_dev); + int ret; u8 addr; + u8 t; switch (mask) { case IIO_CHAN_INFO_CALIBBIAS: @@ -284,21 +242,31 @@ static int adis16260_write_raw(struct iio_dev *indio_dev, addr = adis16260_addresses[chan->scan_index][1]; return adis_write_reg_16(adis, addr, val); + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&indio_dev->mlock); + if (spi_get_device_id(adis->spi)->driver_data) + t = 256 / val; + else + t = 2048 / val; + + if (t > ADIS16260_SMPL_PRD_DIV_MASK) + t = ADIS16260_SMPL_PRD_DIV_MASK; + else if (t > 0) + t--; + + if (t >= 0x0A) + adis->spi->max_speed_hz = ADIS16260_SPI_SLOW; + else + adis->spi->max_speed_hz = ADIS16260_SPI_FAST; + ret = adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t); + + mutex_unlock(&indio_dev->mlock); + return ret; } return -EINVAL; } -static struct attribute *adis16260_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, - NULL -}; - -static const struct attribute_group adis16260_attribute_group = { - .attrs = adis16260_attributes, -}; - static const struct iio_info adis16260_info = { - .attrs = &adis16260_attribute_group, .read_raw = &adis16260_read_raw, .write_raw = &adis16260_write_raw, .update_scan_mode = adis_update_scan_mode, diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c index 8295e318399f..6a8020d48140 100644 --- a/drivers/iio/gyro/itg3200_core.c +++ b/drivers/iio/gyro/itg3200_core.c @@ -90,6 +90,7 @@ static int itg3200_read_raw(struct iio_dev *indio_dev, { int ret = 0; u8 reg; + u8 regval; switch (info) { case IIO_CHAN_INFO_RAW: @@ -107,65 +108,60 @@ static int itg3200_read_raw(struct iio_dev *indio_dev, /* Only the temperature channel has an offset */ *val = 23000; return IIO_VAL_INT; - default: - return -EINVAL; - } -} - -static ssize_t itg3200_read_frequency(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - int ret, sps; - u8 val; - - ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_DLPF, &val); - if (ret) - return ret; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_DLPF, ®val); + if (ret) + return ret; - sps = (val & ITG3200_DLPF_CFG_MASK) ? 1000 : 8000; + *val = (regval & ITG3200_DLPF_CFG_MASK) ? 1000 : 8000; - ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_SAMPLE_RATE_DIV, &val); - if (ret) - return ret; + ret = itg3200_read_reg_8(indio_dev, + ITG3200_REG_SAMPLE_RATE_DIV, + ®val); + if (ret) + return ret; - sps /= val + 1; + *val /= regval + 1; + return IIO_VAL_INT; - return sprintf(buf, "%d\n", sps); + default: + return -EINVAL; + } } -static ssize_t itg3200_write_frequency(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) +static int itg3200_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - unsigned val; int ret; u8 t; - ret = kstrtouint(buf, 10, &val); - if (ret) - return ret; + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + if (val == 0 || val2 != 0) + return -EINVAL; - mutex_lock(&indio_dev->mlock); + mutex_lock(&indio_dev->mlock); - ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_DLPF, &t); - if (ret) - goto err_ret; + ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_DLPF, &t); + if (ret) { + mutex_unlock(&indio_dev->mlock); + return ret; + } + t = ((t & ITG3200_DLPF_CFG_MASK) ? 1000u : 8000u) / val - 1; - if (val == 0) { - ret = -EINVAL; - goto err_ret; - } - t = ((t & ITG3200_DLPF_CFG_MASK) ? 1000u : 8000u) / val - 1; + ret = itg3200_write_reg_8(indio_dev, + ITG3200_REG_SAMPLE_RATE_DIV, + t); - ret = itg3200_write_reg_8(indio_dev, ITG3200_REG_SAMPLE_RATE_DIV, t); - -err_ret: - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&indio_dev->mlock); + return ret; - return ret ? ret : len; + default: + return -EINVAL; + } } /* @@ -255,6 +251,7 @@ err_ret: .channel2 = IIO_MOD_ ## _mod, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .address = ITG3200_REG_GYRO_ ## _mod ## OUT_H, \ .scan_index = ITG3200_SCAN_GYRO_ ## _mod, \ .scan_type = ITG3200_ST, \ @@ -267,6 +264,7 @@ static const struct iio_chan_spec itg3200_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = ITG3200_REG_TEMP_OUT_H, .scan_index = ITG3200_SCAN_TEMP, .scan_type = ITG3200_ST, @@ -277,22 +275,9 @@ static const struct iio_chan_spec itg3200_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(ITG3200_SCAN_ELEMENTS), }; -/* IIO device attributes */ -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, itg3200_read_frequency, - itg3200_write_frequency); - -static struct attribute *itg3200_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, - NULL -}; - -static const struct attribute_group itg3200_attribute_group = { - .attrs = itg3200_attributes, -}; - static const struct iio_info itg3200_info = { - .attrs = &itg3200_attribute_group, .read_raw = &itg3200_read_raw, + .write_raw = &itg3200_write_raw, .driver_module = THIS_MODULE, }; diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index ed74a9069989..f156fc6c5c6c 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -245,6 +245,9 @@ static int st_gyro_read_raw(struct iio_dev *indio_dev, *val = 0; *val2 = gdata->current_fullscale->gain; return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = gdata->odr; + return IIO_VAL_INT; default: return -EINVAL; } @@ -262,6 +265,13 @@ static int st_gyro_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: err = st_sensors_set_fullscale_by_gain(indio_dev, val2); break; + case IIO_CHAN_INFO_SAMP_FREQ: + if (val2) + return -EINVAL; + mutex_lock(&indio_dev->mlock); + err = st_sensors_set_odr(indio_dev, val); + mutex_unlock(&indio_dev->mlock); + return err; default: err = -EINVAL; } @@ -269,14 +279,12 @@ static int st_gyro_write_raw(struct iio_dev *indio_dev, return err; } -static ST_SENSOR_DEV_ATTR_SAMP_FREQ(); static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL(); static ST_SENSORS_DEV_ATTR_SCALE_AVAIL(in_anglvel_scale_available); static struct attribute *st_gyro_attributes[] = { &iio_dev_attr_sampling_frequency_available.dev_attr.attr, &iio_dev_attr_in_anglvel_scale_available.dev_attr.attr, - &iio_dev_attr_sampling_frequency.dev_attr.attr, NULL, }; diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c index 23c12f361b05..8fa0ad2ef4ef 100644 --- a/drivers/iio/gyro/st_gyro_i2c.c +++ b/drivers/iio/gyro/st_gyro_i2c.c @@ -18,6 +18,43 @@ #include <linux/iio/common/st_sensors_i2c.h> #include "st_gyro.h" +#ifdef CONFIG_OF +static const struct of_device_id st_gyro_of_match[] = { + { + .compatible = "st,l3g4200d-gyro", + .data = L3G4200D_GYRO_DEV_NAME, + }, + { + .compatible = "st,lsm330d-gyro", + .data = LSM330D_GYRO_DEV_NAME, + }, + { + .compatible = "st,lsm330dl-gyro", + .data = LSM330DL_GYRO_DEV_NAME, + }, + { + .compatible = "st,lsm330dlc-gyro", + .data = LSM330DLC_GYRO_DEV_NAME, + }, + { + .compatible = "st,l3gd20-gyro", + .data = L3GD20_GYRO_DEV_NAME, + }, + { + .compatible = "st,l3g4is-gyro", + .data = L3G4IS_GYRO_DEV_NAME, + }, + { + .compatible = "st,lsm330-gyro", + .data = LSM330_GYRO_DEV_NAME, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, st_gyro_of_match); +#else +#define st_gyro_of_match NULL +#endif + static int st_gyro_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -31,6 +68,7 @@ static int st_gyro_i2c_probe(struct i2c_client *client, gdata = iio_priv(indio_dev); gdata->dev = &client->dev; + st_sensors_of_i2c_probe(client, st_gyro_of_match); st_sensors_i2c_configure(indio_dev, client, gdata); @@ -65,6 +103,7 @@ static struct i2c_driver st_gyro_driver = { .driver = { .owner = THIS_MODULE, .name = "st-gyro-i2c", + .of_match_table = of_match_ptr(st_gyro_of_match), }, .probe = st_gyro_i2c_probe, .remove = st_gyro_i2c_remove, diff --git a/drivers/iio/imu/adis16400_buffer.c b/drivers/iio/imu/adis16400_buffer.c index f2cf829e5df1..6e727ffe5262 100644 --- a/drivers/iio/imu/adis16400_buffer.c +++ b/drivers/iio/imu/adis16400_buffer.c @@ -18,7 +18,7 @@ int adis16400_update_scan_mode(struct iio_dev *indio_dev, { struct adis16400_state *st = iio_priv(indio_dev); struct adis *adis = &st->adis; - uint16_t *tx, *rx; + uint16_t *tx; if (st->variant->flags & ADIS16400_NO_BURST) return adis_update_scan_mode(indio_dev, scan_mask); @@ -35,7 +35,6 @@ int adis16400_update_scan_mode(struct iio_dev *indio_dev, if (!adis->buffer) return -ENOMEM; - rx = adis->buffer; tx = adis->buffer + indio_dev->scan_bytes; tx[0] = ADIS_READ_REG(ADIS16400_GLOB_CMD); diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c index 433583b6f800..b70873de04ea 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400_core.c @@ -214,21 +214,6 @@ static int adis16400_set_freq(struct adis16400_state *st, unsigned int freq) return adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, val); } -static ssize_t adis16400_read_frequency(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct adis16400_state *st = iio_priv(indio_dev); - int ret; - - ret = st->variant->get_freq(st); - if (ret < 0) - return ret; - - return sprintf(buf, "%d.%.3d\n", ret / 1000, ret % 1000); -} - static const unsigned adis16400_3db_divisors[] = { [0] = 2, /* Special case */ [1] = 6, @@ -260,30 +245,6 @@ static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val) return ret; } -static ssize_t adis16400_write_frequency(struct device *dev, - struct device_attribute *attr, const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct adis16400_state *st = iio_priv(indio_dev); - int i, f, val; - int ret; - - ret = iio_str_to_fixpoint(buf, 100, &i, &f); - if (ret) - return ret; - - val = i * 1000 + f; - - if (val <= 0) - return -EINVAL; - - mutex_lock(&indio_dev->mlock); - st->variant->set_freq(st, val); - mutex_unlock(&indio_dev->mlock); - - return len; -} - /* Power down the device */ static int adis16400_stop_device(struct iio_dev *indio_dev) { @@ -350,10 +311,6 @@ err_ret: return ret; } -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, - adis16400_read_frequency, - adis16400_write_frequency); - static const uint8_t adis16400_addresses[] = { [ADIS16400_SCAN_GYRO_X] = ADIS16400_XGYRO_OFF, [ADIS16400_SCAN_GYRO_Y] = ADIS16400_YGYRO_OFF, @@ -394,6 +351,16 @@ static int adis16400_write_raw(struct iio_dev *indio_dev, val * 1000 + val2 / 1000); mutex_unlock(&indio_dev->mlock); return ret; + case IIO_CHAN_INFO_SAMP_FREQ: + sps = val * 1000 + val2 / 1000; + + if (sps <= 0) + return -EINVAL; + + mutex_lock(&indio_dev->mlock); + ret = st->variant->set_freq(st, sps); + mutex_unlock(&indio_dev->mlock); + return ret; default: return -EINVAL; } @@ -474,6 +441,13 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = st->variant->get_freq(st); + if (ret < 0) + return ret; + *val = ret / 1000; + *val2 = (ret % 1000) * 1000; + return IIO_VAL_INT_PLUS_MICRO; default: return -EINVAL; } @@ -486,6 +460,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, .extend_name = name, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .address = (addr), \ .scan_index = (si), \ .scan_type = { \ @@ -511,6 +486,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, BIT(IIO_CHAN_INFO_CALIBBIAS), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .address = addr, \ .scan_index = ADIS16400_SCAN_GYRO_ ## mod, \ .scan_type = { \ @@ -530,6 +506,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, BIT(IIO_CHAN_INFO_CALIBBIAS), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .address = (addr), \ .scan_index = ADIS16400_SCAN_ACC_ ## mod, \ .scan_type = { \ @@ -548,6 +525,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .address = (addr), \ .scan_index = ADIS16400_SCAN_MAGN_ ## mod, \ .scan_type = { \ @@ -573,6 +551,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, BIT(IIO_CHAN_INFO_SCALE), \ .info_mask_shared_by_type = \ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .address = (addr), \ .scan_index = ADIS16350_SCAN_TEMP_ ## mod, \ .scan_type = { \ @@ -591,6 +570,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_OFFSET) | \ BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .address = (addr), \ .scan_index = ADIS16350_SCAN_TEMP_X, \ .scan_type = { \ @@ -608,6 +588,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, .channel2 = IIO_MOD_ ## mod, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .address = (addr), \ .scan_index = ADIS16300_SCAN_INCLI_ ## mod, \ .scan_type = { \ @@ -649,6 +630,7 @@ static const struct iio_chan_spec adis16448_channels[] = { .type = IIO_PRESSURE, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = ADIS16448_BARO_OUT, .scan_index = ADIS16400_SCAN_BARO, .scan_type = { @@ -704,15 +686,6 @@ static const struct iio_chan_spec adis16334_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), }; -static struct attribute *adis16400_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, - NULL -}; - -static const struct attribute_group adis16400_attribute_group = { - .attrs = adis16400_attributes, -}; - static struct adis16400_chip_info adis16400_chips[] = { [ADIS16300] = { .channels = adis16300_channels, @@ -813,7 +786,6 @@ static const struct iio_info adis16400_info = { .driver_module = THIS_MODULE, .read_raw = &adis16400_read_raw, .write_raw = &adis16400_write_raw, - .attrs = &adis16400_attribute_group, .update_scan_mode = adis16400_update_scan_mode, .debugfs_reg_access = adis_debugfs_reg_access, }; diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index dd4206cac62d..989605dd6f78 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -257,11 +257,16 @@ static int adis16480_debugfs_init(struct iio_dev *indio_dev) #endif -static int adis16480_set_freq(struct adis16480 *st, unsigned int freq) +static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2) { + struct adis16480 *st = iio_priv(indio_dev); unsigned int t; - t = 2460000 / freq; + t = val * 1000 + val2 / 1000; + if (t <= 0) + return -EINVAL; + + t = 2460000 / t; if (t > 2048) t = 2048; @@ -271,65 +276,24 @@ static int adis16480_set_freq(struct adis16480 *st, unsigned int freq) return adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t); } -static int adis16480_get_freq(struct adis16480 *st, unsigned int *freq) +static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) { + struct adis16480 *st = iio_priv(indio_dev); uint16_t t; int ret; + unsigned freq; ret = adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t); if (ret < 0) return ret; - *freq = 2460000 / (t + 1); + freq = 2460000 / (t + 1); + *val = freq / 1000; + *val2 = (freq % 1000) * 1000; - return 0; + return IIO_VAL_INT_PLUS_MICRO; } -static ssize_t adis16480_read_frequency(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct adis16480 *st = iio_priv(indio_dev); - unsigned int freq; - int ret; - - ret = adis16480_get_freq(st, &freq); - if (ret < 0) - return ret; - - return sprintf(buf, "%d.%.3d\n", freq / 1000, freq % 1000); -} - -static ssize_t adis16480_write_frequency(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct adis16480 *st = iio_priv(indio_dev); - int freq_int, freq_fract; - long val; - int ret; - - ret = iio_str_to_fixpoint(buf, 100, &freq_int, &freq_fract); - if (ret) - return ret; - - val = freq_int * 1000 + freq_fract; - - if (val <= 0) - return -EINVAL; - - ret = adis16480_set_freq(st, val); - - return ret ? ret : len; -} - -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, - adis16480_read_frequency, - adis16480_write_frequency); - enum { ADIS16480_SCAN_GYRO_X, ADIS16480_SCAN_GYRO_Y, @@ -571,6 +535,8 @@ static int adis16480_read_raw(struct iio_dev *indio_dev, return adis16480_get_calibscale(indio_dev, chan, val); case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: return adis16480_get_filter_freq(indio_dev, chan, val); + case IIO_CHAN_INFO_SAMP_FREQ: + return adis16480_get_freq(indio_dev, val, val2); default: return -EINVAL; } @@ -586,6 +552,9 @@ static int adis16480_write_raw(struct iio_dev *indio_dev, return adis16480_set_calibscale(indio_dev, chan, val); case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: return adis16480_set_filter_freq(indio_dev, chan, val); + case IIO_CHAN_INFO_SAMP_FREQ: + return adis16480_set_freq(indio_dev, val, val2); + default: return -EINVAL; } @@ -600,6 +569,7 @@ static int adis16480_write_raw(struct iio_dev *indio_dev, BIT(IIO_CHAN_INFO_CALIBBIAS) | \ _info_sep, \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .address = (_address), \ .scan_index = (_si), \ .scan_type = { \ @@ -638,6 +608,7 @@ static int adis16480_write_raw(struct iio_dev *indio_dev, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_CALIBBIAS) | \ BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .address = ADIS16480_REG_BAROM_OUT, \ .scan_index = ADIS16480_SCAN_BARO, \ .scan_type = { \ @@ -655,6 +626,7 @@ static int adis16480_write_raw(struct iio_dev *indio_dev, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_SCALE) | \ BIT(IIO_CHAN_INFO_OFFSET), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .address = ADIS16480_REG_TEMP_OUT, \ .scan_index = ADIS16480_SCAN_TEMP, \ .scan_type = { \ @@ -717,17 +689,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { }, }; -static struct attribute *adis16480_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, - NULL -}; - -static const struct attribute_group adis16480_attribute_group = { - .attrs = adis16480_attributes, -}; - static const struct iio_info adis16480_info = { - .attrs = &adis16480_attribute_group, .read_raw = &adis16480_read_raw, .write_raw = &adis16480_write_raw, .update_scan_mode = adis_update_scan_mode, diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 9f1a14009901..0472ee268271 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -39,10 +39,7 @@ static bool iio_buffer_is_active(struct iio_buffer *buf) static bool iio_buffer_data_available(struct iio_buffer *buf) { - if (buf->access->data_available) - return buf->access->data_available(buf); - - return buf->stufftoread; + return buf->access->data_available(buf); } /** diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 4b1f375c5659..af3e76d652ba 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -87,6 +87,10 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_QUATERNION] = "quaternion", [IIO_MOD_TEMP_AMBIENT] = "ambient", [IIO_MOD_TEMP_OBJECT] = "object", + [IIO_MOD_NORTH_MAGN] = "from_north_magnetic", + [IIO_MOD_NORTH_TRUE] = "from_north_true", + [IIO_MOD_NORTH_MAGN_TILT_COMP] = "from_north_magnetic_tilt_comp", + [IIO_MOD_NORTH_TRUE_TILT_COMP] = "from_north_true_tilt_comp", }; /* relies on pairs of these shared then separate */ diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index bfbf4d419f41..0c1e37e3120a 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -209,6 +209,7 @@ static const char * const iio_ev_info_text[] = { [IIO_EV_INFO_ENABLE] = "en", [IIO_EV_INFO_VALUE] = "value", [IIO_EV_INFO_HYSTERESIS] = "hysteresis", + [IIO_EV_INFO_PERIOD] = "period", }; static enum iio_event_direction iio_ev_attr_dir(struct iio_dev_attr *attr) diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 3383b025f62e..d31098e0c43f 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -114,7 +114,7 @@ static struct iio_trigger *iio_trigger_find_by_name(const char *name, return trig; } -void iio_trigger_poll(struct iio_trigger *trig, s64 time) +void iio_trigger_poll(struct iio_trigger *trig) { int i; @@ -133,12 +133,12 @@ EXPORT_SYMBOL(iio_trigger_poll); irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private) { - iio_trigger_poll(private, iio_get_time_ns()); + iio_trigger_poll(private); return IRQ_HANDLED; } EXPORT_SYMBOL(iio_trigger_generic_data_rdy_poll); -void iio_trigger_poll_chained(struct iio_trigger *trig, s64 time) +void iio_trigger_poll_chained(struct iio_trigger *trig) { int i; @@ -161,7 +161,7 @@ void iio_trigger_notify_done(struct iio_trigger *trig) trig->ops->try_reenable) if (trig->ops->try_reenable(trig)) /* Missed an interrupt so launch new poll now */ - iio_trigger_poll(trig, 0); + iio_trigger_poll(trig); } EXPORT_SYMBOL(iio_trigger_notify_done); diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index c89740d4748f..bf05ca5b0a57 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -62,6 +62,18 @@ config GP2AP020A00F To compile this driver as a module, choose M here: the module will be called gp2ap020a00f. +config ISL29125 + tristate "Intersil ISL29125 digital color light sensor" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say Y here if you want to build a driver for the Intersil ISL29125 + RGB light sensor for I2C. + + To compile this driver as a module, choose M here: the module will be + called isl29125. + config HID_SENSOR_ALS depends on HID_SENSOR_HUB select IIO_BUFFER @@ -116,6 +128,18 @@ config LTR501 This driver can also be built as a module. If so, the module will be called ltr501. +config TCS3414 + tristate "TAOS TCS3414 digital color sensor" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + If you say yes here you get support for the TAOS TCS3414 + family of digital color sensors. + + This driver can also be built as a module. If so, the module + will be called tcs3414. + config TCS3472 tristate "TAOS TCS3472 color light-to-digital converter" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 3eb36e5151fa..8b8c09f9c1f8 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -10,9 +10,11 @@ obj-$(CONFIG_CM36651) += cm36651.o obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o obj-$(CONFIG_HID_SENSOR_PROX) += hid-sensor-prox.o +obj-$(CONFIG_ISL29125) += isl29125.o obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o obj-$(CONFIG_LTR501) += ltr501.o obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o +obj-$(CONFIG_TCS3414) += tcs3414.o obj-$(CONFIG_TCS3472) += tcs3472.o obj-$(CONFIG_TSL4531) += tsl4531.o obj-$(CONFIG_VCNL4000) += vcnl4000.o diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c index d976e6ce60db..ad36b294e4d5 100644 --- a/drivers/iio/light/cm32181.c +++ b/drivers/iio/light/cm32181.c @@ -331,7 +331,7 @@ static int cm32181_probe(struct i2c_client *client, return ret; } - ret = iio_device_register(indio_dev); + ret = devm_iio_device_register(&client->dev, indio_dev); if (ret) { dev_err(&client->dev, "%s: regist device failed\n", @@ -342,14 +342,6 @@ static int cm32181_probe(struct i2c_client *client, return 0; } -static int cm32181_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - iio_device_unregister(indio_dev); - return 0; -} - static const struct i2c_device_id cm32181_id[] = { { "cm32181", 0 }, { } @@ -370,7 +362,6 @@ static struct i2c_driver cm32181_driver = { }, .id_table = cm32181_id, .probe = cm32181_probe, - .remove = cm32181_remove, }; module_i2c_driver(cm32181_driver); diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index 04bdb85d2d9f..221ed16de1f7 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -827,7 +827,7 @@ static void gp2ap020a00f_iio_trigger_work(struct irq_work *work) struct gp2ap020a00f_data *data = container_of(work, struct gp2ap020a00f_data, work); - iio_trigger_poll(data->trig, 0); + iio_trigger_poll(data->trig); } static irqreturn_t gp2ap020a00f_prox_sensing_handler(int irq, void *data) diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c new file mode 100644 index 000000000000..c82f4a6f8464 --- /dev/null +++ b/drivers/iio/light/isl29125.c @@ -0,0 +1,347 @@ +/* + * isl29125.c - Support for Intersil ISL29125 RGB light sensor + * + * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net> + * + * 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 + * directory of this archive for more details. + * + * RGB light sensor with 16-bit channels for red, green, blue); + * 7-bit I2C slave address 0x44 + * + * TODO: interrupt support, IR compensation, thresholds, 12bit + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/pm.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/buffer.h> +#include <linux/iio/triggered_buffer.h> + +#define ISL29125_DRV_NAME "isl29125" + +#define ISL29125_DEVICE_ID 0x00 +#define ISL29125_CONF1 0x01 +#define ISL29125_CONF2 0x02 +#define ISL29125_CONF3 0x03 +#define ISL29125_STATUS 0x08 +#define ISL29125_GREEN_DATA 0x09 +#define ISL29125_RED_DATA 0x0b +#define ISL29125_BLUE_DATA 0x0d + +#define ISL29125_ID 0x7d + +#define ISL29125_MODE_MASK GENMASK(2, 0) +#define ISL29125_MODE_PD 0x0 +#define ISL29125_MODE_G 0x1 +#define ISL29125_MODE_R 0x2 +#define ISL29125_MODE_B 0x3 +#define ISL29125_MODE_RGB 0x5 + +#define ISL29125_MODE_RANGE BIT(3) + +#define ISL29125_STATUS_CONV BIT(1) + +struct isl29125_data { + struct i2c_client *client; + struct mutex lock; + u8 conf1; + u16 buffer[8]; /* 3x 16-bit, padding, 8 bytes timestamp */ +}; + +#define ISL29125_CHANNEL(_color, _si) { \ + .type = IIO_INTENSITY, \ + .modified = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .channel2 = IIO_MOD_LIGHT_##_color, \ + .scan_index = _si, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ +} + +static const struct iio_chan_spec isl29125_channels[] = { + ISL29125_CHANNEL(GREEN, 0), + ISL29125_CHANNEL(RED, 1), + ISL29125_CHANNEL(BLUE, 2), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static const struct { + u8 mode, data; +} isl29125_regs[] = { + {ISL29125_MODE_G, ISL29125_GREEN_DATA}, + {ISL29125_MODE_R, ISL29125_RED_DATA}, + {ISL29125_MODE_B, ISL29125_BLUE_DATA}, +}; + +static int isl29125_read_data(struct isl29125_data *data, int si) +{ + int tries = 5; + int ret; + + ret = i2c_smbus_write_byte_data(data->client, ISL29125_CONF1, + data->conf1 | isl29125_regs[si].mode); + if (ret < 0) + return ret; + + msleep(101); + + while (tries--) { + ret = i2c_smbus_read_byte_data(data->client, ISL29125_STATUS); + if (ret < 0) + goto fail; + if (ret & ISL29125_STATUS_CONV) + break; + msleep(20); + } + + if (tries < 0) { + dev_err(&data->client->dev, "data not ready\n"); + ret = -EIO; + goto fail; + } + + ret = i2c_smbus_read_word_data(data->client, isl29125_regs[si].data); + +fail: + i2c_smbus_write_byte_data(data->client, ISL29125_CONF1, data->conf1); + return ret; +} + +static int isl29125_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct isl29125_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + mutex_lock(&data->lock); + ret = isl29125_read_data(data, chan->scan_index); + mutex_unlock(&data->lock); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + if (data->conf1 & ISL29125_MODE_RANGE) + *val2 = 152590; /* 10k lux full range */ + else + *val2 = 5722; /* 375 lux full range */ + return IIO_VAL_INT_PLUS_MICRO; + } + return -EINVAL; +} + +static int isl29125_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct isl29125_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + if (val != 0) + return -EINVAL; + if (val2 == 152590) + data->conf1 |= ISL29125_MODE_RANGE; + else if (val2 == 5722) + data->conf1 &= ~ISL29125_MODE_RANGE; + else + return -EINVAL; + return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1, + data->conf1); + default: + return -EINVAL; + } +} + +static irqreturn_t isl29125_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct isl29125_data *data = iio_priv(indio_dev); + int i, j = 0; + + for_each_set_bit(i, indio_dev->active_scan_mask, + indio_dev->masklength) { + int ret = i2c_smbus_read_word_data(data->client, + isl29125_regs[i].data); + if (ret < 0) + goto done; + + data->buffer[j++] = ret; + } + + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_get_time_ns()); + +done: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static const struct iio_info isl29125_info = { + .read_raw = isl29125_read_raw, + .write_raw = isl29125_write_raw, + .driver_module = THIS_MODULE, +}; + +static int isl29125_buffer_preenable(struct iio_dev *indio_dev) +{ + struct isl29125_data *data = iio_priv(indio_dev); + + data->conf1 |= ISL29125_MODE_RGB; + return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1, + data->conf1); +} + +static int isl29125_buffer_predisable(struct iio_dev *indio_dev) +{ + struct isl29125_data *data = iio_priv(indio_dev); + int ret; + + ret = iio_triggered_buffer_predisable(indio_dev); + if (ret < 0) + return ret; + + data->conf1 &= ~ISL29125_MODE_MASK; + data->conf1 |= ISL29125_MODE_PD; + return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1, + data->conf1); +} + +static const struct iio_buffer_setup_ops isl29125_buffer_setup_ops = { + .preenable = isl29125_buffer_preenable, + .postenable = &iio_triggered_buffer_postenable, + .predisable = isl29125_buffer_predisable, +}; + +static int isl29125_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct isl29125_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (indio_dev == NULL) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + mutex_init(&data->lock); + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &isl29125_info; + indio_dev->name = ISL29125_DRV_NAME; + indio_dev->channels = isl29125_channels; + indio_dev->num_channels = ARRAY_SIZE(isl29125_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = i2c_smbus_read_byte_data(data->client, ISL29125_DEVICE_ID); + if (ret < 0) + return ret; + if (ret != ISL29125_ID) + return -ENODEV; + + data->conf1 = ISL29125_MODE_PD | ISL29125_MODE_RANGE; + ret = i2c_smbus_write_byte_data(data->client, ISL29125_CONF1, + data->conf1); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(data->client, ISL29125_STATUS, 0); + if (ret < 0) + return ret; + + ret = iio_triggered_buffer_setup(indio_dev, NULL, + isl29125_trigger_handler, &isl29125_buffer_setup_ops); + if (ret < 0) + return ret; + + ret = iio_device_register(indio_dev); + if (ret < 0) + goto buffer_cleanup; + + return 0; + +buffer_cleanup: + iio_triggered_buffer_cleanup(indio_dev); + return ret; +} + +static int isl29125_powerdown(struct isl29125_data *data) +{ + return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1, + (data->conf1 & ~ISL29125_MODE_MASK) | ISL29125_MODE_PD); +} + +static int isl29125_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + isl29125_powerdown(iio_priv(indio_dev)); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int isl29125_suspend(struct device *dev) +{ + struct isl29125_data *data = iio_priv(i2c_get_clientdata( + to_i2c_client(dev))); + return isl29125_powerdown(data); +} + +static int isl29125_resume(struct device *dev) +{ + struct isl29125_data *data = iio_priv(i2c_get_clientdata( + to_i2c_client(dev))); + return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1, + data->conf1); +} +#endif + +static SIMPLE_DEV_PM_OPS(isl29125_pm_ops, isl29125_suspend, isl29125_resume); + +static const struct i2c_device_id isl29125_id[] = { + { "isl29125", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, isl29125_id); + +static struct i2c_driver isl29125_driver = { + .driver = { + .name = ISL29125_DRV_NAME, + .pm = &isl29125_pm_ops, + .owner = THIS_MODULE, + }, + .probe = isl29125_probe, + .remove = isl29125_remove, + .id_table = isl29125_id, +}; +module_i2c_driver(isl29125_driver); + +MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); +MODULE_DESCRIPTION("ISL29125 RGB light sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c new file mode 100644 index 000000000000..a9e449b0be0c --- /dev/null +++ b/drivers/iio/light/tcs3414.c @@ -0,0 +1,405 @@ +/* + * tcs3414.c - Support for TAOS TCS3414 digital color sensor + * + * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net> + * + * 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 + * directory of this archive for more details. + * + * Digital color sensor with 16-bit channels for red, green, blue, clear); + * 7-bit I2C slave address 0x39 (TCS3414) or 0x29, 0x49, 0x59 (TCS3413, + * TCS3415, TCS3416, resp.) + * + * TODO: sync, interrupt support, thresholds, prescaler + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/pm.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/buffer.h> +#include <linux/iio/triggered_buffer.h> + +#define TCS3414_DRV_NAME "tcs3414" + +#define TCS3414_COMMAND BIT(7) +#define TCS3414_COMMAND_WORD (TCS3414_COMMAND | BIT(5)) + +#define TCS3414_CONTROL (TCS3414_COMMAND | 0x00) +#define TCS3414_TIMING (TCS3414_COMMAND | 0x01) +#define TCS3414_ID (TCS3414_COMMAND | 0x04) +#define TCS3414_GAIN (TCS3414_COMMAND | 0x07) +#define TCS3414_DATA_GREEN (TCS3414_COMMAND_WORD | 0x10) +#define TCS3414_DATA_RED (TCS3414_COMMAND_WORD | 0x12) +#define TCS3414_DATA_BLUE (TCS3414_COMMAND_WORD | 0x14) +#define TCS3414_DATA_CLEAR (TCS3414_COMMAND_WORD | 0x16) + +#define TCS3414_CONTROL_ADC_VALID BIT(4) +#define TCS3414_CONTROL_ADC_EN BIT(1) +#define TCS3414_CONTROL_POWER BIT(0) + +#define TCS3414_INTEG_MASK GENMASK(1, 0) +#define TCS3414_INTEG_12MS 0x0 +#define TCS3414_INTEG_100MS 0x1 +#define TCS3414_INTEG_400MS 0x2 + +#define TCS3414_GAIN_MASK GENMASK(5, 4) +#define TCS3414_GAIN_SHIFT 4 + +struct tcs3414_data { + struct i2c_client *client; + struct mutex lock; + u8 control; + u8 gain; + u8 timing; + u16 buffer[8]; /* 4x 16-bit + 8 bytes timestamp */ +}; + +#define TCS3414_CHANNEL(_color, _si, _addr) { \ + .type = IIO_INTENSITY, \ + .modified = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_INT_TIME), \ + .channel2 = IIO_MOD_LIGHT_##_color, \ + .address = _addr, \ + .scan_index = _si, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ +} + +/* scale factors: 1/gain */ +static const int tcs3414_scales[][2] = { + {1, 0}, {0, 250000}, {0, 62500}, {0, 15625} +}; + +/* integration time in ms */ +static const int tcs3414_times[] = { 12, 100, 400 }; + +static const struct iio_chan_spec tcs3414_channels[] = { + TCS3414_CHANNEL(GREEN, 0, TCS3414_DATA_GREEN), + TCS3414_CHANNEL(RED, 1, TCS3414_DATA_RED), + TCS3414_CHANNEL(BLUE, 2, TCS3414_DATA_BLUE), + TCS3414_CHANNEL(CLEAR, 3, TCS3414_DATA_CLEAR), + IIO_CHAN_SOFT_TIMESTAMP(4), +}; + +static int tcs3414_req_data(struct tcs3414_data *data) +{ + int tries = 25; + int ret; + + ret = i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL, + data->control | TCS3414_CONTROL_ADC_EN); + if (ret < 0) + return ret; + + while (tries--) { + ret = i2c_smbus_read_byte_data(data->client, TCS3414_CONTROL); + if (ret < 0) + return ret; + if (ret & TCS3414_CONTROL_ADC_VALID) + break; + msleep(20); + } + + ret = i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL, + data->control); + if (ret < 0) + return ret; + + if (tries < 0) { + dev_err(&data->client->dev, "data not ready\n"); + return -EIO; + } + + return 0; +} + +static int tcs3414_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct tcs3414_data *data = iio_priv(indio_dev); + int i, ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + mutex_lock(&data->lock); + ret = tcs3414_req_data(data); + if (ret < 0) { + mutex_unlock(&data->lock); + return ret; + } + ret = i2c_smbus_read_word_data(data->client, chan->address); + mutex_unlock(&data->lock); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + i = (data->gain & TCS3414_GAIN_MASK) >> TCS3414_GAIN_SHIFT; + *val = tcs3414_scales[i][0]; + *val2 = tcs3414_scales[i][1]; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_INT_TIME: + *val = 0; + *val2 = tcs3414_times[data->timing & TCS3414_INTEG_MASK] * 1000; + return IIO_VAL_INT_PLUS_MICRO; + } + return -EINVAL; +} + +static int tcs3414_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct tcs3414_data *data = iio_priv(indio_dev); + int i; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + for (i = 0; i < ARRAY_SIZE(tcs3414_scales); i++) { + if (val == tcs3414_scales[i][0] && + val2 == tcs3414_scales[i][1]) { + data->gain &= ~TCS3414_GAIN_MASK; + data->gain |= i << TCS3414_GAIN_SHIFT; + return i2c_smbus_write_byte_data( + data->client, TCS3414_GAIN, + data->gain); + } + } + return -EINVAL; + case IIO_CHAN_INFO_INT_TIME: + if (val != 0) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(tcs3414_times); i++) { + if (val == tcs3414_times[i] * 1000) { + data->timing &= ~TCS3414_INTEG_MASK; + data->timing |= i; + return i2c_smbus_write_byte_data( + data->client, TCS3414_TIMING, + data->timing); + } + } + return -EINVAL; + default: + return -EINVAL; + } +} + +static irqreturn_t tcs3414_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct tcs3414_data *data = iio_priv(indio_dev); + int i, j = 0; + + for_each_set_bit(i, indio_dev->active_scan_mask, + indio_dev->masklength) { + int ret = i2c_smbus_read_word_data(data->client, + TCS3414_DATA_GREEN + 2*i); + if (ret < 0) + goto done; + + data->buffer[j++] = ret; + } + + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_get_time_ns()); + +done: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static IIO_CONST_ATTR(scale_available, "1 0.25 0.0625 0.015625"); +static IIO_CONST_ATTR_INT_TIME_AVAIL("0.012 0.1 0.4"); + +static struct attribute *tcs3414_attributes[] = { + &iio_const_attr_scale_available.dev_attr.attr, + &iio_const_attr_integration_time_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group tcs3414_attribute_group = { + .attrs = tcs3414_attributes, +}; + +static const struct iio_info tcs3414_info = { + .read_raw = tcs3414_read_raw, + .write_raw = tcs3414_write_raw, + .attrs = &tcs3414_attribute_group, + .driver_module = THIS_MODULE, +}; + +static int tcs3414_buffer_preenable(struct iio_dev *indio_dev) +{ + struct tcs3414_data *data = iio_priv(indio_dev); + + data->control |= TCS3414_CONTROL_ADC_EN; + return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL, + data->control); +} + +static int tcs3414_buffer_predisable(struct iio_dev *indio_dev) +{ + struct tcs3414_data *data = iio_priv(indio_dev); + int ret; + + ret = iio_triggered_buffer_predisable(indio_dev); + if (ret < 0) + return ret; + + data->control &= ~TCS3414_CONTROL_ADC_EN; + return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL, + data->control); +} + +static const struct iio_buffer_setup_ops tcs3414_buffer_setup_ops = { + .preenable = tcs3414_buffer_preenable, + .postenable = &iio_triggered_buffer_postenable, + .predisable = tcs3414_buffer_predisable, +}; + +static int tcs3414_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tcs3414_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (indio_dev == NULL) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + mutex_init(&data->lock); + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &tcs3414_info; + indio_dev->name = TCS3414_DRV_NAME; + indio_dev->channels = tcs3414_channels; + indio_dev->num_channels = ARRAY_SIZE(tcs3414_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = i2c_smbus_read_byte_data(data->client, TCS3414_ID); + if (ret < 0) + return ret; + + switch (ret & 0xf0) { + case 0x00: + dev_info(&client->dev, "TCS3404 found\n"); + break; + case 0x10: + dev_info(&client->dev, "TCS3413/14/15/16 found\n"); + break; + default: + return -ENODEV; + } + + data->control = TCS3414_CONTROL_POWER; + ret = i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL, + data->control); + if (ret < 0) + return ret; + + data->timing = TCS3414_INTEG_12MS; /* free running */ + ret = i2c_smbus_write_byte_data(data->client, TCS3414_TIMING, + data->timing); + if (ret < 0) + return ret; + + ret = i2c_smbus_read_byte_data(data->client, TCS3414_GAIN); + if (ret < 0) + return ret; + data->gain = ret; + + ret = iio_triggered_buffer_setup(indio_dev, NULL, + tcs3414_trigger_handler, &tcs3414_buffer_setup_ops); + if (ret < 0) + return ret; + + ret = iio_device_register(indio_dev); + if (ret < 0) + goto buffer_cleanup; + + return 0; + +buffer_cleanup: + iio_triggered_buffer_cleanup(indio_dev); + return ret; +} + +static int tcs3414_powerdown(struct tcs3414_data *data) +{ + return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL, + data->control & ~(TCS3414_CONTROL_POWER | + TCS3414_CONTROL_ADC_EN)); +} + +static int tcs3414_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + tcs3414_powerdown(iio_priv(indio_dev)); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int tcs3414_suspend(struct device *dev) +{ + struct tcs3414_data *data = iio_priv(i2c_get_clientdata( + to_i2c_client(dev))); + return tcs3414_powerdown(data); +} + +static int tcs3414_resume(struct device *dev) +{ + struct tcs3414_data *data = iio_priv(i2c_get_clientdata( + to_i2c_client(dev))); + return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL, + data->control); +} +#endif + +static SIMPLE_DEV_PM_OPS(tcs3414_pm_ops, tcs3414_suspend, tcs3414_resume); + +static const struct i2c_device_id tcs3414_id[] = { + { "tcs3414", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tcs3414_id); + +static struct i2c_driver tcs3414_driver = { + .driver = { + .name = TCS3414_DRV_NAME, + .pm = &tcs3414_pm_ops, + .owner = THIS_MODULE, + }, + .probe = tcs3414_probe, + .remove = tcs3414_remove, + .id_table = tcs3414_id, +}; +module_i2c_driver(tcs3414_driver); + +MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); +MODULE_DESCRIPTION("TCS3414 digital color sensors driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index 05a364c543f8..b2dba9e506ab 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -17,6 +17,16 @@ config AK8975 To compile this driver as a module, choose M here: the module will be called ak8975. +config AK09911 + tristate "Asahi Kasei AK09911 3-axis Compass" + depends on I2C + help + Say yes here to build support for Asahi Kasei AK09911 3-Axis + Magnetometer. + + To compile this driver as a module, choose M here: the module + will be called ak09911. + config MAG3110 tristate "Freescale MAG3110 3-Axis Magnetometer" depends on I2C diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile index 0f5d3c985799..b91315e0b826 100644 --- a/drivers/iio/magnetometer/Makefile +++ b/drivers/iio/magnetometer/Makefile @@ -3,6 +3,7 @@ # # When adding new entries keep the list in alphabetical order +obj-$(CONFIG_AK09911) += ak09911.o obj-$(CONFIG_AK8975) += ak8975.o obj-$(CONFIG_MAG3110) += mag3110.o obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o diff --git a/drivers/iio/magnetometer/ak09911.c b/drivers/iio/magnetometer/ak09911.c new file mode 100644 index 000000000000..b2bc942ff6b8 --- /dev/null +++ b/drivers/iio/magnetometer/ak09911.c @@ -0,0 +1,326 @@ +/* + * AK09911 3-axis compass driver + * Copyright (c) 2014, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/acpi.h> +#include <linux/iio/iio.h> + +#define AK09911_REG_WIA1 0x00 +#define AK09911_REG_WIA2 0x01 +#define AK09911_WIA1_VALUE 0x48 +#define AK09911_WIA2_VALUE 0x05 + +#define AK09911_REG_ST1 0x10 +#define AK09911_REG_HXL 0x11 +#define AK09911_REG_HXH 0x12 +#define AK09911_REG_HYL 0x13 +#define AK09911_REG_HYH 0x14 +#define AK09911_REG_HZL 0x15 +#define AK09911_REG_HZH 0x16 + +#define AK09911_REG_ASAX 0x60 +#define AK09911_REG_ASAY 0x61 +#define AK09911_REG_ASAZ 0x62 + +#define AK09911_REG_CNTL1 0x30 +#define AK09911_REG_CNTL2 0x31 +#define AK09911_REG_CNTL3 0x32 + +#define AK09911_MODE_SNG_MEASURE 0x01 +#define AK09911_MODE_SELF_TEST 0x10 +#define AK09911_MODE_FUSE_ACCESS 0x1F +#define AK09911_MODE_POWERDOWN 0x00 +#define AK09911_RESET_DATA 0x01 + +#define AK09911_REG_CNTL1 0x30 +#define AK09911_REG_CNTL2 0x31 +#define AK09911_REG_CNTL3 0x32 + +#define AK09911_RAW_TO_GAUSS(asa) ((((asa) + 128) * 6000) / 256) + +#define AK09911_MAX_CONVERSION_TIMEOUT_MS 500 +#define AK09911_CONVERSION_DONE_POLL_TIME_MS 10 + +struct ak09911_data { + struct i2c_client *client; + struct mutex lock; + u8 asa[3]; + long raw_to_gauss[3]; +}; + +static const int ak09911_index_to_reg[] = { + AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL, +}; + +static int ak09911_set_mode(struct i2c_client *client, u8 mode) +{ + int ret; + + switch (mode) { + case AK09911_MODE_SNG_MEASURE: + case AK09911_MODE_SELF_TEST: + case AK09911_MODE_FUSE_ACCESS: + case AK09911_MODE_POWERDOWN: + ret = i2c_smbus_write_byte_data(client, + AK09911_REG_CNTL2, mode); + if (ret < 0) { + dev_err(&client->dev, "set_mode error\n"); + return ret; + } + /* After mode change wait atleast 100us */ + usleep_range(100, 500); + break; + default: + dev_err(&client->dev, + "%s: Unknown mode(%d).", __func__, mode); + return -EINVAL; + } + + return ret; +} + +/* Get Sensitivity Adjustment value */ +static int ak09911_get_asa(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct ak09911_data *data = iio_priv(indio_dev); + int ret; + + ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS); + if (ret < 0) + return ret; + + /* Get asa data and store in the device data. */ + ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX, + 3, data->asa); + if (ret < 0) { + dev_err(&client->dev, "Not able to read asa data\n"); + return ret; + } + + ret = ak09911_set_mode(client, AK09911_MODE_POWERDOWN); + if (ret < 0) + return ret; + + data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]); + data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]); + data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]); + + return 0; +} + +static int ak09911_verify_chip_id(struct i2c_client *client) +{ + u8 wia_val[2]; + int ret; + + ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1, + 2, wia_val); + if (ret < 0) { + dev_err(&client->dev, "Error reading WIA\n"); + return ret; + } + + dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]); + + if (wia_val[0] != AK09911_WIA1_VALUE || + wia_val[1] != AK09911_WIA2_VALUE) { + dev_err(&client->dev, "Device ak09911 not found\n"); + return -ENODEV; + } + + return 0; +} + +static int wait_conversion_complete_polled(struct ak09911_data *data) +{ + struct i2c_client *client = data->client; + u8 read_status; + u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS; + int ret; + + /* Wait for the conversion to complete. */ + while (timeout_ms) { + msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS); + ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1); + if (ret < 0) { + dev_err(&client->dev, "Error in reading ST1\n"); + return ret; + } + read_status = ret & 0x01; + if (read_status) + break; + timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS; + } + if (!timeout_ms) { + dev_err(&client->dev, "Conversion timeout happened\n"); + return -EIO; + } + + return read_status; +} + +static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val) +{ + struct ak09911_data *data = iio_priv(indio_dev); + struct i2c_client *client = data->client; + int ret; + + mutex_lock(&data->lock); + + ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE); + if (ret < 0) + goto fn_exit; + + ret = wait_conversion_complete_polled(data); + if (ret < 0) + goto fn_exit; + + /* Read data */ + ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]); + if (ret < 0) { + dev_err(&client->dev, "Read axis data fails\n"); + goto fn_exit; + } + + mutex_unlock(&data->lock); + + /* Clamp to valid range. */ + *val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13); + + return IIO_VAL_INT; + +fn_exit: + mutex_unlock(&data->lock); + + return ret; +} + +static int ak09911_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, + long mask) +{ + struct ak09911_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return ak09911_read_axis(indio_dev, chan->address, val); + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = data->raw_to_gauss[chan->address]; + return IIO_VAL_INT_PLUS_MICRO; + } + + return -EINVAL; +} + +#define AK09911_CHANNEL(axis, index) \ + { \ + .type = IIO_MAGN, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .address = index, \ + } + +static const struct iio_chan_spec ak09911_channels[] = { + AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2), +}; + +static const struct iio_info ak09911_info = { + .read_raw = &ak09911_read_raw, + .driver_module = THIS_MODULE, +}; + +static const struct acpi_device_id ak_acpi_match[] = { + {"AK009911", 0}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, ak_acpi_match); + +static int ak09911_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct ak09911_data *data; + const char *name; + int ret; + + ret = ak09911_verify_chip_id(client); + if (ret) { + dev_err(&client->dev, "AK00911 not detected\n"); + return -ENODEV; + } + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (indio_dev == NULL) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + + data->client = client; + mutex_init(&data->lock); + + ret = ak09911_get_asa(client); + if (ret) + return ret; + + if (id) + name = id->name; + else if (ACPI_HANDLE(&client->dev)) + name = dev_name(&client->dev); + else + return -ENODEV; + + dev_dbg(&client->dev, "Asahi compass chip %s\n", name); + + indio_dev->dev.parent = &client->dev; + indio_dev->channels = ak09911_channels; + indio_dev->num_channels = ARRAY_SIZE(ak09911_channels); + indio_dev->info = &ak09911_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->name = name; + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static const struct i2c_device_id ak09911_id[] = { + {"ak09911", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ak09911_id); + +static struct i2c_driver ak09911_driver = { + .driver = { + .name = "ak09911", + .acpi_match_table = ACPI_PTR(ak_acpi_match), + }, + .probe = ak09911_probe, + .id_table = ak09911_id, +}; +module_i2c_driver(ak09911_driver); + +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("AK09911 Compass driver"); diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index ea08313af0d2..a2357921d761 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -165,7 +165,7 @@ static int ak8975_setup_irq(struct ak8975_data *data) else irq = gpio_to_irq(data->eoc_gpio); - rc = request_irq(irq, ak8975_irq_handler, + rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler, IRQF_TRIGGER_RISING | IRQF_ONESHOT, dev_name(&client->dev), data); if (rc < 0) { @@ -513,21 +513,21 @@ static int ak8975_probe(struct i2c_client *client, /* We may not have a GPIO based IRQ to scan, that is fine, we will poll if so */ if (gpio_is_valid(eoc_gpio)) { - err = gpio_request_one(eoc_gpio, GPIOF_IN, "ak_8975"); + err = devm_gpio_request_one(&client->dev, eoc_gpio, + GPIOF_IN, "ak_8975"); if (err < 0) { dev_err(&client->dev, "failed to request GPIO %d, error %d\n", eoc_gpio, err); - goto exit; + return err; } } /* Register with IIO */ - indio_dev = iio_device_alloc(sizeof(*data)); - if (indio_dev == NULL) { - err = -ENOMEM; - goto exit_gpio; - } + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (indio_dev == NULL) + return -ENOMEM; + data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); @@ -542,17 +542,16 @@ static int ak8975_probe(struct i2c_client *client, name = (char *) id->name; } else if (ACPI_HANDLE(&client->dev)) name = ak8975_match_acpi_device(&client->dev, &data->chipset); - else { - err = -ENOSYS; - goto exit_free_iio; - } + else + return -ENOSYS; + dev_dbg(&client->dev, "Asahi compass chip %s\n", name); /* Perform some basic start-of-day setup of the device. */ err = ak8975_setup(client); if (err < 0) { dev_err(&client->dev, "AK8975 initialization fails\n"); - goto exit_free_iio; + return err; } data->client = client; @@ -564,37 +563,9 @@ static int ak8975_probe(struct i2c_client *client, indio_dev->info = &ak8975_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->name = name; - err = iio_device_register(indio_dev); + err = devm_iio_device_register(&client->dev, indio_dev); if (err < 0) - goto exit_free_iio; - - return 0; - -exit_free_iio: - iio_device_free(indio_dev); - if (data->eoc_irq) - free_irq(data->eoc_irq, data); -exit_gpio: - if (gpio_is_valid(eoc_gpio)) - gpio_free(eoc_gpio); -exit: - return err; -} - -static int ak8975_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct ak8975_data *data = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - - if (data->eoc_irq) - free_irq(data->eoc_irq, data); - - if (gpio_is_valid(data->eoc_gpio)) - gpio_free(data->eoc_gpio); - - iio_device_free(indio_dev); + return err; return 0; } @@ -621,7 +592,6 @@ static struct i2c_driver ak8975_driver = { .acpi_match_table = ACPI_PTR(ak_acpi_match), }, .probe = ak8975_probe, - .remove = ak8975_remove, .id_table = ak8975_id, }; module_i2c_driver(ak8975_driver); diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index b2b0937d5133..3ec777a8f64e 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -35,6 +35,10 @@ enum magn_3d_channel { CHANNEL_SCAN_INDEX_X, CHANNEL_SCAN_INDEX_Y, CHANNEL_SCAN_INDEX_Z, + CHANNEL_SCAN_INDEX_NORTH_MAGN_TILT_COMP, + CHANNEL_SCAN_INDEX_NORTH_TRUE_TILT_COMP, + CHANNEL_SCAN_INDEX_NORTH_MAGN, + CHANNEL_SCAN_INDEX_NORTH_TRUE, MAGN_3D_CHANNEL_MAX, }; @@ -42,7 +46,12 @@ struct magn_3d_state { struct hid_sensor_hub_callbacks callbacks; struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info magn[MAGN_3D_CHANNEL_MAX]; - u32 magn_val[MAGN_3D_CHANNEL_MAX]; + + /* dynamically sized array to hold sensor values */ + u32 *iio_vals; + /* array of pointers to sensor value */ + u32 *magn_val_addr[MAGN_3D_CHANNEL_MAX]; + int scale_pre_decml; int scale_post_decml; int scale_precision; @@ -52,7 +61,11 @@ struct magn_3d_state { static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = { HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS, HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS, - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS + HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS, + HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH, + HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH, + HID_USAGE_SENSOR_ORIENT_MAGN_NORTH, + HID_USAGE_SENSOR_ORIENT_TRUE_NORTH, }; /* Channel definitions */ @@ -66,7 +79,6 @@ static const struct iio_chan_spec magn_3d_channels[] = { BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_HYSTERESIS), - .scan_index = CHANNEL_SCAN_INDEX_X, }, { .type = IIO_MAGN, .modified = 1, @@ -76,7 +88,6 @@ static const struct iio_chan_spec magn_3d_channels[] = { BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_HYSTERESIS), - .scan_index = CHANNEL_SCAN_INDEX_Y, }, { .type = IIO_MAGN, .modified = 1, @@ -86,7 +97,42 @@ static const struct iio_chan_spec magn_3d_channels[] = { BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_HYSTERESIS), - .scan_index = CHANNEL_SCAN_INDEX_Z, + }, { + .type = IIO_ROT, + .modified = 1, + .channel2 = IIO_MOD_NORTH_MAGN_TILT_COMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS), + }, { + .type = IIO_ROT, + .modified = 1, + .channel2 = IIO_MOD_NORTH_TRUE_TILT_COMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS), + }, { + .type = IIO_ROT, + .modified = 1, + .channel2 = IIO_MOD_NORTH_MAGN, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS), + }, { + .type = IIO_ROT, + .modified = 1, + .channel2 = IIO_MOD_NORTH_TRUE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS), } }; @@ -126,8 +172,8 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev, msleep_interruptible(poll_value * 2); report_id = - magn_state->magn[chan->scan_index].report_id; - address = magn_3d_addresses[chan->scan_index]; + magn_state->magn[chan->address].report_id; + address = magn_3d_addresses[chan->address]; if (report_id >= 0) *val = sensor_hub_input_attr_get_raw_value( magn_state->common_attributes.hsdev, @@ -218,8 +264,8 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev, dev_dbg(&indio_dev->dev, "magn_3d_proc_event\n"); if (atomic_read(&magn_state->common_attributes.data_ready)) hid_sensor_push_data(indio_dev, - magn_state->magn_val, - sizeof(magn_state->magn_val)); + magn_state->iio_vals, + sizeof(magn_state->iio_vals)); return 0; } @@ -233,52 +279,126 @@ static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev, struct iio_dev *indio_dev = platform_get_drvdata(priv); struct magn_3d_state *magn_state = iio_priv(indio_dev); int offset; - int ret = -EINVAL; + int ret = 0; + u32 *iio_val = NULL; switch (usage_id) { case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS: case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS: case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS: - offset = usage_id - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS; - magn_state->magn_val[CHANNEL_SCAN_INDEX_X + offset] = - *(u32 *)raw_data; - ret = 0; + offset = (usage_id - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS) + + CHANNEL_SCAN_INDEX_X; + break; + case HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH: + case HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH: + case HID_USAGE_SENSOR_ORIENT_MAGN_NORTH: + case HID_USAGE_SENSOR_ORIENT_TRUE_NORTH: + offset = (usage_id - HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH) + + CHANNEL_SCAN_INDEX_NORTH_MAGN_TILT_COMP; break; default: - break; + return -EINVAL; } + iio_val = magn_state->magn_val_addr[offset]; + + if (iio_val != NULL) + *iio_val = *((u32 *)raw_data); + else + ret = -EINVAL; + return ret; } /* Parse report which is specific to an usage id*/ static int magn_3d_parse_report(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, - struct iio_chan_spec *channels, + struct iio_chan_spec **channels, + int *chan_count, unsigned usage_id, struct magn_3d_state *st) { - int ret; int i; + int attr_count = 0; + struct iio_chan_spec *_channels; + + /* Scan for each usage attribute supported */ + for (i = 0; i < MAGN_3D_CHANNEL_MAX; i++) { + int status; + u32 address = magn_3d_addresses[i]; + + /* Check if usage attribute exists in the sensor hub device */ + status = sensor_hub_input_get_attribute_info(hsdev, + HID_INPUT_REPORT, + usage_id, + address, + &(st->magn[i])); + if (!status) + attr_count++; + } - for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) { - ret = sensor_hub_input_get_attribute_info(hsdev, - HID_INPUT_REPORT, - usage_id, - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS + i, - &st->magn[CHANNEL_SCAN_INDEX_X + i]); - if (ret < 0) - break; - magn_3d_adjust_channel_bit_mask(channels, - CHANNEL_SCAN_INDEX_X + i, - st->magn[CHANNEL_SCAN_INDEX_X + i].size); + if (attr_count <= 0) { + dev_err(&pdev->dev, + "failed to find any supported usage attributes in report\n"); + return -EINVAL; } - dev_dbg(&pdev->dev, "magn_3d %x:%x, %x:%x, %x:%x\n", + + dev_dbg(&pdev->dev, "magn_3d Found %d usage attributes\n", + attr_count); + dev_dbg(&pdev->dev, "magn_3d X: %x:%x Y: %x:%x Z: %x:%x\n", st->magn[0].index, st->magn[0].report_id, st->magn[1].index, st->magn[1].report_id, st->magn[2].index, st->magn[2].report_id); + /* Setup IIO channel array */ + _channels = devm_kcalloc(&pdev->dev, attr_count, + sizeof(struct iio_chan_spec), + GFP_KERNEL); + if (!_channels) { + dev_err(&pdev->dev, + "failed to allocate space for iio channels\n"); + return -ENOMEM; + } + + st->iio_vals = devm_kcalloc(&pdev->dev, attr_count, + sizeof(u32), + GFP_KERNEL); + if (!st->iio_vals) { + dev_err(&pdev->dev, + "failed to allocate space for iio values array\n"); + return -ENOMEM; + } + + for (i = 0, *chan_count = 0; + i < MAGN_3D_CHANNEL_MAX && *chan_count < attr_count; + i++){ + if (st->magn[i].index >= 0) { + /* Setup IIO channel struct */ + (_channels[*chan_count]) = magn_3d_channels[i]; + (_channels[*chan_count]).scan_index = *chan_count; + (_channels[*chan_count]).address = i; + + /* Set magn_val_addr to iio value address */ + st->magn_val_addr[i] = &(st->iio_vals[*chan_count]); + magn_3d_adjust_channel_bit_mask(_channels, + *chan_count, + st->magn[i].size); + (*chan_count)++; + } + } + + if (*chan_count <= 0) { + dev_err(&pdev->dev, + "failed to find any magnetic channels setup\n"); + return -EINVAL; + } + + *channels = _channels; + + dev_dbg(&pdev->dev, "magn_3d Setup %d IIO channels\n", + *chan_count); + st->scale_precision = hid_sensor_format_scale( HID_USAGE_SENSOR_COMPASS_3D, &st->magn[CHANNEL_SCAN_INDEX_X], @@ -296,7 +416,7 @@ static int magn_3d_parse_report(struct platform_device *pdev, st->common_attributes.sensitivity.report_id); } - return ret; + return 0; } /* Function to initialize the processing for usage id */ @@ -308,6 +428,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev) struct magn_3d_state *magn_state; struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_chan_spec *channels; + int chan_count = 0; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct magn_3d_state)); @@ -328,22 +449,16 @@ static int hid_magn_3d_probe(struct platform_device *pdev) return ret; } - channels = kmemdup(magn_3d_channels, sizeof(magn_3d_channels), - GFP_KERNEL); - if (!channels) { - dev_err(&pdev->dev, "failed to duplicate channels\n"); - return -ENOMEM; - } - - ret = magn_3d_parse_report(pdev, hsdev, channels, + ret = magn_3d_parse_report(pdev, hsdev, + &channels, &chan_count, HID_USAGE_SENSOR_COMPASS_3D, magn_state); if (ret) { - dev_err(&pdev->dev, "failed to setup attributes\n"); - goto error_free_dev_mem; + dev_err(&pdev->dev, "failed to parse report\n"); + return ret; } indio_dev->channels = channels; - indio_dev->num_channels = ARRAY_SIZE(magn_3d_channels); + indio_dev->num_channels = chan_count; indio_dev->dev.parent = &pdev->dev; indio_dev->info = &magn_3d_info; indio_dev->name = name; @@ -353,7 +468,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev) NULL, NULL); if (ret) { dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); - goto error_free_dev_mem; + return ret; } atomic_set(&magn_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, @@ -387,8 +502,6 @@ error_remove_trigger: hid_sensor_remove_trigger(&magn_state->common_attributes); error_unreg_buffer_funcs: iio_triggered_buffer_cleanup(indio_dev); -error_free_dev_mem: - kfree(indio_dev->channels); return ret; } @@ -403,7 +516,6 @@ static int hid_magn_3d_remove(struct platform_device *pdev) iio_device_unregister(indio_dev); hid_sensor_remove_trigger(&magn_state->common_attributes); iio_triggered_buffer_cleanup(indio_dev); - kfree(indio_dev->channels); return 0; } diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 240a21dd0c61..a4b64130ac2f 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -299,6 +299,9 @@ static int st_magn_read_raw(struct iio_dev *indio_dev, else *val2 = mdata->current_fullscale->gain; return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = mdata->odr; + return IIO_VAL_INT; default: return -EINVAL; } @@ -316,6 +319,13 @@ static int st_magn_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: err = st_sensors_set_fullscale_by_gain(indio_dev, val2); break; + case IIO_CHAN_INFO_SAMP_FREQ: + if (val2) + return -EINVAL; + mutex_lock(&indio_dev->mlock); + err = st_sensors_set_odr(indio_dev, val); + mutex_unlock(&indio_dev->mlock); + return err; default: err = -EINVAL; } @@ -323,14 +333,12 @@ static int st_magn_write_raw(struct iio_dev *indio_dev, return err; } -static ST_SENSOR_DEV_ATTR_SAMP_FREQ(); static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL(); static ST_SENSORS_DEV_ATTR_SCALE_AVAIL(in_magn_scale_available); static struct attribute *st_magn_attributes[] = { &iio_dev_attr_sampling_frequency_available.dev_attr.attr, &iio_dev_attr_in_magn_scale_available.dev_attr.attr, - &iio_dev_attr_sampling_frequency.dev_attr.attr, NULL, }; diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index 892e0feeb5c1..689250058442 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -18,6 +18,27 @@ #include <linux/iio/common/st_sensors_i2c.h> #include "st_magn.h" +#ifdef CONFIG_OF +static const struct of_device_id st_magn_of_match[] = { + { + .compatible = "st,lsm303dlhc-magn", + .data = LSM303DLHC_MAGN_DEV_NAME, + }, + { + .compatible = "st,lsm303dlm-magn", + .data = LSM303DLM_MAGN_DEV_NAME, + }, + { + .compatible = "st,lis3mdl-magn", + .data = LIS3MDL_MAGN_DEV_NAME, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, st_magn_of_match); +#else +#define st_magn_of_match NULL +#endif + static int st_magn_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -31,6 +52,7 @@ static int st_magn_i2c_probe(struct i2c_client *client, mdata = iio_priv(indio_dev); mdata->dev = &client->dev; + st_sensors_of_i2c_probe(client, st_magn_of_match); st_sensors_i2c_configure(indio_dev, client, mdata); @@ -61,6 +83,7 @@ static struct i2c_driver st_magn_driver = { .driver = { .owner = THIS_MODULE, .name = "st-magn-i2c", + .of_match_table = of_match_ptr(st_magn_of_match), }, .probe = st_magn_i2c_probe, .remove = st_magn_i2c_remove, diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index ffac8ac1efca..15afbc919521 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -70,4 +70,14 @@ config IIO_ST_PRESS_SPI depends on IIO_ST_PRESS depends on IIO_ST_SENSORS_SPI +config T5403 + tristate "EPCOS T5403 digital barometric pressure sensor driver" + depends on I2C + help + Say yes here to build support for the EPCOS T5403 pressure sensor + connected via I2C. + + To compile this driver as a module, choose M here: the module + will be called t5403. + endmenu diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile index c53d2500737a..90a37e85cf21 100644 --- a/drivers/iio/pressure/Makefile +++ b/drivers/iio/pressure/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_MPL3115) += mpl3115.o obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o st_pressure-y := st_pressure_core.o st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o +obj-$(CONFIG_T5403) += t5403.o obj-$(CONFIG_IIO_ST_PRESS_I2C) += st_pressure_i2c.o obj-$(CONFIG_IIO_ST_PRESS_SPI) += st_pressure_spi.o diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index cd7e01f3a93b..473d914ef470 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -307,6 +307,27 @@ static const struct st_sensors st_press_sensors[] = { }, }; +static int st_press_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *ch, + int val, + int val2, + long mask) +{ + int err; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + if (val2) + return -EINVAL; + mutex_lock(&indio_dev->mlock); + err = st_sensors_set_odr(indio_dev, val); + mutex_unlock(&indio_dev->mlock); + return err; + default: + return -EINVAL; + } +} + static int st_press_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask) @@ -349,6 +370,9 @@ static int st_press_read_raw(struct iio_dev *indio_dev, } return IIO_VAL_FRACTIONAL; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = pdata->odr; + return IIO_VAL_INT; default: return -EINVAL; } @@ -357,12 +381,10 @@ read_error: return err; } -static ST_SENSOR_DEV_ATTR_SAMP_FREQ(); static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL(); static struct attribute *st_press_attributes[] = { &iio_dev_attr_sampling_frequency_available.dev_attr.attr, - &iio_dev_attr_sampling_frequency.dev_attr.attr, NULL, }; @@ -374,6 +396,7 @@ static const struct iio_info press_info = { .driver_module = THIS_MODULE, .attrs = &st_press_attribute_group, .read_raw = &st_press_read_raw, + .write_raw = &st_press_write_raw, }; #ifdef CONFIG_IIO_TRIGGER diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c index 3cd73e39b840..acaf165260bb 100644 --- a/drivers/iio/pressure/st_pressure_i2c.c +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -18,6 +18,27 @@ #include <linux/iio/common/st_sensors_i2c.h> #include "st_pressure.h" +#ifdef CONFIG_OF +static const struct of_device_id st_press_of_match[] = { + { + .compatible = "st,lps001wp-press", + .data = LPS001WP_PRESS_DEV_NAME, + }, + { + .compatible = "st,lps25h-press", + .data = LPS25H_PRESS_DEV_NAME, + }, + { + .compatible = "st,lps331ap-press", + .data = LPS331AP_PRESS_DEV_NAME, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, st_press_of_match); +#else +#define st_press_of_match NULL +#endif + static int st_press_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -31,6 +52,7 @@ static int st_press_i2c_probe(struct i2c_client *client, pdata = iio_priv(indio_dev); pdata->dev = &client->dev; + st_sensors_of_i2c_probe(client, st_press_of_match); st_sensors_i2c_configure(indio_dev, client, pdata); @@ -60,6 +82,7 @@ static struct i2c_driver st_press_driver = { .driver = { .owner = THIS_MODULE, .name = "st-press-i2c", + .of_match_table = of_match_ptr(st_press_of_match), }, .probe = st_press_i2c_probe, .remove = st_press_i2c_remove, diff --git a/drivers/iio/pressure/t5403.c b/drivers/iio/pressure/t5403.c new file mode 100644 index 000000000000..e11cd3938d67 --- /dev/null +++ b/drivers/iio/pressure/t5403.c @@ -0,0 +1,275 @@ +/* + * t5403.c - Support for EPCOS T5403 pressure/temperature sensor + * + * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net> + * + * 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 + * directory of this archive for more details. + * + * (7-bit I2C slave address 0x77) + * + * TODO: end-of-conversion irq + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/delay.h> + +#define T5403_DATA 0xf5 /* data, LSB first, 16 bit */ +#define T5403_CALIB_DATA 0x8e /* 10 calibration coeff., LSB first, 16 bit */ +#define T5403_SLAVE_ADDR 0x88 /* I2C slave address, 0x77 */ +#define T5403_COMMAND 0xf1 + +/* command bits */ +#define T5403_MODE_SHIFT 3 /* conversion time: 2, 8, 16, 66 ms */ +#define T5403_PT BIT(1) /* 0 .. pressure, 1 .. temperature measurement */ +#define T5403_SCO BIT(0) /* start conversion */ + +#define T5403_MODE_LOW 0 +#define T5403_MODE_STANDARD 1 +#define T5403_MODE_HIGH 2 +#define T5403_MODE_ULTRA_HIGH 3 + +#define T5403_I2C_MASK (~BIT(7)) +#define T5403_I2C_ADDR 0x77 + +static const int t5403_pressure_conv_ms[] = {2, 8, 16, 66}; + +struct t5403_data { + struct i2c_client *client; + struct mutex lock; + int mode; + __le16 c[10]; +}; + +#define T5403_C_U16(i) le16_to_cpu(data->c[(i) - 1]) +#define T5403_C(i) sign_extend32(T5403_C_U16(i), 15) + +static int t5403_read(struct t5403_data *data, bool pressure) +{ + int wait_time = 3; /* wakeup time in ms */ + + int ret = i2c_smbus_write_byte_data(data->client, T5403_COMMAND, + (pressure ? (data->mode << T5403_MODE_SHIFT) : T5403_PT) | + T5403_SCO); + if (ret < 0) + return ret; + + wait_time += pressure ? t5403_pressure_conv_ms[data->mode] : 2; + + msleep(wait_time); + + return i2c_smbus_read_word_data(data->client, T5403_DATA); +} + +static int t5403_comp_pressure(struct t5403_data *data, int *val, int *val2) +{ + int ret; + s16 t_r; + u16 p_r; + s32 S, O, X; + + mutex_lock(&data->lock); + + ret = t5403_read(data, false); + if (ret < 0) + goto done; + t_r = ret; + + ret = t5403_read(data, true); + if (ret < 0) + goto done; + p_r = ret; + + /* see EPCOS application note */ + S = T5403_C_U16(3) + (s32) T5403_C_U16(4) * t_r / 0x20000 + + T5403_C(5) * t_r / 0x8000 * t_r / 0x80000 + + T5403_C(9) * t_r / 0x8000 * t_r / 0x8000 * t_r / 0x10000; + + O = T5403_C(6) * 0x4000 + T5403_C(7) * t_r / 8 + + T5403_C(8) * t_r / 0x8000 * t_r / 16 + + T5403_C(9) * t_r / 0x8000 * t_r / 0x10000 * t_r; + + X = (S * p_r + O) / 0x4000; + + X += ((X - 75000) * (X - 75000) / 0x10000 - 9537) * + T5403_C(10) / 0x10000; + + *val = X / 1000; + *val2 = (X % 1000) * 1000; + +done: + mutex_unlock(&data->lock); + return ret; +} + +static int t5403_comp_temp(struct t5403_data *data, int *val) +{ + int ret; + s16 t_r; + + mutex_lock(&data->lock); + ret = t5403_read(data, false); + if (ret < 0) + goto done; + t_r = ret; + + /* see EPCOS application note */ + *val = ((s32) T5403_C_U16(1) * t_r / 0x100 + + (s32) T5403_C_U16(2) * 0x40) * 1000 / 0x10000; + +done: + mutex_unlock(&data->lock); + return ret; +} + +static int t5403_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct t5403_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + switch (chan->type) { + case IIO_PRESSURE: + ret = t5403_comp_pressure(data, val, val2); + if (ret < 0) + return ret; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_TEMP: + ret = t5403_comp_temp(data, val); + if (ret < 0) + return ret; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_INT_TIME: + *val = 0; + *val2 = t5403_pressure_conv_ms[data->mode] * 1000; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int t5403_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct t5403_data *data = iio_priv(indio_dev); + int i; + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + if (val != 0) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(t5403_pressure_conv_ms); i++) + if (val2 == t5403_pressure_conv_ms[i] * 1000) { + mutex_lock(&data->lock); + data->mode = i; + mutex_unlock(&data->lock); + return 0; + } + return -EINVAL; + default: + return -EINVAL; + } +} + +static const struct iio_chan_spec t5403_channels[] = { + { + .type = IIO_PRESSURE, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_INT_TIME), + }, + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + }, +}; + +static IIO_CONST_ATTR_INT_TIME_AVAIL("0.002 0.008 0.016 0.066"); + +static struct attribute *t5403_attributes[] = { + &iio_const_attr_integration_time_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group t5403_attribute_group = { + .attrs = t5403_attributes, +}; + +static const struct iio_info t5403_info = { + .read_raw = &t5403_read_raw, + .write_raw = &t5403_write_raw, + .attrs = &t5403_attribute_group, + .driver_module = THIS_MODULE, +}; + +static int t5403_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct t5403_data *data; + struct iio_dev *indio_dev; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK)) + return -ENODEV; + + ret = i2c_smbus_read_byte_data(client, T5403_SLAVE_ADDR); + if (ret < 0) + return ret; + if ((ret & T5403_I2C_MASK) != T5403_I2C_ADDR) + return -ENODEV; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->client = client; + mutex_init(&data->lock); + + i2c_set_clientdata(client, indio_dev); + indio_dev->info = &t5403_info; + indio_dev->name = id->name; + indio_dev->dev.parent = &client->dev; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = t5403_channels; + indio_dev->num_channels = ARRAY_SIZE(t5403_channels); + + data->mode = T5403_MODE_STANDARD; + + ret = i2c_smbus_read_i2c_block_data(data->client, T5403_CALIB_DATA, + sizeof(data->c), (u8 *) data->c); + if (ret < 0) + return ret; + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static const struct i2c_device_id t5403_id[] = { + { "t5403", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, t5403_id); + +static struct i2c_driver t5403_driver = { + .driver = { + .name = "t5403", + }, + .probe = t5403_probe, + .id_table = t5403_id, +}; +module_i2c_driver(t5403_driver); + +MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); +MODULE_DESCRIPTION("EPCOS T5403 pressure/temperature sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index bf677bfe8eb2..5e780ef206f3 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -232,7 +232,7 @@ static void as3935_event_work(struct work_struct *work) switch (val) { case AS3935_EVENT_INT: - iio_trigger_poll(st->trig, iio_get_time_ns()); + iio_trigger_poll(st->trig); break; case AS3935_NOISE_INT: dev_warn(&st->spi->dev, "noise level is too high"); diff --git a/drivers/iio/trigger/iio-trig-interrupt.c b/drivers/iio/trigger/iio-trig-interrupt.c index 02577ec54c6b..7a149a7822bc 100644 --- a/drivers/iio/trigger/iio-trig-interrupt.c +++ b/drivers/iio/trigger/iio-trig-interrupt.c @@ -24,8 +24,7 @@ struct iio_interrupt_trigger_info { static irqreturn_t iio_interrupt_trigger_poll(int irq, void *private) { - /* Timestamp not currently provided */ - iio_trigger_poll(private, 0); + iio_trigger_poll(private); return IRQ_HANDLED; } diff --git a/drivers/iio/trigger/iio-trig-sysfs.c b/drivers/iio/trigger/iio-trig-sysfs.c index 15e3b850f513..254c7e906127 100644 --- a/drivers/iio/trigger/iio-trig-sysfs.c +++ b/drivers/iio/trigger/iio-trig-sysfs.c @@ -96,7 +96,7 @@ static void iio_sysfs_trigger_work(struct irq_work *work) struct iio_sysfs_trig *trig = container_of(work, struct iio_sysfs_trig, work); - iio_trigger_poll(trig->trig, 0); + iio_trigger_poll(trig->trig); } static ssize_t iio_sysfs_trigger_poll(struct device *dev, |