Commit 5da65454 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'iio-for-4.4b' of...

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

Jonathan writes:

Second set of new drivers, functionality and cleanups for IIO in the 4.4 cycle.

Core stuff
* adjust resistance documentation to allow for output devices.

New device support:
* bmc150
 - split the i2c driver up into a core and i2c_regmap part including regmap
   conversion.
 - add spi support.
* mcp4531 digitial potentiometer driver.
* Measurement Specialties set of drivers with a core library module providing
  common functionality.  Note that the htu21 has a driver in hwmon, but the
  view from that side was that, given the range of devices the same silicon
  turns up in are not all typical hwmon material, that driver would be
  deprecated in favour of this new support.
 - ms8607 temperature, pressure and humidty sensor
 - ms5637 temperature and pressure sensor
 - htu21 temperature and humidity sensor
 - tsys02d temperature sensor
 - tsys01 temperature sensor

Cleanups
* tree wide.
 - squish cases where irq 0 is still considered valid.
* apds9960
 - sparse endian warning cleanups by making endianness explicit.
* ad5504
 - leave group naming to the core.
* ad7746
 - cleanup comment style.
 - drop an unnecessary bit of dev_info
 - add some appropriate uses of the BIT macro.
* ad799x
 - leave group naming to the core.
* hdc100x - introduced this cycle,.
 - fix a wrong offset value.
* lidar
 - add missing MODULE_DEVICE_TABLE for dt.
* max1363
 - leave sysfs group naming to the core.
* m62332 got the Harmut treatment and as ever he found a 'few' bits the
  rest of us had missed!
 - Share scale and offset attributes across channels.
 - Shutdown the device on driver remove
 - Use ARRAY_SIZE rather than a hard coded count for channels.
 - Return more directly in the write_raw callback dropping a local variable
   along the way.
 - a few style issues
 - move to reading the regulator voltage for each use allowing for dynamic
   regulators.  This is a common feature across drivers so we might end
   up with more fixes throughout the tree for this.
* mlx96014 - introduced this cycle.
 - fixed up a spot of error handling.
* vz89x - introduced this cycle.
 - work around a hardware quirk.
