mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-15 06:55:13 +08:00
Third set of IIO new device support, features and cleanups for the 4.6 cycle.
Good to see several new contributors in this set - and more generally a number of new 'faces' over this whole cycle. Staging movements * hmc5843 - out of staging. * periodic RTC trigger - driver dropped. This is an ancient driver (brings back some memories ;) that was always somewhat of a bodge. Originally there was a driver that never went into mainline that supported large numbers of periodict timers on the PXA270 via this route. Discussions to have a generic periodic timer subsystem never went anywhere. At the time RTC periodic interrupts were real - now they are emulated using high resolution timers so with the HRT driver this has become pointless. New device support * mpu6050 driver - Add support for the mpu6500. * TI tpl0102 potentiometer - new driver. * Vybrid SoC DAC - new driver. The ADC on this SoC has been supported for a while, this adds a separate driver for the DAC. New Features * hmc5844 - Attributes to configure the bias current (typically part of a self test) This could be done before via a somewhat obscure custom interface. This at least makes it easy to tell what is going on. - Document all custom attributes. * mpu6050 - Add support for calibration offset control and readback. * ms5611 - power regulator support. This is always one that gets added the first time someone has a board that needs it. Here it was needed, hence it was added. Cleanups / minor fixes * tree wide - clean up all the myriad different return values in response to a failure of i2c_check_functionality. After discussions everyone seemed happy wiht -EOPNOTSUPP which seems to describe the situation well. I encouraged a tree wide cleanup to set a good example in future for this. * core - Typos in the iio_event_spec documentation in iio.h * afe4403 - select REGMAP_SPI to avoid dependency issues - mark suspend/resume as __maybe_unused to avoid warnings *afe4404
- mark suspend/resume as __maybe_unused to avoid warnings * atlas-ph-sensor - switch the regmap cache type from linear to rbtree to gain reading of registers on initial startup. It's not immediately obvious, but regmap flat is meant for high performances cases so doesn't read these registers. - use regmap_bulk_read in one case where it was using i2c_smbus_read_i2c_block_data directly (unlike everything else that was through regmap). * ina2xx - stype cleanups (lots of them!) * isl29018 - Get the struct device back from regmap rather than storing another copy of it in the private data. This cleanup makes sense in a number of other drivers so patches may well follow. * mpu6050 - style cleanups (lots of them!) - improved return value handling - use usleep_range to avoid the usual issues with very short msleeps. - add some missing documentation. * ms5611 - use the probed device name for the device rather than the driver name. - select IIO_BUFFER to avoid dependency issues * palmas - drop IRQF_EARLY_RESUME as no longer needed after genirq changes. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJW0ygBAAoJEFSFNJnE9BaIJDQP/RpVwCxgxgUi0QyuLFAfQ0Ab FJFZznvmK6aGtGBAt/uKwBD5K/JcX9zGgm82j10+rVCtnLxFmusNXB180jUjvknu ZAEzJ58IWX+FqEsbVUZsx8qpef+yCCLP/HHvyctqXhtVTrlVlyoGSfn6+xzP3766 PxkXpdWSd3IEdITYZrZo7BsZ6h6Tjz9c4i40f3RdnEce48nNnzM5IKMNbvU2puRs NxGDXflKKkA5N4uIW2n6pLxIyyW/LdwChmHkR+U7dxxj3/wUK9BC46qvhyqtgC3I U6uYCI+p2up22bfQsZ+p/CKRRhhrOtBs9//wSMapK96CVbI3HGcJLZP1yJENwfW8 5sWEypaZNlpZVnjtREQpk5oz2hOsunxI+7FHSqUjLe+wwON79WXVFZz2qx3NcIle YPZFIQiYZTVauE/PsPy22I2vBoHxpgsD+A8M1d4+nQAH8SkRqvnnu5WVgd3ftm/u kXUjj+s+M1Pn84EIWYlEaIypAnhaNgIDW8M269rRdC0hH6yAxjJ9PXm45TGcRxr/ qmkUKfD5wfPgE3FwYoyH8da22dc7dRSgLdizxtSS7rInmFH1HJ3xb566VszXsPVH tJjM2KtIC16czGUh5V+MmCpdSfOT1wR0wFPdUhGoJGm7sGkTsuoQRkQzgHwJM/aF ITuCZWLR/2YXw0bx4MKM =rDIQ -----END PGP SIGNATURE----- Merge tag 'iio-for-4.6c' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next Jonathan writes: Third set of IIO new device support, features and cleanups for the 4.6 cycle. Good to see several new contributors in this set - and more generally a number of new 'faces' over this whole cycle. Staging movements * hmc5843 - out of staging. * periodic RTC trigger - driver dropped. This is an ancient driver (brings back some memories ;) that was always somewhat of a bodge. Originally there was a driver that never went into mainline that supported large numbers of periodict timers on the PXA270 via this route. Discussions to have a generic periodic timer subsystem never went anywhere. At the time RTC periodic interrupts were real - now they are emulated using high resolution timers so with the HRT driver this has become pointless. New device support * mpu6050 driver - Add support for the mpu6500. * TI tpl0102 potentiometer - new driver. * Vybrid SoC DAC - new driver. The ADC on this SoC has been supported for a while, this adds a separate driver for the DAC. New Features * hmc5844 - Attributes to configure the bias current (typically part of a self test) This could be done before via a somewhat obscure custom interface. This at least makes it easy to tell what is going on. - Document all custom attributes. * mpu6050 - Add support for calibration offset control and readback. * ms5611 - power regulator support. This is always one that gets added the first time someone has a board that needs it. Here it was needed, hence it was added. Cleanups / minor fixes * tree wide - clean up all the myriad different return values in response to a failure of i2c_check_functionality. After discussions everyone seemed happy wiht -EOPNOTSUPP which seems to describe the situation well. I encouraged a tree wide cleanup to set a good example in future for this. * core - Typos in the iio_event_spec documentation in iio.h * afe4403 - select REGMAP_SPI to avoid dependency issues - mark suspend/resume as __maybe_unused to avoid warnings *afe4404
- mark suspend/resume as __maybe_unused to avoid warnings * atlas-ph-sensor - switch the regmap cache type from linear to rbtree to gain reading of registers on initial startup. It's not immediately obvious, but regmap flat is meant for high performances cases so doesn't read these registers. - use regmap_bulk_read in one case where it was using i2c_smbus_read_i2c_block_data directly (unlike everything else that was through regmap). * ina2xx - stype cleanups (lots of them!) * isl29018 - Get the struct device back from regmap rather than storing another copy of it in the private data. This cleanup makes sense in a number of other drivers so patches may well follow. * mpu6050 - style cleanups (lots of them!) - improved return value handling - use usleep_range to avoid the usual issues with very short msleeps. - add some missing documentation. * ms5611 - use the probed device name for the device rather than the driver name. - select IIO_BUFFER to avoid dependency issues * palmas - drop IRQF_EARLY_RESUME as no longer needed after genirq changes.
This commit is contained in:
commit
ec3c13e4ac
15
Documentation/ABI/testing/sysfs-bus-iio-magnetometer-hmc5843
Normal file
15
Documentation/ABI/testing/sysfs-bus-iio-magnetometer-hmc5843
Normal file
@ -0,0 +1,15 @@
|
||||
What: /sys/bus/iio/devices/iio:deviceX/meas_conf
|
||||
What: /sys/bus/iio/devices/iio:deviceX/meas_conf_available
|
||||
KernelVersion: 4.5
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Current configuration and available configurations
|
||||
for the bias current.
|
||||
normal - Normal measurement configurations (default)
|
||||
positivebias - Positive bias configuration
|
||||
negativebias - Negative bias configuration
|
||||
disabled - Only available on HMC5983. Disables magnetic
|
||||
sensor and enables temperature sensor.
|
||||
Note: The effect of this configuration may vary
|
||||
according to the device. For exact documentation
|
||||
check the device's datasheet.
|
@ -5,3 +5,12 @@ Description:
|
||||
Specifies the hardware conversion mode used. The three
|
||||
available modes are "normal", "high-speed" and "low-power",
|
||||
where the last is the default mode.
|
||||
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_conversion_mode
|
||||
KernelVersion: 4.6
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Specifies the hardware conversion mode used within DAC.
|
||||
The two available modes are "high-power" and "low-power",
|
||||
where "low-power" mode is the default mode.
|
||||
|
20
Documentation/devicetree/bindings/iio/dac/vf610-dac.txt
Normal file
20
Documentation/devicetree/bindings/iio/dac/vf610-dac.txt
Normal file
@ -0,0 +1,20 @@
|
||||
Freescale vf610 Digital to Analog Converter bindings
|
||||
|
||||
The devicetree bindings are for the new DAC driver written for
|
||||
vf610 SoCs from Freescale.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should contain "fsl,vf610-dac"
|
||||
- reg: Offset and length of the register set for the device
|
||||
- interrupts: Should contain the interrupt for the device
|
||||
- clocks: The clock is needed by the DAC controller
|
||||
- clock-names: Must contain "dac" matching entry in the clocks property.
|
||||
|
||||
Example:
|
||||
dac0: dac@400cc000 {
|
||||
compatible = "fsl,vf610-dac";
|
||||
reg = <0x400cc000 0x1000>;
|
||||
interrupts = <55 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clock-names = "dac";
|
||||
clocks = <&clks VF610_CLK_DAC0>;
|
||||
};
|
@ -19,17 +19,18 @@
|
||||
*
|
||||
* Configurable 7-bit I2C slave address from 0x40 to 0x4F
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/kthread.h>
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iio/kfifo_buf.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/platform_data/ina2xx.h>
|
||||
|
||||
#include <linux/util_macros.h>
|
||||
|
||||
#include <linux/platform_data/ina2xx.h>
|
||||
|
||||
/* INA2XX registers definition */
|
||||
#define INA2XX_CONFIG 0x00
|
||||
#define INA2XX_SHUNT_VOLTAGE 0x01 /* readonly */
|
||||
@ -38,7 +39,7 @@
|
||||
#define INA2XX_CURRENT 0x04 /* readonly */
|
||||
#define INA2XX_CALIBRATION 0x05
|
||||
|
||||
#define INA226_ALERT_MASK 0x06
|
||||
#define INA226_ALERT_MASK GENMASK(2, 1)
|
||||
#define INA266_CVRF BIT(3)
|
||||
|
||||
#define INA2XX_MAX_REGISTERS 8
|
||||
@ -113,7 +114,7 @@ struct ina2xx_chip_info {
|
||||
struct mutex state_lock;
|
||||
unsigned int shunt_resistor;
|
||||
int avg;
|
||||
s64 prev_ns; /* track buffer capture time, check for underruns*/
|
||||
s64 prev_ns; /* track buffer capture time, check for underruns */
|
||||
int int_time_vbus; /* Bus voltage integration time uS */
|
||||
int int_time_vshunt; /* Shunt voltage integration time uS */
|
||||
bool allow_async_readout;
|
||||
@ -121,21 +122,21 @@ struct ina2xx_chip_info {
|
||||
|
||||
static const struct ina2xx_config ina2xx_config[] = {
|
||||
[ina219] = {
|
||||
.config_default = INA219_CONFIG_DEFAULT,
|
||||
.calibration_factor = 40960000,
|
||||
.shunt_div = 100,
|
||||
.bus_voltage_shift = 3,
|
||||
.bus_voltage_lsb = 4000,
|
||||
.power_lsb = 20000,
|
||||
},
|
||||
.config_default = INA219_CONFIG_DEFAULT,
|
||||
.calibration_factor = 40960000,
|
||||
.shunt_div = 100,
|
||||
.bus_voltage_shift = 3,
|
||||
.bus_voltage_lsb = 4000,
|
||||
.power_lsb = 20000,
|
||||
},
|
||||
[ina226] = {
|
||||
.config_default = INA226_CONFIG_DEFAULT,
|
||||
.calibration_factor = 5120000,
|
||||
.shunt_div = 400,
|
||||
.bus_voltage_shift = 0,
|
||||
.bus_voltage_lsb = 1250,
|
||||
.power_lsb = 25000,
|
||||
},
|
||||
.config_default = INA226_CONFIG_DEFAULT,
|
||||
.calibration_factor = 5120000,
|
||||
.shunt_div = 400,
|
||||
.bus_voltage_shift = 0,
|
||||
.bus_voltage_lsb = 1250,
|
||||
.power_lsb = 25000,
|
||||
},
|
||||
};
|
||||
|
||||
static int ina2xx_read_raw(struct iio_dev *indio_dev,
|
||||
@ -149,7 +150,7 @@ static int ina2xx_read_raw(struct iio_dev *indio_dev,
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
ret = regmap_read(chip->regmap, chan->address, ®val);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (is_signed_reg(chan->address))
|
||||
@ -251,7 +252,7 @@ static int ina226_set_int_time_vbus(struct ina2xx_chip_info *chip,
|
||||
return -EINVAL;
|
||||
|
||||
bits = find_closest(val_us, ina226_conv_time_tab,
|
||||
ARRAY_SIZE(ina226_conv_time_tab));
|
||||
ARRAY_SIZE(ina226_conv_time_tab));
|
||||
|
||||
chip->int_time_vbus = ina226_conv_time_tab[bits];
|
||||
|
||||
@ -270,7 +271,7 @@ static int ina226_set_int_time_vshunt(struct ina2xx_chip_info *chip,
|
||||
return -EINVAL;
|
||||
|
||||
bits = find_closest(val_us, ina226_conv_time_tab,
|
||||
ARRAY_SIZE(ina226_conv_time_tab));
|
||||
ARRAY_SIZE(ina226_conv_time_tab));
|
||||
|
||||
chip->int_time_vshunt = ina226_conv_time_tab[bits];
|
||||
|
||||
@ -285,8 +286,8 @@ static int ina2xx_write_raw(struct iio_dev *indio_dev,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct ina2xx_chip_info *chip = iio_priv(indio_dev);
|
||||
int ret;
|
||||
unsigned int config, tmp;
|
||||
int ret;
|
||||
|
||||
if (iio_buffer_enabled(indio_dev))
|
||||
return -EBUSY;
|
||||
@ -294,8 +295,8 @@ static int ina2xx_write_raw(struct iio_dev *indio_dev,
|
||||
mutex_lock(&chip->state_lock);
|
||||
|
||||
ret = regmap_read(chip->regmap, INA2XX_CONFIG, &config);
|
||||
if (ret < 0)
|
||||
goto _err;
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
tmp = config;
|
||||
|
||||
@ -310,19 +311,19 @@ static int ina2xx_write_raw(struct iio_dev *indio_dev,
|
||||
else
|
||||
ret = ina226_set_int_time_vbus(chip, val2, &tmp);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (!ret && (tmp != config))
|
||||
ret = regmap_write(chip->regmap, INA2XX_CONFIG, tmp);
|
||||
_err:
|
||||
err:
|
||||
mutex_unlock(&chip->state_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t ina2xx_allow_async_readout_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -355,6 +356,7 @@ static int set_shunt_resistor(struct ina2xx_chip_info *chip, unsigned int val)
|
||||
return -EINVAL;
|
||||
|
||||
chip->shunt_resistor = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -438,7 +440,6 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
|
||||
struct ina2xx_chip_info *chip = iio_priv(indio_dev);
|
||||
unsigned short data[8];
|
||||
int bit, ret, i = 0;
|
||||
unsigned long buffer_us, elapsed_us;
|
||||
s64 time_a, time_b;
|
||||
unsigned int alert;
|
||||
|
||||
@ -462,8 +463,6 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
|
||||
return ret;
|
||||
|
||||
alert &= INA266_CVRF;
|
||||
trace_printk("Conversion ready: %d\n", !!alert);
|
||||
|
||||
} while (!alert);
|
||||
|
||||
/*
|
||||
@ -488,19 +487,14 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
|
||||
iio_push_to_buffers_with_timestamp(indio_dev,
|
||||
(unsigned int *)data, time_a);
|
||||
|
||||
buffer_us = (unsigned long)(time_b - time_a) / 1000;
|
||||
elapsed_us = (unsigned long)(time_a - chip->prev_ns) / 1000;
|
||||
|
||||
trace_printk("uS: elapsed: %lu, buf: %lu\n", elapsed_us, buffer_us);
|
||||
|
||||
chip->prev_ns = time_a;
|
||||
|
||||
return buffer_us;
|
||||
return (unsigned long)(time_b - time_a) / 1000;
|
||||
};
|
||||
|
||||
static int ina2xx_capture_thread(void *data)
|
||||
{
|
||||
struct iio_dev *indio_dev = (struct iio_dev *)data;
|
||||
struct iio_dev *indio_dev = data;
|
||||
struct ina2xx_chip_info *chip = iio_priv(indio_dev);
|
||||
unsigned int sampling_us = SAMPLING_PERIOD(chip);
|
||||
int buffer_us;
|
||||
@ -530,12 +524,13 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev)
|
||||
struct ina2xx_chip_info *chip = iio_priv(indio_dev);
|
||||
unsigned int sampling_us = SAMPLING_PERIOD(chip);
|
||||
|
||||
trace_printk("Enabling buffer w/ scan_mask %02x, freq = %d, avg =%u\n",
|
||||
(unsigned int)(*indio_dev->active_scan_mask),
|
||||
1000000/sampling_us, chip->avg);
|
||||
dev_dbg(&indio_dev->dev, "Enabling buffer w/ scan_mask %02x, freq = %d, avg =%u\n",
|
||||
(unsigned int)(*indio_dev->active_scan_mask),
|
||||
1000000 / sampling_us, chip->avg);
|
||||
|
||||
trace_printk("Expected work period: %u us\n", sampling_us);
|
||||
trace_printk("Async readout mode: %d\n", chip->allow_async_readout);
|
||||
dev_dbg(&indio_dev->dev, "Expected work period: %u us\n", sampling_us);
|
||||
dev_dbg(&indio_dev->dev, "Async readout mode: %d\n",
|
||||
chip->allow_async_readout);
|
||||
|
||||
chip->prev_ns = iio_get_time_ns();
|
||||
|
||||
@ -575,8 +570,7 @@ static int ina2xx_debug_reg(struct iio_dev *indio_dev,
|
||||
}
|
||||
|
||||
/* Possible integration times for vshunt and vbus */
|
||||
static IIO_CONST_ATTR_INT_TIME_AVAIL \
|
||||
("0.000140 0.000204 0.000332 0.000588 0.001100 0.002116 0.004156 0.008244");
|
||||
static IIO_CONST_ATTR_INT_TIME_AVAIL("0.000140 0.000204 0.000332 0.000588 0.001100 0.002116 0.004156 0.008244");
|
||||
|
||||
static IIO_DEVICE_ATTR(in_allow_async_readout, S_IRUGO | S_IWUSR,
|
||||
ina2xx_allow_async_readout_show,
|
||||
@ -598,21 +592,23 @@ static const struct attribute_group ina2xx_attribute_group = {
|
||||
};
|
||||
|
||||
static const struct iio_info ina2xx_info = {
|
||||
.debugfs_reg_access = &ina2xx_debug_reg,
|
||||
.read_raw = &ina2xx_read_raw,
|
||||
.write_raw = &ina2xx_write_raw,
|
||||
.attrs = &ina2xx_attribute_group,
|
||||
.driver_module = THIS_MODULE,
|
||||
.attrs = &ina2xx_attribute_group,
|
||||
.read_raw = ina2xx_read_raw,
|
||||
.write_raw = ina2xx_write_raw,
|
||||
.debugfs_reg_access = ina2xx_debug_reg,
|
||||
};
|
||||
|
||||
/* Initialize the configuration and calibration registers. */
|
||||
static int ina2xx_init(struct ina2xx_chip_info *chip, unsigned int config)
|
||||
{
|
||||
u16 regval;
|
||||
int ret = regmap_write(chip->regmap, INA2XX_CONFIG, config);
|
||||
int ret;
|
||||
|
||||
if (ret < 0)
|
||||
ret = regmap_write(chip->regmap, INA2XX_CONFIG, config);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Set current LSB to 1mA, shunt is in uOhms
|
||||
* (equation 13 in datasheet). We hardcode a Current_LSB
|
||||
@ -621,7 +617,7 @@ static int ina2xx_init(struct ina2xx_chip_info *chip, unsigned int config)
|
||||
* to the user for now.
|
||||
*/
|
||||
regval = DIV_ROUND_CLOSEST(chip->config->calibration_factor,
|
||||
chip->shunt_resistor);
|
||||
chip->shunt_resistor);
|
||||
|
||||
return regmap_write(chip->regmap, INA2XX_CALIBRATION, regval);
|
||||
}
|
||||
@ -632,8 +628,8 @@ static int ina2xx_probe(struct i2c_client *client,
|
||||
struct ina2xx_chip_info *chip;
|
||||
struct iio_dev *indio_dev;
|
||||
struct iio_buffer *buffer;
|
||||
int ret;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
|
||||
if (!indio_dev)
|
||||
@ -641,8 +637,19 @@ static int ina2xx_probe(struct i2c_client *client,
|
||||
|
||||
chip = iio_priv(indio_dev);
|
||||
|
||||
/* This is only used for device removal purposes. */
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
|
||||
chip->regmap = devm_regmap_init_i2c(client, &ina2xx_regmap_config);
|
||||
if (IS_ERR(chip->regmap)) {
|
||||
dev_err(&client->dev, "failed to allocate register map\n");
|
||||
return PTR_ERR(chip->regmap);
|
||||
}
|
||||
|
||||
chip->config = &ina2xx_config[id->driver_data];
|
||||
|
||||
mutex_init(&chip->state_lock);
|
||||
|
||||
if (of_property_read_u32(client->dev.of_node,
|
||||
"shunt-resistor", &val) < 0) {
|
||||
struct ina2xx_platform_data *pdata =
|
||||
@ -658,25 +665,6 @@ static int ina2xx_probe(struct i2c_client *client,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_init(&chip->state_lock);
|
||||
|
||||
/* This is only used for device removal purposes. */
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->channels = ina2xx_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ina2xx_channels);
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->info = &ina2xx_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
|
||||
|
||||
chip->regmap = devm_regmap_init_i2c(client, &ina2xx_regmap_config);
|
||||
if (IS_ERR(chip->regmap)) {
|
||||
dev_err(&client->dev, "failed to allocate register map\n");
|
||||
return PTR_ERR(chip->regmap);
|
||||
}
|
||||
|
||||
/* Patch the current config register with default. */
|
||||
val = chip->config->config_default;
|
||||
|
||||
@ -687,24 +675,28 @@ static int ina2xx_probe(struct i2c_client *client,
|
||||
}
|
||||
|
||||
ret = ina2xx_init(chip, val);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "error configuring the device: %d\n",
|
||||
ret);
|
||||
return -ENODEV;
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "error configuring the device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->channels = ina2xx_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ina2xx_channels);
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->info = &ina2xx_info;
|
||||
indio_dev->setup_ops = &ina2xx_setup_ops;
|
||||
|
||||
buffer = devm_iio_kfifo_allocate(&indio_dev->dev);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
indio_dev->setup_ops = &ina2xx_setup_ops;
|
||||
|
||||
iio_device_attach_buffer(indio_dev, buffer);
|
||||
|
||||
return iio_device_register(indio_dev);
|
||||
}
|
||||
|
||||
|
||||
static int ina2xx_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
@ -717,7 +709,6 @@ static int ina2xx_remove(struct i2c_client *client)
|
||||
INA2XX_MODE_MASK, 0);
|
||||
}
|
||||
|
||||
|
||||
static const struct i2c_device_id ina2xx_id[] = {
|
||||
{"ina219", ina219},
|
||||
{"ina220", ina219},
|
||||
@ -726,7 +717,6 @@ static const struct i2c_device_id ina2xx_id[] = {
|
||||
{"ina231", ina226},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, ina2xx_id);
|
||||
|
||||
static struct i2c_driver ina2xx_driver = {
|
||||
@ -737,7 +727,6 @@ static struct i2c_driver ina2xx_driver = {
|
||||
.remove = ina2xx_remove,
|
||||
.id_table = ina2xx_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(ina2xx_driver);
|
||||
|
||||
MODULE_AUTHOR("Marc Titinger <marc.titinger@baylibre.com>");
|
||||
|
@ -339,7 +339,7 @@ static int mcp3422_probe(struct i2c_client *client,
|
||||
u8 config;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
|
||||
return -ENODEV;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*adc));
|
||||
if (!indio_dev)
|
||||
|
@ -534,7 +534,7 @@ static int palmas_gpadc_probe(struct platform_device *pdev)
|
||||
}
|
||||
ret = request_threaded_irq(adc->irq, NULL,
|
||||
palmas_gpadc_irq,
|
||||
IRQF_ONESHOT | IRQF_EARLY_RESUME, dev_name(adc->dev),
|
||||
IRQF_ONESHOT, dev_name(adc->dev),
|
||||
adc);
|
||||
if (ret < 0) {
|
||||
dev_err(adc->dev,
|
||||
@ -549,7 +549,7 @@ static int palmas_gpadc_probe(struct platform_device *pdev)
|
||||
adc->irq_auto_0 = platform_get_irq(pdev, 1);
|
||||
ret = request_threaded_irq(adc->irq_auto_0, NULL,
|
||||
palmas_gpadc_irq_auto,
|
||||
IRQF_ONESHOT | IRQF_EARLY_RESUME,
|
||||
IRQF_ONESHOT,
|
||||
"palmas-adc-auto-0", adc);
|
||||
if (ret < 0) {
|
||||
dev_err(adc->dev, "request auto0 irq %d failed: %d\n",
|
||||
@ -565,7 +565,7 @@ static int palmas_gpadc_probe(struct platform_device *pdev)
|
||||
adc->irq_auto_1 = platform_get_irq(pdev, 2);
|
||||
ret = request_threaded_irq(adc->irq_auto_1, NULL,
|
||||
palmas_gpadc_irq_auto,
|
||||
IRQF_ONESHOT | IRQF_EARLY_RESUME,
|
||||
IRQF_ONESHOT,
|
||||
"palmas-adc-auto-1", adc);
|
||||
if (ret < 0) {
|
||||
dev_err(adc->dev, "request auto1 irq %d failed: %d\n",
|
||||
|
@ -73,7 +73,7 @@ static int adc081c_probe(struct i2c_client *client,
|
||||
int err;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -ENODEV;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
iio = devm_iio_device_alloc(&client->dev, sizeof(*adc));
|
||||
if (!iio)
|
||||
|
@ -65,8 +65,6 @@ struct atlas_data {
|
||||
|
||||
static const struct regmap_range atlas_volatile_ranges[] = {
|
||||
regmap_reg_range(ATLAS_REG_INT_CONTROL, ATLAS_REG_INT_CONTROL),
|
||||
regmap_reg_range(ATLAS_REG_CALIB_STATUS, ATLAS_REG_CALIB_STATUS),
|
||||
regmap_reg_range(ATLAS_REG_TEMP_DATA, ATLAS_REG_TEMP_DATA + 4),
|
||||
regmap_reg_range(ATLAS_REG_PH_DATA, ATLAS_REG_PH_DATA + 4),
|
||||
};
|
||||
|
||||
@ -83,7 +81,7 @@ static const struct regmap_config atlas_regmap_config = {
|
||||
|
||||
.volatile_table = &atlas_volatile_table,
|
||||
.max_register = ATLAS_REG_PH_DATA + 4,
|
||||
.cache_type = REGCACHE_FLAT,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec atlas_channels[] = {
|
||||
@ -180,10 +178,10 @@ static irqreturn_t atlas_trigger_handler(int irq, void *private)
|
||||
struct atlas_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(data->client, ATLAS_REG_PH_DATA,
|
||||
sizeof(data->buffer[0]), (u8 *) &data->buffer);
|
||||
ret = regmap_bulk_read(data->regmap, ATLAS_REG_PH_DATA,
|
||||
(u8 *) &data->buffer, sizeof(data->buffer[0]));
|
||||
|
||||
if (ret > 0)
|
||||
if (!ret)
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
iio_get_time_ns());
|
||||
|
||||
|
@ -249,7 +249,7 @@ static int vz89x_probe(struct i2c_client *client,
|
||||
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE))
|
||||
data->xfer = vz89x_smbus_xfer;
|
||||
else
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
|
@ -217,4 +217,14 @@ config STX104
|
||||
addresses for the devices may be configured via the "base" module
|
||||
parameter array.
|
||||
|
||||
config VF610_DAC
|
||||
tristate "Vybrid vf610 DAC driver"
|
||||
depends on OF
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
Say yes here to support Vybrid board digital-to-analog converter.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called vf610_dac.
|
||||
|
||||
endmenu
|
||||
|
@ -23,3 +23,4 @@ obj-$(CONFIG_MAX5821) += max5821.o
|
||||
obj-$(CONFIG_MCP4725) += mcp4725.o
|
||||
obj-$(CONFIG_MCP4922) += mcp4922.o
|
||||
obj-$(CONFIG_STX104) += stx104.o
|
||||
obj-$(CONFIG_VF610_DAC) += vf610_dac.o
|
||||
|
298
drivers/iio/dac/vf610_dac.c
Normal file
298
drivers/iio/dac/vf610_dac.c
Normal file
@ -0,0 +1,298 @@
|
||||
/*
|
||||
* Freescale Vybrid vf610 DAC driver
|
||||
*
|
||||
* Copyright 2016 Toradex AG
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
#define VF610_DACx_STATCTRL 0x20
|
||||
|
||||
#define VF610_DAC_DACEN BIT(15)
|
||||
#define VF610_DAC_DACRFS BIT(14)
|
||||
#define VF610_DAC_LPEN BIT(11)
|
||||
|
||||
#define VF610_DAC_DAT0(x) ((x) & 0xFFF)
|
||||
|
||||
enum vf610_conversion_mode_sel {
|
||||
VF610_DAC_CONV_HIGH_POWER,
|
||||
VF610_DAC_CONV_LOW_POWER,
|
||||
};
|
||||
|
||||
struct vf610_dac {
|
||||
struct clk *clk;
|
||||
struct device *dev;
|
||||
enum vf610_conversion_mode_sel conv_mode;
|
||||
void __iomem *regs;
|
||||
};
|
||||
|
||||
static void vf610_dac_init(struct vf610_dac *info)
|
||||
{
|
||||
int val;
|
||||
|
||||
info->conv_mode = VF610_DAC_CONV_LOW_POWER;
|
||||
val = VF610_DAC_DACEN | VF610_DAC_DACRFS |
|
||||
VF610_DAC_LPEN;
|
||||
writel(val, info->regs + VF610_DACx_STATCTRL);
|
||||
}
|
||||
|
||||
static void vf610_dac_exit(struct vf610_dac *info)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = readl(info->regs + VF610_DACx_STATCTRL);
|
||||
val &= ~VF610_DAC_DACEN;
|
||||
writel(val, info->regs + VF610_DACx_STATCTRL);
|
||||
}
|
||||
|
||||
static int vf610_set_conversion_mode(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
unsigned int mode)
|
||||
{
|
||||
struct vf610_dac *info = iio_priv(indio_dev);
|
||||
int val;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
info->conv_mode = mode;
|
||||
val = readl(info->regs + VF610_DACx_STATCTRL);
|
||||
if (mode)
|
||||
val |= VF610_DAC_LPEN;
|
||||
else
|
||||
val &= ~VF610_DAC_LPEN;
|
||||
writel(val, info->regs + VF610_DACx_STATCTRL);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vf610_get_conversion_mode(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
struct vf610_dac *info = iio_priv(indio_dev);
|
||||
|
||||
return info->conv_mode;
|
||||
}
|
||||
|
||||
static const char * const vf610_conv_modes[] = { "high-power", "low-power" };
|
||||
|
||||
static const struct iio_enum vf610_conversion_mode = {
|
||||
.items = vf610_conv_modes,
|
||||
.num_items = ARRAY_SIZE(vf610_conv_modes),
|
||||
.get = vf610_get_conversion_mode,
|
||||
.set = vf610_set_conversion_mode,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec_ext_info vf610_ext_info[] = {
|
||||
IIO_ENUM("conversion_mode", IIO_SHARED_BY_DIR,
|
||||
&vf610_conversion_mode),
|
||||
{},
|
||||
};
|
||||
|
||||
#define VF610_DAC_CHAN(_chan_type) { \
|
||||
.type = (_chan_type), \
|
||||
.output = 1, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.ext_info = vf610_ext_info, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec vf610_dac_iio_channels[] = {
|
||||
VF610_DAC_CHAN(IIO_VOLTAGE),
|
||||
};
|
||||
|
||||
static int vf610_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2,
|
||||
long mask)
|
||||
{
|
||||
struct vf610_dac *info = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
*val = VF610_DAC_DAT0(readl(info->regs));
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
/*
|
||||
* DACRFS is always 1 for valid reference and typical
|
||||
* reference voltage as per Vybrid datasheet is 3.3V
|
||||
* from section 9.1.2.1 of Vybrid datasheet
|
||||
*/
|
||||
*val = 3300 /* mV */;
|
||||
*val2 = 12;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int vf610_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2,
|
||||
long mask)
|
||||
{
|
||||
struct vf610_dac *info = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
writel(VF610_DAC_DAT0(val), info->regs);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_info vf610_dac_iio_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.read_raw = &vf610_read_raw,
|
||||
.write_raw = &vf610_write_raw,
|
||||
};
|
||||
|
||||
static const struct of_device_id vf610_dac_match[] = {
|
||||
{ .compatible = "fsl,vf610-dac", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, vf610_dac_match);
|
||||
|
||||
static int vf610_dac_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct vf610_dac *info;
|
||||
struct resource *mem;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev,
|
||||
sizeof(struct vf610_dac));
|
||||
if (!indio_dev) {
|
||||
dev_err(&pdev->dev, "Failed allocating iio device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
info = iio_priv(indio_dev);
|
||||
info->dev = &pdev->dev;
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
info->regs = devm_ioremap_resource(&pdev->dev, mem);
|
||||
if (IS_ERR(info->regs))
|
||||
return PTR_ERR(info->regs);
|
||||
|
||||
info->clk = devm_clk_get(&pdev->dev, "dac");
|
||||
if (IS_ERR(info->clk)) {
|
||||
dev_err(&pdev->dev, "Failed getting clock, err = %ld\n",
|
||||
PTR_ERR(info->clk));
|
||||
return PTR_ERR(info->clk);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
|
||||
indio_dev->name = dev_name(&pdev->dev);
|
||||
indio_dev->dev.parent = &pdev->dev;
|
||||
indio_dev->dev.of_node = pdev->dev.of_node;
|
||||
indio_dev->info = &vf610_dac_iio_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = vf610_dac_iio_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(vf610_dac_iio_channels);
|
||||
|
||||
ret = clk_prepare_enable(info->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"Could not prepare or enable the clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
vf610_dac_init(info);
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Couldn't register the device\n");
|
||||
goto error_iio_device_register;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_iio_device_register:
|
||||
clk_disable_unprepare(info->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vf610_dac_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
struct vf610_dac *info = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
vf610_dac_exit(info);
|
||||
clk_disable_unprepare(info->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int vf610_dac_suspend(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct vf610_dac *info = iio_priv(indio_dev);
|
||||
|
||||
vf610_dac_exit(info);
|
||||
clk_disable_unprepare(info->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vf610_dac_resume(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct vf610_dac *info = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(info->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vf610_dac_init(info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(vf610_dac_pm_ops, vf610_dac_suspend, vf610_dac_resume);
|
||||
|
||||
static struct platform_driver vf610_dac_driver = {
|
||||
.probe = vf610_dac_probe,
|
||||
.remove = vf610_dac_remove,
|
||||
.driver = {
|
||||
.name = "vf610-dac",
|
||||
.of_match_table = vf610_dac_match,
|
||||
.pm = &vf610_dac_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(vf610_dac_driver);
|
||||
|
||||
MODULE_AUTHOR("Sanchayan Maity <sanchayan.maity@toradex.com>");
|
||||
MODULE_DESCRIPTION("Freescale VF610 DAC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -10,6 +10,7 @@ menu "Heart Rate Monitors"
|
||||
config AFE4403
|
||||
tristate "TI AFE4403 Heart Rate Monitor"
|
||||
depends on SPI_MASTER
|
||||
select REGMAP_SPI
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
|
@ -506,7 +506,7 @@ static const struct of_device_id afe4403_of_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, afe4403_of_match);
|
||||
#endif
|
||||
|
||||
static int afe4403_suspend(struct device *dev)
|
||||
static int __maybe_unused afe4403_suspend(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct afe4403_data *afe = iio_priv(indio_dev);
|
||||
@ -527,7 +527,7 @@ static int afe4403_suspend(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int afe4403_resume(struct device *dev)
|
||||
static int __maybe_unused afe4403_resume(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct afe4403_data *afe = iio_priv(indio_dev);
|
||||
|
@ -477,7 +477,7 @@ static const struct of_device_id afe4404_of_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, afe4404_of_match);
|
||||
#endif
|
||||
|
||||
static int afe4404_suspend(struct device *dev)
|
||||
static int __maybe_unused afe4404_suspend(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct afe4404_data *afe = iio_priv(indio_dev);
|
||||
@ -498,7 +498,7 @@ static int afe4404_suspend(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int afe4404_resume(struct device *dev)
|
||||
static int __maybe_unused afe4404_resume(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct afe4404_data *afe = iio_priv(indio_dev);
|
||||
|
@ -274,7 +274,7 @@ static int hdc100x_probe(struct i2c_client *client,
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE))
|
||||
return -ENODEV;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
|
@ -192,7 +192,7 @@ static int htu21_probe(struct i2c_client *client,
|
||||
I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
|
||||
dev_err(&client->dev,
|
||||
"Adapter does not support some i2c transaction\n");
|
||||
return -ENODEV;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
|
||||
|
@ -135,7 +135,7 @@ static int si7005_probe(struct i2c_client *client,
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -ENODEV;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
|
@ -121,7 +121,7 @@ static int si7020_probe(struct i2c_client *client,
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_WRITE_BYTE |
|
||||
I2C_FUNC_SMBUS_READ_WORD_DATA))
|
||||
return -ENODEV;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Reset device, loads default settings. */
|
||||
ret = i2c_smbus_write_byte(client, SI7020CMD_RESET);
|
||||
|
@ -66,11 +66,11 @@ static int asus_acpi_get_sensor_info(struct acpi_device *adev,
|
||||
union acpi_object *elem;
|
||||
int j;
|
||||
|
||||
elem = &(cpm->package.elements[i]);
|
||||
elem = &cpm->package.elements[i];
|
||||
for (j = 0; j < elem->package.count; ++j) {
|
||||
union acpi_object *sub_elem;
|
||||
|
||||
sub_elem = &(elem->package.elements[j]);
|
||||
sub_elem = &elem->package.elements[j];
|
||||
if (sub_elem->type == ACPI_TYPE_STRING)
|
||||
strlcpy(info->type, sub_elem->string.pointer,
|
||||
sizeof(info->type));
|
||||
@ -186,7 +186,6 @@ int inv_mpu_acpi_create_mux_client(struct i2c_client *client)
|
||||
st->mux_client = i2c_new_device(st->mux_adapter, &info);
|
||||
if (!st->mux_client)
|
||||
return -ENODEV;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -195,6 +194,7 @@ int inv_mpu_acpi_create_mux_client(struct i2c_client *client)
|
||||
void inv_mpu_acpi_delete_mux_client(struct i2c_client *client)
|
||||
{
|
||||
struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(&client->dev));
|
||||
|
||||
if (st->mux_client)
|
||||
i2c_unregister_device(st->mux_client);
|
||||
}
|
||||
|
@ -39,6 +39,26 @@ static const int gyro_scale_6050[] = {133090, 266181, 532362, 1064724};
|
||||
*/
|
||||
static const int accel_scale[] = {598, 1196, 2392, 4785};
|
||||
|
||||
static const struct inv_mpu6050_reg_map reg_set_6500 = {
|
||||
.sample_rate_div = INV_MPU6050_REG_SAMPLE_RATE_DIV,
|
||||
.lpf = INV_MPU6050_REG_CONFIG,
|
||||
.user_ctrl = INV_MPU6050_REG_USER_CTRL,
|
||||
.fifo_en = INV_MPU6050_REG_FIFO_EN,
|
||||
.gyro_config = INV_MPU6050_REG_GYRO_CONFIG,
|
||||
.accl_config = INV_MPU6050_REG_ACCEL_CONFIG,
|
||||
.fifo_count_h = INV_MPU6050_REG_FIFO_COUNT_H,
|
||||
.fifo_r_w = INV_MPU6050_REG_FIFO_R_W,
|
||||
.raw_gyro = INV_MPU6050_REG_RAW_GYRO,
|
||||
.raw_accl = INV_MPU6050_REG_RAW_ACCEL,
|
||||
.temperature = INV_MPU6050_REG_TEMPERATURE,
|
||||
.int_enable = INV_MPU6050_REG_INT_ENABLE,
|
||||
.pwr_mgmt_1 = INV_MPU6050_REG_PWR_MGMT_1,
|
||||
.pwr_mgmt_2 = INV_MPU6050_REG_PWR_MGMT_2,
|
||||
.int_pin_cfg = INV_MPU6050_REG_INT_PIN_CFG,
|
||||
.accl_offset = INV_MPU6500_REG_ACCEL_OFFSET,
|
||||
.gyro_offset = INV_MPU6050_REG_GYRO_OFFSET,
|
||||
};
|
||||
|
||||
static const struct inv_mpu6050_reg_map reg_set_6050 = {
|
||||
.sample_rate_div = INV_MPU6050_REG_SAMPLE_RATE_DIV,
|
||||
.lpf = INV_MPU6050_REG_CONFIG,
|
||||
@ -55,6 +75,8 @@ static const struct inv_mpu6050_reg_map reg_set_6050 = {
|
||||
.pwr_mgmt_1 = INV_MPU6050_REG_PWR_MGMT_1,
|
||||
.pwr_mgmt_2 = INV_MPU6050_REG_PWR_MGMT_2,
|
||||
.int_pin_cfg = INV_MPU6050_REG_INT_PIN_CFG,
|
||||
.accl_offset = INV_MPU6050_REG_ACCEL_OFFSET,
|
||||
.gyro_offset = INV_MPU6050_REG_GYRO_OFFSET,
|
||||
};
|
||||
|
||||
static const struct inv_mpu6050_chip_config chip_config_6050 = {
|
||||
@ -66,7 +88,13 @@ static const struct inv_mpu6050_chip_config chip_config_6050 = {
|
||||
.accl_fs = INV_MPU6050_FS_02G,
|
||||
};
|
||||
|
||||
static const struct inv_mpu6050_hw hw_info[INV_NUM_PARTS] = {
|
||||
static const struct inv_mpu6050_hw hw_info[] = {
|
||||
{
|
||||
.num_reg = 117,
|
||||
.name = "MPU6500",
|
||||
.reg = ®_set_6500,
|
||||
.config = &chip_config_6050,
|
||||
},
|
||||
{
|
||||
.num_reg = 117,
|
||||
.name = "MPU6050",
|
||||
@ -79,11 +107,12 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
|
||||
{
|
||||
unsigned int d, mgmt_1;
|
||||
int result;
|
||||
|
||||
/* switch clock needs to be careful. Only when gyro is on, can
|
||||
clock source be switched to gyro. Otherwise, it must be set to
|
||||
internal clock */
|
||||
if (INV_MPU6050_BIT_PWR_GYRO_STBY == mask) {
|
||||
/*
|
||||
* switch clock needs to be careful. Only when gyro is on, can
|
||||
* clock source be switched to gyro. Otherwise, it must be set to
|
||||
* internal clock
|
||||
*/
|
||||
if (mask == INV_MPU6050_BIT_PWR_GYRO_STBY) {
|
||||
result = regmap_read(st->map, st->reg->pwr_mgmt_1, &mgmt_1);
|
||||
if (result)
|
||||
return result;
|
||||
@ -91,9 +120,11 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
|
||||
mgmt_1 &= ~INV_MPU6050_BIT_CLK_MASK;
|
||||
}
|
||||
|
||||
if ((INV_MPU6050_BIT_PWR_GYRO_STBY == mask) && (!en)) {
|
||||
/* turning off gyro requires switch to internal clock first.
|
||||
Then turn off gyro engine */
|
||||
if ((mask == INV_MPU6050_BIT_PWR_GYRO_STBY) && (!en)) {
|
||||
/*
|
||||
* turning off gyro requires switch to internal clock first.
|
||||
* Then turn off gyro engine
|
||||
*/
|
||||
mgmt_1 |= INV_CLK_INTERNAL;
|
||||
result = regmap_write(st->map, st->reg->pwr_mgmt_1, mgmt_1);
|
||||
if (result)
|
||||
@ -114,11 +145,11 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
|
||||
if (en) {
|
||||
/* Wait for output stabilize */
|
||||
msleep(INV_MPU6050_TEMP_UP_TIME);
|
||||
if (INV_MPU6050_BIT_PWR_GYRO_STBY == mask) {
|
||||
if (mask == INV_MPU6050_BIT_PWR_GYRO_STBY) {
|
||||
/* switch internal clock to PLL */
|
||||
mgmt_1 |= INV_CLK_PLL;
|
||||
result = regmap_write(st->map,
|
||||
st->reg->pwr_mgmt_1, mgmt_1);
|
||||
st->reg->pwr_mgmt_1, mgmt_1);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
@ -148,7 +179,8 @@ int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on)
|
||||
return result;
|
||||
|
||||
if (power_on)
|
||||
msleep(INV_MPU6050_REG_UP_TIME);
|
||||
usleep_range(INV_MPU6050_REG_UP_TIME_MIN,
|
||||
INV_MPU6050_REG_UP_TIME_MAX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -193,14 +225,28 @@ static int inv_mpu6050_init_config(struct iio_dev *indio_dev)
|
||||
return result;
|
||||
|
||||
memcpy(&st->chip_config, hw_info[st->chip_type].config,
|
||||
sizeof(struct inv_mpu6050_chip_config));
|
||||
sizeof(struct inv_mpu6050_chip_config));
|
||||
result = inv_mpu6050_set_power_itg(st, false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int inv_mpu6050_sensor_set(struct inv_mpu6050_state *st, int reg,
|
||||
int axis, int val)
|
||||
{
|
||||
int ind, result;
|
||||
__be16 d = cpu_to_be16(val);
|
||||
|
||||
ind = (axis - IIO_MOD_X) * 2;
|
||||
result = regmap_bulk_write(st->map, reg + ind, (u8 *)&d, 2);
|
||||
if (result)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int inv_mpu6050_sensor_show(struct inv_mpu6050_state *st, int reg,
|
||||
int axis, int *val)
|
||||
int axis, int *val)
|
||||
{
|
||||
int ind, result;
|
||||
__be16 d;
|
||||
@ -214,17 +260,18 @@ static int inv_mpu6050_sensor_show(struct inv_mpu6050_state *st, int reg,
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int inv_mpu6050_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val,
|
||||
int *val2,
|
||||
long mask) {
|
||||
static int
|
||||
inv_mpu6050_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct inv_mpu6050_state *st = iio_priv(indio_dev);
|
||||
int ret = 0;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
{
|
||||
int ret, result;
|
||||
int result;
|
||||
|
||||
ret = IIO_VAL_INT;
|
||||
result = 0;
|
||||
@ -238,16 +285,16 @@ static int inv_mpu6050_read_raw(struct iio_dev *indio_dev,
|
||||
switch (chan->type) {
|
||||
case IIO_ANGL_VEL:
|
||||
if (!st->chip_config.gyro_fifo_enable ||
|
||||
!st->chip_config.enable) {
|
||||
!st->chip_config.enable) {
|
||||
result = inv_mpu6050_switch_engine(st, true,
|
||||
INV_MPU6050_BIT_PWR_GYRO_STBY);
|
||||
if (result)
|
||||
goto error_read_raw;
|
||||
}
|
||||
ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro,
|
||||
chan->channel2, val);
|
||||
ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro,
|
||||
chan->channel2, val);
|
||||
if (!st->chip_config.gyro_fifo_enable ||
|
||||
!st->chip_config.enable) {
|
||||
!st->chip_config.enable) {
|
||||
result = inv_mpu6050_switch_engine(st, false,
|
||||
INV_MPU6050_BIT_PWR_GYRO_STBY);
|
||||
if (result)
|
||||
@ -256,16 +303,16 @@ static int inv_mpu6050_read_raw(struct iio_dev *indio_dev,
|
||||
break;
|
||||
case IIO_ACCEL:
|
||||
if (!st->chip_config.accl_fifo_enable ||
|
||||
!st->chip_config.enable) {
|
||||
!st->chip_config.enable) {
|
||||
result = inv_mpu6050_switch_engine(st, true,
|
||||
INV_MPU6050_BIT_PWR_ACCL_STBY);
|
||||
if (result)
|
||||
goto error_read_raw;
|
||||
}
|
||||
ret = inv_mpu6050_sensor_show(st, st->reg->raw_accl,
|
||||
chan->channel2, val);
|
||||
chan->channel2, val);
|
||||
if (!st->chip_config.accl_fifo_enable ||
|
||||
!st->chip_config.enable) {
|
||||
!st->chip_config.enable) {
|
||||
result = inv_mpu6050_switch_engine(st, false,
|
||||
INV_MPU6050_BIT_PWR_ACCL_STBY);
|
||||
if (result)
|
||||
@ -275,8 +322,8 @@ static int inv_mpu6050_read_raw(struct iio_dev *indio_dev,
|
||||
case IIO_TEMP:
|
||||
/* wait for stablization */
|
||||
msleep(INV_MPU6050_SENSOR_UP_TIME);
|
||||
inv_mpu6050_sensor_show(st, st->reg->temperature,
|
||||
IIO_MOD_X, val);
|
||||
ret = inv_mpu6050_sensor_show(st, st->reg->temperature,
|
||||
IIO_MOD_X, val);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
@ -320,6 +367,20 @@ error_read_raw:
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
switch (chan->type) {
|
||||
case IIO_ANGL_VEL:
|
||||
ret = inv_mpu6050_sensor_show(st, st->reg->gyro_offset,
|
||||
chan->channel2, val);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_ACCEL:
|
||||
ret = inv_mpu6050_sensor_show(st, st->reg->accl_offset,
|
||||
chan->channel2, val);
|
||||
return IIO_VAL_INT;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -362,6 +423,7 @@ static int inv_write_raw_get_fmt(struct iio_dev *indio_dev,
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int inv_mpu6050_write_accel_scale(struct inv_mpu6050_state *st, int val)
|
||||
{
|
||||
int result, i;
|
||||
@ -383,16 +445,17 @@ static int inv_mpu6050_write_accel_scale(struct inv_mpu6050_state *st, int val)
|
||||
}
|
||||
|
||||
static int inv_mpu6050_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)
|
||||
{
|
||||
struct inv_mpu6050_state *st = iio_priv(indio_dev);
|
||||
int result;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
/* we should only update scale when the chip is disabled, i.e.,
|
||||
not running */
|
||||
/*
|
||||
* we should only update scale when the chip is disabled, i.e.
|
||||
* not running
|
||||
*/
|
||||
if (st->chip_config.enable) {
|
||||
result = -EBUSY;
|
||||
goto error_write_raw;
|
||||
@ -415,6 +478,21 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
switch (chan->type) {
|
||||
case IIO_ANGL_VEL:
|
||||
result = inv_mpu6050_sensor_set(st,
|
||||
st->reg->gyro_offset,
|
||||
chan->channel2, val);
|
||||
break;
|
||||
case IIO_ACCEL:
|
||||
result = inv_mpu6050_sensor_set(st,
|
||||
st->reg->accl_offset,
|
||||
chan->channel2, val);
|
||||
break;
|
||||
default:
|
||||
result = -EINVAL;
|
||||
}
|
||||
default:
|
||||
result = -EINVAL;
|
||||
break;
|
||||
@ -461,8 +539,9 @@ static int inv_mpu6050_set_lpf(struct inv_mpu6050_state *st, int rate)
|
||||
/**
|
||||
* inv_mpu6050_fifo_rate_store() - Set fifo rate.
|
||||
*/
|
||||
static ssize_t inv_mpu6050_fifo_rate_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
static ssize_t
|
||||
inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
s32 fifo_rate;
|
||||
u8 d;
|
||||
@ -473,7 +552,7 @@ static ssize_t inv_mpu6050_fifo_rate_store(struct device *dev,
|
||||
if (kstrtoint(buf, 10, &fifo_rate))
|
||||
return -EINVAL;
|
||||
if (fifo_rate < INV_MPU6050_MIN_FIFO_RATE ||
|
||||
fifo_rate > INV_MPU6050_MAX_FIFO_RATE)
|
||||
fifo_rate > INV_MPU6050_MAX_FIFO_RATE)
|
||||
return -EINVAL;
|
||||
if (fifo_rate == st->chip_config.fifo_rate)
|
||||
return count;
|
||||
@ -509,8 +588,9 @@ fifo_rate_fail:
|
||||
/**
|
||||
* inv_fifo_rate_show() - Get the current sampling rate.
|
||||
*/
|
||||
static ssize_t inv_fifo_rate_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static ssize_t
|
||||
inv_fifo_rate_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct inv_mpu6050_state *st = iio_priv(dev_to_iio_dev(dev));
|
||||
|
||||
@ -521,16 +601,18 @@ static ssize_t inv_fifo_rate_show(struct device *dev,
|
||||
* inv_attr_show() - calling this function will show current
|
||||
* parameters.
|
||||
*/
|
||||
static ssize_t inv_attr_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static ssize_t inv_attr_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct inv_mpu6050_state *st = iio_priv(dev_to_iio_dev(dev));
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
s8 *m;
|
||||
|
||||
switch (this_attr->address) {
|
||||
/* In MPU6050, the two matrix are the same because gyro and accel
|
||||
are integrated in one chip */
|
||||
/*
|
||||
* In MPU6050, the two matrix are the same because gyro and accel
|
||||
* are integrated in one chip
|
||||
*/
|
||||
case ATTR_GYRO_MATRIX:
|
||||
case ATTR_ACCL_MATRIX:
|
||||
m = st->plat_data.orientation;
|
||||
@ -567,14 +649,15 @@ static int inv_mpu6050_validate_trigger(struct iio_dev *indio_dev,
|
||||
.type = _type, \
|
||||
.modified = 1, \
|
||||
.channel2 = _channel2, \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS), \
|
||||
.scan_index = _index, \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = 16, \
|
||||
.storagebits = 16, \
|
||||
.shift = 0 , \
|
||||
.shift = 0, \
|
||||
.endianness = IIO_BE, \
|
||||
}, \
|
||||
}
|
||||
@ -587,7 +670,7 @@ static const struct iio_chan_spec inv_mpu_channels[] = {
|
||||
*/
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
|
||||
| BIT(IIO_CHAN_INFO_OFFSET)
|
||||
| BIT(IIO_CHAN_INFO_SCALE),
|
||||
.scan_index = -1,
|
||||
@ -644,7 +727,6 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
|
||||
{
|
||||
int result;
|
||||
|
||||
st->chip_type = INV_MPU6050;
|
||||
st->hw = &hw_info[st->chip_type];
|
||||
st->reg = hw_info[st->chip_type].reg;
|
||||
|
||||
@ -654,10 +736,12 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
|
||||
if (result)
|
||||
return result;
|
||||
msleep(INV_MPU6050_POWER_UP_TIME);
|
||||
/* toggle power state. After reset, the sleep bit could be on
|
||||
or off depending on the OTP settings. Toggling power would
|
||||
make it in a definite state as well as making the hardware
|
||||
state align with the software state */
|
||||
/*
|
||||
* toggle power state. After reset, the sleep bit could be on
|
||||
* or off depending on the OTP settings. Toggling power would
|
||||
* make it in a definite state as well as making the hardware
|
||||
* state align with the software state
|
||||
*/
|
||||
result = inv_mpu6050_set_power_itg(st, false);
|
||||
if (result)
|
||||
return result;
|
||||
@ -666,11 +750,11 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
|
||||
return result;
|
||||
|
||||
result = inv_mpu6050_switch_engine(st, false,
|
||||
INV_MPU6050_BIT_PWR_ACCL_STBY);
|
||||
INV_MPU6050_BIT_PWR_ACCL_STBY);
|
||||
if (result)
|
||||
return result;
|
||||
result = inv_mpu6050_switch_engine(st, false,
|
||||
INV_MPU6050_BIT_PWR_GYRO_STBY);
|
||||
INV_MPU6050_BIT_PWR_GYRO_STBY);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
@ -678,7 +762,7 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
|
||||
}
|
||||
|
||||
int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
|
||||
int (*inv_mpu_bus_setup)(struct iio_dev *))
|
||||
int (*inv_mpu_bus_setup)(struct iio_dev *), int chip_type)
|
||||
{
|
||||
struct inv_mpu6050_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
@ -691,6 +775,7 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
|
||||
return -ENOMEM;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
st->chip_type = chip_type;
|
||||
st->powerup_count = 0;
|
||||
st->irq = irq;
|
||||
st->map = regmap;
|
||||
|
@ -68,7 +68,8 @@ static int inv_mpu6050_select_bypass(struct i2c_adapter *adap, void *mux_priv,
|
||||
if (ret)
|
||||
goto write_error;
|
||||
|
||||
msleep(INV_MPU6050_REG_UP_TIME);
|
||||
usleep_range(INV_MPU6050_REG_UP_TIME_MIN,
|
||||
INV_MPU6050_REG_UP_TIME_MAX);
|
||||
}
|
||||
if (!ret) {
|
||||
st->powerup_count++;
|
||||
@ -111,7 +112,7 @@ static int inv_mpu6050_deselect_bypass(struct i2c_adapter *adap,
|
||||
* Returns 0 on success, a negative error code otherwise.
|
||||
*/
|
||||
static int inv_mpu_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct inv_mpu6050_state *st;
|
||||
int result;
|
||||
@ -120,7 +121,7 @@ static int inv_mpu_probe(struct i2c_client *client,
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK))
|
||||
return -ENOSYS;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, &inv_mpu_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
@ -129,7 +130,8 @@ static int inv_mpu_probe(struct i2c_client *client,
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
result = inv_mpu_core_probe(regmap, client->irq, name, NULL);
|
||||
result = inv_mpu_core_probe(regmap, client->irq, name,
|
||||
NULL, id->driver_data);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
|
@ -39,6 +39,9 @@
|
||||
* @int_enable: Interrupt enable register.
|
||||
* @pwr_mgmt_1: Controls chip's power state and clock source.
|
||||
* @pwr_mgmt_2: Controls power state of individual sensors.
|
||||
* @int_pin_cfg; Controls interrupt pin configuration.
|
||||
* @accl_offset: Controls the accelerometer calibration offset.
|
||||
* @gyro_offset: Controls the gyroscope calibration offset.
|
||||
*/
|
||||
struct inv_mpu6050_reg_map {
|
||||
u8 sample_rate_div;
|
||||
@ -56,6 +59,8 @@ struct inv_mpu6050_reg_map {
|
||||
u8 pwr_mgmt_1;
|
||||
u8 pwr_mgmt_2;
|
||||
u8 int_pin_cfg;
|
||||
u8 accl_offset;
|
||||
u8 gyro_offset;
|
||||
};
|
||||
|
||||
/*device enum */
|
||||
@ -132,6 +137,9 @@ struct inv_mpu6050_state {
|
||||
};
|
||||
|
||||
/*register and associated bit definition*/
|
||||
#define INV_MPU6050_REG_ACCEL_OFFSET 0x06
|
||||
#define INV_MPU6050_REG_GYRO_OFFSET 0x13
|
||||
|
||||
#define INV_MPU6050_REG_SAMPLE_RATE_DIV 0x19
|
||||
#define INV_MPU6050_REG_CONFIG 0x1A
|
||||
#define INV_MPU6050_REG_GYRO_CONFIG 0x1B
|
||||
@ -172,10 +180,18 @@ struct inv_mpu6050_state {
|
||||
#define INV_MPU6050_BYTES_PER_3AXIS_SENSOR 6
|
||||
#define INV_MPU6050_FIFO_COUNT_BYTE 2
|
||||
#define INV_MPU6050_FIFO_THRESHOLD 500
|
||||
|
||||
/* mpu6500 registers */
|
||||
#define INV_MPU6500_REG_ACCEL_OFFSET 0x77
|
||||
|
||||
/* delay time in milliseconds */
|
||||
#define INV_MPU6050_POWER_UP_TIME 100
|
||||
#define INV_MPU6050_TEMP_UP_TIME 100
|
||||
#define INV_MPU6050_SENSOR_UP_TIME 30
|
||||
#define INV_MPU6050_REG_UP_TIME 5
|
||||
|
||||
/* delay time in microseconds */
|
||||
#define INV_MPU6050_REG_UP_TIME_MIN 5000
|
||||
#define INV_MPU6050_REG_UP_TIME_MAX 10000
|
||||
|
||||
#define INV_MPU6050_TEMP_OFFSET 12421
|
||||
#define INV_MPU6050_TEMP_SCALE 2941
|
||||
@ -261,7 +277,7 @@ int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on);
|
||||
int inv_mpu_acpi_create_mux_client(struct i2c_client *client);
|
||||
void inv_mpu_acpi_delete_mux_client(struct i2c_client *client);
|
||||
int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
|
||||
int (*inv_mpu_bus_setup)(struct iio_dev *));
|
||||
int (*inv_mpu_bus_setup)(struct iio_dev *), int chip_type);
|
||||
int inv_mpu_core_remove(struct device *dev);
|
||||
int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on);
|
||||
extern const struct dev_pm_ops inv_mpu_pmops;
|
||||
|
@ -57,7 +57,7 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
|
||||
|
||||
/* reset FIFO*/
|
||||
result = regmap_write(st->map, st->reg->user_ctrl,
|
||||
INV_MPU6050_BIT_FIFO_RST);
|
||||
INV_MPU6050_BIT_FIFO_RST);
|
||||
if (result)
|
||||
goto reset_fifo_fail;
|
||||
|
||||
@ -68,13 +68,13 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
|
||||
if (st->chip_config.accl_fifo_enable ||
|
||||
st->chip_config.gyro_fifo_enable) {
|
||||
result = regmap_write(st->map, st->reg->int_enable,
|
||||
INV_MPU6050_BIT_DATA_RDY_EN);
|
||||
INV_MPU6050_BIT_DATA_RDY_EN);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
/* enable FIFO reading and I2C master interface*/
|
||||
result = regmap_write(st->map, st->reg->user_ctrl,
|
||||
INV_MPU6050_BIT_FIFO_EN);
|
||||
INV_MPU6050_BIT_FIFO_EN);
|
||||
if (result)
|
||||
goto reset_fifo_fail;
|
||||
/* enable sensor output to FIFO */
|
||||
@ -92,7 +92,7 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
|
||||
reset_fifo_fail:
|
||||
dev_err(regmap_get_device(st->map), "reset fifo failed %d\n", result);
|
||||
result = regmap_write(st->map, st->reg->int_enable,
|
||||
INV_MPU6050_BIT_DATA_RDY_EN);
|
||||
INV_MPU6050_BIT_DATA_RDY_EN);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -109,7 +109,7 @@ irqreturn_t inv_mpu6050_irq_handler(int irq, void *p)
|
||||
|
||||
timestamp = iio_get_time_ns();
|
||||
kfifo_in_spinlocked(&st->timestamps, ×tamp, 1,
|
||||
&st->time_stamp_lock);
|
||||
&st->time_stamp_lock);
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
@ -143,9 +143,8 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
|
||||
* read fifo_count register to know how many bytes inside FIFO
|
||||
* right now
|
||||
*/
|
||||
result = regmap_bulk_read(st->map,
|
||||
st->reg->fifo_count_h,
|
||||
data, INV_MPU6050_FIFO_COUNT_BYTE);
|
||||
result = regmap_bulk_read(st->map, st->reg->fifo_count_h, data,
|
||||
INV_MPU6050_FIFO_COUNT_BYTE);
|
||||
if (result)
|
||||
goto end_session;
|
||||
fifo_count = be16_to_cpup((__be16 *)(&data[0]));
|
||||
@ -158,8 +157,8 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
|
||||
goto flush_fifo;
|
||||
/* Timestamp mismatch. */
|
||||
if (kfifo_len(&st->timestamps) >
|
||||
fifo_count / bytes_per_datum + INV_MPU6050_TIME_STAMP_TOR)
|
||||
goto flush_fifo;
|
||||
fifo_count / bytes_per_datum + INV_MPU6050_TIME_STAMP_TOR)
|
||||
goto flush_fifo;
|
||||
while (fifo_count >= bytes_per_datum) {
|
||||
result = regmap_bulk_read(st->map, st->reg->fifo_r_w,
|
||||
data, bytes_per_datum);
|
||||
@ -168,11 +167,11 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
|
||||
|
||||
result = kfifo_out(&st->timestamps, ×tamp, 1);
|
||||
/* when there is no timestamp, put timestamp as 0 */
|
||||
if (0 == result)
|
||||
if (result == 0)
|
||||
timestamp = 0;
|
||||
|
||||
result = iio_push_to_buffers_with_timestamp(indio_dev, data,
|
||||
timestamp);
|
||||
timestamp);
|
||||
if (result)
|
||||
goto flush_fifo;
|
||||
fifo_count -= bytes_per_datum;
|
||||
|
@ -54,7 +54,8 @@ static int inv_mpu_probe(struct spi_device *spi)
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
return inv_mpu_core_probe(regmap, spi->irq, name, inv_mpu_i2c_disable);
|
||||
return inv_mpu_core_probe(regmap, spi->irq, name,
|
||||
inv_mpu_i2c_disable, id->driver_data);
|
||||
}
|
||||
|
||||
static int inv_mpu_remove(struct spi_device *spi)
|
||||
|
@ -19,19 +19,19 @@ static void inv_scan_query(struct iio_dev *indio_dev)
|
||||
|
||||
st->chip_config.gyro_fifo_enable =
|
||||
test_bit(INV_MPU6050_SCAN_GYRO_X,
|
||||
indio_dev->active_scan_mask) ||
|
||||
test_bit(INV_MPU6050_SCAN_GYRO_Y,
|
||||
indio_dev->active_scan_mask) ||
|
||||
test_bit(INV_MPU6050_SCAN_GYRO_Z,
|
||||
indio_dev->active_scan_mask);
|
||||
indio_dev->active_scan_mask) ||
|
||||
test_bit(INV_MPU6050_SCAN_GYRO_Y,
|
||||
indio_dev->active_scan_mask) ||
|
||||
test_bit(INV_MPU6050_SCAN_GYRO_Z,
|
||||
indio_dev->active_scan_mask);
|
||||
|
||||
st->chip_config.accl_fifo_enable =
|
||||
test_bit(INV_MPU6050_SCAN_ACCL_X,
|
||||
indio_dev->active_scan_mask) ||
|
||||
test_bit(INV_MPU6050_SCAN_ACCL_Y,
|
||||
indio_dev->active_scan_mask) ||
|
||||
test_bit(INV_MPU6050_SCAN_ACCL_Z,
|
||||
indio_dev->active_scan_mask);
|
||||
indio_dev->active_scan_mask) ||
|
||||
test_bit(INV_MPU6050_SCAN_ACCL_Y,
|
||||
indio_dev->active_scan_mask) ||
|
||||
test_bit(INV_MPU6050_SCAN_ACCL_Z,
|
||||
indio_dev->active_scan_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -101,7 +101,7 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
|
||||
* @state: Desired trigger state
|
||||
*/
|
||||
static int inv_mpu_data_rdy_trigger_set_state(struct iio_trigger *trig,
|
||||
bool state)
|
||||
bool state)
|
||||
{
|
||||
return inv_mpu6050_set_enable(iio_trigger_get_drvdata(trig), state);
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ static int bh1750_probe(struct i2c_client *client,
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
|
||||
I2C_FUNC_SMBUS_WRITE_BYTE))
|
||||
return -ENODEV;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
|
@ -326,7 +326,7 @@ static int jsa1212_probe(struct i2c_client *client,
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
|
@ -105,4 +105,37 @@ config IIO_ST_MAGN_SPI_3AXIS
|
||||
depends on IIO_ST_MAGN_3AXIS
|
||||
depends on IIO_ST_SENSORS_SPI
|
||||
|
||||
config SENSORS_HMC5843
|
||||
tristate
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
|
||||
config SENSORS_HMC5843_I2C
|
||||
tristate "Honeywell HMC5843/5883/5883L 3-Axis Magnetometer (I2C)"
|
||||
depends on I2C
|
||||
select SENSORS_HMC5843
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say Y here to add support for the Honeywell HMC5843, HMC5883 and
|
||||
HMC5883L 3-Axis Magnetometer (digital compass).
|
||||
|
||||
This driver can also be compiled as a set of modules.
|
||||
If so, these modules will be created:
|
||||
- hmc5843_core (core functions)
|
||||
- hmc5843_i2c (support for HMC5843, HMC5883, HMC5883L and HMC5983)
|
||||
|
||||
config SENSORS_HMC5843_SPI
|
||||
tristate "Honeywell HMC5983 3-Axis Magnetometer (SPI)"
|
||||
depends on SPI_MASTER
|
||||
select SENSORS_HMC5843
|
||||
select REGMAP_SPI
|
||||
help
|
||||
Say Y here to add support for the Honeywell HMC5983 3-Axis Magnetometer
|
||||
(digital compass).
|
||||
|
||||
This driver can also be compiled as a set of modules.
|
||||
If so, these modules will be created:
|
||||
- hmc5843_core (core functions)
|
||||
- hmc5843_spi (support for HMC5983)
|
||||
|
||||
endmenu
|
||||
|
@ -15,3 +15,7 @@ st_magn-$(CONFIG_IIO_BUFFER) += st_magn_buffer.o
|
||||
|
||||
obj-$(CONFIG_IIO_ST_MAGN_I2C_3AXIS) += st_magn_i2c.o
|
||||
obj-$(CONFIG_IIO_ST_MAGN_SPI_3AXIS) += st_magn_spi.o
|
||||
|
||||
obj-$(CONFIG_SENSORS_HMC5843) += hmc5843_core.o
|
||||
obj-$(CONFIG_SENSORS_HMC5843_I2C) += hmc5843_i2c.o
|
||||
obj-$(CONFIG_SENSORS_HMC5843_SPI) += hmc5843_spi.o
|
||||
|
@ -18,7 +18,6 @@
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -66,6 +65,33 @@
|
||||
#define HMC5843_MEAS_CONF_NEGATIVE_BIAS 0x02
|
||||
#define HMC5843_MEAS_CONF_MASK 0x03
|
||||
|
||||
/*
|
||||
* API for setting the measurement configuration to
|
||||
* Normal, Positive bias and Negative bias
|
||||
*
|
||||
* From the datasheet:
|
||||
* 0 - Normal measurement configuration (default): In normal measurement
|
||||
* configuration the device follows normal measurement flow. Pins BP
|
||||
* and BN are left floating and high impedance.
|
||||
*
|
||||
* 1 - Positive bias configuration: In positive bias configuration, a
|
||||
* positive current is forced across the resistive load on pins BP
|
||||
* and BN.
|
||||
*
|
||||
* 2 - Negative bias configuration. In negative bias configuration, a
|
||||
* negative current is forced across the resistive load on pins BP
|
||||
* and BN.
|
||||
*
|
||||
* 3 - Only available on HMC5983. Magnetic sensor is disabled.
|
||||
* Temperature sensor is enabled.
|
||||
*/
|
||||
|
||||
static const char *const hmc5843_meas_conf_modes[] = {"normal", "positivebias",
|
||||
"negativebias"};
|
||||
|
||||
static const char *const hmc5983_meas_conf_modes[] = {"normal", "positivebias",
|
||||
"negativebias",
|
||||
"disabled"};
|
||||
/* Scaling factors: 10000000/Gain */
|
||||
static const int hmc5843_regval_to_nanoscale[] = {
|
||||
6173, 7692, 10309, 12821, 18868, 21739, 25641, 35714
|
||||
@ -174,24 +200,6 @@ static int hmc5843_read_measurement(struct hmc5843_data *data,
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
/*
|
||||
* API for setting the measurement configuration to
|
||||
* Normal, Positive bias and Negative bias
|
||||
*
|
||||
* From the datasheet:
|
||||
* 0 - Normal measurement configuration (default): In normal measurement
|
||||
* configuration the device follows normal measurement flow. Pins BP
|
||||
* and BN are left floating and high impedance.
|
||||
*
|
||||
* 1 - Positive bias configuration: In positive bias configuration, a
|
||||
* positive current is forced across the resistive load on pins BP
|
||||
* and BN.
|
||||
*
|
||||
* 2 - Negative bias configuration. In negative bias configuration, a
|
||||
* negative current is forced across the resistive load on pins BP
|
||||
* and BN.
|
||||
*
|
||||
*/
|
||||
static int hmc5843_set_meas_conf(struct hmc5843_data *data, u8 meas_conf)
|
||||
{
|
||||
int ret;
|
||||
@ -205,48 +213,55 @@ static int hmc5843_set_meas_conf(struct hmc5843_data *data, u8 meas_conf)
|
||||
}
|
||||
|
||||
static
|
||||
ssize_t hmc5843_show_measurement_configuration(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
int hmc5843_show_measurement_configuration(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev));
|
||||
struct hmc5843_data *data = iio_priv(indio_dev);
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(data->regmap, HMC5843_CONFIG_REG_A, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
val &= HMC5843_MEAS_CONF_MASK;
|
||||
|
||||
return sprintf(buf, "%d\n", val);
|
||||
return val & HMC5843_MEAS_CONF_MASK;
|
||||
}
|
||||
|
||||
static
|
||||
ssize_t hmc5843_set_measurement_configuration(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
int hmc5843_set_measurement_configuration(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
unsigned int meas_conf)
|
||||
{
|
||||
struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev));
|
||||
unsigned long meas_conf = 0;
|
||||
int ret;
|
||||
struct hmc5843_data *data = iio_priv(indio_dev);
|
||||
|
||||
ret = kstrtoul(buf, 10, &meas_conf);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (meas_conf >= HMC5843_MEAS_CONF_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
ret = hmc5843_set_meas_conf(data, meas_conf);
|
||||
|
||||
return (ret < 0) ? ret : count;
|
||||
return hmc5843_set_meas_conf(data, meas_conf);
|
||||
}
|
||||
|
||||
static IIO_DEVICE_ATTR(meas_conf,
|
||||
S_IWUSR | S_IRUGO,
|
||||
hmc5843_show_measurement_configuration,
|
||||
hmc5843_set_measurement_configuration,
|
||||
0);
|
||||
static const struct iio_enum hmc5843_meas_conf_enum = {
|
||||
.items = hmc5843_meas_conf_modes,
|
||||
.num_items = ARRAY_SIZE(hmc5843_meas_conf_modes),
|
||||
.get = hmc5843_show_measurement_configuration,
|
||||
.set = hmc5843_set_measurement_configuration,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec_ext_info hmc5843_ext_info[] = {
|
||||
IIO_ENUM("meas_conf", true, &hmc5843_meas_conf_enum),
|
||||
IIO_ENUM_AVAILABLE("meas_conf", &hmc5843_meas_conf_enum),
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct iio_enum hmc5983_meas_conf_enum = {
|
||||
.items = hmc5983_meas_conf_modes,
|
||||
.num_items = ARRAY_SIZE(hmc5983_meas_conf_modes),
|
||||
.get = hmc5843_show_measurement_configuration,
|
||||
.set = hmc5843_set_measurement_configuration,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec_ext_info hmc5983_ext_info[] = {
|
||||
IIO_ENUM("meas_conf", true, &hmc5983_meas_conf_enum),
|
||||
IIO_ENUM_AVAILABLE("meas_conf", &hmc5983_meas_conf_enum),
|
||||
{ },
|
||||
};
|
||||
|
||||
static
|
||||
ssize_t hmc5843_show_samp_freq_avail(struct device *dev,
|
||||
@ -459,6 +474,25 @@ done:
|
||||
.storagebits = 16, \
|
||||
.endianness = IIO_BE, \
|
||||
}, \
|
||||
.ext_info = hmc5843_ext_info, \
|
||||
}
|
||||
|
||||
#define HMC5983_CHANNEL(axis, idx) \
|
||||
{ \
|
||||
.type = IIO_MAGN, \
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_##axis, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.scan_index = idx, \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = 16, \
|
||||
.storagebits = 16, \
|
||||
.endianness = IIO_BE, \
|
||||
}, \
|
||||
.ext_info = hmc5983_ext_info, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec hmc5843_channels[] = {
|
||||
@ -476,8 +510,14 @@ static const struct iio_chan_spec hmc5883_channels[] = {
|
||||
IIO_CHAN_SOFT_TIMESTAMP(3),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec hmc5983_channels[] = {
|
||||
HMC5983_CHANNEL(X, 0),
|
||||
HMC5983_CHANNEL(Z, 1),
|
||||
HMC5983_CHANNEL(Y, 2),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(3),
|
||||
};
|
||||
|
||||
static struct attribute *hmc5843_attributes[] = {
|
||||
&iio_dev_attr_meas_conf.dev_attr.attr,
|
||||
&iio_dev_attr_scale_available.dev_attr.attr,
|
||||
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
|
||||
NULL
|
||||
@ -516,7 +556,7 @@ static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = {
|
||||
ARRAY_SIZE(hmc5883l_regval_to_nanoscale),
|
||||
},
|
||||
[HMC5983_ID] = {
|
||||
.channels = hmc5883_channels,
|
||||
.channels = hmc5983_channels,
|
||||
.regval_to_samp_freq = hmc5983_regval_to_samp_freq,
|
||||
.n_regval_to_samp_freq =
|
||||
ARRAY_SIZE(hmc5983_regval_to_samp_freq),
|
||||
@ -554,9 +594,9 @@ static int hmc5843_init(struct hmc5843_data *data)
|
||||
|
||||
static const struct iio_info hmc5843_info = {
|
||||
.attrs = &hmc5843_group,
|
||||
.read_raw = hmc5843_read_raw,
|
||||
.write_raw = hmc5843_write_raw,
|
||||
.write_raw_get_fmt = hmc5843_write_raw_get_fmt,
|
||||
.read_raw = &hmc5843_read_raw,
|
||||
.write_raw = &hmc5843_write_raw,
|
||||
.write_raw_get_fmt = &hmc5843_write_raw_get_fmt,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
@ -17,4 +17,16 @@ config MCP4531
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called mcp4531.
|
||||
|
||||
config TPL0102
|
||||
tristate "Texas Instruments digital potentiometer driver"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say yes here to build support for the Texas Instruments
|
||||
TPL0102, TPL0402
|
||||
digital potentiometer chips.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called tpl0102.
|
||||
|
||||
endmenu
|
||||
|
@ -4,3 +4,4 @@
|
||||
|
||||
# When adding new entries keep the list in alphabetical order
|
||||
obj-$(CONFIG_MCP4531) += mcp4531.o
|
||||
obj-$(CONFIG_TPL0102) += tpl0102.o
|
||||
|
@ -159,7 +159,7 @@ static int mcp4531_probe(struct i2c_client *client,
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_WORD_DATA)) {
|
||||
dev_err(dev, "SMBUS Word Data not supported\n");
|
||||
return -EIO;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
|
||||
|
166
drivers/iio/potentiometer/tpl0102.c
Normal file
166
drivers/iio/potentiometer/tpl0102.c
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* tpl0102.c - Support for Texas Instruments digital potentiometers
|
||||
*
|
||||
* Copyright (C) 2016 Matt Ranostay <mranostay@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* TODO: enable/disable hi-z output control
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
struct tpl0102_cfg {
|
||||
int wipers;
|
||||
int max_pos;
|
||||
int kohms;
|
||||
};
|
||||
|
||||
enum tpl0102_type {
|
||||
CAT5140_503,
|
||||
CAT5140_104,
|
||||
TPL0102_104,
|
||||
TPL0401_103,
|
||||
};
|
||||
|
||||
static const struct tpl0102_cfg tpl0102_cfg[] = {
|
||||
/* on-semiconductor parts */
|
||||
[CAT5140_503] = { .wipers = 1, .max_pos = 256, .kohms = 50, },
|
||||
[CAT5140_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, },
|
||||
/* ti parts */
|
||||
[TPL0102_104] = { .wipers = 2, .max_pos = 256, .kohms = 100 },
|
||||
[TPL0401_103] = { .wipers = 1, .max_pos = 128, .kohms = 10, },
|
||||
};
|
||||
|
||||
struct tpl0102_data {
|
||||
struct regmap *regmap;
|
||||
unsigned long devid;
|
||||
};
|
||||
|
||||
static const struct regmap_config tpl0102_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
};
|
||||
|
||||
#define TPL0102_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 tpl0102_channels[] = {
|
||||
TPL0102_CHANNEL(0),
|
||||
TPL0102_CHANNEL(1),
|
||||
};
|
||||
|
||||
static int tpl0102_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct tpl0102_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW: {
|
||||
int ret = regmap_read(data->regmap, chan->channel, val);
|
||||
|
||||
return ret ? ret : IIO_VAL_INT;
|
||||
}
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 1000 * tpl0102_cfg[data->devid].kohms;
|
||||
*val2 = tpl0102_cfg[data->devid].max_pos;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int tpl0102_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct tpl0102_data *data = iio_priv(indio_dev);
|
||||
|
||||
if (mask != IIO_CHAN_INFO_RAW)
|
||||
return -EINVAL;
|
||||
|
||||
if (val >= tpl0102_cfg[data->devid].max_pos || val < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return regmap_write(data->regmap, chan->channel, val);
|
||||
}
|
||||
|
||||
static const struct iio_info tpl0102_info = {
|
||||
.read_raw = tpl0102_read_raw,
|
||||
.write_raw = tpl0102_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int tpl0102_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct tpl0102_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -ENOTSUPP;
|
||||
|
||||
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->devid = id->driver_data;
|
||||
data->regmap = devm_regmap_init_i2c(client, &tpl0102_regmap_config);
|
||||
if (IS_ERR(data->regmap)) {
|
||||
dev_err(dev, "regmap initialization failed\n");
|
||||
return PTR_ERR(data->regmap);
|
||||
}
|
||||
|
||||
indio_dev->dev.parent = dev;
|
||||
indio_dev->info = &tpl0102_info;
|
||||
indio_dev->channels = tpl0102_channels;
|
||||
indio_dev->num_channels = tpl0102_cfg[data->devid].wipers;
|
||||
indio_dev->name = client->name;
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id tpl0102_id[] = {
|
||||
{ "cat5140-503", CAT5140_503 },
|
||||
{ "cat5140-104", CAT5140_104 },
|
||||
{ "tpl0102-104", TPL0102_104 },
|
||||
{ "tpl0401-103", TPL0401_103 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tpl0102_id);
|
||||
|
||||
static struct i2c_driver tpl0102_driver = {
|
||||
.driver = {
|
||||
.name = "tpl0102",
|
||||
},
|
||||
.probe = tpl0102_probe,
|
||||
.id_table = tpl0102_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(tpl0102_driver);
|
||||
|
||||
MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
|
||||
MODULE_DESCRIPTION("TPL0102 digital potentiometer");
|
||||
MODULE_LICENSE("GPL");
|
@ -69,6 +69,7 @@ config MPL3115
|
||||
|
||||
config MS5611
|
||||
tristate "Measurement Specialties MS5611 pressure sensor driver"
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say Y here to build support for the Measurement Specialties
|
||||
|
@ -42,7 +42,7 @@ static int mpl115_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -ENODEV;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return mpl115_probe(&client->dev, id->name, &mpl115_i2c_ops);
|
||||
}
|
||||
|
@ -51,7 +51,8 @@ struct ms5611_state {
|
||||
struct ms5611_chip_info *chip_info;
|
||||
};
|
||||
|
||||
int ms5611_probe(struct iio_dev *indio_dev, struct device *dev, int type);
|
||||
int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
|
||||
const char* name, int type);
|
||||
int ms5611_remove(struct iio_dev *indio_dev);
|
||||
|
||||
#endif /* _MS5611_H */
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
@ -136,17 +137,17 @@ static int ms5607_temp_and_pressure_compensate(struct ms5611_chip_info *chip_inf
|
||||
|
||||
t = 2000 + ((chip_info->prom[6] * dt) >> 23);
|
||||
if (t < 2000) {
|
||||
s64 off2, sens2, t2;
|
||||
s64 off2, sens2, t2, tmp;
|
||||
|
||||
t2 = (dt * dt) >> 31;
|
||||
off2 = (61 * (t - 2000) * (t - 2000)) >> 4;
|
||||
sens2 = off2 << 1;
|
||||
tmp = (t - 2000) * (t - 2000);
|
||||
off2 = (61 * tmp) >> 4;
|
||||
sens2 = tmp << 1;
|
||||
|
||||
if (t < -1500) {
|
||||
s64 tmp = (t + 1500) * (t + 1500);
|
||||
|
||||
tmp = (t + 1500) * (t + 1500);
|
||||
off2 += 15 * tmp;
|
||||
sens2 += (8 * tmp);
|
||||
sens2 += 8 * tmp;
|
||||
}
|
||||
|
||||
t -= t2;
|
||||
@ -290,6 +291,18 @@ static const struct iio_info ms5611_info = {
|
||||
static int ms5611_init(struct iio_dev *indio_dev)
|
||||
{
|
||||
int ret;
|
||||
struct regulator *vdd = devm_regulator_get(indio_dev->dev.parent,
|
||||
"vdd");
|
||||
|
||||
/* Enable attached regulator if any. */
|
||||
if (!IS_ERR(vdd)) {
|
||||
ret = regulator_enable(vdd);
|
||||
if (ret) {
|
||||
dev_err(indio_dev->dev.parent,
|
||||
"failed to enable Vdd supply: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ms5611_reset(indio_dev);
|
||||
if (ret < 0)
|
||||
@ -298,7 +311,8 @@ static int ms5611_init(struct iio_dev *indio_dev)
|
||||
return ms5611_read_prom(indio_dev);
|
||||
}
|
||||
|
||||
int ms5611_probe(struct iio_dev *indio_dev, struct device *dev, int type)
|
||||
int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
|
||||
const char *name, int type)
|
||||
{
|
||||
int ret;
|
||||
struct ms5611_state *st = iio_priv(indio_dev);
|
||||
@ -306,7 +320,7 @@ int ms5611_probe(struct iio_dev *indio_dev, struct device *dev, int type)
|
||||
mutex_init(&st->lock);
|
||||
st->chip_info = &chip_info_tbl[type];
|
||||
indio_dev->dev.parent = dev;
|
||||
indio_dev->name = dev->driver->name;
|
||||
indio_dev->name = name;
|
||||
indio_dev->info = &ms5611_info;
|
||||
indio_dev->channels = ms5611_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ms5611_channels);
|
||||
|
@ -92,7 +92,7 @@ static int ms5611_i2c_probe(struct i2c_client *client,
|
||||
I2C_FUNC_SMBUS_WRITE_BYTE |
|
||||
I2C_FUNC_SMBUS_READ_WORD_DATA |
|
||||
I2C_FUNC_SMBUS_READ_I2C_BLOCK))
|
||||
return -ENODEV;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
@ -105,7 +105,7 @@ static int ms5611_i2c_probe(struct i2c_client *client,
|
||||
st->read_adc_temp_and_pressure = ms5611_i2c_read_adc_temp_and_pressure;
|
||||
st->client = client;
|
||||
|
||||
return ms5611_probe(indio_dev, &client->dev, id->driver_data);
|
||||
return ms5611_probe(indio_dev, &client->dev, id->name, id->driver_data);
|
||||
}
|
||||
|
||||
static int ms5611_i2c_remove(struct i2c_client *client)
|
||||
|
@ -105,8 +105,8 @@ static int ms5611_spi_probe(struct spi_device *spi)
|
||||
st->read_adc_temp_and_pressure = ms5611_spi_read_adc_temp_and_pressure;
|
||||
st->client = spi;
|
||||
|
||||
return ms5611_probe(indio_dev, &spi->dev,
|
||||
spi_get_device_id(spi)->driver_data);
|
||||
return ms5611_probe(indio_dev, &spi->dev, spi_get_device_id(spi)->name,
|
||||
spi_get_device_id(spi)->driver_data);
|
||||
}
|
||||
|
||||
static int ms5611_spi_remove(struct spi_device *spi)
|
||||
|
@ -136,7 +136,7 @@ static int ms5637_probe(struct i2c_client *client,
|
||||
I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
|
||||
dev_err(&client->dev,
|
||||
"Adapter does not support some i2c transaction\n");
|
||||
return -ENODEV;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
|
||||
|
@ -221,7 +221,7 @@ static int t5403_probe(struct i2c_client *client,
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA |
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK))
|
||||
return -ENODEV;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, T5403_SLAVE_ADDR);
|
||||
if (ret < 0)
|
||||
|
@ -278,7 +278,7 @@ static int lidar_probe(struct i2c_client *client,
|
||||
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE))
|
||||
data->xfer = lidar_smbus_xfer;
|
||||
else
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
indio_dev->info = &lidar_info;
|
||||
indio_dev->name = LIDAR_DRV_NAME;
|
||||
|
@ -516,7 +516,7 @@ static int mlx90614_probe(struct i2c_client *client,
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -ENODEV;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
|
@ -205,7 +205,7 @@ static int tmp006_probe(struct i2c_client *client,
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -ENODEV;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!tmp006_check_identification(client)) {
|
||||
dev_err(&client->dev, "no TMP006 sensor\n");
|
||||
|
@ -190,7 +190,7 @@ static int tsys01_i2c_probe(struct i2c_client *client,
|
||||
I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
|
||||
dev_err(&client->dev,
|
||||
"Adapter does not support some i2c transaction\n");
|
||||
return -ENODEV;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
|
||||
|
@ -137,7 +137,7 @@ static int tsys02d_probe(struct i2c_client *client,
|
||||
I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
|
||||
dev_err(&client->dev,
|
||||
"Adapter does not support some i2c transaction\n");
|
||||
return -ENODEV;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
|
||||
|
@ -12,7 +12,6 @@ source "drivers/staging/iio/frequency/Kconfig"
|
||||
source "drivers/staging/iio/gyro/Kconfig"
|
||||
source "drivers/staging/iio/impedance-analyzer/Kconfig"
|
||||
source "drivers/staging/iio/light/Kconfig"
|
||||
source "drivers/staging/iio/magnetometer/Kconfig"
|
||||
source "drivers/staging/iio/meter/Kconfig"
|
||||
source "drivers/staging/iio/resolver/Kconfig"
|
||||
source "drivers/staging/iio/trigger/Kconfig"
|
||||
|
@ -10,7 +10,6 @@ obj-y += frequency/
|
||||
obj-y += gyro/
|
||||
obj-y += impedance-analyzer/
|
||||
obj-y += light/
|
||||
obj-y += magnetometer/
|
||||
obj-y += meter/
|
||||
obj-y += resolver/
|
||||
obj-y += trigger/
|
||||
|
@ -58,14 +58,6 @@ different requirements. This one suits mid range
|
||||
frequencies (100Hz - 4kHz).
|
||||
2) Lots of testing
|
||||
|
||||
Periodic Timer trigger
|
||||
1) Move to a more general hardware periodic timer request
|
||||
subsystem. Current approach is abusing purpose of RTC.
|
||||
Initial discussions have taken place, but no actual code
|
||||
is in place as yet. This topic will be reopened on lkml
|
||||
shortly. I don't really envision this patch being merged
|
||||
in anything like its current form.
|
||||
|
||||
GPIO trigger
|
||||
1) Add control over the type of interrupt etc. This will
|
||||
necessitate a header that is also visible from arch board
|
||||
|
@ -100,7 +100,6 @@ static const struct isl29018_scale {
|
||||
};
|
||||
|
||||
struct isl29018_chip {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct mutex lock;
|
||||
int type;
|
||||
@ -180,30 +179,31 @@ static int isl29018_read_sensor_input(struct isl29018_chip *chip, int mode)
|
||||
int status;
|
||||
unsigned int lsb;
|
||||
unsigned int msb;
|
||||
struct device *dev = regmap_get_device(chip->regmap);
|
||||
|
||||
/* Set mode */
|
||||
status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1,
|
||||
mode << COMMMAND1_OPMODE_SHIFT);
|
||||
if (status) {
|
||||
dev_err(chip->dev,
|
||||
dev_err(dev,
|
||||
"Error in setting operating mode err %d\n", status);
|
||||
return status;
|
||||
}
|
||||
msleep(CONVERSION_TIME_MS);
|
||||
status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_LSB, &lsb);
|
||||
if (status < 0) {
|
||||
dev_err(chip->dev,
|
||||
dev_err(dev,
|
||||
"Error in reading LSB DATA with err %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_MSB, &msb);
|
||||
if (status < 0) {
|
||||
dev_err(chip->dev,
|
||||
dev_err(dev,
|
||||
"Error in reading MSB DATA with error %d\n", status);
|
||||
return status;
|
||||
}
|
||||
dev_vdbg(chip->dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb);
|
||||
dev_vdbg(dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb);
|
||||
|
||||
return (msb << 8) | lsb;
|
||||
}
|
||||
@ -246,13 +246,14 @@ static int isl29018_read_proximity_ir(struct isl29018_chip *chip, int scheme,
|
||||
int status;
|
||||
int prox_data = -1;
|
||||
int ir_data = -1;
|
||||
struct device *dev = regmap_get_device(chip->regmap);
|
||||
|
||||
/* Do proximity sensing with required scheme */
|
||||
status = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII,
|
||||
COMMANDII_SCHEME_MASK,
|
||||
scheme << COMMANDII_SCHEME_SHIFT);
|
||||
if (status) {
|
||||
dev_err(chip->dev, "Error in setting operating mode\n");
|
||||
dev_err(dev, "Error in setting operating mode\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -525,10 +526,11 @@ static int isl29035_detect(struct isl29018_chip *chip)
|
||||
{
|
||||
int status;
|
||||
unsigned int id;
|
||||
struct device *dev = regmap_get_device(chip->regmap);
|
||||
|
||||
status = regmap_read(chip->regmap, ISL29035_REG_DEVICE_ID, &id);
|
||||
if (status < 0) {
|
||||
dev_err(chip->dev,
|
||||
dev_err(dev,
|
||||
"Error reading ID register with error %d\n",
|
||||
status);
|
||||
return status;
|
||||
@ -553,6 +555,7 @@ enum {
|
||||
static int isl29018_chip_init(struct isl29018_chip *chip)
|
||||
{
|
||||
int status;
|
||||
struct device *dev = regmap_get_device(chip->regmap);
|
||||
|
||||
if (chip->type == isl29035) {
|
||||
status = isl29035_detect(chip);
|
||||
@ -582,7 +585,7 @@ static int isl29018_chip_init(struct isl29018_chip *chip)
|
||||
*/
|
||||
status = regmap_write(chip->regmap, ISL29018_REG_TEST, 0x0);
|
||||
if (status < 0) {
|
||||
dev_err(chip->dev, "Failed to clear isl29018 TEST reg.(%d)\n",
|
||||
dev_err(dev, "Failed to clear isl29018 TEST reg.(%d)\n",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
@ -593,7 +596,7 @@ static int isl29018_chip_init(struct isl29018_chip *chip)
|
||||
*/
|
||||
status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1, 0);
|
||||
if (status < 0) {
|
||||
dev_err(chip->dev, "Failed to clear isl29018 CMD1 reg.(%d)\n",
|
||||
dev_err(dev, "Failed to clear isl29018 CMD1 reg.(%d)\n",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
@ -604,14 +607,14 @@ static int isl29018_chip_init(struct isl29018_chip *chip)
|
||||
status = isl29018_set_scale(chip, chip->scale.scale,
|
||||
chip->scale.uscale);
|
||||
if (status < 0) {
|
||||
dev_err(chip->dev, "Init of isl29018 fails\n");
|
||||
dev_err(dev, "Init of isl29018 fails\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
status = isl29018_set_integration_time(chip,
|
||||
isl29018_int_utimes[chip->type][chip->int_time]);
|
||||
if (status < 0) {
|
||||
dev_err(chip->dev, "Init of isl29018 fails\n");
|
||||
dev_err(dev, "Init of isl29018 fails\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -728,7 +731,6 @@ static int isl29018_probe(struct i2c_client *client,
|
||||
chip = iio_priv(indio_dev);
|
||||
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
chip->dev = &client->dev;
|
||||
|
||||
if (id) {
|
||||
name = id->name;
|
||||
@ -751,7 +753,7 @@ static int isl29018_probe(struct i2c_client *client,
|
||||
chip_info_tbl[dev_id].regmap_cfg);
|
||||
if (IS_ERR(chip->regmap)) {
|
||||
err = PTR_ERR(chip->regmap);
|
||||
dev_err(chip->dev, "regmap initialization failed: %d\n", err);
|
||||
dev_err(&client->dev, "regmap initialization fails: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1,40 +0,0 @@
|
||||
#
|
||||
# Magnetometer sensors
|
||||
#
|
||||
menu "Magnetometer sensors"
|
||||
|
||||
config SENSORS_HMC5843
|
||||
tristate
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
|
||||
config SENSORS_HMC5843_I2C
|
||||
tristate "Honeywell HMC5843/5883/5883L 3-Axis Magnetometer (I2C)"
|
||||
depends on I2C
|
||||
select SENSORS_HMC5843
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say Y here to add support for the Honeywell HMC5843, HMC5883 and
|
||||
HMC5883L 3-Axis Magnetometer (digital compass).
|
||||
|
||||
This driver can also be compiled as a set of modules.
|
||||
If so, these modules will be created:
|
||||
- hmc5843_core (core functions)
|
||||
- hmc5843_i2c (support for HMC5843, HMC5883, HMC5883L and HMC5983)
|
||||
|
||||
config SENSORS_HMC5843_SPI
|
||||
tristate "Honeywell HMC5983 3-Axis Magnetometer (SPI)"
|
||||
depends on SPI_MASTER
|
||||
select SENSORS_HMC5843
|
||||
select REGMAP_SPI
|
||||
help
|
||||
Say Y here to add support for the Honeywell HMC5983 3-Axis Magnetometer
|
||||
(digital compass).
|
||||
|
||||
This driver can also be compiled as a set of modules.
|
||||
If so, these modules will be created:
|
||||
- hmc5843_core (core functions)
|
||||
- hmc5843_spi (support for HMC5983)
|
||||
|
||||
|
||||
endmenu
|
@ -1,7 +0,0 @@
|
||||
#
|
||||
# Makefile for industrial I/O Magnetometer sensors
|
||||
#
|
||||
|
||||
obj-$(CONFIG_SENSORS_HMC5843) += hmc5843_core.o
|
||||
obj-$(CONFIG_SENSORS_HMC5843_I2C) += hmc5843_i2c.o
|
||||
obj-$(CONFIG_SENSORS_HMC5843_SPI) += hmc5843_spi.o
|
@ -5,16 +5,6 @@ comment "Triggers - standalone"
|
||||
|
||||
if IIO_TRIGGER
|
||||
|
||||
config IIO_PERIODIC_RTC_TRIGGER
|
||||
tristate "Periodic RTC triggers"
|
||||
depends on RTC_CLASS
|
||||
help
|
||||
Provides support for using periodic capable real time
|
||||
clocks as IIO triggers.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called iio-trig-periodic-rtc.
|
||||
|
||||
config IIO_BFIN_TMR_TRIGGER
|
||||
tristate "Blackfin TIMER trigger"
|
||||
depends on BLACKFIN
|
||||
|
@ -2,5 +2,4 @@
|
||||
# Makefile for triggers not associated with iio-devices
|
||||
#
|
||||
|
||||
obj-$(CONFIG_IIO_PERIODIC_RTC_TRIGGER) += iio-trig-periodic-rtc.o
|
||||
obj-$(CONFIG_IIO_BFIN_TMR_TRIGGER) += iio-trig-bfin-timer.o
|
||||
|
@ -1,216 +0,0 @@
|
||||
/* The industrial I/O periodic RTC trigger driver
|
||||
*
|
||||
* Copyright (c) 2008 Jonathan Cameron
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This is a heavily rewritten version of the periodic timer system in
|
||||
* earlier version of industrialio. It supplies the same functionality
|
||||
* but via a trigger rather than a specific periodic timer system.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
|
||||
static LIST_HEAD(iio_prtc_trigger_list);
|
||||
static DEFINE_MUTEX(iio_prtc_trigger_list_lock);
|
||||
|
||||
struct iio_prtc_trigger_info {
|
||||
struct rtc_device *rtc;
|
||||
unsigned int frequency;
|
||||
struct rtc_task task;
|
||||
bool state;
|
||||
};
|
||||
|
||||
static int iio_trig_periodic_rtc_set_state(struct iio_trigger *trig, bool state)
|
||||
{
|
||||
struct iio_prtc_trigger_info *trig_info = iio_trigger_get_drvdata(trig);
|
||||
int ret;
|
||||
|
||||
if (trig_info->frequency == 0 && state)
|
||||
return -EINVAL;
|
||||
dev_dbg(&trig_info->rtc->dev, "trigger frequency is %u\n",
|
||||
trig_info->frequency);
|
||||
ret = rtc_irq_set_state(trig_info->rtc, &trig_info->task, state);
|
||||
if (!ret)
|
||||
trig_info->state = state;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t iio_trig_periodic_read_freq(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_trigger *trig = to_iio_trigger(dev);
|
||||
struct iio_prtc_trigger_info *trig_info = iio_trigger_get_drvdata(trig);
|
||||
|
||||
return sprintf(buf, "%u\n", trig_info->frequency);
|
||||
}
|
||||
|
||||
static ssize_t iio_trig_periodic_write_freq(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct iio_trigger *trig = to_iio_trigger(dev);
|
||||
struct iio_prtc_trigger_info *trig_info = iio_trigger_get_drvdata(trig);
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = kstrtouint(buf, 10, &val);
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
|
||||
if (val > 0) {
|
||||
ret = rtc_irq_set_freq(trig_info->rtc, &trig_info->task, val);
|
||||
if (ret == 0 && trig_info->state && trig_info->frequency == 0)
|
||||
ret = rtc_irq_set_state(trig_info->rtc,
|
||||
&trig_info->task, 1);
|
||||
} else {
|
||||
ret = rtc_irq_set_state(trig_info->rtc, &trig_info->task, 0);
|
||||
}
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
|
||||
trig_info->frequency = val;
|
||||
|
||||
return len;
|
||||
|
||||
error_ret:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(frequency, S_IRUGO | S_IWUSR,
|
||||
iio_trig_periodic_read_freq,
|
||||
iio_trig_periodic_write_freq);
|
||||
|
||||
static struct attribute *iio_trig_prtc_attrs[] = {
|
||||
&dev_attr_frequency.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group iio_trig_prtc_attr_group = {
|
||||
.attrs = iio_trig_prtc_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *iio_trig_prtc_attr_groups[] = {
|
||||
&iio_trig_prtc_attr_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
static void iio_prtc_trigger_poll(void *private_data)
|
||||
{
|
||||
iio_trigger_poll(private_data);
|
||||
}
|
||||
|
||||
static const struct iio_trigger_ops iio_prtc_trigger_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.set_trigger_state = &iio_trig_periodic_rtc_set_state,
|
||||
};
|
||||
|
||||
static int iio_trig_periodic_rtc_probe(struct platform_device *dev)
|
||||
{
|
||||
char **pdata = dev->dev.platform_data;
|
||||
struct iio_prtc_trigger_info *trig_info;
|
||||
struct iio_trigger *trig, *trig2;
|
||||
|
||||
int i, ret;
|
||||
|
||||
for (i = 0;; i++) {
|
||||
if (!pdata[i])
|
||||
break;
|
||||
trig = iio_trigger_alloc("periodic%s", pdata[i]);
|
||||
if (!trig) {
|
||||
ret = -ENOMEM;
|
||||
goto error_free_completed_registrations;
|
||||
}
|
||||
list_add(&trig->alloc_list, &iio_prtc_trigger_list);
|
||||
|
||||
trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL);
|
||||
if (!trig_info) {
|
||||
ret = -ENOMEM;
|
||||
goto error_put_trigger_and_remove_from_list;
|
||||
}
|
||||
iio_trigger_set_drvdata(trig, trig_info);
|
||||
trig->ops = &iio_prtc_trigger_ops;
|
||||
/* RTC access */
|
||||
trig_info->rtc = rtc_class_open(pdata[i]);
|
||||
if (!trig_info->rtc) {
|
||||
ret = -EINVAL;
|
||||
goto error_free_trig_info;
|
||||
}
|
||||
trig_info->task.func = iio_prtc_trigger_poll;
|
||||
trig_info->task.private_data = trig;
|
||||
ret = rtc_irq_register(trig_info->rtc, &trig_info->task);
|
||||
if (ret)
|
||||
goto error_close_rtc;
|
||||
trig->dev.groups = iio_trig_prtc_attr_groups;
|
||||
ret = iio_trigger_register(trig);
|
||||
if (ret)
|
||||
goto error_unregister_rtc_irq;
|
||||
}
|
||||
return 0;
|
||||
error_unregister_rtc_irq:
|
||||
rtc_irq_unregister(trig_info->rtc, &trig_info->task);
|
||||
error_close_rtc:
|
||||
rtc_class_close(trig_info->rtc);
|
||||
error_free_trig_info:
|
||||
kfree(trig_info);
|
||||
error_put_trigger_and_remove_from_list:
|
||||
list_del(&trig->alloc_list);
|
||||
iio_trigger_put(trig);
|
||||
error_free_completed_registrations:
|
||||
list_for_each_entry_safe(trig,
|
||||
trig2,
|
||||
&iio_prtc_trigger_list,
|
||||
alloc_list) {
|
||||
trig_info = iio_trigger_get_drvdata(trig);
|
||||
rtc_irq_unregister(trig_info->rtc, &trig_info->task);
|
||||
rtc_class_close(trig_info->rtc);
|
||||
kfree(trig_info);
|
||||
iio_trigger_unregister(trig);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iio_trig_periodic_rtc_remove(struct platform_device *dev)
|
||||
{
|
||||
struct iio_trigger *trig, *trig2;
|
||||
struct iio_prtc_trigger_info *trig_info;
|
||||
|
||||
mutex_lock(&iio_prtc_trigger_list_lock);
|
||||
list_for_each_entry_safe(trig,
|
||||
trig2,
|
||||
&iio_prtc_trigger_list,
|
||||
alloc_list) {
|
||||
trig_info = iio_trigger_get_drvdata(trig);
|
||||
rtc_irq_unregister(trig_info->rtc, &trig_info->task);
|
||||
rtc_class_close(trig_info->rtc);
|
||||
kfree(trig_info);
|
||||
iio_trigger_unregister(trig);
|
||||
}
|
||||
mutex_unlock(&iio_prtc_trigger_list_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver iio_trig_periodic_rtc_driver = {
|
||||
.probe = iio_trig_periodic_rtc_probe,
|
||||
.remove = iio_trig_periodic_rtc_remove,
|
||||
.driver = {
|
||||
.name = "iio_prtc_trigger",
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(iio_trig_periodic_rtc_driver);
|
||||
|
||||
MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
|
||||
MODULE_DESCRIPTION("Periodic realtime clock trigger for the iio subsystem");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -180,18 +180,18 @@ struct iio_event_spec {
|
||||
* @address: Driver specific identifier.
|
||||
* @scan_index: Monotonic index to give ordering in scans when read
|
||||
* from a buffer.
|
||||
* @scan_type: Sign: 's' or 'u' to specify signed or unsigned
|
||||
* @scan_type: sign: 's' or 'u' to specify signed or unsigned
|
||||
* realbits: Number of valid bits of data
|
||||
* storage_bits: Realbits + padding
|
||||
* storagebits: Realbits + padding
|
||||
* shift: Shift right by this before masking out
|
||||
* realbits.
|
||||
* endianness: little or big endian
|
||||
* repeat: Number of times real/storage bits
|
||||
* repeats. When the repeat element is
|
||||
* more than 1, then the type element in
|
||||
* sysfs will show a repeat value.
|
||||
* Otherwise, the number of repetitions is
|
||||
* omitted.
|
||||
* endianness: little or big endian
|
||||
* @info_mask_separate: What information is to be exported that is specific to
|
||||
* this channel.
|
||||
* @info_mask_shared_by_type: What information is to be exported that is shared
|
||||
|
Loading…
Reference in New Issue
Block a user