Merge tag 'iio-for-3.17c' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next

Jonathan writes:

3rd round of IIO new drivers, cleanups and functionality for the 3.17 cycle.

New drivers
* isl29125 digital color light sensor driver
* TAOS/AMS tcs3414 digital color sensor

Staging graduation
* ad7291 ADC driver.

New functionality
* st_sensors - device tree support and bindings
* mma8452 - device tree support

Cleanups
* Drop redundant variables in a number of drivers.
* Reorder a structure definition to ealy wiht a warning about static
  not being at the beginning in the hid-sensors driver.
* Switch a few more drivers away from using explicit sampling_frequency
  attribute to providing this through the core.
* Make hid_sensor_get_reporting_interval static as only used within a single
  file.
* Drop a redundant check for negative values in an unsigned variable from
  ad9832
* Drop some duplicate case labels in the event monitor example code.
* Use devm_ioremap_resource to simplify error handling.
* Use devm_kzalloc within the blackfin timer driver to simplify error
  handling and removal.
* A number of cleanups of the ad7291 from Hartmut Knaack in response
  to a patch moving it out of staging.
* Core support for the period info element about events.  It has been
  in the abi for a while, but not added until now to the newer handling
  of information related to events.
* Add HAS_IOMEM dependency to mxs_lradc to avoid build issues when testing
  enabled.
This commit is contained in:
Greg Kroah-Hartman
2014-07-13 12:31:47 -07:00
47 changed files with 1392 additions and 481 deletions

View File

@@ -423,9 +423,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,

View File

@@ -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,
};

View File

@@ -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,

View File

@@ -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

View File

@@ -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

585
drivers/iio/adc/ad7291.c Normal file
View File

@@ -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");

View File

@@ -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) {

View File

@@ -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)

View File

@@ -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)
{

View File

@@ -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");

View File

@@ -125,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:
@@ -134,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[] = {

View File

@@ -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[] = {

View File

@@ -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)

View File

@@ -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,

View File

@@ -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;
case IIO_CHAN_INFO_SAMP_FREQ:
ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_DLPF, &regval);
if (ret)
return ret;
*val = (regval & ITG3200_DLPF_CFG_MASK) ? 1000 : 8000;
ret = itg3200_read_reg_8(indio_dev,
ITG3200_REG_SAMPLE_RATE_DIV,
&regval);
if (ret)
return ret;
*val /= regval + 1;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static ssize_t itg3200_read_frequency(struct device *dev,
struct device_attribute *attr, char *buf)
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);
int ret, sps;
u8 val;
ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_DLPF, &val);
if (ret)
return ret;
sps = (val & ITG3200_DLPF_CFG_MASK) ? 1000 : 8000;
ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_SAMPLE_RATE_DIV, &val);
if (ret)
return ret;
sps /= val + 1;
return sprintf(buf, "%d\n", sps);
}
static ssize_t itg3200_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);
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;
ret = itg3200_write_reg_8(indio_dev,
ITG3200_REG_SAMPLE_RATE_DIV,
t);
mutex_unlock(&indio_dev->mlock);
return ret;
default:
return -EINVAL;
}
t = ((t & ITG3200_DLPF_CFG_MASK) ? 1000u : 8000u) / val - 1;
ret = itg3200_write_reg_8(indio_dev, ITG3200_REG_SAMPLE_RATE_DIV, t);
err_ret:
mutex_unlock(&indio_dev->mlock);
return ret ? ret : len;
}
/*
@@ -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,
};

View File

@@ -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,
};

View File

@@ -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,

View File

@@ -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);

View File

@@ -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,
};

View File

@@ -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,

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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");

405
drivers/iio/light/tcs3414.c Normal file
View File

@@ -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");

View File

@@ -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,
};

View File

@@ -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,

View File

@@ -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

View File

@@ -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,