parents 26368fd7 801ab335
......@@ -1474,8 +1474,20 @@ Description:
What: /sys/bus/iio/devices/iio:deviceX/in_resistance_raw
What: /sys/bus/iio/devices/iio:deviceX/in_resistanceX_raw
What: /sys/bus/iio/devices/iio:deviceX/out_resistance_raw
What: /sys/bus/iio/devices/iio:deviceX/out_resistanceX_raw
KernelVersion: 4.3
Contact: linux-iio@vger.kernel.org
Description:
Raw (unscaled no offset etc.) resistance reading that can be processed
into an ohm value.
What: /sys/bus/iio/devices/iio:deviceX/heater_enable
KernelVersion: 4.1.0
Contact: linux-iio@vger.kernel.org
Description:
'1' (enable) or '0' (disable) specifying the enable
of heater function. Same reading values apply
This ABI is especially applicable for humidity sensors
to heatup the device and get rid of any condensation
in some humidity environment
What: /sys/bus/iio/devices/iio:deviceX/battery_low
KernelVersion: 4.1.0
Contact: linux-iio@vger.kernel.org
Description:
Reading returns either '1' or '0'. '1' means that the
battery level supplied to sensor is below 2.25V.
This ABI is available for tsys02d, htu21, ms8607
This ABI is available for htu21, ms8607
......@@ -6682,6 +6682,12 @@ W: http://linuxtv.org
S: Maintained
F: drivers/media/radio/radio-maxiradio*
MCP4531 MICROCHIP DIGITAL POTENTIOMETER DRIVER
M: Peter Rosin <peda@axentia.se>
L: linux-iio@vger.kernel.org
S: Maintained
F: drivers/iio/potentiometer/mcp4531.c
MEDIA DRIVERS FOR RENESAS - VSP1
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
L: linux-media@vger.kernel.org
......
......@@ -60,6 +60,7 @@ source "drivers/iio/orientation/Kconfig"
if IIO_TRIGGER
source "drivers/iio/trigger/Kconfig"
endif #IIO_TRIGGER
source "drivers/iio/potentiometer/Kconfig"
source "drivers/iio/pressure/Kconfig"
source "drivers/iio/proximity/Kconfig"
source "drivers/iio/temperature/Kconfig"
......
......@@ -23,6 +23,7 @@ obj-y += imu/
obj-y += light/
obj-y += magnetometer/
obj-y += orientation/
obj-y += potentiometer/
obj-y += pressure/
obj-y += proximity/
obj-y += temperature/
......
......@@ -19,19 +19,27 @@ config BMA180
config BMC150_ACCEL
tristate "Bosch BMC150 Accelerometer Driver"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select REGMAP
select BMC150_ACCEL_I2C if I2C
select BMC150_ACCEL_SPI if SPI
help
Say yes here to build support for the following Bosch accelerometers:
BMC150, BMI055, BMA250E, BMA222E, BMA255, BMA280.
Currently this only supports the device via an i2c interface.
This is a combo module with both accelerometer and magnetometer.
This driver is only implementing accelerometer part, which has
its own address and register map.
config BMC150_ACCEL_I2C
tristate
select REGMAP_I2C
config BMC150_ACCEL_SPI
tristate
select REGMAP_SPI
config HID_SENSOR_ACCEL_3D
depends on HID_SENSOR_HUB
select IIO_BUFFER
......
......@@ -4,7 +4,9 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_BMA180) += bma180.o
obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel.o
obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o
obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o
obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o
obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
obj-$(CONFIG_KXSD9) += kxsd9.o
......
/*
* 3-axis accelerometer driver supporting following I2C Bosch-Sensortec chips:
* - BMC150
* - BMI055
* - BMA255
* - BMA250E
* - BMA222E
* - BMA280
*
* 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/device.h>
#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/acpi.h>
#include <linux/regmap.h>
#include "bmc150-accel.h"
static const struct regmap_config bmc150_i2c_regmap_conf = {
.reg_bits = 8,
.val_bits = 8,
};
static int bmc150_accel_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct regmap *regmap;
const char *name = NULL;
bool block_supported =
i2c_check_functionality(client->adapter, I2C_FUNC_I2C) ||
i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_I2C_BLOCK);
regmap = devm_regmap_init_i2c(client, &bmc150_i2c_regmap_conf);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "Failed to initialize i2c regmap\n");
return PTR_ERR(regmap);
}
if (id)
name = id->name;
return bmc150_accel_core_probe(&client->dev, regmap, client->irq, name,
block_supported);
}
static int bmc150_accel_remove(struct i2c_client *client)
{
return bmc150_accel_core_remove(&client->dev);
}
static const struct acpi_device_id bmc150_accel_acpi_match[] = {
{"BSBA0150", bmc150},
{"BMC150A", bmc150},
{"BMI055A", bmi055},
{"BMA0255", bma255},
{"BMA250E", bma250e},
{"BMA222E", bma222e},
{"BMA0280", bma280},
{ },
};
MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match);
static const struct i2c_device_id bmc150_accel_id[] = {
{"bmc150_accel", bmc150},
{"bmi055_accel", bmi055},
{"bma255", bma255},
{"bma250e", bma250e},
{"bma222e", bma222e},
{"bma280", bma280},
{}
};
MODULE_DEVICE_TABLE(i2c, bmc150_accel_id);
static struct i2c_driver bmc150_accel_driver = {
.driver = {
.name = "bmc150_accel_i2c",
.acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match),
.pm = &bmc150_accel_pm_ops,
},
.probe = bmc150_accel_probe,
.remove = bmc150_accel_remove,
.id_table = bmc150_accel_id,
};
module_i2c_driver(bmc150_accel_driver);
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("BMC150 I2C accelerometer driver");
/*
* 3-axis accelerometer driver supporting SPI Bosch-Sensortec accelerometer chip
* Copyright © 2015 Pengutronix, Markus Pargmann <mpa@pengutronix.de>
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/acpi.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include "bmc150-accel.h"
static const struct regmap_config bmc150_spi_regmap_conf = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x3f,
};
static int bmc150_accel_probe(struct spi_device *spi)
{
struct regmap *regmap;
const struct spi_device_id *id = spi_get_device_id(spi);
regmap = devm_regmap_init_spi(spi, &bmc150_spi_regmap_conf);
if (IS_ERR(regmap)) {
dev_err(&spi->dev, "Failed to initialize spi regmap\n");
return PTR_ERR(regmap);
}
return bmc150_accel_core_probe(&spi->dev, regmap, spi->irq, id->name,
true);
}
static int bmc150_accel_remove(struct spi_device *spi)
{
return bmc150_accel_core_remove(&spi->dev);
}
static const struct acpi_device_id bmc150_accel_acpi_match[] = {
{"BSBA0150", bmc150},
{"BMC150A", bmc150},
{"BMI055A", bmi055},
{"BMA0255", bma255},
{"BMA250E", bma250e},
{"BMA222E", bma222e},
{"BMA0280", bma280},
{ },
};
MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match);
static const struct spi_device_id bmc150_accel_id[] = {
{"bmc150_accel", bmc150},
{"bmi055_accel", bmi055},
{"bma255", bma255},
{"bma250e", bma250e},
{"bma222e", bma222e},
{"bma280", bma280},
{}
};
MODULE_DEVICE_TABLE(spi, bmc150_accel_id);
static struct spi_driver bmc150_accel_driver = {
.driver = {
.name = "bmc150_accel_spi",
.acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match),
.pm = &bmc150_accel_pm_ops,
},
.probe = bmc150_accel_probe,
.remove = bmc150_accel_remove,
.id_table = bmc150_accel_id,
};
module_spi_driver(bmc150_accel_driver);
MODULE_AUTHOR("Markus Pargmann <mpa@pengutronix.de>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("BMC150 SPI accelerometer driver");
#ifndef _BMC150_ACCEL_H_
#define _BMC150_ACCEL_H_
struct regmap;
enum {
bmc150,
bmi055,
bma255,
bma250e,
bma222e,
bma280,
};
int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
const char *name, bool block_supported);
int bmc150_accel_core_remove(struct device *dev);
extern const struct dev_pm_ops bmc150_accel_pm_ops;
#endif /* _BMC150_ACCEL_H_ */
......@@ -1162,35 +1162,6 @@ static const char *kxcjk1013_match_acpi_device(struct device *dev,
return dev_name(dev);
}
static int kxcjk1013_gpio_probe(struct i2c_client *client,
struct kxcjk1013_data *data)
{
struct device *dev;
struct gpio_desc *gpio;
int ret;
if (!client)
return -EINVAL;
if (data->is_smo8500_device)
return -ENOTSUPP;
dev = &client->dev;
/* data ready gpio interrupt pin */
gpio = devm_gpiod_get_index(dev, "kxcjk1013_int", 0, GPIOD_IN);
if (IS_ERR(gpio)) {
dev_err(dev, "acpi gpio get index failed\n");
return PTR_ERR(gpio);
}
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)
{
......@@ -1237,10 +1208,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &kxcjk1013_info;
if (client->irq < 0)
client->irq = kxcjk1013_gpio_probe(client, data);
if (client->irq > 0) {
if (client->irq > 0 && !data->is_smo8500_device) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
kxcjk1013_data_rdy_trig_poll,
kxcjk1013_event_handler,
......
......@@ -26,7 +26,6 @@
#define MMA9553_DRV_NAME "mma9553"
#define MMA9553_IRQ_NAME "mma9553_event"
#define MMA9553_GPIO_NAME "mma9553_int"
/* Pedometer configuration registers (R/W) */
#define MMA9553_REG_CONF_SLEEPMIN 0x00
......@@ -1073,31 +1072,6 @@ static irqreturn_t mma9553_event_handler(int irq, void *private)
return IRQ_HANDLED;
}
static int mma9553_gpio_probe(struct i2c_client *client)
{
struct device *dev;
struct gpio_desc *gpio;
int ret;
if (!client)
return -EINVAL;
dev = &client->dev;
/* data ready GPIO interrupt pin */
gpio = devm_gpiod_get_index(dev, MMA9553_GPIO_NAME, 0, GPIOD_IN);
if (IS_ERR(gpio)) {
dev_err(dev, "ACPI GPIO get index failed\n");
return PTR_ERR(gpio);
}
ret = gpiod_to_irq(gpio);
dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
return ret;
}
static const char *mma9553_match_acpi_device(struct device *dev)
{
const struct acpi_device_id *id;
......@@ -1146,9 +1120,6 @@ static int mma9553_probe(struct i2c_client *client,
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &mma9553_info;
if (client->irq < 0)
client->irq = mma9553_gpio_probe(client);
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
mma9553_irq_handler,
......
......@@ -50,7 +50,6 @@
#define STK8312_ALL_CHANNEL_SIZE 3
#define STK8312_DRIVER_NAME "stk8312"
#define STK8312_GPIO "stk8312_gpio"
#define STK8312_IRQ_NAME "stk8312_event"
/*
......@@ -504,30 +503,6 @@ static const struct iio_buffer_setup_ops stk8312_buffer_setup_ops = {
.postdisable = stk8312_buffer_postdisable,
};
static int stk8312_gpio_probe(struct i2c_client *client)
{
struct device *dev;
struct gpio_desc *gpio;
int ret;
if (!client)
return -EINVAL;
dev = &client->dev;
/* data ready gpio interrupt pin */
gpio = devm_gpiod_get_index(dev, STK8312_GPIO, 0, GPIOD_IN);
if (IS_ERR(gpio)) {
dev_err(dev, "acpi gpio get index failed\n");
return PTR_ERR(gpio);
}
ret = gpiod_to_irq(gpio);
dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
return ret;
}
static int stk8312_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
......@@ -569,10 +544,7 @@ static int stk8312_probe(struct i2c_client *client,
if (ret < 0)
return ret;
if (client->irq < 0)
client->irq = stk8312_gpio_probe(client);
if (client->irq >= 0) {
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
stk8312_data_rdy_trig_poll,
NULL,
......
......@@ -45,7 +45,6 @@
#define STK8BA50_ALL_CHANNEL_SIZE 6
#define STK8BA50_DRIVER_NAME "stk8ba50"
#define STK8BA50_GPIO "stk8ba50_gpio"
#define STK8BA50_IRQ_NAME "stk8ba50_event"
#define STK8BA50_SCALE_AVAIL "0.0384 0.0767 0.1534 0.3069"
......@@ -388,30 +387,6 @@ static const struct iio_buffer_setup_ops stk8ba50_buffer_setup_ops = {
.postdisable = stk8ba50_buffer_postdisable,
};
static int stk8ba50_gpio_probe(struct i2c_client *client)
{
struct device *dev;
struct gpio_desc *gpio;
int ret;
if (!client)
return -EINVAL;
dev = &client->dev;
/* data ready gpio interrupt pin */
gpio = devm_gpiod_get_index(dev, STK8BA50_GPIO, 0, GPIOD_IN);
if (IS_ERR(gpio)) {
dev_err(dev, "acpi gpio get index failed\n");
return PTR_ERR(gpio);
}
ret = gpiod_to_irq(gpio);
dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
return ret;
}
static int stk8ba50_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
......@@ -465,10 +440,7 @@ static int stk8ba50_probe(struct i2c_client *client,
goto err_power_off;
}
if (client->irq < 0)
client->irq = stk8ba50_gpio_probe(client);
if (client->irq >= 0) {
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
stk8ba50_data_rdy_trig_poll,
NULL,
......
......@@ -528,7 +528,6 @@ static struct attribute *ad799x_event_attributes[] = {
static struct attribute_group ad799x_event_attrs_group = {
.attrs = ad799x_event_attributes,
.name = "events",
};
static const struct iio_info ad7991_info = {
......
......@@ -1007,7 +1007,6 @@ static struct attribute *max1363_event_attributes[] = {
static struct attribute_group max1363_event_attribute_group = {
.attrs = max1363_event_attributes,
.name = "events",
};
static int max1363_update_scan_mode(struct iio_dev *indio_dev,
......
......@@ -85,6 +85,21 @@ static const struct attribute_group vz89x_attrs_group = {
.attrs = vz89x_attributes,
};
/*
* Chipset sometime updates in the middle of a reading causing it to reset the
* data pointer, and causing invalid reading of previous data.
* We can check for this by reading MSB of the resistance reading that is
* always zero, and by also confirming the VOC_short isn't zero.
*/
static int vz89x_measurement_is_valid(struct vz89x_data *data)
{
if (data->buffer[VZ89X_VOC_SHORT_IDX] == 0)
return 1;
return !!(data->buffer[VZ89X_REG_MEASUREMENT_SIZE - 1] > 0);
}
static int vz89x_get_measurement(struct vz89x_data *data)
{
int ret;
......@@ -106,6 +121,10 @@ static int vz89x_get_measurement(struct vz89x_data *data)
data->buffer[i] = ret;
}
ret = vz89x_measurement_is_valid(data);
if (ret)
return -EAGAIN;
data->last_update = jiffies;
return 0;
......@@ -113,9 +132,9 @@ static int vz89x_get_measurement(struct vz89x_data *data)
static int vz89x_get_resistance_reading(struct vz89x_data *data)
{
u8 *buf = &data->buffer[VZ89X_VOC_TVOC_IDX];
u8 *buf = &data->buffer[VZ89X_VOC_RESISTANCE_IDX];
return buf[0] | (buf[1] << 8) | (buf[2] << 16);
return buf[0] | (buf[1] << 8);
}
static int vz89x_read_raw(struct iio_dev *indio_dev,
......
......@@ -3,5 +3,6 @@
#
source "drivers/iio/common/hid-sensors/Kconfig"
source "drivers/iio/common/ms_sensors/Kconfig"
source "drivers/iio/common/ssp_sensors/Kconfig"
source "drivers/iio/common/st_sensors/Kconfig"
......@@ -8,5 +8,6 @@
# When adding new entries keep the list in alphabetical order
obj-y += hid-sensors/
obj-y += ms_sensors/
obj-y += ssp_sensors/
obj-y += st_sensors/
#
# Measurements Specialties sensors common library
#
config IIO_MS_SENSORS_I2C
tristate
#
# Makefile for the Measurement Specialties sensor common modules.
#
obj-$(CONFIG_IIO_MS_SENSORS_I2C) += ms_sensors_i2c.o
This diff is collapsed.
/*
* Measurements Specialties common sensor driver
*
* Copyright (c) 2015 Measurement-Specialties
*
* 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.
*/
#ifndef _MS_SENSORS_I2C_H
#define _MS_SENSORS_I2C_H
#include <linux/i2c.h>
#include <linux/mutex.h>
#define MS_SENSORS_TP_PROM_WORDS_NB 7
/**
* struct ms_ht_dev - Humidity/Temperature sensor device structure
* @client: i2c client
* @lock: lock protecting the i2c conversion
* @res_index: index to selected sensor resolution
*/
struct ms_ht_dev {
struct i2c_client *client;
struct mutex lock;
u8 res_index;
};
/**
* struct ms_tp_dev - Temperature/Pressure sensor device structure
* @client: i2c client
* @lock: lock protecting the i2c conversion
* @prom: array of PROM coefficients used for conversion. Added element
* for CRC computation
* @res_index: index to selected sensor resolution
*/
struct ms_tp_dev {
struct i2c_client *client;
struct mutex lock;
u16 prom[MS_SENSORS_TP_PROM_WORDS_NB + 1];
u8 res_index;
};
int ms_sensors_reset(void *cli, u8 cmd, unsigned int delay);
int ms_sensors_read_prom_word(void *cli, int cmd, u16 *word);
int ms_sensors_convert_and_read(void *cli, u8 conv, u8 rd,
unsigned int delay, u32 *adc);
int ms_sensors_read_serial(struct i2c_client *client, u64 *sn);
ssize_t ms_sensors_show_serial(struct ms_ht_dev *dev_data, char *buf);
ssize_t ms_sensors_write_resolution(struct ms_ht_dev *dev_data, u8 i);
ssize_t ms_sensors_show_battery_low(struct ms_ht_dev *dev_data, char *buf);
ssize_t ms_sensors_show_heater(struct ms_ht_dev *dev_data, char *buf);
ssize_t ms_sensors_write_heater(struct ms_ht_dev *dev_data,
const char *buf, size_t len);
int ms_sensors_ht_read_temperature(struct ms_ht_dev *dev_data,
s32 *temperature);
int ms_sensors_ht_read_humidity(struct ms_ht_dev *dev_data,
u32 *humidity);
int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data);
int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
int *temperature,
unsigned int *pressure);
#endif /* _MS_SENSORS_I2C_H */
......@@ -214,7 +214,6 @@ static struct attribute *ad5504_ev_attributes[] = {
static struct attribute_group ad5504_ev_attribute_group = {
.attrs = ad5504_ev_attributes,
.name = "events",
};
static irqreturn_t ad5504_event_handler(int irq, void *private)
......
......@@ -31,7 +31,6 @@
struct m62332_data {
struct i2c_client *client;
u16 vref_mv;
struct regulator *vcc;
struct mutex mutex;
u8 raw[M62332_CHANNELS];
......@@ -40,8 +39,7 @@ struct m62332_data {
#endif
};
static int m62332_set_value(struct iio_dev *indio_dev,
u8 val, int channel)
static int m62332_set_value(struct iio_dev *indio_dev, u8 val, int channel)
{
struct m62332_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
......@@ -62,8 +60,8 @@ static int m62332_set_value(struct iio_dev *indio_dev,
goto out;
}
res = i2c_master_send(client, outbuf, 2);
if (res >= 0 && res != 2)
res = i2c_master_send(client, outbuf, ARRAY_SIZE(outbuf));
if (res >= 0 && res != ARRAY_SIZE(outbuf))
res = -EIO;
if (res < 0)
goto out;
......@@ -87,46 +85,52 @@ static int m62332_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
long mask)
{
struct m62332_data *data = iio_priv(indio_dev);
int ret;
switch (m) {
switch (mask) {
case IIO_CHAN_INFO_SCALE:
/* Corresponds to Vref / 2^(bits) */
*val = data->vref_mv;
ret = regulator_get_voltage(data->vcc);
if (ret < 0)
return ret;
*val = ret / 1000; /* mV */
*val2 = 8;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_RAW:
*val = data->raw[chan->channel];
return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
*val = 1;
return IIO_VAL_INT;
default:
break;
}
return -EINVAL;
}
static int m62332_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long mask)
struct iio_chan_spec const *chan, int val, int val2,
long mask)
{
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val < 0 || val > 255)
return -EINVAL;
ret = m62332_set_value(indio_dev, val, chan->channel);
break;
return m62332_set_value(indio_dev, val, chan->channel);
default:
ret = -EINVAL;
break;
}
return ret;
return -EINVAL;
}
#ifdef CONFIG_PM_SLEEP
......@@ -173,15 +177,15 @@ static const struct iio_info m62332_info = {
.driver_module = THIS_MODULE,
};
#define M62332_CHANNEL(chan) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = (chan), \
.datasheet_name = "CH" #chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OFFSET), \
#define M62332_CHANNEL(chan) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = (chan), \
.datasheet_name = "CH" #chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OFFSET), \
}
static const struct iio_chan_spec m62332_channels[M62332_CHANNELS] = {
......@@ -199,6 +203,7 @@ static int m62332_probe(struct i2c_client *client,
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
......@@ -212,16 +217,11 @@ static int m62332_probe(struct i2c_client *client,
/* establish that the iio_dev is a child of the i2c device */
indio_dev->dev.parent = &client->dev;
indio_dev->num_channels = M62332_CHANNELS;
indio_dev->num_channels = ARRAY_SIZE(m62332_channels);
indio_dev->channels = m62332_channels;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &m62332_info;
ret = regulator_get_voltage(data->vcc);
if (ret < 0)
return ret;
data->vref_mv = ret / 1000; /* mV */
ret = iio_map_array_register(indio_dev, client->dev.platform_data);
if (ret < 0)
return ret;
......@@ -234,6 +234,7 @@ static int m62332_probe(struct i2c_client *client,
err:
iio_map_array_unregister(indio_dev);
return ret;
}
......@@ -243,6 +244,8 @@ static int m62332_remove(struct i2c_client *client)
iio_device_unregister(indio_dev);
iio_map_array_unregister(indio_dev);
m62332_set_value(indio_dev, 0, 0);
m62332_set_value(indio_dev, 0, 1);
return 0;
}
......
......@@ -22,6 +22,19 @@ config HDC100X
To compile this driver as a module, choose M here: the module
will be called hdc100x.
config HTU21
tristate "Measurement Specialties HTU21 humidity & temperature sensor"
depends on I2C
select IIO_MS_SENSORS_I2C
help
If you say yes here you get support for the Measurement Specialties
HTU21 humidity and temperature sensor.
This driver is also used for MS8607 temperature, pressure & humidity
sensor
This driver can also be built as a module. If so, the module will
be called htu21.
config SI7005
tristate "SI7005 relative humidity and temperature sensor"
depends on I2C
......
......@@ -4,5 +4,6 @@
obj-$(CONFIG_DHT11) += dht11.o
obj-$(CONFIG_HDC100X) += hdc100x.o
obj-$(CONFIG_HTU21) += htu21.o
obj-$(CONFIG_SI7005) += si7005.o
obj-$(CONFIG_SI7020) += si7020.o
......@@ -221,8 +221,9 @@ static int hdc100x_read_raw(struct iio_dev *indio_dev,
}
break;
case IIO_CHAN_INFO_OFFSET:
*val = -40;
return IIO_VAL_INT;
*val = -3971;
*val2 = 879096;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
......
/*
* htu21.c - Support for Measurement-Specialties
* htu21 temperature & humidity sensor
* and humidity part of MS8607 sensor
*
* Copyright (c) 2014 Measurement-Specialties
*
* Licensed under the GPL-2.
*
* (7-bit I2C slave address 0x40)
*
* Datasheet:
* http://www.meas-spec.com/downloads/HTU21D.pdf
* Datasheet:
* http://www.meas-spec.com/downloads/MS8607-02BA01.pdf
*/
#include <linux/init.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/stat.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include "../common/ms_sensors/ms_sensors_i2c.h"
#define HTU21_RESET 0xFE
enum {
HTU21,
MS8607
};
static const int htu21_samp_freq[4] = { 20, 40, 70, 120 };
/* String copy of the above const for readability purpose */
static const char htu21_show_samp_freq[] = "20 40 70 120";
static int htu21_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *val,
int *val2, long mask)
{
int ret, temperature;
unsigned int humidity;
struct ms_ht_dev *dev_data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
switch (channel->type) {
case IIO_TEMP: /* in milli °C */
ret = ms_sensors_ht_read_temperature(dev_data,
&temperature);
if (ret)
return ret;
*val = temperature;
return IIO_VAL_INT;
case IIO_HUMIDITYRELATIVE: /* in milli %RH */
ret = ms_sensors_ht_read_humidity(dev_data,
&humidity);
if (ret)
return ret;
*val = humidity;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SAMP_FREQ:
*val = htu21_samp_freq[dev_data->res_index];
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int htu21_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct ms_ht_dev *dev_data = iio_priv(indio_dev);
int i, ret;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
i = ARRAY_SIZE(htu21_samp_freq);
while (i-- > 0)
if (val == htu21_samp_freq[i])
break;
if (i < 0)
return -EINVAL;
mutex_lock(&dev_data->lock);
dev_data->res_index = i;
ret = ms_sensors_write_resolution(dev_data, i);
mutex_unlock(&dev_data->lock);
return ret;
default:
return -EINVAL;
}
}
static const struct iio_chan_spec htu21_channels[] = {
{
.type = IIO_TEMP,
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
},
{
.type = IIO_HUMIDITYRELATIVE,
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
}
};
/*
* Meas Spec recommendation is to not read temperature
* on this driver part for MS8607
*/
static const struct iio_chan_spec ms8607_channels[] = {
{
.type = IIO_HUMIDITYRELATIVE,
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
}
};
static ssize_t htu21_show_battery_low(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ms_ht_dev *dev_data = iio_priv(indio_dev);
return ms_sensors_show_battery_low(dev_data, buf);
}
static ssize_t htu21_show_heater(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ms_ht_dev *dev_data = iio_priv(indio_dev);
return ms_sensors_show_heater(dev_data, buf);
}
static ssize_t htu21_write_heater(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ms_ht_dev *dev_data = iio_priv(indio_dev);
return ms_sensors_write_heater(dev_data, buf, len);
}
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(htu21_show_samp_freq);
static IIO_DEVICE_ATTR(battery_low, S_IRUGO,
htu21_show_battery_low, NULL, 0);
static IIO_DEVICE_ATTR(heater_enable, S_IRUGO | S_IWUSR,
htu21_show_heater, htu21_write_heater, 0);
static struct attribute *htu21_attributes[] = {
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_battery_low.dev_attr.attr,
&iio_dev_attr_heater_enable.dev_attr.attr,
NULL,
};
static const struct attribute_group htu21_attribute_group = {
.attrs = htu21_attributes,
};
static const struct iio_info htu21_info = {
.read_raw = htu21_read_raw,
.write_raw = htu21_write_raw,
.attrs = &htu21_attribute_group,
.driver_module = THIS_MODULE,
};
static int htu21_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ms_ht_dev *dev_data;
struct iio_dev *indio_dev;
int ret;
u64 serial_number;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
I2C_FUNC_SMBUS_WRITE_BYTE |
I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
dev_err(&client->dev,
"Adapter does not support some i2c transaction\n");
return -ENODEV;
}
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
if (!indio_dev)
return -ENOMEM;
dev_data = iio_priv(indio_dev);
dev_data->client = client;
dev_data->res_index = 0;
mutex_init(&dev_data->lock);
indio_dev->info = &htu21_info;
indio_dev->name = id->name;
indio_dev->dev.parent = &client->dev;
indio_dev->modes = INDIO_DIRECT_MODE;
if (id->driver_data == MS8607) {
indio_dev->channels = ms8607_channels;
indio_dev->num_channels = ARRAY_SIZE(ms8607_channels);
} else {
indio_dev->channels = htu21_channels;
indio_dev->num_channels = ARRAY_SIZE(htu21_channels);
}
i2c_set_clientdata(client, indio_dev);
ret = ms_sensors_reset(client, HTU21_RESET, 15000);
if (ret)
return ret;
ret = ms_sensors_read_serial(client, &serial_number);
if (ret)
return ret;
dev_info(&client->dev, "Serial number : %llx", serial_number);
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id htu21_id[] = {
{"htu21", HTU21},
{"ms8607-humidity", MS8607},
{}
};
static struct i2c_driver htu21_driver = {
.probe = htu21_probe,
.id_table = htu21_id,
.driver = {
.name = "htu21",
},
};
module_i2c_driver(htu21_driver);
MODULE_DESCRIPTION("Measurement-Specialties htu21 temperature and humidity driver");
MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
MODULE_LICENSE("GPL v2");
......@@ -27,7 +27,6 @@
#include <linux/iio/trigger_consumer.h>
#define KMX61_DRV_NAME "kmx61"
#define KMX61_GPIO_NAME "kmx61_int"
#define KMX61_IRQ_NAME "kmx61_event"
#define KMX61_REG_WHO_AM_I 0x00
......@@ -1243,30 +1242,6 @@ static const char *kmx61_match_acpi_device(struct device *dev)
return dev_name(dev);
}
static int kmx61_gpio_probe(struct i2c_client *client, struct kmx61_data *data)
{
struct device *dev;
struct gpio_desc *gpio;
int ret;
if (!client)
return -EINVAL;
dev = &client->dev;
/* data ready gpio interrupt pin */
gpio = devm_gpiod_get_index(dev, KMX61_GPIO_NAME, 0, GPIOD_IN);
if (IS_ERR(gpio)) {
dev_err(dev, "acpi gpio get index failed\n");
return PTR_ERR(gpio);
}
ret = gpiod_to_irq(gpio);
dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
return ret;
}
static struct iio_dev *kmx61_indiodev_setup(struct kmx61_data *data,
const struct iio_info *info,
const struct iio_chan_spec *chan,
......@@ -1360,9 +1335,6 @@ static int kmx61_probe(struct i2c_client *client,
if (ret < 0)
return ret;
if (client->irq < 0)
client->irq = kmx61_gpio_probe(client, data);
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
kmx61_data_rdy_trig_poll,
......
......@@ -472,7 +472,7 @@ static int apds9960_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct apds9960_data *data = iio_priv(indio_dev);
u16 buf;
__le16 buf;
int ret = -EINVAL;
if (data->gesture_mode_running)
......@@ -613,7 +613,7 @@ static int apds9960_read_event(struct iio_dev *indio_dev,
int *val, int *val2)
{
u8 reg;
u16 buf;
__le16 buf;
int ret = 0;
struct apds9960_data *data = iio_priv(indio_dev);
......@@ -649,7 +649,7 @@ static int apds9960_write_event(struct iio_dev *indio_dev,
int val, int val2)
{
u8 reg;
u16 buf;
__le16 buf;
int ret = 0;
struct apds9960_data *data = iio_priv(indio_dev);
......
......@@ -47,7 +47,6 @@
#define STK3310_DRIVER_NAME "stk3310"
#define STK3310_REGMAP_NAME "stk3310_regmap"
#define STK3310_EVENT "stk3310_event"
#define STK3310_GPIO "stk3310_gpio"
#define STK3310_SCALE_AVAILABLE "6.4 1.6 0.4 0.1"
......@@ -477,30 +476,6 @@ static int stk3310_init(struct iio_dev *indio_dev)
return ret;
}
static int stk3310_gpio_probe(struct i2c_client *client)
{
struct device *dev;
struct gpio_desc *gpio;
int ret;
if (!client)
return -EINVAL;
dev = &client->dev;
/* gpio interrupt pin */
gpio = devm_gpiod_get_index(dev, STK3310_GPIO, 0, GPIOD_IN);
if (IS_ERR(gpio)) {
dev_err(dev, "acpi gpio get index failed\n");
return PTR_ERR(gpio);
}
ret = gpiod_to_irq(gpio);
dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
return ret;
}
static bool stk3310_is_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
......@@ -624,15 +599,7 @@ static int stk3310_probe(struct i2c_client *client,
if (ret < 0)
return ret;
if (client->irq < 0) {
client->irq = stk3310_gpio_probe(client);
if (client->irq < 0) {
ret = client->irq;
goto err_standby;
}
}
if (client->irq >= 0) {
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
stk3310_irq_handler,
stk3310_irq_event_handler,
......
......@@ -37,7 +37,6 @@
#define BMC150_MAGN_DRV_NAME "bmc150_magn"
#define BMC150_MAGN_IRQ_NAME "bmc150_magn_event"
#define BMC150_MAGN_GPIO_INT "interrupt"
#define BMC150_MAGN_REG_CHIP_ID 0x40
#define BMC150_MAGN_CHIP_ID_VAL 0x32
......@@ -833,31 +832,6 @@ static const struct iio_buffer_setup_ops bmc150_magn_buffer_setup_ops = {
.postdisable = bmc150_magn_buffer_postdisable,
};
static int bmc150_magn_gpio_probe(struct i2c_client *client)
{
struct device *dev;
struct gpio_desc *gpio;
int ret;
if (!client)
return -EINVAL;
dev = &client->dev;
/* data ready GPIO interrupt pin */
gpio = devm_gpiod_get_index(dev, BMC150_MAGN_GPIO_INT, 0, GPIOD_IN);
if (IS_ERR(gpio)) {
dev_err(dev, "ACPI GPIO get index failed\n");
return PTR_ERR(gpio);
}
ret = gpiod_to_irq(gpio);
dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
return ret;
}
static const char *bmc150_magn_match_acpi_device(struct device *dev)
{
const struct acpi_device_id *id;
......@@ -911,9 +885,6 @@ static int bmc150_magn_probe(struct i2c_client *client,
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &bmc150_magn_info;
if (client->irq <= 0)
client->irq = bmc150_magn_gpio_probe(client);
if (client->irq > 0) {
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d",
......
#
# Potentiometer drivers
#
# When adding new entries keep the list in alphabetical order
menu "Digital potentiometers"
config MCP4531
tristate "Microchip MCP45xx/MCP46xx Digital Potentiometer driver"
depends on I2C
help
Say yes here to build support for the Microchip
MCP4531, MCP4532, MCP4551, MCP4552,
MCP4631, MCP4632, MCP4651, MCP4652
digital potentiomenter chips.
To compile this driver as a module, choose M here: the
module will be called mcp4531.
endmenu
#
# Makefile for industrial I/O potentiometer drivers
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_MCP4531) += mcp4531.o
/*
* Industrial I/O driver for Microchip digital potentiometers
* Copyright (c) 2015 Axentia Technologies AB
* Author: Peter Rosin <peda@axentia.se>
*
* Datasheet: http://www.microchip.com/downloads/en/DeviceDoc/22096b.pdf
*
* DEVID #Wipers #Positions Resistor Opts (kOhm) i2c address
* mcp4531 1 129 5, 10, 50, 100 010111x
* mcp4532 1 129 5, 10, 50, 100 01011xx
* mcp4551 1 257 5, 10, 50, 100 010111x
* mcp4552 1 257 5, 10, 50, 100 01011xx
* mcp4631 2 129 5, 10, 50, 100 0101xxx
* mcp4632 2 129 5, 10, 50, 100 01011xx
* mcp4651 2 257 5, 10, 50, 100 0101xxx
* mcp4652 2 257 5, 10, 50, 100 01011xx
*
* 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.
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/iio/iio.h>
struct mcp4531_cfg {
int wipers;
int max_pos;
int kohms;
};
enum mcp4531_type {
MCP453x_502,
MCP453x_103,
MCP453x_503,
MCP453x_104,
MCP455x_502,
MCP455x_103,
MCP455x_503,
MCP455x_104,
MCP463x_502,
MCP463x_103,
MCP463x_503,
MCP463x_104,
MCP465x_502,
MCP465x_103,
MCP465x_503,
MCP465x_104,
};
static const struct mcp4531_cfg mcp4531_cfg[] = {
[MCP453x_502] = { .wipers = 1, .max_pos = 128, .kohms = 5, },
[MCP453x_103] = { .wipers = 1, .max_pos = 128, .kohms = 10, },
[MCP453x_503] = { .wipers = 1, .max_pos = 128, .kohms = 50, },
[MCP453x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, },
[MCP455x_502] = { .wipers = 1, .max_pos = 256, .kohms = 5, },
[MCP455x_103] = { .wipers = 1, .max_pos = 256, .kohms = 10, },
[MCP455x_503] = { .wipers = 1, .max_pos = 256, .kohms = 50, },
[MCP455x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, },
[MCP463x_502] = { .wipers = 2, .max_pos = 128, .kohms = 5, },
[MCP463x_103] = { .wipers = 2, .max_pos = 128, .kohms = 10, },
[MCP463x_503] = { .wipers = 2, .max_pos = 128, .kohms = 50, },
[MCP463x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, },
[MCP465x_502] = { .wipers = 2, .max_pos = 256, .kohms = 5, },
[MCP465x_103] = { .wipers = 2, .max_pos = 256, .kohms = 10, },
[MCP465x_503] = { .wipers = 2, .max_pos = 256, .kohms = 50, },
[MCP465x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, },
};
#define MCP4531_WRITE (0 << 2)
#define MCP4531_INCR (1 << 2)
#define MCP4531_DECR (2 << 2)
#define MCP4531_READ (3 << 2)
#define MCP4531_WIPER_SHIFT (4)
struct mcp4531_data {
struct i2c_client *client;
unsigned long devid;
};
#define MCP4531_CHANNEL(ch) { \
.type = IIO_RESISTANCE, \
.indexed = 1, \
.output = 1, \
.channel = (ch), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
}
static const struct iio_chan_spec mcp4531_channels[] = {
MCP4531_CHANNEL(0),
MCP4531_CHANNEL(1),
};
static int mcp4531_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct mcp4531_data *data = iio_priv(indio_dev);
int address = chan->channel << MCP4531_WIPER_SHIFT;
s32 ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = i2c_smbus_read_word_swapped(data->client,
MCP4531_READ | address);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 1000 * mcp4531_cfg[data->devid].kohms;
*val2 = mcp4531_cfg[data->devid].max_pos;
return IIO_VAL_FRACTIONAL;
}
return -EINVAL;
}
static int mcp4531_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct mcp4531_data *data = iio_priv(indio_dev);
int address = chan->channel << MCP4531_WIPER_SHIFT;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val > mcp4531_cfg[data->devid].max_pos || val < 0)
return -EINVAL;
break;
default:
return -EINVAL;
}
return i2c_smbus_write_byte_data(data->client,
MCP4531_WRITE | address | (val >> 8),
val & 0xff);
}
static const struct iio_info mcp4531_info = {
.read_raw = mcp4531_read_raw,
.write_raw = mcp4531_write_raw,
.driver_module = THIS_MODULE,
};
static int mcp4531_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
unsigned long devid = id->driver_data;
struct mcp4531_data *data;
struct iio_dev *indio_dev;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WORD_DATA)) {
dev_err(dev, "SMBUS Word Data not supported\n");
return -EIO;
}
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
data->devid = devid;
indio_dev->dev.parent = dev;
indio_dev->info = &mcp4531_info;
indio_dev->channels = mcp4531_channels;
indio_dev->num_channels = mcp4531_cfg[devid].wipers;
indio_dev->name = client->name;
return devm_iio_device_register(dev, indio_dev);
}
static const struct i2c_device_id mcp4531_id[] = {
{ "mcp4531-502", MCP453x_502 },
{ "mcp4531-103", MCP453x_103 },
{ "mcp4531-503", MCP453x_503 },
{ "mcp4531-104", MCP453x_104 },
{ "mcp4532-502", MCP453x_502 },
{ "mcp4532-103", MCP453x_103 },
{ "mcp4532-503", MCP453x_503 },
{ "mcp4532-104", MCP453x_104 },
{ "mcp4551-502", MCP455x_502 },
{ "mcp4551-103", MCP455x_103 },
{ "mcp4551-503", MCP455x_503 },
{ "mcp4551-104", MCP455x_104 },
{ "mcp4552-502", MCP455x_502 },
{ "mcp4552-103", MCP455x_103 },
{ "mcp4552-503", MCP455x_503 },
{ "mcp4552-104", MCP455x_104 },
{ "mcp4631-502", MCP463x_502 },
{ "mcp4631-103", MCP463x_103 },
{ "mcp4631-503", MCP463x_503 },
{ "mcp4631-104", MCP463x_104 },
{ "mcp4632-502", MCP463x_502 },
{ "mcp4632-103", MCP463x_103 },
{ "mcp4632-503", MCP463x_503 },
{ "mcp4632-104", MCP463x_104 },
{ "mcp4651-502", MCP465x_502 },
{ "mcp4651-103", MCP465x_103 },
{ "mcp4651-503", MCP465x_503 },
{ "mcp4651-104", MCP465x_104 },
{ "mcp4652-502", MCP465x_502 },
{ "mcp4652-103", MCP465x_103 },
{ "mcp4652-503", MCP465x_503 },
{ "mcp4652-104", MCP465x_104 },
{}
};
MODULE_DEVICE_TABLE(i2c, mcp4531_id);
static struct i2c_driver mcp4531_driver = {
.driver = {
.name = "mcp4531",
},
.probe = mcp4531_probe,
.id_table = mcp4531_id,
};
module_i2c_driver(mcp4531_driver);
MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
MODULE_DESCRIPTION("MCP4531 digital potentiometer");
MODULE_LICENSE("GPL");
......@@ -79,6 +79,19 @@ config MS5611_SPI
To compile this driver as a module, choose M here: the module will
be called ms5611_spi.
config MS5637
tristate "Measurement Specialties MS5637 pressure & temperature sensor"
depends on I2C
select IIO_MS_SENSORS_I2C
help
If you say yes here you get support for the Measurement Specialties
MS5637 pressure and temperature sensor.
This driver is also used for MS8607 temperature, pressure & humidity
sensor
This driver can also be built as a module. If so, the module will
be called ms5637.
config IIO_ST_PRESS
tristate "STMicroelectronics pressure sensor Driver"
depends on (I2C || SPI_MASTER) && SYSFS
......
......@@ -10,6 +10,7 @@ obj-$(CONFIG_MPL3115) += mpl3115.o
obj-$(CONFIG_MS5611) += ms5611_core.o
obj-$(CONFIG_MS5611_I2C) += ms5611_i2c.o
obj-$(CONFIG_MS5611_SPI) += ms5611_spi.o
obj-$(CONFIG_MS5637) += ms5637.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
......
/*
* ms5637.c - Support for Measurement-Specialties ms5637 and ms8607
* pressure & temperature sensor
*
* Copyright (c) 2015 Measurement-Specialties
*
* Licensed under the GPL-2.
*
* (7-bit I2C slave address 0x76)
*
* Datasheet:
* http://www.meas-spec.com/downloads/MS5637-02BA03.pdf
* Datasheet:
* http://www.meas-spec.com/downloads/MS8607-02BA01.pdf
*/
#include <linux/init.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/stat.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/mutex.h>
#include "../common/ms_sensors/ms_sensors_i2c.h"
static const int ms5637_samp_freq[6] = { 960, 480, 240, 120, 60, 30 };
/* String copy of the above const for readability purpose */
static const char ms5637_show_samp_freq[] = "960 480 240 120 60 30";
static int ms5637_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *val,
int *val2, long mask)
{
int ret;
int temperature;
unsigned int pressure;
struct ms_tp_dev *dev_data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
ret = ms_sensors_read_temp_and_pressure(dev_data,
&temperature,
&pressure);
if (ret)
return ret;
switch (channel->type) {
case IIO_TEMP: /* in milli °C */
*val = temperature;
return IIO_VAL_INT;
case IIO_PRESSURE: /* in kPa */
*val = pressure / 1000;
*val2 = (pressure % 1000) * 1000;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SAMP_FREQ:
*val = ms5637_samp_freq[dev_data->res_index];
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int ms5637_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct ms_tp_dev *dev_data = iio_priv(indio_dev);
int i;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
i = ARRAY_SIZE(ms5637_samp_freq);
while (i-- > 0)
if (val == ms5637_samp_freq[i])
break;
if (i < 0)
return -EINVAL;
dev_data->res_index = i;
return 0;
default:
return -EINVAL;
}
}
static const struct iio_chan_spec ms5637_channels[] = {
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
},
{
.type = IIO_PRESSURE,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
}
};
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(ms5637_show_samp_freq);
static struct attribute *ms5637_attributes[] = {
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
NULL,
};
static const struct attribute_group ms5637_attribute_group = {
.attrs = ms5637_attributes,
};
static const struct iio_info ms5637_info = {
.read_raw = ms5637_read_raw,
.write_raw = ms5637_write_raw,
.attrs = &ms5637_attribute_group,
.driver_module = THIS_MODULE,
};
static int ms5637_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ms_tp_dev *dev_data;
struct iio_dev *indio_dev;
int ret;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_WORD_DATA |
I2C_FUNC_SMBUS_WRITE_BYTE |
I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
dev_err(&client->dev,
"Adapter does not support some i2c transaction\n");
return -ENODEV;
}
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
if (!indio_dev)
return -ENOMEM;
dev_data = iio_priv(indio_dev);
dev_data->client = client;
dev_data->res_index = 5;
mutex_init(&dev_data->lock);
indio_dev->info = &ms5637_info;
indio_dev->name = id->name;
indio_dev->dev.parent = &client->dev;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ms5637_channels;
indio_dev->num_channels = ARRAY_SIZE(ms5637_channels);
i2c_set_clientdata(client, indio_dev);
ret = ms_sensors_reset(client, 0x1E, 3000);
if (ret)
return ret;
ret = ms_sensors_tp_read_prom(dev_data);
if (ret)
return ret;
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id ms5637_id[] = {
{"ms5637", 0},
{"ms8607-temppressure", 1},
{}
};
static struct i2c_driver ms5637_driver = {
.probe = ms5637_probe,
.id_table = ms5637_id,
.driver = {
.name = "ms5637"
},
};
module_i2c_driver(ms5637_driver);
MODULE_DESCRIPTION("Measurement-Specialties ms5637 temperature & pressure driver");
MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
MODULE_LICENSE("GPL v2");
......@@ -271,6 +271,7 @@ static const struct of_device_id lidar_dt_ids[] = {
{ .compatible = "pulsedlight,lidar-lite-v2" },
{ }
};
MODULE_DEVICE_TABLE(of, lidar_dt_ids);
static struct i2c_driver lidar_driver = {
.driver = {
......
......@@ -868,21 +868,12 @@ static void sx9500_gpio_probe(struct i2c_client *client,
struct sx9500_data *data)
{
struct device *dev;
struct gpio_desc *gpio;
if (!client)
return;
dev = &client->dev;
if (client->irq <= 0) {
gpio = devm_gpiod_get_index(dev, SX9500_GPIO_INT, 0, GPIOD_IN);
if (IS_ERR(gpio))
dev_err(dev, "gpio get irq failed\n");
else
client->irq = gpiod_to_irq(gpio);
}
data->gpiod_rst = devm_gpiod_get_index(dev, SX9500_GPIO_RESET,
0, GPIOD_OUT_HIGH);
if (IS_ERR(data->gpiod_rst)) {
......
......@@ -23,4 +23,26 @@ config TMP006
This driver can also be built as a module. If so, the module will
be called tmp006.
config TSYS01
tristate "Measurement Specialties TSYS01 temperature sensor using I2C bus connection"
depends on I2C
select IIO_MS_SENSORS_I2C
help
If you say yes here you get support for the Measurement Specialties
TSYS01 I2C temperature sensor.
This driver can also be built as a module. If so, the module will
be called tsys01.
config TSYS02D
tristate "Measurement Specialties TSYS02D temperature sensor"
depends on I2C
select IIO_MS_SENSORS_I2C
help
If you say yes here you get support for the Measurement Specialties
TSYS02D temperature sensor.
This driver can also be built as a module. If so, the module will
be called tsys02d.
endmenu
......@@ -4,3 +4,5 @@
obj-$(CONFIG_MLX90614) += mlx90614.o
obj-$(CONFIG_TMP006) += tmp006.o
obj-$(CONFIG_TSYS01) += tsys01.o
obj-$(CONFIG_TSYS02D) += tsys02d.o
......@@ -72,6 +72,7 @@
#define MLX90614_CONST_SCALE 20 /* Scale in milliKelvin (0.02 * 1000) */
#define MLX90614_CONST_RAW_EMISSIVITY_MAX 65535 /* max value for emissivity */
#define MLX90614_CONST_EMISSIVITY_RESOLUTION 15259 /* 1/65535 ~ 0.000015259 */
#define MLX90614_CONST_FIR 0x7 /* Fixed value for FIR part of low pass filter */
struct mlx90614_data {
struct i2c_client *client;
......@@ -156,15 +157,16 @@ static inline s32 mlx90614_iir_search(const struct i2c_client *client,
* changes
*/
ret = i2c_smbus_read_word_data(client, MLX90614_CONFIG);
if (ret > 0)
if (ret < 0)
return ret;
ret &= ~MLX90614_CONFIG_FIR_MASK;
ret |= MLX90614_CONST_FIR << MLX90614_CONFIG_FIR_SHIFT;
ret &= ~MLX90614_CONFIG_IIR_MASK;
ret |= i << MLX90614_CONFIG_IIR_SHIFT;
/* Write changed values */
ret = mlx90614_write_word(client, MLX90614_CONFIG,
(i << MLX90614_CONFIG_IIR_SHIFT) |
(((u16) ((0x7 << MLX90614_CONFIG_FIR_SHIFT) |
((u16) ret & (~((u16) MLX90614_CONFIG_FIR_MASK))))) &
(~(u16) MLX90614_CONFIG_IIR_MASK)));
ret = mlx90614_write_word(client, MLX90614_CONFIG, ret);
return ret;
}
......
/*
* tsys01.c - Support for Measurement-Specialties tsys01 temperature sensor
*
* Copyright (c) 2015 Measurement-Specialties
*
* Licensed under the GPL-2.
*
* Datasheet:
* http://www.meas-spec.com/downloads/TSYS01_Digital_Temperature_Sensor.pdf
*/
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/stat.h>
#include "../common/ms_sensors/ms_sensors_i2c.h"
/* TSYS01 Commands */
#define TSYS01_RESET 0x1E
#define TSYS01_CONVERSION_START 0x48
#define TSYS01_ADC_READ 0x00
#define TSYS01_PROM_READ 0xA0
#define TSYS01_PROM_WORDS_NB 8
struct tsys01_dev {
void *client;
struct mutex lock; /* lock during conversion */
int (*reset)(void *cli, u8 cmd, unsigned int delay);
int (*convert_and_read)(void *cli, u8 conv, u8 rd,
unsigned int delay, u32 *adc);
int (*read_prom_word)(void *cli, int cmd, u16 *word);
u16 prom[TSYS01_PROM_WORDS_NB];
};
/* Multiplication coefficients for temperature computation */
static const int coeff_mul[] = { -1500000, 1000000, -2000000,
4000000, -2000000 };
static int tsys01_read_temperature(struct iio_dev *indio_dev,
s32 *temperature)
{
int ret, i;
u32 adc;
s64 temp = 0;
struct tsys01_dev *dev_data = iio_priv(indio_dev);
mutex_lock(&dev_data->lock);
ret = dev_data->convert_and_read(dev_data->client,
TSYS01_CONVERSION_START,
TSYS01_ADC_READ, 9000, &adc);
mutex_unlock(&dev_data->lock);
if (ret)
return ret;
adc >>= 8;
/* Temperature algorithm */
for (i = 4; i > 0; i--) {
temp += coeff_mul[i] *
(s64)dev_data->prom[5 - i];
temp *= (s64)adc;
temp = div64_s64(temp, 100000);
}
temp *= 10;
temp += coeff_mul[0] * (s64)dev_data->prom[5];
temp = div64_s64(temp, 100000);
*temperature = temp;
return 0;
}
static int tsys01_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *val,
int *val2, long mask)
{
int ret;
s32 temperature;
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
switch (channel->type) {
case IIO_TEMP: /* in milli °C */
ret = tsys01_read_temperature(indio_dev, &temperature);
if (ret)
return ret;
*val = temperature;
return IIO_VAL_INT;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static const struct iio_chan_spec tsys01_channels[] = {
{
.type = IIO_TEMP,
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
}
};
static const struct iio_info tsys01_info = {
.read_raw = tsys01_read_raw,
.driver_module = THIS_MODULE,
};
static bool tsys01_crc_valid(u16 *n_prom)
{
u8 cnt;
u8 sum = 0;
for (cnt = 0; cnt < TSYS01_PROM_WORDS_NB; cnt++)
sum += ((n_prom[0] >> 8) + (n_prom[0] & 0xFF));
return (sum == 0);
}
static int tsys01_read_prom(struct iio_dev *indio_dev)
{
int i, ret;
struct tsys01_dev *dev_data = iio_priv(indio_dev);
char buf[7 * TSYS01_PROM_WORDS_NB + 1];
char *ptr = buf;
for (i = 0; i < TSYS01_PROM_WORDS_NB; i++) {
ret = dev_data->read_prom_word(dev_data->client,
TSYS01_PROM_READ + (i << 1),
&dev_data->prom[i]);
if (ret)
return ret;
ret = sprintf(ptr, "0x%04x ", dev_data->prom[i]);
ptr += ret;
}
if (!tsys01_crc_valid(dev_data->prom)) {
dev_err(&indio_dev->dev, "prom crc check error\n");
return -ENODEV;
}
*ptr = 0;
dev_info(&indio_dev->dev, "PROM coefficients : %s\n", buf);
return 0;
}
static int tsys01_probe(struct iio_dev *indio_dev, struct device *dev)
{
int ret;
struct tsys01_dev *dev_data = iio_priv(indio_dev);
mutex_init(&dev_data->lock);
indio_dev->info = &tsys01_info;
indio_dev->name = dev->driver->name;
indio_dev->dev.parent = dev;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = tsys01_channels;
indio_dev->num_channels = ARRAY_SIZE(tsys01_channels);
ret = dev_data->reset(dev_data->client, TSYS01_RESET, 3000);
if (ret)
return ret;
ret = tsys01_read_prom(indio_dev);
if (ret)
return ret;
return devm_iio_device_register(dev, indio_dev);
}
static int tsys01_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct tsys01_dev *dev_data;
struct iio_dev *indio_dev;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_WRITE_BYTE |
I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
dev_err(&client->dev,
"Adapter does not support some i2c transaction\n");
return -ENODEV;
}
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
if (!indio_dev)
return -ENOMEM;
dev_data = iio_priv(indio_dev);
dev_data->client = client;
dev_data->reset = ms_sensors_reset;
dev_data->read_prom_word = ms_sensors_read_prom_word;
dev_data->convert_and_read = ms_sensors_convert_and_read;
i2c_set_clientdata(client, indio_dev);
return tsys01_probe(indio_dev, &client->dev);
}
static const struct i2c_device_id tsys01_id[] = {
{"tsys01", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, tsys01_id);
static struct i2c_driver tsys01_driver = {
.probe = tsys01_i2c_probe,
.id_table = tsys01_id,
.driver = {
.name = "tsys01",
},
};
module_i2c_driver(tsys01_driver);
MODULE_DESCRIPTION("Measurement-Specialties tsys01 temperature driver");
MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
MODULE_LICENSE("GPL v2");
/*
* tsys02d.c - Support for Measurement-Specialties tsys02d temperature sensor
*
* Copyright (c) 2015 Measurement-Specialties
*
* Licensed under the GPL-2.
*
* (7-bit I2C slave address 0x40)
*
* Datasheet:
* http://www.meas-spec.com/downloads/Digital_Sensor_TSYS02D.pdf
*/
#include <linux/init.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/stat.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include "../common/ms_sensors/ms_sensors_i2c.h"
#define TSYS02D_RESET 0xFE
static const int tsys02d_samp_freq[4] = { 20, 40, 70, 140 };
/* String copy of the above const for readability purpose */
static const char tsys02d_show_samp_freq[] = "20 40 70 140";
static int tsys02d_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *val,
int *val2, long mask)
{
int ret;
s32 temperature;
struct ms_ht_dev *dev_data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
switch (channel->type) {
case IIO_TEMP: /* in milli °C */
ret = ms_sensors_ht_read_temperature(dev_data,
&temperature);
if (ret)
return ret;
*val = temperature;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SAMP_FREQ:
*val = tsys02d_samp_freq[dev_data->res_index];
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int tsys02d_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct ms_ht_dev *dev_data = iio_priv(indio_dev);
int i, ret;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
i = ARRAY_SIZE(tsys02d_samp_freq);
while (i-- > 0)
if (val == tsys02d_samp_freq[i])
break;
if (i < 0)
return -EINVAL;
mutex_lock(&dev_data->lock);
dev_data->res_index = i;
ret = ms_sensors_write_resolution(dev_data, i);
mutex_unlock(&dev_data->lock);
return ret;
default:
return -EINVAL;
}
}
static const struct iio_chan_spec tsys02d_channels[] = {
{
.type = IIO_TEMP,
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
}
};
static ssize_t tsys02_read_battery_low(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ms_ht_dev *dev_data = iio_priv(indio_dev);
return ms_sensors_show_battery_low(dev_data, buf);
}
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(tsys02d_show_samp_freq);
static IIO_DEVICE_ATTR(battery_low, S_IRUGO,
tsys02_read_battery_low, NULL, 0);
static struct attribute *tsys02d_attributes[] = {
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_battery_low.dev_attr.attr,
NULL,
};
static const struct attribute_group tsys02d_attribute_group = {
.attrs = tsys02d_attributes,
};
static const struct iio_info tsys02d_info = {
.read_raw = tsys02d_read_raw,
.write_raw = tsys02d_write_raw,
.attrs = &tsys02d_attribute_group,
.driver_module = THIS_MODULE,
};
static int tsys02d_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ms_ht_dev *dev_data;
struct iio_dev *indio_dev;
int ret;
u64 serial_number;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
I2C_FUNC_SMBUS_WRITE_BYTE |
I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
dev_err(&client->dev,
"Adapter does not support some i2c transaction\n");
return -ENODEV;
}
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
if (!indio_dev)
return -ENOMEM;
dev_data = iio_priv(indio_dev);
dev_data->client = client;
dev_data->res_index = 0;
mutex_init(&dev_data->lock);
indio_dev->info = &tsys02d_info;
indio_dev->name = id->name;
indio_dev->dev.parent = &client->dev;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = tsys02d_channels;
indio_dev->num_channels = ARRAY_SIZE(tsys02d_channels);
i2c_set_clientdata(client, indio_dev);
ret = ms_sensors_reset(client, TSYS02D_RESET, 15000);
if (ret)
return ret;
ret = ms_sensors_read_serial(client, &serial_number);
if (ret)
return ret;
dev_info(&client->dev, "Serial number : %llx", serial_number);
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id tsys02d_id[] = {
{"tsys02d", 0},
{}
};
static struct i2c_driver tsys02d_driver = {
.probe = tsys02d_probe,
.id_table = tsys02d_id,
.driver = {
.name = "tsys02d",
},
};
module_i2c_driver(tsys02d_driver);
MODULE_DESCRIPTION("Measurement-Specialties tsys02d temperature driver");
MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
MODULE_LICENSE("GPL v2");
......@@ -68,12 +68,12 @@
#define AD7746_VTSETUP_VTCHOP (1 << 0)
/* Excitation Setup Register Bit Designations (AD7746_REG_EXC_SETUP) */
#define AD7746_EXCSETUP_CLKCTRL (1 << 7)
#define AD7746_EXCSETUP_EXCON (1 << 6)
#define AD7746_EXCSETUP_EXCB (1 << 5)
#define AD7746_EXCSETUP_NEXCB (1 << 4)
#define AD7746_EXCSETUP_EXCA (1 << 3)
#define AD7746_EXCSETUP_NEXCA (1 << 2)
#define AD7746_EXCSETUP_CLKCTRL BIT(7)
#define AD7746_EXCSETUP_EXCON BIT(6)
#define AD7746_EXCSETUP_EXCB BIT(5)
#define AD7746_EXCSETUP_NEXCB BIT(4)
#define AD7746_EXCSETUP_EXCA BIT(3)
#define AD7746_EXCSETUP_NEXCA BIT(2)
#define AD7746_EXCSETUP_EXCLVL(x) (((x) & 0x3) << 0)
/* Config Register Bit Designations (AD7746_REG_CFG) */
......@@ -528,7 +528,8 @@ static int ad7746_write_raw(struct iio_dev *indio_dev,
goto out;
}
/* CAPDAC Scale = 21pF_typ / 127
/*
* CAPDAC Scale = 21pF_typ / 127
* CIN Scale = 8.192pF / 2^24
* Offset Scale = CAPDAC Scale / CIN Scale = 338646
*/
......@@ -600,7 +601,8 @@ static int ad7746_read_raw(struct iio_dev *indio_dev,
switch (chan->type) {
case IIO_TEMP:
/* temperature in milli degrees Celsius
/*
* temperature in milli degrees Celsius
* T = ((*val / 2048) - 4096) * 1000
*/
*val = (*val * 125) / 256;
......@@ -753,8 +755,6 @@ static int ad7746_probe(struct i2c_client *client,
if (ret)
return ret;
dev_info(&client->dev, "%s capacitive sensor registered\n", id->name);
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment