mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 03:27:44 -04:00
Second set of new device support, features and cleanup for the 4.3 cycle.
Take 2 also includes a fix set that was too late for the 4.2 cycle.
As we had a lot of tools and docs work in this set, I have broken those
out into their own categories in this description.
Fixes from the pull request '4th set of IIO fixes for the 4.2 cycle'.
* Poll functions for both event chardev and the buffer one were returning
negative error codes (via a positive value).
* A recent change to lsiio adding some error handling that was wrong and
stopped the tool working.
* bmg160 was missing some dependencies in Kconfig
* berlin2-adc had a misshandled register (wrote a value rather than a bitmap)
New device support
* TI opt3001 light sensor
* TXC PA12 ALS and proximity sensor.
* mcp3301 ADC support (in mcp320x driver)
* ST lsm303agr accelerometer and magnetometer drivers (plus some st-sensors
common support to allow different WHOAMI register addresses, devices with
fixed scale and allow interrupt equiped magnetometers).
* ADIS16305, ADIS16367, ADIS16445IMUs (in the adis16400 driver)
* ADIS16266 gyro (in the adis16260 driver)
* ADIS16137 gyro (in the adis16136 driver)
New functionality
* mmc35240 DT bindings.
* Inverse unit conversion macros to aid handing of values written to sysfs
attributes.
Core cleanup
* Forward declaration of struct iio_trigger to avoid a compile warning.
Driver cleanup / fixes
* mxs-lradc
- Clarify which parts are supported.
- Fix spelling erorrs.
- Missing/extra includes
- reorder includes
- add datasheet name listings for all usable channels (to allow them
to be bound by name from consumer drivers)
* acpi-als - add some function prefixes as per general iio style.
* bmc150_magn - replace a magic value with the existing define.
* vf610 - determine possible sample frequencies taking into account the
electrical characteristics (defining a minimum sample time)
* dht11
- whitespace
- additional docs
- avoid mulitple assignments in one line
- Use the new funciton ktime_get_resolution_ns to cleanup a nasty trick
previously used for timing.
* Fix all drivers that consider 0 a valid IRQ for historical reasons.
* Export I2C module alias info where previously missing (to allow autoprobing)
* Export OF module alias info where previously missing.
* mmc35240 - switch some variables into arrays to improve readability.
* mlx90614 - define some magic numbers for readability.
* bmc150_magn
- expand area locked by a mutex to cover all the use of the
data->buffer.
- use descriptive naming for a mask instead of a magic value.
* berin2-adc
- pass up an error code rather that a generic error
- constify the iio_chan_spec
- some other little tidy ups.
* stk8312
- fix a dependency on triggered buffers in kconfig
- add a check for invalid attribute values
- improve error handling by returning error codes where possible and
return immediately where relevant
- rework macro defs to use GENMASK etc
- change some variable types to reduce unnecessary casting
- clean up code style
- drop a local buffer copy for bulk reads and use the one in data->buffer
instead.
* adis16400 - the adis16448 gyroscope scale was wrong.
* adis16480 - some more wrong scales for various parts.
* adis16300 - has an undocumented product id and serial number registers so
use them.
* iio_simple_dummy - fix some wrong code indentation.
* bmc150-accel - use the chip ID to detect the chip present rather than
verifying the expected part was there. This was in response to a wrong
ACPI entry on the WinBook TW100.
* mma8452
- fix _get_hp_filter_index
- drop a double include
- pass up an error code rather than rewriting it
- range check input values to attribute writes
- register defs tidy up using GENMASK and reordering them to be easier to
follow.
- various coding style cleanups
- put the Kconfig entry in the write place (alphabetically).
Tools related
* Tools cleanup - drop an explicity NULL comparison, some unnecessary braces,
use the ARRAY_SIZE macro, send error messages to stderr instead of dropping
them in the middle of normal output.
* Fix tools to allow that scale and offset attributes are optional.
* More tools fixes including allowing true 32bit data (previously an overflow
prevented more than 31bits)
* Drop a stray header guard that ended up in a c file.
* Make calc_digits static as it isn't exported or in the header.
* Set ci_array pointer to NULL after free as a protection against non safe
usage of the tools core code. Also convert a double pointer to a single
one as the extra level of indirection was unnecessary.
Docs
* DocBook introduction by Daniel Baluta. Glad we are beginning to
draw together some more introductory docs to suplement the various
tools / examples.
* Drop bytes_per_datum sysfs attribute docs as it no longer exists.
* A whole load of missing / fixing of kernel-doc for the core of IIO.
* Document the trigger name sysfs attribute in the ABI docs.
* Minor typos in the ABI docs related to power down modes.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
iQIcBAABCAAGBQJVy5EbAAoJEFSFNJnE9BaIyjEQAIXc+mjgdyMJEXLKlKKGCSY5
EX7saX91IeSK5y0CWX0hd0VPewaj4ExG7PWo3gqUSm1L9zmusLcyJm8W2pev3CGE
m7s40efxZJw0Jmmu18a3LCfcHUu/LWl4mHQtZy/AFGgWhZzWIyKA2XLqgc+Wu9qb
sjzleSJ05etDksyA7JWFCrrwBnJlW4lD25o0nD0kt3Wry2wlbN2JvZ9QLmmoc0ex
shvtI556Ew0FRywT9ir555EoJNAQQMW85Ft0dWFBnLwgc67nFTa4YNRXgoRlzhh/
sRnGKzrs5SVc1c9sxiVS4utiazxy/irHgZ5FkvTTq7F+GXeIwPK9Xv/SXZTmvs5w
lrSazRIjiLqWgpv/5oaOOGlikbpctI2kSXO0GbCW8th+l3KnKcKfComa3fnU7dca
/lofp/JzpIfwM+Bnjl1nlNuEbT0mlfJySfhUSSu/kHJxOcvDfkK4vv3oSfFp5nbF
rhA9vbVEfopXTGIOwWDjV4j0HtMCEHgOPN3T0kuyiYiWZUIjfJXchXG8e5h9/ncd
ACjH3fg6FQtHzTtzqLQky/NVAKcnFrgJSokN25GXF7R95TxufYJ6RIfnenJiCd2n
QCIdPam4bZh3/C2QYtiqWKY5e+zfkqs88/Er/HGgvxRUhKCbTvCcey1RY7FEDFHY
+9nMx/Yts8L1ulUEMjsm
=/b3G
-----END PGP SIGNATURE-----
Merge tag 'iio-for-4.3b-2' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next
Jonathan writes:
Second set of new device support, features and cleanup for the 4.3 cycle.
Take 2 also includes a fix set that was too late for the 4.2 cycle.
As we had a lot of tools and docs work in this set, I have broken those
out into their own categories in this description.
Fixes from the pull request '4th set of IIO fixes for the 4.2 cycle'.
* Poll functions for both event chardev and the buffer one were returning
negative error codes (via a positive value).
* A recent change to lsiio adding some error handling that was wrong and
stopped the tool working.
* bmg160 was missing some dependencies in Kconfig
* berlin2-adc had a misshandled register (wrote a value rather than a bitmap)
New device support
* TI opt3001 light sensor
* TXC PA12 ALS and proximity sensor.
* mcp3301 ADC support (in mcp320x driver)
* ST lsm303agr accelerometer and magnetometer drivers (plus some st-sensors
common support to allow different WHOAMI register addresses, devices with
fixed scale and allow interrupt equiped magnetometers).
* ADIS16305, ADIS16367, ADIS16445IMUs (in the adis16400 driver)
* ADIS16266 gyro (in the adis16260 driver)
* ADIS16137 gyro (in the adis16136 driver)
New functionality
* mmc35240 DT bindings.
* Inverse unit conversion macros to aid handing of values written to sysfs
attributes.
Core cleanup
* Forward declaration of struct iio_trigger to avoid a compile warning.
Driver cleanup / fixes
* mxs-lradc
- Clarify which parts are supported.
- Fix spelling erorrs.
- Missing/extra includes
- reorder includes
- add datasheet name listings for all usable channels (to allow them
to be bound by name from consumer drivers)
* acpi-als - add some function prefixes as per general iio style.
* bmc150_magn - replace a magic value with the existing define.
* vf610 - determine possible sample frequencies taking into account the
electrical characteristics (defining a minimum sample time)
* dht11
- whitespace
- additional docs
- avoid mulitple assignments in one line
- Use the new funciton ktime_get_resolution_ns to cleanup a nasty trick
previously used for timing.
* Fix all drivers that consider 0 a valid IRQ for historical reasons.
* Export I2C module alias info where previously missing (to allow autoprobing)
* Export OF module alias info where previously missing.
* mmc35240 - switch some variables into arrays to improve readability.
* mlx90614 - define some magic numbers for readability.
* bmc150_magn
- expand area locked by a mutex to cover all the use of the
data->buffer.
- use descriptive naming for a mask instead of a magic value.
* berin2-adc
- pass up an error code rather that a generic error
- constify the iio_chan_spec
- some other little tidy ups.
* stk8312
- fix a dependency on triggered buffers in kconfig
- add a check for invalid attribute values
- improve error handling by returning error codes where possible and
return immediately where relevant
- rework macro defs to use GENMASK etc
- change some variable types to reduce unnecessary casting
- clean up code style
- drop a local buffer copy for bulk reads and use the one in data->buffer
instead.
* adis16400 - the adis16448 gyroscope scale was wrong.
* adis16480 - some more wrong scales for various parts.
* adis16300 - has an undocumented product id and serial number registers so
use them.
* iio_simple_dummy - fix some wrong code indentation.
* bmc150-accel - use the chip ID to detect the chip present rather than
verifying the expected part was there. This was in response to a wrong
ACPI entry on the WinBook TW100.
* mma8452
- fix _get_hp_filter_index
- drop a double include
- pass up an error code rather than rewriting it
- range check input values to attribute writes
- register defs tidy up using GENMASK and reordering them to be easier to
follow.
- various coding style cleanups
- put the Kconfig entry in the write place (alphabetically).
Tools related
* Tools cleanup - drop an explicity NULL comparison, some unnecessary braces,
use the ARRAY_SIZE macro, send error messages to stderr instead of dropping
them in the middle of normal output.
* Fix tools to allow that scale and offset attributes are optional.
* More tools fixes including allowing true 32bit data (previously an overflow
prevented more than 31bits)
* Drop a stray header guard that ended up in a c file.
* Make calc_digits static as it isn't exported or in the header.
* Set ci_array pointer to NULL after free as a protection against non safe
usage of the tools core code. Also convert a double pointer to a single
one as the extra level of indirection was unnecessary.
Docs
* DocBook introduction by Daniel Baluta. Glad we are beginning to
draw together some more introductory docs to suplement the various
tools / examples.
* Drop bytes_per_datum sysfs attribute docs as it no longer exists.
* A whole load of missing / fixing of kernel-doc for the core of IIO.
* Document the trigger name sysfs attribute in the ABI docs.
* Minor typos in the ABI docs related to power down modes.
This commit is contained in:
commit
1c46ae0af6
67 changed files with 3148 additions and 574 deletions
|
|
@ -86,18 +86,6 @@ config KXSD9
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called kxsd9.
|
||||
|
||||
config MMA8452
|
||||
tristate "Freescale MMA8452Q Accelerometer Driver"
|
||||
depends on I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for the Freescale MMA8452Q 3-axis
|
||||
accelerometer.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called mma8452.
|
||||
|
||||
config KXCJK1013
|
||||
tristate "Kionix 3-Axis Accelerometer Driver"
|
||||
depends on I2C
|
||||
|
|
@ -111,6 +99,18 @@ config KXCJK1013
|
|||
To compile this driver as a module, choose M here: the module will
|
||||
be called kxcjk-1013.
|
||||
|
||||
config MMA8452
|
||||
tristate "Freescale MMA8452Q Accelerometer Driver"
|
||||
depends on I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for the Freescale MMA8452Q 3-axis
|
||||
accelerometer.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called mma8452.
|
||||
|
||||
config MMA9551_CORE
|
||||
tristate
|
||||
|
||||
|
|
@ -140,6 +140,8 @@ config MMA9553
|
|||
config STK8312
|
||||
tristate "Sensortek STK8312 3-Axis Accelerometer Driver"
|
||||
depends on I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to get support for the Sensortek STK8312 3-axis
|
||||
accelerometer.
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ struct bmc150_scale_info {
|
|||
};
|
||||
|
||||
struct bmc150_accel_chip_info {
|
||||
const char *name;
|
||||
u8 chip_id;
|
||||
const struct iio_chan_spec *channels;
|
||||
int num_channels;
|
||||
|
|
@ -345,63 +346,6 @@ static int bmc150_accel_any_motion_setup(struct bmc150_accel_trigger *t,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error: Reading chip id\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_dbg(&data->client->dev, "Chip Id %x\n", ret);
|
||||
if (ret != data->chip_info->chip_id) {
|
||||
dev_err(&data->client->dev, "Invalid chip %x\n", ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set Bandwidth */
|
||||
ret = bmc150_accel_set_bw(data, BMC150_ACCEL_DEF_BW, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set Default Range */
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
BMC150_ACCEL_REG_PMU_RANGE,
|
||||
BMC150_ACCEL_DEF_RANGE_4G);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error writing reg_pmu_range\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->range = BMC150_ACCEL_DEF_RANGE_4G;
|
||||
|
||||
/* Set default slope duration and thresholds */
|
||||
data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD;
|
||||
data->slope_dur = BMC150_ACCEL_DEF_SLOPE_DURATION;
|
||||
ret = bmc150_accel_update_slope(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set default as latched interrupts */
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
BMC150_ACCEL_REG_INT_RST_LATCH,
|
||||
BMC150_ACCEL_INT_MODE_LATCH_INT |
|
||||
BMC150_ACCEL_INT_MODE_LATCH_RESET);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev,
|
||||
"Error writing reg_int_rst_latch\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bmc150_accel_get_bw(struct bmc150_accel_data *data, int *val,
|
||||
int *val2)
|
||||
{
|
||||
|
|
@ -1119,6 +1063,7 @@ enum {
|
|||
|
||||
static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
|
||||
[bmc150] = {
|
||||
.name = "BMC150A",
|
||||
.chip_id = 0xFA,
|
||||
.channels = bmc150_accel_channels,
|
||||
.num_channels = ARRAY_SIZE(bmc150_accel_channels),
|
||||
|
|
@ -1128,6 +1073,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
|
|||
{76590, BMC150_ACCEL_DEF_RANGE_16G} },
|
||||
},
|
||||
[bmi055] = {
|
||||
.name = "BMI055A",
|
||||
.chip_id = 0xFA,
|
||||
.channels = bmc150_accel_channels,
|
||||
.num_channels = ARRAY_SIZE(bmc150_accel_channels),
|
||||
|
|
@ -1137,6 +1083,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
|
|||
{76590, BMC150_ACCEL_DEF_RANGE_16G} },
|
||||
},
|
||||
[bma255] = {
|
||||
.name = "BMA0255",
|
||||
.chip_id = 0xFA,
|
||||
.channels = bmc150_accel_channels,
|
||||
.num_channels = ARRAY_SIZE(bmc150_accel_channels),
|
||||
|
|
@ -1146,6 +1093,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
|
|||
{76590, BMC150_ACCEL_DEF_RANGE_16G} },
|
||||
},
|
||||
[bma250e] = {
|
||||
.name = "BMA250E",
|
||||
.chip_id = 0xF9,
|
||||
.channels = bma250e_accel_channels,
|
||||
.num_channels = ARRAY_SIZE(bma250e_accel_channels),
|
||||
|
|
@ -1155,6 +1103,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
|
|||
{306457, BMC150_ACCEL_DEF_RANGE_16G} },
|
||||
},
|
||||
[bma222e] = {
|
||||
.name = "BMA222E",
|
||||
.chip_id = 0xF8,
|
||||
.channels = bma222e_accel_channels,
|
||||
.num_channels = ARRAY_SIZE(bma222e_accel_channels),
|
||||
|
|
@ -1164,6 +1113,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
|
|||
{1225831, BMC150_ACCEL_DEF_RANGE_16G} },
|
||||
},
|
||||
[bma280] = {
|
||||
.name = "BMA0280",
|
||||
.chip_id = 0xFB,
|
||||
.channels = bma280_accel_channels,
|
||||
.num_channels = ARRAY_SIZE(bma280_accel_channels),
|
||||
|
|
@ -1410,20 +1360,6 @@ static irqreturn_t bmc150_accel_irq_handler(int irq, void *private)
|
|||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static const char *bmc150_accel_match_acpi_device(struct device *dev, int *data)
|
||||
{
|
||||
const struct acpi_device_id *id;
|
||||
|
||||
id = acpi_match_device(dev->driver->acpi_match_table, dev);
|
||||
|
||||
if (!id)
|
||||
return NULL;
|
||||
|
||||
*data = (int)id->driver_data;
|
||||
|
||||
return dev_name(dev);
|
||||
}
|
||||
|
||||
static int bmc150_accel_gpio_probe(struct i2c_client *client,
|
||||
struct bmc150_accel_data *data)
|
||||
{
|
||||
|
|
@ -1618,6 +1554,70 @@ static const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = {
|
|||
.postdisable = bmc150_accel_buffer_postdisable,
|
||||
};
|
||||
|
||||
static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error: Reading chip id\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_dbg(&data->client->dev, "Chip Id %x\n", ret);
|
||||
for (i = 0; i < ARRAY_SIZE(bmc150_accel_chip_info_tbl); i++) {
|
||||
if (bmc150_accel_chip_info_tbl[i].chip_id == ret) {
|
||||
data->chip_info = &bmc150_accel_chip_info_tbl[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!data->chip_info) {
|
||||
dev_err(&data->client->dev, "Unsupported chip %x\n", ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set Bandwidth */
|
||||
ret = bmc150_accel_set_bw(data, BMC150_ACCEL_DEF_BW, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set Default Range */
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
BMC150_ACCEL_REG_PMU_RANGE,
|
||||
BMC150_ACCEL_DEF_RANGE_4G);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error writing reg_pmu_range\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->range = BMC150_ACCEL_DEF_RANGE_4G;
|
||||
|
||||
/* Set default slope duration and thresholds */
|
||||
data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD;
|
||||
data->slope_dur = BMC150_ACCEL_DEF_SLOPE_DURATION;
|
||||
ret = bmc150_accel_update_slope(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set default as latched interrupts */
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
BMC150_ACCEL_REG_INT_RST_LATCH,
|
||||
BMC150_ACCEL_INT_MODE_LATCH_INT |
|
||||
BMC150_ACCEL_INT_MODE_LATCH_RESET);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev,
|
||||
"Error writing reg_int_rst_latch\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bmc150_accel_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
|
@ -1625,7 +1625,6 @@ static int bmc150_accel_probe(struct i2c_client *client,
|
|||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
const char *name = NULL;
|
||||
int chip_id = 0;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
|
|
@ -1635,15 +1634,8 @@ static int bmc150_accel_probe(struct i2c_client *client,
|
|||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
|
||||
if (id) {
|
||||
if (id)
|
||||
name = id->name;
|
||||
chip_id = id->driver_data;
|
||||
}
|
||||
|
||||
if (ACPI_HANDLE(&client->dev))
|
||||
name = bmc150_accel_match_acpi_device(&client->dev, &chip_id);
|
||||
|
||||
data->chip_info = &bmc150_accel_chip_info_tbl[chip_id];
|
||||
|
||||
ret = bmc150_accel_chip_init(data);
|
||||
if (ret < 0)
|
||||
|
|
@ -1654,7 +1646,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
|
|||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->channels = data->chip_info->channels;
|
||||
indio_dev->num_channels = data->chip_info->num_channels;
|
||||
indio_dev->name = name;
|
||||
indio_dev->name = name ? name : data->chip_info->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &bmc150_accel_info;
|
||||
|
||||
|
|
@ -1670,7 +1662,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
|
|||
if (client->irq < 0)
|
||||
client->irq = bmc150_accel_gpio_probe(client, data);
|
||||
|
||||
if (client->irq >= 0) {
|
||||
if (client->irq > 0) {
|
||||
ret = devm_request_threaded_irq(
|
||||
&client->dev, client->irq,
|
||||
bmc150_accel_irq_handler,
|
||||
|
|
|
|||
|
|
@ -1240,7 +1240,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
|
|||
if (client->irq < 0)
|
||||
client->irq = kxcjk1013_gpio_probe(client, data);
|
||||
|
||||
if (client->irq >= 0) {
|
||||
if (client->irq > 0) {
|
||||
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
kxcjk1013_data_rdy_trig_poll,
|
||||
kxcjk1013_event_handler,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
|
|
@ -24,54 +23,51 @@
|
|||
#include <linux/iio/events.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define MMA8452_STATUS 0x00
|
||||
#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */
|
||||
#define MMA8452_OUT_Y 0x03
|
||||
#define MMA8452_OUT_Z 0x05
|
||||
#define MMA8452_INT_SRC 0x0c
|
||||
#define MMA8452_WHO_AM_I 0x0d
|
||||
#define MMA8452_DATA_CFG 0x0e
|
||||
#define MMA8452_HP_FILTER_CUTOFF 0x0f
|
||||
#define MMA8452_HP_FILTER_CUTOFF_SEL_MASK (BIT(0) | BIT(1))
|
||||
#define MMA8452_TRANSIENT_CFG 0x1d
|
||||
#define MMA8452_TRANSIENT_CFG_ELE BIT(4)
|
||||
#define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1)
|
||||
#define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0)
|
||||
#define MMA8452_TRANSIENT_SRC 0x1e
|
||||
#define MMA8452_TRANSIENT_SRC_XTRANSE BIT(1)
|
||||
#define MMA8452_TRANSIENT_SRC_YTRANSE BIT(3)
|
||||
#define MMA8452_TRANSIENT_SRC_ZTRANSE BIT(5)
|
||||
#define MMA8452_TRANSIENT_THS 0x1f
|
||||
#define MMA8452_TRANSIENT_THS_MASK 0x7f
|
||||
#define MMA8452_TRANSIENT_COUNT 0x20
|
||||
#define MMA8452_OFF_X 0x2f
|
||||
#define MMA8452_OFF_Y 0x30
|
||||
#define MMA8452_OFF_Z 0x31
|
||||
#define MMA8452_CTRL_REG1 0x2a
|
||||
#define MMA8452_CTRL_REG2 0x2b
|
||||
#define MMA8452_CTRL_REG2_RST BIT(6)
|
||||
#define MMA8452_CTRL_REG4 0x2d
|
||||
#define MMA8452_CTRL_REG5 0x2e
|
||||
#define MMA8452_STATUS 0x00
|
||||
#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
|
||||
#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */
|
||||
#define MMA8452_OUT_Y 0x03
|
||||
#define MMA8452_OUT_Z 0x05
|
||||
#define MMA8452_INT_SRC 0x0c
|
||||
#define MMA8452_WHO_AM_I 0x0d
|
||||
#define MMA8452_DATA_CFG 0x0e
|
||||
#define MMA8452_DATA_CFG_FS_MASK GENMASK(1, 0)
|
||||
#define MMA8452_DATA_CFG_FS_2G 0
|
||||
#define MMA8452_DATA_CFG_FS_4G 1
|
||||
#define MMA8452_DATA_CFG_FS_8G 2
|
||||
#define MMA8452_DATA_CFG_HPF_MASK BIT(4)
|
||||
#define MMA8452_HP_FILTER_CUTOFF 0x0f
|
||||
#define MMA8452_HP_FILTER_CUTOFF_SEL_MASK GENMASK(1, 0)
|
||||
#define MMA8452_TRANSIENT_CFG 0x1d
|
||||
#define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0)
|
||||
#define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1)
|
||||
#define MMA8452_TRANSIENT_CFG_ELE BIT(4)
|
||||
#define MMA8452_TRANSIENT_SRC 0x1e
|
||||
#define MMA8452_TRANSIENT_SRC_XTRANSE BIT(1)
|
||||
#define MMA8452_TRANSIENT_SRC_YTRANSE BIT(3)
|
||||
#define MMA8452_TRANSIENT_SRC_ZTRANSE BIT(5)
|
||||
#define MMA8452_TRANSIENT_THS 0x1f
|
||||
#define MMA8452_TRANSIENT_THS_MASK GENMASK(6, 0)
|
||||
#define MMA8452_TRANSIENT_COUNT 0x20
|
||||
#define MMA8452_CTRL_REG1 0x2a
|
||||
#define MMA8452_CTRL_ACTIVE BIT(0)
|
||||
#define MMA8452_CTRL_DR_MASK GENMASK(5, 3)
|
||||
#define MMA8452_CTRL_DR_SHIFT 3
|
||||
#define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */
|
||||
#define MMA8452_CTRL_REG2 0x2b
|
||||
#define MMA8452_CTRL_REG2_RST BIT(6)
|
||||
#define MMA8452_CTRL_REG4 0x2d
|
||||
#define MMA8452_CTRL_REG5 0x2e
|
||||
#define MMA8452_OFF_X 0x2f
|
||||
#define MMA8452_OFF_Y 0x30
|
||||
#define MMA8452_OFF_Z 0x31
|
||||
|
||||
#define MMA8452_MAX_REG 0x31
|
||||
#define MMA8452_MAX_REG 0x31
|
||||
|
||||
#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
|
||||
#define MMA8452_INT_DRDY BIT(0)
|
||||
#define MMA8452_INT_TRANS BIT(5)
|
||||
|
||||
#define MMA8452_CTRL_DR_MASK (BIT(5) | BIT(4) | BIT(3))
|
||||
#define MMA8452_CTRL_DR_SHIFT 3
|
||||
#define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */
|
||||
#define MMA8452_CTRL_ACTIVE BIT(0)
|
||||
|
||||
#define MMA8452_DATA_CFG_FS_MASK (BIT(1) | BIT(0))
|
||||
#define MMA8452_DATA_CFG_FS_2G 0
|
||||
#define MMA8452_DATA_CFG_FS_4G 1
|
||||
#define MMA8452_DATA_CFG_FS_8G 2
|
||||
#define MMA8452_DATA_CFG_HPF_MASK BIT(4)
|
||||
|
||||
#define MMA8452_INT_DRDY BIT(0)
|
||||
#define MMA8452_INT_TRANS BIT(5)
|
||||
|
||||
#define MMA8452_DEVICE_ID 0x2a
|
||||
#define MMA8452_DEVICE_ID 0x2a
|
||||
|
||||
struct mma8452_data {
|
||||
struct i2c_client *client;
|
||||
|
|
@ -91,30 +87,34 @@ static int mma8452_drdy(struct mma8452_data *data)
|
|||
return ret;
|
||||
if ((ret & MMA8452_STATUS_DRDY) == MMA8452_STATUS_DRDY)
|
||||
return 0;
|
||||
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
dev_err(&data->client->dev, "data not ready\n");
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int mma8452_read(struct mma8452_data *data, __be16 buf[3])
|
||||
{
|
||||
int ret = mma8452_drdy(data);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return i2c_smbus_read_i2c_block_data(data->client,
|
||||
MMA8452_OUT_X, 3 * sizeof(__be16), (u8 *) buf);
|
||||
|
||||
return i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X,
|
||||
3 * sizeof(__be16), (u8 *)buf);
|
||||
}
|
||||
|
||||
static ssize_t mma8452_show_int_plus_micros(char *buf,
|
||||
const int (*vals)[2], int n)
|
||||
static ssize_t mma8452_show_int_plus_micros(char *buf, const int (*vals)[2],
|
||||
int n)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
while (n-- > 0)
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len,
|
||||
"%d.%06d ", vals[n][0], vals[n][1]);
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ",
|
||||
vals[n][0], vals[n][1]);
|
||||
|
||||
/* replace trailing space by newline */
|
||||
buf[len - 1] = '\n';
|
||||
|
|
@ -123,7 +123,7 @@ static ssize_t mma8452_show_int_plus_micros(char *buf,
|
|||
}
|
||||
|
||||
static int mma8452_get_int_plus_micros_index(const int (*vals)[2], int n,
|
||||
int val, int val2)
|
||||
int val, int val2)
|
||||
{
|
||||
while (n-- > 0)
|
||||
if (val == vals[n][0] && val2 == vals[n][1])
|
||||
|
|
@ -147,7 +147,7 @@ static const int mma8452_samp_freq[8][2] = {
|
|||
* Hardware has fullscale of -2G, -4G, -8G corresponding to raw value -2048
|
||||
* The userspace interface uses m/s^2 and we declare micro units
|
||||
* So scale factor is given by:
|
||||
* g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665
|
||||
* g * N * 1000000 / 2048 for N = 2, 4, 8 and g = 9.80665
|
||||
*/
|
||||
static const int mma8452_scales[3][2] = {
|
||||
{0, 9577}, {0, 19154}, {0, 38307}
|
||||
|
|
@ -178,17 +178,19 @@ static const int mma8452_hp_filter_cutoff[8][4][2] = {
|
|||
};
|
||||
|
||||
static ssize_t mma8452_show_samp_freq_avail(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return mma8452_show_int_plus_micros(buf, mma8452_samp_freq,
|
||||
ARRAY_SIZE(mma8452_samp_freq));
|
||||
ARRAY_SIZE(mma8452_samp_freq));
|
||||
}
|
||||
|
||||
static ssize_t mma8452_show_scale_avail(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return mma8452_show_int_plus_micros(buf, mma8452_scales,
|
||||
ARRAY_SIZE(mma8452_scales));
|
||||
ARRAY_SIZE(mma8452_scales));
|
||||
}
|
||||
|
||||
static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev,
|
||||
|
|
@ -205,22 +207,23 @@ static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev,
|
|||
|
||||
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail);
|
||||
static IIO_DEVICE_ATTR(in_accel_scale_available, S_IRUGO,
|
||||
mma8452_show_scale_avail, NULL, 0);
|
||||
mma8452_show_scale_avail, NULL, 0);
|
||||
static IIO_DEVICE_ATTR(in_accel_filter_high_pass_3db_frequency_available,
|
||||
S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0);
|
||||
S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0);
|
||||
|
||||
static int mma8452_get_samp_freq_index(struct mma8452_data *data,
|
||||
int val, int val2)
|
||||
int val, int val2)
|
||||
{
|
||||
return mma8452_get_int_plus_micros_index(mma8452_samp_freq,
|
||||
ARRAY_SIZE(mma8452_samp_freq), val, val2);
|
||||
ARRAY_SIZE(mma8452_samp_freq),
|
||||
val, val2);
|
||||
}
|
||||
|
||||
static int mma8452_get_scale_index(struct mma8452_data *data,
|
||||
int val, int val2)
|
||||
static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2)
|
||||
{
|
||||
return mma8452_get_int_plus_micros_index(mma8452_scales,
|
||||
ARRAY_SIZE(mma8452_scales), val, val2);
|
||||
ARRAY_SIZE(mma8452_scales),
|
||||
val, val2);
|
||||
}
|
||||
|
||||
static int mma8452_get_hp_filter_index(struct mma8452_data *data,
|
||||
|
|
@ -229,7 +232,7 @@ static int mma8452_get_hp_filter_index(struct mma8452_data *data,
|
|||
int i = mma8452_get_odr_index(data);
|
||||
|
||||
return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[i],
|
||||
ARRAY_SIZE(mma8452_scales[0]), val, val2);
|
||||
ARRAY_SIZE(mma8452_hp_filter_cutoff[0]), val, val2);
|
||||
}
|
||||
|
||||
static int mma8452_read_hp_filter(struct mma8452_data *data, int *hz, int *uHz)
|
||||
|
|
@ -266,25 +269,31 @@ static int mma8452_read_raw(struct iio_dev *indio_dev,
|
|||
mutex_unlock(&data->lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = sign_extend32(
|
||||
be16_to_cpu(buffer[chan->scan_index]) >> 4, 11);
|
||||
|
||||
*val = sign_extend32(be16_to_cpu(buffer[chan->scan_index]) >> 4,
|
||||
11);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK;
|
||||
*val = mma8452_scales[i][0];
|
||||
*val2 = mma8452_scales[i][1];
|
||||
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
i = mma8452_get_odr_index(data);
|
||||
*val = mma8452_samp_freq[i][0];
|
||||
*val2 = mma8452_samp_freq[i][1];
|
||||
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
ret = i2c_smbus_read_byte_data(data->client, MMA8452_OFF_X +
|
||||
chan->scan_index);
|
||||
ret = i2c_smbus_read_byte_data(data->client,
|
||||
MMA8452_OFF_X + chan->scan_index);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = sign_extend32(ret, 7);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
|
||||
if (data->data_cfg & MMA8452_DATA_CFG_HPF_MASK) {
|
||||
|
|
@ -295,21 +304,23 @@ static int mma8452_read_raw(struct iio_dev *indio_dev,
|
|||
*val = 0;
|
||||
*val2 = 0;
|
||||
}
|
||||
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int mma8452_standby(struct mma8452_data *data)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1,
|
||||
data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE);
|
||||
data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE);
|
||||
}
|
||||
|
||||
static int mma8452_active(struct mma8452_data *data)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1,
|
||||
data->ctrl_reg1);
|
||||
data->ctrl_reg1);
|
||||
}
|
||||
|
||||
static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val)
|
||||
|
|
@ -334,6 +345,7 @@ static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val)
|
|||
ret = 0;
|
||||
fail:
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -344,12 +356,13 @@ static int mma8452_set_hp_filter_frequency(struct mma8452_data *data,
|
|||
|
||||
i = mma8452_get_hp_filter_index(data, val, val2);
|
||||
if (i < 0)
|
||||
return -EINVAL;
|
||||
return i;
|
||||
|
||||
reg = i2c_smbus_read_byte_data(data->client,
|
||||
MMA8452_HP_FILTER_CUTOFF);
|
||||
if (reg < 0)
|
||||
return reg;
|
||||
|
||||
reg &= ~MMA8452_HP_FILTER_CUTOFF_SEL_MASK;
|
||||
reg |= i;
|
||||
|
||||
|
|
@ -370,25 +383,30 @@ static int mma8452_write_raw(struct iio_dev *indio_dev,
|
|||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
i = mma8452_get_samp_freq_index(data, val, val2);
|
||||
if (i < 0)
|
||||
return -EINVAL;
|
||||
return i;
|
||||
|
||||
data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK;
|
||||
data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT;
|
||||
|
||||
return mma8452_change_config(data, MMA8452_CTRL_REG1,
|
||||
data->ctrl_reg1);
|
||||
data->ctrl_reg1);
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
i = mma8452_get_scale_index(data, val, val2);
|
||||
if (i < 0)
|
||||
return -EINVAL;
|
||||
return i;
|
||||
|
||||
data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK;
|
||||
data->data_cfg |= i;
|
||||
|
||||
return mma8452_change_config(data, MMA8452_DATA_CFG,
|
||||
data->data_cfg);
|
||||
data->data_cfg);
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
if (val < -128 || val > 127)
|
||||
return -EINVAL;
|
||||
return mma8452_change_config(data, MMA8452_OFF_X +
|
||||
chan->scan_index, val);
|
||||
|
||||
return mma8452_change_config(data,
|
||||
MMA8452_OFF_X + chan->scan_index,
|
||||
val);
|
||||
|
||||
case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
|
||||
if (val == 0 && val2 == 0) {
|
||||
|
|
@ -399,8 +417,9 @@ static int mma8452_write_raw(struct iio_dev *indio_dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return mma8452_change_config(data, MMA8452_DATA_CFG,
|
||||
data->data_cfg);
|
||||
data->data_cfg);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
|
@ -425,6 +444,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev,
|
|||
return ret;
|
||||
|
||||
*val = ret & MMA8452_TRANSIENT_THS_MASK;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_EV_INFO_PERIOD:
|
||||
|
|
@ -437,6 +457,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev,
|
|||
mma8452_get_odr_index(data)];
|
||||
*val = us / USEC_PER_SEC;
|
||||
*val2 = us % USEC_PER_SEC;
|
||||
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
|
||||
case IIO_EV_INFO_HIGH_PASS_FILTER_3DB:
|
||||
|
|
@ -453,6 +474,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
|
||||
default:
|
||||
|
|
@ -472,19 +494,22 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev,
|
|||
|
||||
switch (info) {
|
||||
case IIO_EV_INFO_VALUE:
|
||||
return mma8452_change_config(data, MMA8452_TRANSIENT_THS,
|
||||
val & MMA8452_TRANSIENT_THS_MASK);
|
||||
if (val < 0 || val > MMA8452_TRANSIENT_THS_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
return mma8452_change_config(data, MMA8452_TRANSIENT_THS, val);
|
||||
|
||||
case IIO_EV_INFO_PERIOD:
|
||||
steps = (val * USEC_PER_SEC + val2) /
|
||||
mma8452_transient_time_step_us[
|
||||
mma8452_get_odr_index(data)];
|
||||
|
||||
if (steps > 0xff)
|
||||
if (steps < 0 || steps > 0xff)
|
||||
return -EINVAL;
|
||||
|
||||
return mma8452_change_config(data, MMA8452_TRANSIENT_COUNT,
|
||||
steps);
|
||||
|
||||
case IIO_EV_INFO_HIGH_PASS_FILTER_3DB:
|
||||
reg = i2c_smbus_read_byte_data(data->client,
|
||||
MMA8452_TRANSIENT_CFG);
|
||||
|
|
@ -499,6 +524,7 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, reg);
|
||||
|
||||
default:
|
||||
|
|
@ -608,15 +634,16 @@ static irqreturn_t mma8452_trigger_handler(int irq, void *p)
|
|||
u8 buffer[16]; /* 3 16-bit channels + padding + ts */
|
||||
int ret;
|
||||
|
||||
ret = mma8452_read(data, (__be16 *) buffer);
|
||||
ret = mma8452_read(data, (__be16 *)buffer);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buffer,
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns());
|
||||
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
|
@ -674,10 +701,10 @@ static struct attribute_group mma8452_event_attribute_group = {
|
|||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_##axis, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS), \
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
|
||||
BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \
|
||||
BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \
|
||||
.scan_index = idx, \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
|
|
@ -780,6 +807,7 @@ static int mma8452_trigger_setup(struct iio_dev *indio_dev)
|
|||
return ret;
|
||||
|
||||
indio_dev->trig = trig;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -849,7 +877,7 @@ static int mma8452_probe(struct i2c_client *client,
|
|||
|
||||
data->data_cfg = MMA8452_DATA_CFG_FS_2G;
|
||||
ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG,
|
||||
data->data_cfg);
|
||||
data->data_cfg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
@ -891,14 +919,14 @@ static int mma8452_probe(struct i2c_client *client,
|
|||
}
|
||||
|
||||
data->ctrl_reg1 = MMA8452_CTRL_ACTIVE |
|
||||
(MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT);
|
||||
(MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT);
|
||||
ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1,
|
||||
data->ctrl_reg1);
|
||||
if (ret < 0)
|
||||
goto trigger_cleanup;
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
mma8452_trigger_handler, NULL);
|
||||
mma8452_trigger_handler, NULL);
|
||||
if (ret < 0)
|
||||
goto trigger_cleanup;
|
||||
|
||||
|
|
@ -968,6 +996,7 @@ static const struct of_device_id mma8452_dt_ids[] = {
|
|||
{ .compatible = "fsl,mma8452" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mma8452_dt_ids);
|
||||
|
||||
static struct i2c_driver mma8452_driver = {
|
||||
.driver = {
|
||||
|
|
|
|||
|
|
@ -1149,7 +1149,7 @@ static int mma9553_probe(struct i2c_client *client,
|
|||
if (client->irq < 0)
|
||||
client->irq = mma9553_gpio_probe(client);
|
||||
|
||||
if (client->irq >= 0) {
|
||||
if (client->irq > 0) {
|
||||
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
mma9553_irq_handler,
|
||||
mma9553_event_handler,
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#define LSM303DLH_ACCEL_DEV_NAME "lsm303dlh_accel"
|
||||
#define LSM303DLM_ACCEL_DEV_NAME "lsm303dlm_accel"
|
||||
#define LSM330_ACCEL_DEV_NAME "lsm330_accel"
|
||||
#define LSM303AGR_ACCEL_DEV_NAME "lsm303agr_accel"
|
||||
|
||||
/**
|
||||
* struct st_sensors_platform_data - default accel platform data
|
||||
|
|
|
|||
|
|
@ -226,12 +226,14 @@ static const struct iio_chan_spec st_accel_16bit_channels[] = {
|
|||
static const struct st_sensor_settings st_accel_sensors_settings[] = {
|
||||
{
|
||||
.wai = ST_ACCEL_1_WAI_EXP,
|
||||
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
|
||||
.sensors_supported = {
|
||||
[0] = LIS3DH_ACCEL_DEV_NAME,
|
||||
[1] = LSM303DLHC_ACCEL_DEV_NAME,
|
||||
[2] = LSM330D_ACCEL_DEV_NAME,
|
||||
[3] = LSM330DL_ACCEL_DEV_NAME,
|
||||
[4] = LSM330DLC_ACCEL_DEV_NAME,
|
||||
[5] = LSM303AGR_ACCEL_DEV_NAME,
|
||||
},
|
||||
.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
|
||||
.odr = {
|
||||
|
|
@ -297,6 +299,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
|
|||
},
|
||||
{
|
||||
.wai = ST_ACCEL_2_WAI_EXP,
|
||||
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
|
||||
.sensors_supported = {
|
||||
[0] = LIS331DLH_ACCEL_DEV_NAME,
|
||||
[1] = LSM303DL_ACCEL_DEV_NAME,
|
||||
|
|
@ -359,6 +362,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
|
|||
},
|
||||
{
|
||||
.wai = ST_ACCEL_3_WAI_EXP,
|
||||
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
|
||||
.sensors_supported = {
|
||||
[0] = LSM330_ACCEL_DEV_NAME,
|
||||
},
|
||||
|
|
@ -437,6 +441,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
|
|||
},
|
||||
{
|
||||
.wai = ST_ACCEL_4_WAI_EXP,
|
||||
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
|
||||
.sensors_supported = {
|
||||
[0] = LIS3LV02DL_ACCEL_DEV_NAME,
|
||||
},
|
||||
|
|
@ -494,6 +499,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
|
|||
},
|
||||
{
|
||||
.wai = ST_ACCEL_5_WAI_EXP,
|
||||
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
|
||||
.sensors_supported = {
|
||||
[0] = LIS331DL_ACCEL_DEV_NAME,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -68,6 +68,10 @@ static const struct of_device_id st_accel_of_match[] = {
|
|||
.compatible = "st,lsm330-accel",
|
||||
.data = LSM330_ACCEL_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm303agr-accel",
|
||||
.data = LSM303AGR_ACCEL_DEV_NAME,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st_accel_of_match);
|
||||
|
|
@ -116,6 +120,7 @@ static const struct i2c_device_id st_accel_id_table[] = {
|
|||
{ LSM303DL_ACCEL_DEV_NAME },
|
||||
{ LSM303DLM_ACCEL_DEV_NAME },
|
||||
{ LSM330_ACCEL_DEV_NAME },
|
||||
{ LSM303AGR_ACCEL_DEV_NAME },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ static const struct spi_device_id st_accel_id_table[] = {
|
|||
{ LSM303DL_ACCEL_DEV_NAME },
|
||||
{ LSM303DLM_ACCEL_DEV_NAME },
|
||||
{ LSM330_ACCEL_DEV_NAME },
|
||||
{ LSM303AGR_ACCEL_DEV_NAME },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, st_accel_id_table);
|
||||
|
|
|
|||
|
|
@ -37,16 +37,16 @@
|
|||
#define STK8312_REG_OTPDATA 0x3E
|
||||
#define STK8312_REG_OTPCTRL 0x3F
|
||||
|
||||
#define STK8312_MODE_ACTIVE 0x01
|
||||
#define STK8312_MODE_ACTIVE BIT(0)
|
||||
#define STK8312_MODE_STANDBY 0x00
|
||||
#define STK8312_DREADY_BIT 0x10
|
||||
#define STK8312_INT_MODE 0xC0
|
||||
#define STK8312_RNG_MASK 0xC0
|
||||
#define STK8312_SR_MASK 0x07
|
||||
#define STK8312_SR_400HZ_IDX 0
|
||||
#define STK8312_MODE_INT_AH_PP 0xC0 /* active-high, push-pull */
|
||||
#define STK8312_DREADY_BIT BIT(4)
|
||||
#define STK8312_RNG_6G 1
|
||||
#define STK8312_RNG_SHIFT 6
|
||||
#define STK8312_READ_RETRIES 16
|
||||
#define STK8312_ALL_CHANNEL_MASK 7
|
||||
#define STK8312_RNG_MASK GENMASK(7, 6)
|
||||
#define STK8312_SR_MASK GENMASK(2, 0)
|
||||
#define STK8312_SR_400HZ_IDX 0
|
||||
#define STK8312_ALL_CHANNEL_MASK GENMASK(2, 0)
|
||||
#define STK8312_ALL_CHANNEL_SIZE 3
|
||||
|
||||
#define STK8312_DRIVER_NAME "stk8312"
|
||||
|
|
@ -69,8 +69,8 @@ static const int stk8312_scale_table[][2] = {
|
|||
};
|
||||
|
||||
static const struct {
|
||||
u16 val;
|
||||
u32 val2;
|
||||
int val;
|
||||
int val2;
|
||||
} stk8312_samp_freq_table[] = {
|
||||
{400, 0}, {200, 0}, {100, 0}, {50, 0}, {25, 0},
|
||||
{12, 500000}, {6, 250000}, {3, 125000}
|
||||
|
|
@ -103,7 +103,7 @@ static const struct iio_chan_spec stk8312_channels[] = {
|
|||
struct stk8312_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
int range;
|
||||
u8 range;
|
||||
u8 sample_rate_idx;
|
||||
u8 mode;
|
||||
struct iio_trigger *dready_trig;
|
||||
|
|
@ -144,22 +144,25 @@ static int stk8312_otp_init(struct stk8312_data *data)
|
|||
if (ret < 0)
|
||||
goto exit_err;
|
||||
count--;
|
||||
} while (!(ret & 0x80) && count > 0);
|
||||
} while (!(ret & BIT(7)) && count > 0);
|
||||
|
||||
if (count == 0)
|
||||
if (count == 0) {
|
||||
ret = -ETIMEDOUT;
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, STK8312_REG_OTPDATA);
|
||||
if (ret == 0)
|
||||
ret = -EINVAL;
|
||||
if (ret < 0)
|
||||
goto exit_err;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
STK8312_REG_AFECTRL, ret);
|
||||
ret = i2c_smbus_write_byte_data(data->client, STK8312_REG_AFECTRL, ret);
|
||||
if (ret < 0)
|
||||
goto exit_err;
|
||||
msleep(150);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
|
||||
exit_err:
|
||||
dev_err(&client->dev, "failed to initialize sensor\n");
|
||||
|
|
@ -203,8 +206,11 @@ static int stk8312_set_interrupts(struct stk8312_data *data, u8 int_mask)
|
|||
return ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, STK8312_REG_INTSU, int_mask);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "failed to set interrupts\n");
|
||||
stk8312_set_mode(data, mode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return stk8312_set_mode(data, mode);
|
||||
}
|
||||
|
|
@ -228,7 +234,7 @@ static int stk8312_data_rdy_trigger_set_state(struct iio_trigger *trig,
|
|||
|
||||
data->dready_trigger_on = state;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iio_trigger_ops stk8312_trigger_ops = {
|
||||
|
|
@ -236,7 +242,7 @@ static const struct iio_trigger_ops stk8312_trigger_ops = {
|
|||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int stk8312_set_sample_rate(struct stk8312_data *data, int rate)
|
||||
static int stk8312_set_sample_rate(struct stk8312_data *data, u8 rate)
|
||||
{
|
||||
int ret;
|
||||
u8 masked_reg;
|
||||
|
|
@ -253,20 +259,24 @@ static int stk8312_set_sample_rate(struct stk8312_data *data, int rate)
|
|||
return ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, STK8312_REG_SR);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "failed to set sampling rate\n");
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
goto err_activate;
|
||||
|
||||
masked_reg = (ret & (~STK8312_SR_MASK)) | rate;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, STK8312_REG_SR, masked_reg);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "failed to set sampling rate\n");
|
||||
else
|
||||
data->sample_rate_idx = rate;
|
||||
goto err_activate;
|
||||
|
||||
data->sample_rate_idx = rate;
|
||||
|
||||
return stk8312_set_mode(data, mode);
|
||||
|
||||
err_activate:
|
||||
dev_err(&client->dev, "failed to set sampling rate\n");
|
||||
stk8312_set_mode(data, mode);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stk8312_set_range(struct stk8312_data *data, u8 range)
|
||||
|
|
@ -288,21 +298,25 @@ static int stk8312_set_range(struct stk8312_data *data, u8 range)
|
|||
return ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, STK8312_REG_STH);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "failed to change sensor range\n");
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
goto err_activate;
|
||||
|
||||
masked_reg = ret & (~STK8312_RNG_MASK);
|
||||
masked_reg |= range << STK8312_RNG_SHIFT;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, STK8312_REG_STH, masked_reg);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "failed to change sensor range\n");
|
||||
else
|
||||
data->range = range;
|
||||
goto err_activate;
|
||||
|
||||
data->range = range;
|
||||
|
||||
return stk8312_set_mode(data, mode);
|
||||
|
||||
err_activate:
|
||||
dev_err(&client->dev, "failed to change sensor range\n");
|
||||
stk8312_set_mode(data, mode);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stk8312_read_accel(struct stk8312_data *data, u8 address)
|
||||
|
|
@ -335,18 +349,21 @@ static int stk8312_read_raw(struct iio_dev *indio_dev,
|
|||
ret = stk8312_set_mode(data, data->mode | STK8312_MODE_ACTIVE);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->lock);
|
||||
return -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
ret = stk8312_read_accel(data, chan->address);
|
||||
if (ret < 0) {
|
||||
stk8312_set_mode(data,
|
||||
data->mode & (~STK8312_MODE_ACTIVE));
|
||||
mutex_unlock(&data->lock);
|
||||
return -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
*val = sign_extend32(ret, 7);
|
||||
stk8312_set_mode(data, data->mode & (~STK8312_MODE_ACTIVE));
|
||||
ret = stk8312_set_mode(data,
|
||||
data->mode & (~STK8312_MODE_ACTIVE));
|
||||
mutex_unlock(&data->lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = stk8312_scale_table[data->range - 1][0];
|
||||
|
|
@ -418,7 +435,6 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p)
|
|||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct stk8312_data *data = iio_priv(indio_dev);
|
||||
int bit, ret, i = 0;
|
||||
u8 buffer[STK8312_ALL_CHANNEL_SIZE];
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
/*
|
||||
|
|
@ -429,18 +445,15 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p)
|
|||
ret = i2c_smbus_read_i2c_block_data(data->client,
|
||||
STK8312_REG_XOUT,
|
||||
STK8312_ALL_CHANNEL_SIZE,
|
||||
buffer);
|
||||
data->buffer);
|
||||
if (ret < STK8312_ALL_CHANNEL_SIZE) {
|
||||
dev_err(&data->client->dev, "register read failed\n");
|
||||
mutex_unlock(&data->lock);
|
||||
goto err;
|
||||
}
|
||||
data->buffer[0] = buffer[0];
|
||||
data->buffer[1] = buffer[1];
|
||||
data->buffer[2] = buffer[2];
|
||||
} else {
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
indio_dev->masklength) {
|
||||
ret = stk8312_read_accel(data, bit);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->lock);
|
||||
|
|
@ -547,11 +560,12 @@ static int stk8312_probe(struct i2c_client *client,
|
|||
return ret;
|
||||
}
|
||||
data->sample_rate_idx = STK8312_SR_400HZ_IDX;
|
||||
ret = stk8312_set_range(data, 1);
|
||||
ret = stk8312_set_range(data, STK8312_RNG_6G);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = stk8312_set_mode(data, STK8312_INT_MODE | STK8312_MODE_ACTIVE);
|
||||
ret = stk8312_set_mode(data,
|
||||
STK8312_MODE_INT_AH_PP | STK8312_MODE_ACTIVE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
@ -606,7 +620,7 @@ static int stk8312_probe(struct i2c_client *client,
|
|||
goto err_buffer_cleanup;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
|
||||
err_buffer_cleanup:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
|
|
@ -662,6 +676,7 @@ static const struct i2c_device_id stk8312_i2c_id[] = {
|
|||
{"STK8312", 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id);
|
||||
|
||||
static const struct acpi_device_id stk8312_acpi_id[] = {
|
||||
{"STK8312", 0},
|
||||
|
|
@ -672,7 +687,7 @@ MODULE_DEVICE_TABLE(acpi, stk8312_acpi_id);
|
|||
|
||||
static struct i2c_driver stk8312_driver = {
|
||||
.driver = {
|
||||
.name = "stk8312",
|
||||
.name = STK8312_DRIVER_NAME,
|
||||
.pm = STK8312_PM_OPS,
|
||||
.acpi_match_table = ACPI_PTR(stk8312_acpi_id),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -572,6 +572,7 @@ static const struct i2c_device_id stk8ba50_i2c_id[] = {
|
|||
{"stk8ba50", 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, stk8ba50_i2c_id);
|
||||
|
||||
static const struct acpi_device_id stk8ba50_acpi_id[] = {
|
||||
{"STK8BA50", 0},
|
||||
|
|
|
|||
|
|
@ -228,8 +228,8 @@ config MCP320X
|
|||
depends on SPI
|
||||
help
|
||||
Say yes here to build support for Microchip Technology's
|
||||
MCP3001, MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204 or
|
||||
MCP3208 analog to digital converter.
|
||||
MCP3001, MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204,
|
||||
MCP3208 or MCP3301 analog to digital converter.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called mcp320x.
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
#define BERLIN2_SM_CTRL 0x14
|
||||
#define BERLIN2_SM_CTRL_SM_SOC_INT BIT(1)
|
||||
#define BERLIN2_SM_CTRL_SOC_SM_INT BIT(2)
|
||||
#define BERLIN2_SM_CTRL_ADC_SEL(x) (BIT(x) << 5) /* 0-15 */
|
||||
#define BERLIN2_SM_CTRL_ADC_SEL(x) ((x) << 5) /* 0-15 */
|
||||
#define BERLIN2_SM_CTRL_ADC_SEL_MASK (0xf << 5)
|
||||
#define BERLIN2_SM_CTRL_ADC_POWER BIT(9)
|
||||
#define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV2 (0x0 << 10)
|
||||
|
|
@ -53,14 +53,14 @@
|
|||
#define BERLIN2_SM_ADC_MASK 0x3ff
|
||||
#define BERLIN2_SM_ADC_STATUS 0x1c
|
||||
#define BERLIN2_SM_ADC_STATUS_DATA_RDY(x) BIT(x) /* 0-15 */
|
||||
#define BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK 0xf
|
||||
#define BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK GENMASK(15, 0)
|
||||
#define BERLIN2_SM_ADC_STATUS_INT_EN(x) (BIT(x) << 16) /* 0-15 */
|
||||
#define BERLIN2_SM_ADC_STATUS_INT_EN_MASK (0xf << 16)
|
||||
#define BERLIN2_SM_ADC_STATUS_INT_EN_MASK GENMASK(31, 16)
|
||||
#define BERLIN2_SM_TSEN_STATUS 0x24
|
||||
#define BERLIN2_SM_TSEN_STATUS_DATA_RDY BIT(0)
|
||||
#define BERLIN2_SM_TSEN_STATUS_INT_EN BIT(1)
|
||||
#define BERLIN2_SM_TSEN_DATA 0x28
|
||||
#define BERLIN2_SM_TSEN_MASK 0xfff
|
||||
#define BERLIN2_SM_TSEN_MASK GENMASK(9, 0)
|
||||
#define BERLIN2_SM_TSEN_CTRL 0x74
|
||||
#define BERLIN2_SM_TSEN_CTRL_START BIT(8)
|
||||
#define BERLIN2_SM_TSEN_CTRL_SETTLING_4 (0x0 << 21) /* 4 us */
|
||||
|
|
@ -86,7 +86,7 @@ struct berlin2_adc_priv {
|
|||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
}
|
||||
|
||||
static struct iio_chan_spec berlin2_adc_channels[] = {
|
||||
static const struct iio_chan_spec berlin2_adc_channels[] = {
|
||||
BERLIN2_ADC_CHANNEL(0, IIO_VOLTAGE), /* external input */
|
||||
BERLIN2_ADC_CHANNEL(1, IIO_VOLTAGE), /* external input */
|
||||
BERLIN2_ADC_CHANNEL(2, IIO_VOLTAGE), /* external input */
|
||||
|
|
@ -103,7 +103,6 @@ static struct iio_chan_spec berlin2_adc_channels[] = {
|
|||
BERLIN2_ADC_CHANNEL(7, IIO_VOLTAGE), /* reserved */
|
||||
IIO_CHAN_SOFT_TIMESTAMP(8), /* timestamp */
|
||||
};
|
||||
#define BERLIN2_N_CHANNELS ARRAY_SIZE(berlin2_adc_channels)
|
||||
|
||||
static int berlin2_adc_read(struct iio_dev *indio_dev, int channel)
|
||||
{
|
||||
|
|
@ -221,7 +220,7 @@ static int berlin2_adc_read_raw(struct iio_dev *indio_dev,
|
|||
return temp;
|
||||
|
||||
if (temp > 2047)
|
||||
temp = -(4096 - temp);
|
||||
temp -= 4096;
|
||||
|
||||
/* Convert to milli Celsius */
|
||||
*val = ((temp * 100000) / 264 - 270000);
|
||||
|
|
@ -286,8 +285,7 @@ static int berlin2_adc_probe(struct platform_device *pdev)
|
|||
int irq, tsen_irq;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev,
|
||||
sizeof(struct berlin2_adc_priv));
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -301,11 +299,11 @@ static int berlin2_adc_probe(struct platform_device *pdev)
|
|||
|
||||
irq = platform_get_irq_byname(pdev, "adc");
|
||||
if (irq < 0)
|
||||
return -ENODEV;
|
||||
return irq;
|
||||
|
||||
tsen_irq = platform_get_irq_byname(pdev, "tsen");
|
||||
if (tsen_irq < 0)
|
||||
return -ENODEV;
|
||||
return tsen_irq;
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, irq, berlin2_adc_irq, 0,
|
||||
pdev->dev.driver->name, indio_dev);
|
||||
|
|
@ -325,8 +323,8 @@ static int berlin2_adc_probe(struct platform_device *pdev)
|
|||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &berlin2_adc_info;
|
||||
|
||||
indio_dev->num_channels = BERLIN2_N_CHANNELS;
|
||||
indio_dev->channels = berlin2_adc_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(berlin2_adc_channels);
|
||||
|
||||
/* Power up the ADC */
|
||||
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
* http://ww1.microchip.com/downloads/en/DeviceDoc/21290D.pdf mcp3201
|
||||
* http://ww1.microchip.com/downloads/en/DeviceDoc/21034D.pdf mcp3202
|
||||
* http://ww1.microchip.com/downloads/en/DeviceDoc/21298c.pdf mcp3204/08
|
||||
* http://ww1.microchip.com/downloads/en/DeviceDoc/21700E.pdf mcp3301
|
||||
*
|
||||
* 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
|
||||
|
|
@ -47,6 +48,7 @@ enum {
|
|||
mcp3202,
|
||||
mcp3204,
|
||||
mcp3208,
|
||||
mcp3301,
|
||||
};
|
||||
|
||||
struct mcp320x_chip_info {
|
||||
|
|
@ -76,6 +78,7 @@ static int mcp320x_channel_to_tx_data(int device_index,
|
|||
switch (device_index) {
|
||||
case mcp3001:
|
||||
case mcp3201:
|
||||
case mcp3301:
|
||||
return 0;
|
||||
case mcp3002:
|
||||
case mcp3202:
|
||||
|
|
@ -102,7 +105,7 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel,
|
|||
adc->tx_buf = mcp320x_channel_to_tx_data(device_index,
|
||||
channel, differential);
|
||||
|
||||
if (device_index != mcp3001 && device_index != mcp3201) {
|
||||
if (device_index != mcp3001 && device_index != mcp3201 && device_index != mcp3301) {
|
||||
ret = spi_sync(adc->spi, &adc->msg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
@ -125,6 +128,8 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel,
|
|||
case mcp3204:
|
||||
case mcp3208:
|
||||
return (adc->rx_buf[0] << 4 | adc->rx_buf[1] >> 4);
|
||||
case mcp3301:
|
||||
return sign_extend32((adc->rx_buf[0] & 0x1f) << 8 | adc->rx_buf[1], 12);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -274,6 +279,11 @@ static const struct mcp320x_chip_info mcp320x_chip_infos[] = {
|
|||
.num_channels = ARRAY_SIZE(mcp3208_channels),
|
||||
.resolution = 12
|
||||
},
|
||||
[mcp3301] = {
|
||||
.channels = mcp3201_channels,
|
||||
.num_channels = ARRAY_SIZE(mcp3201_channels),
|
||||
.resolution = 13
|
||||
},
|
||||
};
|
||||
|
||||
static int mcp320x_probe(struct spi_device *spi)
|
||||
|
|
@ -368,6 +378,9 @@ static const struct of_device_id mcp320x_dt_ids[] = {
|
|||
}, {
|
||||
.compatible = "mcp3208",
|
||||
.data = &mcp320x_chip_infos[mcp3208],
|
||||
}, {
|
||||
.compatible = "mcp3301",
|
||||
.data = &mcp320x_chip_infos[mcp3301],
|
||||
}, {
|
||||
}
|
||||
};
|
||||
|
|
@ -383,6 +396,7 @@ static const struct spi_device_id mcp320x_id[] = {
|
|||
{ "mcp3202", mcp3202 },
|
||||
{ "mcp3204", mcp3204 },
|
||||
{ "mcp3208", mcp3208 },
|
||||
{ "mcp3301", mcp3301 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, mcp320x_id);
|
||||
|
|
|
|||
|
|
@ -68,6 +68,9 @@
|
|||
#define VF610_ADC_CLK_DIV8 0x60
|
||||
#define VF610_ADC_CLK_MASK 0x60
|
||||
#define VF610_ADC_ADLSMP_LONG 0x10
|
||||
#define VF610_ADC_ADSTS_SHORT 0x100
|
||||
#define VF610_ADC_ADSTS_NORMAL 0x200
|
||||
#define VF610_ADC_ADSTS_LONG 0x300
|
||||
#define VF610_ADC_ADSTS_MASK 0x300
|
||||
#define VF610_ADC_ADLPC_EN 0x80
|
||||
#define VF610_ADC_ADHSC_EN 0x400
|
||||
|
|
@ -98,6 +101,8 @@
|
|||
#define VF610_ADC_CALF 0x2
|
||||
#define VF610_ADC_TIMEOUT msecs_to_jiffies(100)
|
||||
|
||||
#define DEFAULT_SAMPLE_TIME 1000
|
||||
|
||||
enum clk_sel {
|
||||
VF610_ADCIOC_BUSCLK_SET,
|
||||
VF610_ADCIOC_ALTCLK_SET,
|
||||
|
|
@ -124,6 +129,17 @@ enum conversion_mode_sel {
|
|||
VF610_ADC_CONV_LOW_POWER,
|
||||
};
|
||||
|
||||
enum lst_adder_sel {
|
||||
VF610_ADCK_CYCLES_3,
|
||||
VF610_ADCK_CYCLES_5,
|
||||
VF610_ADCK_CYCLES_7,
|
||||
VF610_ADCK_CYCLES_9,
|
||||
VF610_ADCK_CYCLES_13,
|
||||
VF610_ADCK_CYCLES_17,
|
||||
VF610_ADCK_CYCLES_21,
|
||||
VF610_ADCK_CYCLES_25,
|
||||
};
|
||||
|
||||
struct vf610_adc_feature {
|
||||
enum clk_sel clk_sel;
|
||||
enum vol_ref vol_ref;
|
||||
|
|
@ -132,6 +148,8 @@ struct vf610_adc_feature {
|
|||
int clk_div;
|
||||
int sample_rate;
|
||||
int res_mode;
|
||||
u32 lst_adder_index;
|
||||
u32 default_sample_time;
|
||||
|
||||
bool calibration;
|
||||
bool ovwren;
|
||||
|
|
@ -155,11 +173,13 @@ struct vf610_adc {
|
|||
};
|
||||
|
||||
static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
|
||||
static const u32 vf610_lst_adder[] = { 3, 5, 7, 9, 13, 17, 21, 25 };
|
||||
|
||||
static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
|
||||
{
|
||||
struct vf610_adc_feature *adc_feature = &info->adc_feature;
|
||||
unsigned long adck_rate, ipg_rate = clk_get_rate(info->clk);
|
||||
u32 adck_period, lst_addr_min;
|
||||
int divisor, i;
|
||||
|
||||
adck_rate = info->max_adck_rate[adc_feature->conv_mode];
|
||||
|
|
@ -173,6 +193,19 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
|
|||
adc_feature->clk_div = 8;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the long sample time adder value to be used based
|
||||
* on the default minimum sample time provided.
|
||||
*/
|
||||
adck_period = NSEC_PER_SEC / adck_rate;
|
||||
lst_addr_min = adc_feature->default_sample_time / adck_period;
|
||||
for (i = 0; i < ARRAY_SIZE(vf610_lst_adder); i++) {
|
||||
if (vf610_lst_adder[i] > lst_addr_min) {
|
||||
adc_feature->lst_adder_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate ADC sample frequencies
|
||||
* Sample time unit is ADCK cycles. ADCK clk source is ipg clock,
|
||||
|
|
@ -182,12 +215,13 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
|
|||
* SFCAdder: fixed to 6 ADCK cycles
|
||||
* AverageNum: 1, 4, 8, 16, 32 samples for hardware average.
|
||||
* BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode
|
||||
* LSTAdder(Long Sample Time): fixed to 3 ADCK cycles
|
||||
* LSTAdder(Long Sample Time): 3, 5, 7, 9, 13, 17, 21, 25 ADCK cycles
|
||||
*/
|
||||
adck_rate = ipg_rate / info->adc_feature.clk_div;
|
||||
for (i = 0; i < ARRAY_SIZE(vf610_hw_avgs); i++)
|
||||
info->sample_freq_avail[i] =
|
||||
adck_rate / (6 + vf610_hw_avgs[i] * (25 + 3));
|
||||
adck_rate / (6 + vf610_hw_avgs[i] *
|
||||
(25 + vf610_lst_adder[adc_feature->lst_adder_index]));
|
||||
}
|
||||
|
||||
static inline void vf610_adc_cfg_init(struct vf610_adc *info)
|
||||
|
|
@ -347,8 +381,40 @@ static void vf610_adc_sample_set(struct vf610_adc *info)
|
|||
break;
|
||||
}
|
||||
|
||||
/* Use the short sample mode */
|
||||
cfg_data &= ~(VF610_ADC_ADLSMP_LONG | VF610_ADC_ADSTS_MASK);
|
||||
/*
|
||||
* Set ADLSMP and ADSTS based on the Long Sample Time Adder value
|
||||
* determined.
|
||||
*/
|
||||
switch (adc_feature->lst_adder_index) {
|
||||
case VF610_ADCK_CYCLES_3:
|
||||
break;
|
||||
case VF610_ADCK_CYCLES_5:
|
||||
cfg_data |= VF610_ADC_ADSTS_SHORT;
|
||||
break;
|
||||
case VF610_ADCK_CYCLES_7:
|
||||
cfg_data |= VF610_ADC_ADSTS_NORMAL;
|
||||
break;
|
||||
case VF610_ADCK_CYCLES_9:
|
||||
cfg_data |= VF610_ADC_ADSTS_LONG;
|
||||
break;
|
||||
case VF610_ADCK_CYCLES_13:
|
||||
cfg_data |= VF610_ADC_ADLSMP_LONG;
|
||||
break;
|
||||
case VF610_ADCK_CYCLES_17:
|
||||
cfg_data |= VF610_ADC_ADLSMP_LONG;
|
||||
cfg_data |= VF610_ADC_ADSTS_SHORT;
|
||||
break;
|
||||
case VF610_ADCK_CYCLES_21:
|
||||
cfg_data |= VF610_ADC_ADLSMP_LONG;
|
||||
cfg_data |= VF610_ADC_ADSTS_NORMAL;
|
||||
break;
|
||||
case VF610_ADCK_CYCLES_25:
|
||||
cfg_data |= VF610_ADC_ADLSMP_LONG;
|
||||
cfg_data |= VF610_ADC_ADSTS_NORMAL;
|
||||
break;
|
||||
default:
|
||||
dev_err(info->dev, "error in sample time select\n");
|
||||
}
|
||||
|
||||
/* update hardware average selection */
|
||||
cfg_data &= ~VF610_ADC_AVGS_MASK;
|
||||
|
|
@ -713,6 +779,11 @@ static int vf610_adc_probe(struct platform_device *pdev)
|
|||
of_property_read_u32_array(pdev->dev.of_node, "fsl,adck-max-frequency",
|
||||
info->max_adck_rate, 3);
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node, "min-sample-time",
|
||||
&info->adc_feature.default_sample_time);
|
||||
if (ret)
|
||||
info->adc_feature.default_sample_time = DEFAULT_SAMPLE_TIME;
|
||||
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
|
||||
init_completion(&info->completion);
|
||||
|
|
|
|||
|
|
@ -126,6 +126,9 @@ static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs)
|
|||
int err, i = 0;
|
||||
struct st_sensor_data *sdata = iio_priv(indio_dev);
|
||||
|
||||
if (sdata->sensor_settings->fs.addr == 0)
|
||||
return 0;
|
||||
|
||||
err = st_sensors_match_fs(sdata->sensor_settings, fs, &i);
|
||||
if (err < 0)
|
||||
goto st_accel_set_fullscale_error;
|
||||
|
|
@ -479,46 +482,43 @@ int st_sensors_check_device_support(struct iio_dev *indio_dev,
|
|||
int num_sensors_list,
|
||||
const struct st_sensor_settings *sensor_settings)
|
||||
{
|
||||
u8 wai;
|
||||
int i, n, err;
|
||||
u8 wai;
|
||||
struct st_sensor_data *sdata = iio_priv(indio_dev);
|
||||
|
||||
for (i = 0; i < num_sensors_list; i++) {
|
||||
for (n = 0; n < ST_SENSORS_MAX_4WAI; n++) {
|
||||
if (strcmp(indio_dev->name,
|
||||
sensor_settings[i].sensors_supported[n]) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n < ST_SENSORS_MAX_4WAI)
|
||||
break;
|
||||
}
|
||||
if (i == num_sensors_list) {
|
||||
dev_err(&indio_dev->dev, "device name %s not recognized.\n",
|
||||
indio_dev->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
|
||||
ST_SENSORS_DEFAULT_WAI_ADDRESS, &wai);
|
||||
sensor_settings[i].wai_addr, &wai);
|
||||
if (err < 0) {
|
||||
dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n");
|
||||
goto read_wai_error;
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_sensors_list; i++) {
|
||||
if (sensor_settings[i].wai == wai)
|
||||
break;
|
||||
}
|
||||
if (i == num_sensors_list)
|
||||
goto device_not_supported;
|
||||
|
||||
for (n = 0; n < ARRAY_SIZE(sensor_settings[i].sensors_supported); n++) {
|
||||
if (strcmp(indio_dev->name,
|
||||
&sensor_settings[i].sensors_supported[n][0]) == 0)
|
||||
break;
|
||||
}
|
||||
if (n == ARRAY_SIZE(sensor_settings[i].sensors_supported)) {
|
||||
dev_err(&indio_dev->dev, "device name \"%s\" and WhoAmI (0x%02x) mismatch",
|
||||
indio_dev->name, wai);
|
||||
goto sensor_name_mismatch;
|
||||
if (sensor_settings[i].wai != wai) {
|
||||
dev_err(&indio_dev->dev, "%s: WhoAmI mismatch (0x%x).\n",
|
||||
indio_dev->name, wai);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sdata->sensor_settings =
|
||||
(struct st_sensor_settings *)&sensor_settings[i];
|
||||
|
||||
return i;
|
||||
|
||||
device_not_supported:
|
||||
dev_err(&indio_dev->dev, "device not supported: WhoAmI (0x%x).\n", wai);
|
||||
sensor_name_mismatch:
|
||||
err = -ENODEV;
|
||||
read_wai_error:
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(st_sensors_check_device_support);
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,8 @@ config ADXRS450
|
|||
config BMG160
|
||||
tristate "BOSCH BMG160 Gyro Sensor"
|
||||
depends on I2C
|
||||
select IIO_TRIGGERED_BUFFER if IIO_BUFFER
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for Bosch BMG160 Tri-axis Gyro Sensor
|
||||
driver. This driver also supports BMI055 gyroscope.
|
||||
|
|
|
|||
|
|
@ -473,6 +473,7 @@ enum adis16136_id {
|
|||
ID_ADIS16133,
|
||||
ID_ADIS16135,
|
||||
ID_ADIS16136,
|
||||
ID_ADIS16137,
|
||||
};
|
||||
|
||||
static const struct adis16136_chip_info adis16136_chip_info[] = {
|
||||
|
|
@ -488,6 +489,10 @@ static const struct adis16136_chip_info adis16136_chip_info[] = {
|
|||
.precision = IIO_DEGREE_TO_RAD(450),
|
||||
.fullscale = 24623,
|
||||
},
|
||||
[ID_ADIS16137] = {
|
||||
.precision = IIO_DEGREE_TO_RAD(1000),
|
||||
.fullscale = 24609,
|
||||
},
|
||||
};
|
||||
|
||||
static int adis16136_probe(struct spi_device *spi)
|
||||
|
|
@ -557,6 +562,7 @@ static const struct spi_device_id adis16136_ids[] = {
|
|||
{ "adis16133", ID_ADIS16133 },
|
||||
{ "adis16135", ID_ADIS16135 },
|
||||
{ "adis16136", ID_ADIS16136 },
|
||||
{ "adis16137", ID_ADIS16137 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, adis16136_ids);
|
||||
|
|
|
|||
|
|
@ -101,19 +101,24 @@
|
|||
#define ADIS16260_SCAN_TEMP 3
|
||||
#define ADIS16260_SCAN_ANGL 4
|
||||
|
||||
/* Power down the device */
|
||||
static int adis16260_stop_device(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct adis *adis = iio_priv(indio_dev);
|
||||
int ret;
|
||||
u16 val = ADIS16260_SLP_CNT_POWER_OFF;
|
||||
struct adis16260_chip_info {
|
||||
unsigned int gyro_max_val;
|
||||
unsigned int gyro_max_scale;
|
||||
const struct iio_chan_spec *channels;
|
||||
unsigned int num_channels;
|
||||
};
|
||||
|
||||
ret = adis_write_reg_16(adis, ADIS16260_SLP_CNT, val);
|
||||
if (ret)
|
||||
dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT");
|
||||
struct adis16260 {
|
||||
const struct adis16260_chip_info *info;
|
||||
|
||||
return ret;
|
||||
}
|
||||
struct adis adis;
|
||||
};
|
||||
|
||||
enum adis16260_type {
|
||||
ADIS16251,
|
||||
ADIS16260,
|
||||
ADIS16266,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec adis16260_channels[] = {
|
||||
ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO,
|
||||
|
|
@ -131,6 +136,55 @@ static const struct iio_chan_spec adis16260_channels[] = {
|
|||
IIO_CHAN_SOFT_TIMESTAMP(5),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec adis16266_channels[] = {
|
||||
ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO,
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS) |
|
||||
BIT(IIO_CHAN_INFO_CALIBSCALE),
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), 14),
|
||||
ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP,
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),
|
||||
ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY,
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),
|
||||
ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC,
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
};
|
||||
|
||||
static const struct adis16260_chip_info adis16260_chip_info_table[] = {
|
||||
[ADIS16251] = {
|
||||
.gyro_max_scale = 80,
|
||||
.gyro_max_val = IIO_RAD_TO_DEGREE(4368),
|
||||
.channels = adis16260_channels,
|
||||
.num_channels = ARRAY_SIZE(adis16260_channels),
|
||||
},
|
||||
[ADIS16260] = {
|
||||
.gyro_max_scale = 320,
|
||||
.gyro_max_val = IIO_RAD_TO_DEGREE(4368),
|
||||
.channels = adis16260_channels,
|
||||
.num_channels = ARRAY_SIZE(adis16260_channels),
|
||||
},
|
||||
[ADIS16266] = {
|
||||
.gyro_max_scale = 14000,
|
||||
.gyro_max_val = IIO_RAD_TO_DEGREE(3357),
|
||||
.channels = adis16266_channels,
|
||||
.num_channels = ARRAY_SIZE(adis16266_channels),
|
||||
},
|
||||
};
|
||||
|
||||
/* Power down the device */
|
||||
static int adis16260_stop_device(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct adis16260 *adis16260 = iio_priv(indio_dev);
|
||||
int ret;
|
||||
u16 val = ADIS16260_SLP_CNT_POWER_OFF;
|
||||
|
||||
ret = adis_write_reg_16(&adis16260->adis, ADIS16260_SLP_CNT, val);
|
||||
if (ret)
|
||||
dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const u8 adis16260_addresses[][2] = {
|
||||
[ADIS16260_SCAN_GYRO] = { ADIS16260_GYRO_OFF, ADIS16260_GYRO_SCALE },
|
||||
};
|
||||
|
|
@ -140,7 +194,9 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
|
|||
int *val, int *val2,
|
||||
long mask)
|
||||
{
|
||||
struct adis *adis = iio_priv(indio_dev);
|
||||
struct adis16260 *adis16260 = iio_priv(indio_dev);
|
||||
const struct adis16260_chip_info *info = adis16260->info;
|
||||
struct adis *adis = &adis16260->adis;
|
||||
int ret;
|
||||
u8 addr;
|
||||
s16 val16;
|
||||
|
|
@ -152,15 +208,9 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
|
|||
case IIO_CHAN_INFO_SCALE:
|
||||
switch (chan->type) {
|
||||
case IIO_ANGL_VEL:
|
||||
*val = 0;
|
||||
if (spi_get_device_id(adis->spi)->driver_data) {
|
||||
/* 0.01832 degree / sec */
|
||||
*val2 = IIO_DEGREE_TO_RAD(18320);
|
||||
} else {
|
||||
/* 0.07326 degree / sec */
|
||||
*val2 = IIO_DEGREE_TO_RAD(73260);
|
||||
}
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
*val = info->gyro_max_scale;
|
||||
*val2 = info->gyro_max_val;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
case IIO_INCLI:
|
||||
*val = 0;
|
||||
*val2 = IIO_DEGREE_TO_RAD(36630);
|
||||
|
|
@ -224,7 +274,8 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
|
|||
int val2,
|
||||
long mask)
|
||||
{
|
||||
struct adis *adis = iio_priv(indio_dev);
|
||||
struct adis16260 *adis16260 = iio_priv(indio_dev);
|
||||
struct adis *adis = &adis16260->adis;
|
||||
int ret;
|
||||
u8 addr;
|
||||
u8 t;
|
||||
|
|
@ -305,35 +356,42 @@ static const struct adis_data adis16260_data = {
|
|||
|
||||
static int adis16260_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct spi_device_id *id;
|
||||
struct adis16260 *adis16260;
|
||||
struct iio_dev *indio_dev;
|
||||
struct adis *adis;
|
||||
int ret;
|
||||
|
||||
id = spi_get_device_id(spi);
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
|
||||
/* setup the industrialio driver allocated elements */
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis));
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis16260));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
adis = iio_priv(indio_dev);
|
||||
adis16260 = iio_priv(indio_dev);
|
||||
/* this is only used for removal purposes */
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
adis16260->info = &adis16260_chip_info_table[id->driver_data];
|
||||
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->info = &adis16260_info;
|
||||
indio_dev->channels = adis16260_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(adis16260_channels);
|
||||
indio_dev->channels = adis16260->info->channels;
|
||||
indio_dev->num_channels = adis16260->info->num_channels;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
ret = adis_init(adis, indio_dev, spi, &adis16260_data);
|
||||
ret = adis_init(&adis16260->adis, indio_dev, spi, &adis16260_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = adis_setup_buffer_and_trigger(adis, indio_dev, NULL);
|
||||
ret = adis_setup_buffer_and_trigger(&adis16260->adis, indio_dev, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Get the device into a sane initial state */
|
||||
ret = adis_initial_startup(adis);
|
||||
ret = adis_initial_startup(&adis16260->adis);
|
||||
if (ret)
|
||||
goto error_cleanup_buffer_trigger;
|
||||
ret = iio_device_register(indio_dev);
|
||||
|
|
@ -343,18 +401,18 @@ static int adis16260_probe(struct spi_device *spi)
|
|||
return 0;
|
||||
|
||||
error_cleanup_buffer_trigger:
|
||||
adis_cleanup_buffer_and_trigger(adis, indio_dev);
|
||||
adis_cleanup_buffer_and_trigger(&adis16260->adis, indio_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adis16260_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct adis *adis = iio_priv(indio_dev);
|
||||
struct adis16260 *adis16260 = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
adis16260_stop_device(indio_dev);
|
||||
adis_cleanup_buffer_and_trigger(adis, indio_dev);
|
||||
adis_cleanup_buffer_and_trigger(&adis16260->adis, indio_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -364,11 +422,12 @@ static int adis16260_remove(struct spi_device *spi)
|
|||
* support for the on chip filtering.
|
||||
*/
|
||||
static const struct spi_device_id adis16260_id[] = {
|
||||
{"adis16260", 0},
|
||||
{"adis16265", 0},
|
||||
{"adis16250", 0},
|
||||
{"adis16255", 0},
|
||||
{"adis16251", 1},
|
||||
{"adis16260", ADIS16260},
|
||||
{"adis16265", ADIS16260},
|
||||
{"adis16266", ADIS16266},
|
||||
{"adis16250", ADIS16260},
|
||||
{"adis16255", ADIS16260},
|
||||
{"adis16251", ADIS16251},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, adis16260_id);
|
||||
|
|
|
|||
|
|
@ -131,6 +131,7 @@ static const struct iio_chan_spec st_gyro_16bit_channels[] = {
|
|||
static const struct st_sensor_settings st_gyro_sensors_settings[] = {
|
||||
{
|
||||
.wai = ST_GYRO_1_WAI_EXP,
|
||||
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
|
||||
.sensors_supported = {
|
||||
[0] = L3G4200D_GYRO_DEV_NAME,
|
||||
[1] = LSM330DL_GYRO_DEV_NAME,
|
||||
|
|
@ -190,6 +191,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
|
|||
},
|
||||
{
|
||||
.wai = ST_GYRO_2_WAI_EXP,
|
||||
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
|
||||
.sensors_supported = {
|
||||
[0] = L3GD20_GYRO_DEV_NAME,
|
||||
[1] = LSM330D_GYRO_DEV_NAME,
|
||||
|
|
@ -252,6 +254,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
|
|||
},
|
||||
{
|
||||
.wai = ST_GYRO_3_WAI_EXP,
|
||||
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
|
||||
.sensors_supported = {
|
||||
[0] = L3GD20_GYRO_DEV_NAME,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/timekeeping.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
|
|
@ -46,7 +47,8 @@
|
|||
* Note that when reading the sensor actually 84 edges are detected, but
|
||||
* since the last edge is not significant, we only store 83:
|
||||
*/
|
||||
#define DHT11_EDGES_PER_READ (2*DHT11_BITS_PER_READ + DHT11_EDGES_PREAMBLE + 1)
|
||||
#define DHT11_EDGES_PER_READ (2 * DHT11_BITS_PER_READ + \
|
||||
DHT11_EDGES_PREAMBLE + 1)
|
||||
|
||||
/* Data transmission timing (nano seconds) */
|
||||
#define DHT11_START_TRANSMISSION 18 /* ms */
|
||||
|
|
@ -62,6 +64,7 @@ struct dht11 {
|
|||
int irq;
|
||||
|
||||
struct completion completion;
|
||||
/* The iio sysfs interface doesn't prevent concurrent reads: */
|
||||
struct mutex lock;
|
||||
|
||||
s64 timestamp;
|
||||
|
|
@ -87,32 +90,20 @@ static unsigned char dht11_decode_byte(int *timing, int threshold)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int dht11_decode(struct dht11 *dht11, int offset)
|
||||
static int dht11_decode(struct dht11 *dht11, int offset, int timeres)
|
||||
{
|
||||
int i, t, timing[DHT11_BITS_PER_READ], threshold,
|
||||
timeres = DHT11_SENSOR_RESPONSE;
|
||||
int i, t, timing[DHT11_BITS_PER_READ], threshold;
|
||||
unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum;
|
||||
|
||||
/* Calculate timestamp resolution */
|
||||
for (i = 1; i < dht11->num_edges; ++i) {
|
||||
t = dht11->edges[i].ts - dht11->edges[i-1].ts;
|
||||
if (t > 0 && t < timeres)
|
||||
timeres = t;
|
||||
}
|
||||
if (2*timeres > DHT11_DATA_BIT_HIGH) {
|
||||
pr_err("dht11: timeresolution %d too bad for decoding\n",
|
||||
timeres);
|
||||
return -EIO;
|
||||
}
|
||||
threshold = DHT11_DATA_BIT_HIGH / timeres;
|
||||
if (DHT11_DATA_BIT_LOW/timeres + 1 >= threshold)
|
||||
if (DHT11_DATA_BIT_LOW / timeres + 1 >= threshold)
|
||||
pr_err("dht11: WARNING: decoding ambiguous\n");
|
||||
|
||||
/* scale down with timeres and check validity */
|
||||
for (i = 0; i < DHT11_BITS_PER_READ; ++i) {
|
||||
t = dht11->edges[offset + 2*i + 2].ts -
|
||||
dht11->edges[offset + 2*i + 1].ts;
|
||||
if (!dht11->edges[offset + 2*i + 1].value)
|
||||
t = dht11->edges[offset + 2 * i + 2].ts -
|
||||
dht11->edges[offset + 2 * i + 1].ts;
|
||||
if (!dht11->edges[offset + 2 * i + 1].value)
|
||||
return -EIO; /* lost synchronisation */
|
||||
timing[i] = t / timeres;
|
||||
}
|
||||
|
|
@ -126,7 +117,7 @@ static int dht11_decode(struct dht11 *dht11, int offset)
|
|||
if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum)
|
||||
return -EIO;
|
||||
|
||||
dht11->timestamp = iio_get_time_ns();
|
||||
dht11->timestamp = ktime_get_real_ns();
|
||||
if (hum_int < 20) { /* DHT22 */
|
||||
dht11->temperature = (((temp_int & 0x7f) << 8) + temp_dec) *
|
||||
((temp_int & 0x80) ? -100 : 100);
|
||||
|
|
@ -154,7 +145,7 @@ static irqreturn_t dht11_handle_irq(int irq, void *data)
|
|||
|
||||
/* TODO: Consider making the handler safe for IRQ sharing */
|
||||
if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) {
|
||||
dht11->edges[dht11->num_edges].ts = iio_get_time_ns();
|
||||
dht11->edges[dht11->num_edges].ts = ktime_get_real_ns();
|
||||
dht11->edges[dht11->num_edges++].value =
|
||||
gpio_get_value(dht11->gpio);
|
||||
|
||||
|
|
@ -166,14 +157,26 @@ static irqreturn_t dht11_handle_irq(int irq, void *data)
|
|||
}
|
||||
|
||||
static int dht11_read_raw(struct iio_dev *iio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
const struct iio_chan_spec *chan,
|
||||
int *val, int *val2, long m)
|
||||
{
|
||||
struct dht11 *dht11 = iio_priv(iio_dev);
|
||||
int ret;
|
||||
int ret, timeres;
|
||||
|
||||
mutex_lock(&dht11->lock);
|
||||
if (dht11->timestamp + DHT11_DATA_VALID_TIME < iio_get_time_ns()) {
|
||||
if (dht11->timestamp + DHT11_DATA_VALID_TIME < ktime_get_real_ns()) {
|
||||
timeres = ktime_get_resolution_ns();
|
||||
if (DHT11_DATA_BIT_HIGH < 2 * timeres) {
|
||||
dev_err(dht11->dev, "timeresolution %dns too low\n",
|
||||
timeres);
|
||||
/* In theory a better clock could become available
|
||||
* at some point ... and there is no error code
|
||||
* that really fits better.
|
||||
*/
|
||||
ret = -EAGAIN;
|
||||
goto err;
|
||||
}
|
||||
|
||||
reinit_completion(&dht11->completion);
|
||||
|
||||
dht11->num_edges = 0;
|
||||
|
|
@ -192,13 +195,13 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
|
|||
goto err;
|
||||
|
||||
ret = wait_for_completion_killable_timeout(&dht11->completion,
|
||||
HZ);
|
||||
HZ);
|
||||
|
||||
free_irq(dht11->irq, iio_dev);
|
||||
|
||||
if (ret == 0 && dht11->num_edges < DHT11_EDGES_PER_READ - 1) {
|
||||
dev_err(&iio_dev->dev,
|
||||
"Only %d signal edges detected\n",
|
||||
"Only %d signal edges detected\n",
|
||||
dht11->num_edges);
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
|
|
@ -206,9 +209,10 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
|
|||
goto err;
|
||||
|
||||
ret = dht11_decode(dht11,
|
||||
dht11->num_edges == DHT11_EDGES_PER_READ ?
|
||||
dht11->num_edges == DHT11_EDGES_PER_READ ?
|
||||
DHT11_EDGES_PREAMBLE :
|
||||
DHT11_EDGES_PREAMBLE - 2);
|
||||
DHT11_EDGES_PREAMBLE - 2,
|
||||
timeres);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
|
@ -261,9 +265,10 @@ static int dht11_probe(struct platform_device *pdev)
|
|||
dht11 = iio_priv(iio);
|
||||
dht11->dev = dev;
|
||||
|
||||
dht11->gpio = ret = of_get_gpio(node, 0);
|
||||
ret = of_get_gpio(node, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
dht11->gpio = ret;
|
||||
ret = devm_gpio_request_one(dev, dht11->gpio, GPIOF_IN, pdev->name);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -274,7 +279,7 @@ static int dht11_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
dht11->timestamp = iio_get_time_ns() - DHT11_DATA_VALID_TIME - 1;
|
||||
dht11->timestamp = ktime_get_real_ns() - DHT11_DATA_VALID_TIME - 1;
|
||||
dht11->num_edges = -1;
|
||||
|
||||
platform_set_drvdata(pdev, iio);
|
||||
|
|
|
|||
|
|
@ -139,7 +139,9 @@ enum adis16400_chip_variant {
|
|||
ADIS16360,
|
||||
ADIS16362,
|
||||
ADIS16364,
|
||||
ADIS16367,
|
||||
ADIS16400,
|
||||
ADIS16445,
|
||||
ADIS16448,
|
||||
};
|
||||
|
||||
|
|
@ -622,6 +624,17 @@ static const struct iio_chan_spec adis16400_channels[] = {
|
|||
IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec adis16445_channels[] = {
|
||||
ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 16),
|
||||
ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 16),
|
||||
ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 16),
|
||||
ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 16),
|
||||
ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 16),
|
||||
ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 16),
|
||||
ADIS16400_TEMP_CHAN(ADIS16448_TEMP_OUT, 12),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec adis16448_channels[] = {
|
||||
ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 16),
|
||||
ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 16),
|
||||
|
|
@ -696,7 +709,8 @@ static struct adis16400_chip_info adis16400_chips[] = {
|
|||
[ADIS16300] = {
|
||||
.channels = adis16300_channels,
|
||||
.num_channels = ARRAY_SIZE(adis16300_channels),
|
||||
.flags = ADIS16400_HAS_SLOW_MODE,
|
||||
.flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE |
|
||||
ADIS16400_HAS_SERIAL_NUMBER,
|
||||
.gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
|
||||
.accel_scale_micro = 5884,
|
||||
.temp_scale_nano = 140000000, /* 0.14 C */
|
||||
|
|
@ -763,6 +777,18 @@ static struct adis16400_chip_info adis16400_chips[] = {
|
|||
.set_freq = adis16400_set_freq,
|
||||
.get_freq = adis16400_get_freq,
|
||||
},
|
||||
[ADIS16367] = {
|
||||
.channels = adis16350_channels,
|
||||
.num_channels = ARRAY_SIZE(adis16350_channels),
|
||||
.flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE |
|
||||
ADIS16400_HAS_SERIAL_NUMBER,
|
||||
.gyro_scale_micro = IIO_DEGREE_TO_RAD(2000), /* 0.2 deg/s */
|
||||
.accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */
|
||||
.temp_scale_nano = 136000000, /* 0.136 C */
|
||||
.temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
|
||||
.set_freq = adis16400_set_freq,
|
||||
.get_freq = adis16400_get_freq,
|
||||
},
|
||||
[ADIS16400] = {
|
||||
.channels = adis16400_channels,
|
||||
.num_channels = ARRAY_SIZE(adis16400_channels),
|
||||
|
|
@ -774,13 +800,26 @@ static struct adis16400_chip_info adis16400_chips[] = {
|
|||
.set_freq = adis16400_set_freq,
|
||||
.get_freq = adis16400_get_freq,
|
||||
},
|
||||
[ADIS16445] = {
|
||||
.channels = adis16445_channels,
|
||||
.num_channels = ARRAY_SIZE(adis16445_channels),
|
||||
.flags = ADIS16400_HAS_PROD_ID |
|
||||
ADIS16400_HAS_SERIAL_NUMBER |
|
||||
ADIS16400_BURST_DIAG_STAT,
|
||||
.gyro_scale_micro = IIO_DEGREE_TO_RAD(10000), /* 0.01 deg/s */
|
||||
.accel_scale_micro = IIO_G_TO_M_S_2(250), /* 1/4000 g */
|
||||
.temp_scale_nano = 73860000, /* 0.07386 C */
|
||||
.temp_offset = 31000000 / 73860, /* 31 C = 0x00 */
|
||||
.set_freq = adis16334_set_freq,
|
||||
.get_freq = adis16334_get_freq,
|
||||
},
|
||||
[ADIS16448] = {
|
||||
.channels = adis16448_channels,
|
||||
.num_channels = ARRAY_SIZE(adis16448_channels),
|
||||
.flags = ADIS16400_HAS_PROD_ID |
|
||||
ADIS16400_HAS_SERIAL_NUMBER |
|
||||
ADIS16400_BURST_DIAG_STAT,
|
||||
.gyro_scale_micro = IIO_DEGREE_TO_RAD(10000), /* 0.01 deg/s */
|
||||
.gyro_scale_micro = IIO_DEGREE_TO_RAD(40000), /* 0.04 deg/s */
|
||||
.accel_scale_micro = IIO_G_TO_M_S_2(833), /* 1/1200 g */
|
||||
.temp_scale_nano = 73860000, /* 0.07386 C */
|
||||
.temp_offset = 31000000 / 73860, /* 31 C = 0x00 */
|
||||
|
|
@ -926,6 +965,7 @@ static int adis16400_remove(struct spi_device *spi)
|
|||
|
||||
static const struct spi_device_id adis16400_id[] = {
|
||||
{"adis16300", ADIS16300},
|
||||
{"adis16305", ADIS16300},
|
||||
{"adis16334", ADIS16334},
|
||||
{"adis16350", ADIS16350},
|
||||
{"adis16354", ADIS16350},
|
||||
|
|
@ -934,8 +974,10 @@ static const struct spi_device_id adis16400_id[] = {
|
|||
{"adis16362", ADIS16362},
|
||||
{"adis16364", ADIS16364},
|
||||
{"adis16365", ADIS16360},
|
||||
{"adis16367", ADIS16367},
|
||||
{"adis16400", ADIS16400},
|
||||
{"adis16405", ADIS16400},
|
||||
{"adis16445", ADIS16445},
|
||||
{"adis16448", ADIS16448},
|
||||
{}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -110,6 +110,10 @@
|
|||
struct adis16480_chip_info {
|
||||
unsigned int num_channels;
|
||||
const struct iio_chan_spec *channels;
|
||||
unsigned int gyro_max_val;
|
||||
unsigned int gyro_max_scale;
|
||||
unsigned int accel_max_val;
|
||||
unsigned int accel_max_scale;
|
||||
};
|
||||
|
||||
struct adis16480 {
|
||||
|
|
@ -497,19 +501,21 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
|
|||
static int adis16480_read_raw(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan, int *val, int *val2, long info)
|
||||
{
|
||||
struct adis16480 *st = iio_priv(indio_dev);
|
||||
|
||||
switch (info) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
return adis_single_conversion(indio_dev, chan, 0, val);
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
switch (chan->type) {
|
||||
case IIO_ANGL_VEL:
|
||||
*val = 0;
|
||||
*val2 = IIO_DEGREE_TO_RAD(20000); /* 0.02 degree/sec */
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
*val = st->chip_info->gyro_max_scale;
|
||||
*val2 = st->chip_info->gyro_max_val;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
case IIO_ACCEL:
|
||||
*val = 0;
|
||||
*val2 = IIO_G_TO_M_S_2(800); /* 0.8 mg */
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
*val = st->chip_info->accel_max_scale;
|
||||
*val2 = st->chip_info->accel_max_val;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
case IIO_MAGN:
|
||||
*val = 0;
|
||||
*val2 = 100; /* 0.0001 gauss */
|
||||
|
|
@ -674,18 +680,39 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
|
|||
[ADIS16375] = {
|
||||
.channels = adis16485_channels,
|
||||
.num_channels = ARRAY_SIZE(adis16485_channels),
|
||||
/*
|
||||
* storing the value in rad/degree and the scale in degree
|
||||
* gives us the result in rad and better precession than
|
||||
* storing the scale directly in rad.
|
||||
*/
|
||||
.gyro_max_val = IIO_RAD_TO_DEGREE(22887),
|
||||
.gyro_max_scale = 300,
|
||||
.accel_max_val = IIO_M_S_2_TO_G(21973),
|
||||
.accel_max_scale = 18,
|
||||
},
|
||||
[ADIS16480] = {
|
||||
.channels = adis16480_channels,
|
||||
.num_channels = ARRAY_SIZE(adis16480_channels),
|
||||
.gyro_max_val = IIO_RAD_TO_DEGREE(22500),
|
||||
.gyro_max_scale = 450,
|
||||
.accel_max_val = IIO_M_S_2_TO_G(12500),
|
||||
.accel_max_scale = 5,
|
||||
},
|
||||
[ADIS16485] = {
|
||||
.channels = adis16485_channels,
|
||||
.num_channels = ARRAY_SIZE(adis16485_channels),
|
||||
.gyro_max_val = IIO_RAD_TO_DEGREE(22500),
|
||||
.gyro_max_scale = 450,
|
||||
.accel_max_val = IIO_M_S_2_TO_G(20000),
|
||||
.accel_max_scale = 5,
|
||||
},
|
||||
[ADIS16488] = {
|
||||
.channels = adis16480_channels,
|
||||
.num_channels = ARRAY_SIZE(adis16480_channels),
|
||||
.gyro_max_val = IIO_RAD_TO_DEGREE(22500),
|
||||
.gyro_max_scale = 450,
|
||||
.accel_max_val = IIO_M_S_2_TO_G(22500),
|
||||
.accel_max_scale = 18,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1363,7 +1363,7 @@ static int kmx61_probe(struct i2c_client *client,
|
|||
if (client->irq < 0)
|
||||
client->irq = kmx61_gpio_probe(client, data);
|
||||
|
||||
if (client->irq >= 0) {
|
||||
if (client->irq > 0) {
|
||||
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
kmx61_data_rdy_trig_poll,
|
||||
kmx61_event_handler,
|
||||
|
|
@ -1445,10 +1445,10 @@ err_iio_unregister_mag:
|
|||
err_iio_unregister_acc:
|
||||
iio_device_unregister(data->acc_indio_dev);
|
||||
err_buffer_cleanup_mag:
|
||||
if (client->irq >= 0)
|
||||
if (client->irq > 0)
|
||||
iio_triggered_buffer_cleanup(data->mag_indio_dev);
|
||||
err_buffer_cleanup_acc:
|
||||
if (client->irq >= 0)
|
||||
if (client->irq > 0)
|
||||
iio_triggered_buffer_cleanup(data->acc_indio_dev);
|
||||
err_trigger_unregister_motion:
|
||||
iio_trigger_unregister(data->motion_trig);
|
||||
|
|
@ -1472,7 +1472,7 @@ static int kmx61_remove(struct i2c_client *client)
|
|||
iio_device_unregister(data->acc_indio_dev);
|
||||
iio_device_unregister(data->mag_indio_dev);
|
||||
|
||||
if (client->irq >= 0) {
|
||||
if (client->irq > 0) {
|
||||
iio_triggered_buffer_cleanup(data->acc_indio_dev);
|
||||
iio_triggered_buffer_cleanup(data->mag_indio_dev);
|
||||
iio_trigger_unregister(data->acc_dready_trig);
|
||||
|
|
|
|||
|
|
@ -91,9 +91,16 @@ static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf,
|
|||
|
||||
/**
|
||||
* iio_buffer_read_first_n_outer() - chrdev read for buffer access
|
||||
* @filp: File structure pointer for the char device
|
||||
* @buf: Destination buffer for iio buffer read
|
||||
* @n: First n bytes to read
|
||||
* @f_ps: Long offset provided by the user as a seek position
|
||||
*
|
||||
* This function relies on all buffer implementations having an
|
||||
* iio_buffer as their first element.
|
||||
*
|
||||
* Return: negative values corresponding to error codes or ret != 0
|
||||
* for ending the reading activity
|
||||
**/
|
||||
ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
|
||||
size_t n, loff_t *f_ps)
|
||||
|
|
@ -143,6 +150,12 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
|
|||
|
||||
/**
|
||||
* iio_buffer_poll() - poll the buffer to find out if it has data
|
||||
* @filp: File structure pointer for device access
|
||||
* @wait: Poll table structure pointer for which the driver adds
|
||||
* a wait queue
|
||||
*
|
||||
* Return: (POLLIN | POLLRDNORM) if data is available for reading
|
||||
* or 0 for other cases
|
||||
*/
|
||||
unsigned int iio_buffer_poll(struct file *filp,
|
||||
struct poll_table_struct *wait)
|
||||
|
|
@ -151,7 +164,7 @@ unsigned int iio_buffer_poll(struct file *filp,
|
|||
struct iio_buffer *rb = indio_dev->buffer;
|
||||
|
||||
if (!indio_dev->info)
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
|
||||
poll_wait(filp, &rb->pollq, wait);
|
||||
if (iio_buffer_ready(indio_dev, rb, rb->watermark, 0))
|
||||
|
|
@ -1136,7 +1149,7 @@ int iio_scan_mask_query(struct iio_dev *indio_dev,
|
|||
EXPORT_SYMBOL_GPL(iio_scan_mask_query);
|
||||
|
||||
/**
|
||||
* struct iio_demux_table() - table describing demux memcpy ops
|
||||
* struct iio_demux_table - table describing demux memcpy ops
|
||||
* @from: index to copy from
|
||||
* @to: index to copy to
|
||||
* @length: how many bytes to copy
|
||||
|
|
|
|||
|
|
@ -406,10 +406,16 @@ EXPORT_SYMBOL_GPL(iio_enum_write);
|
|||
|
||||
/**
|
||||
* iio_format_value() - Formats a IIO value into its string representation
|
||||
* @buf: The buffer to which the formated value gets written
|
||||
* @type: One of the IIO_VAL_... constants. This decides how the val and val2
|
||||
* parameters are formatted.
|
||||
* @vals: pointer to the values, exact meaning depends on the type parameter.
|
||||
* @buf: The buffer to which the formatted value gets written
|
||||
* @type: One of the IIO_VAL_... constants. This decides how the val
|
||||
* and val2 parameters are formatted.
|
||||
* @size: Number of IIO value entries contained in vals
|
||||
* @vals: Pointer to the values, exact meaning depends on the
|
||||
* type parameter.
|
||||
*
|
||||
* Return: 0 by default, a negative number on failure or the
|
||||
* total number of characters written for a type that belongs
|
||||
* to the IIO_VAL_... constant.
|
||||
*/
|
||||
ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals)
|
||||
{
|
||||
|
|
@ -1096,6 +1102,11 @@ EXPORT_SYMBOL_GPL(devm_iio_device_free);
|
|||
|
||||
/**
|
||||
* iio_chrdev_open() - chrdev file open for buffer access and ioctls
|
||||
* @inode: Inode structure for identifying the device in the file system
|
||||
* @filp: File structure for iio device used to keep and later access
|
||||
* private data
|
||||
*
|
||||
* Return: 0 on success or -EBUSY if the device is already opened
|
||||
**/
|
||||
static int iio_chrdev_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
|
|
@ -1114,7 +1125,11 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp)
|
|||
|
||||
/**
|
||||
* iio_chrdev_release() - chrdev file close buffer access and ioctls
|
||||
**/
|
||||
* @inode: Inode structure pointer for the char device
|
||||
* @filp: File structure pointer for the char device
|
||||
*
|
||||
* Return: 0 for successful release
|
||||
*/
|
||||
static int iio_chrdev_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct iio_dev *indio_dev = container_of(inode->i_cdev,
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
* @dev_attr_list: list of event interface sysfs attribute
|
||||
* @flags: file operations related flags including busy flag.
|
||||
* @group: event interface sysfs attribute group
|
||||
* @read_lock: lock to protect kfifo read operations
|
||||
*/
|
||||
struct iio_event_interface {
|
||||
wait_queue_head_t wait;
|
||||
|
|
@ -75,6 +76,11 @@ EXPORT_SYMBOL(iio_push_event);
|
|||
|
||||
/**
|
||||
* iio_event_poll() - poll the event queue to find out if it has data
|
||||
* @filep: File structure pointer to identify the device
|
||||
* @wait: Poll table pointer to add the wait queue on
|
||||
*
|
||||
* Return: (POLLIN | POLLRDNORM) if data is available for reading
|
||||
* or a negative error code on failure
|
||||
*/
|
||||
static unsigned int iio_event_poll(struct file *filep,
|
||||
struct poll_table_struct *wait)
|
||||
|
|
@ -84,7 +90,7 @@ static unsigned int iio_event_poll(struct file *filep,
|
|||
unsigned int events = 0;
|
||||
|
||||
if (!indio_dev->info)
|
||||
return -ENODEV;
|
||||
return events;
|
||||
|
||||
poll_wait(filep, &ev_int->wait, wait);
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,14 @@ static DEFINE_MUTEX(iio_trigger_list_lock);
|
|||
|
||||
/**
|
||||
* iio_trigger_read_name() - retrieve useful identifying name
|
||||
**/
|
||||
* @dev: device associated with the iio_trigger
|
||||
* @attr: pointer to the device_attribute structure that is
|
||||
* being processed
|
||||
* @buf: buffer to print the name into
|
||||
*
|
||||
* Return: a negative number on failure or the number of written
|
||||
* characters on success.
|
||||
*/
|
||||
static ssize_t iio_trigger_read_name(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
|
|
@ -288,10 +295,17 @@ EXPORT_SYMBOL_GPL(iio_dealloc_pollfunc);
|
|||
|
||||
/**
|
||||
* iio_trigger_read_current() - trigger consumer sysfs query current trigger
|
||||
* @dev: device associated with an industrial I/O device
|
||||
* @attr: pointer to the device_attribute structure that
|
||||
* is being processed
|
||||
* @buf: buffer where the current trigger name will be printed into
|
||||
*
|
||||
* For trigger consumers the current_trigger interface allows the trigger
|
||||
* used by the device to be queried.
|
||||
**/
|
||||
*
|
||||
* Return: a negative number on failure, the number of characters written
|
||||
* on success or 0 if no trigger is available
|
||||
*/
|
||||
static ssize_t iio_trigger_read_current(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
|
|
@ -305,11 +319,18 @@ static ssize_t iio_trigger_read_current(struct device *dev,
|
|||
|
||||
/**
|
||||
* iio_trigger_write_current() - trigger consumer sysfs set current trigger
|
||||
* @dev: device associated with an industrial I/O device
|
||||
* @attr: device attribute that is being processed
|
||||
* @buf: string buffer that holds the name of the trigger
|
||||
* @len: length of the trigger name held by buf
|
||||
*
|
||||
* For trigger consumers the current_trigger interface allows the trigger
|
||||
* used for this device to be specified at run time based on the trigger's
|
||||
* name.
|
||||
**/
|
||||
*
|
||||
* Return: negative error code on failure or length of the buffer
|
||||
* on success
|
||||
*/
|
||||
static ssize_t iio_trigger_write_current(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
|
|
|
|||
|
|
@ -210,6 +210,27 @@ config LTR501
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called ltr501.
|
||||
|
||||
config OPT3001
|
||||
tristate "Texas Instruments OPT3001 Light Sensor"
|
||||
depends on I2C
|
||||
help
|
||||
If you say Y or M here, you get support for Texas Instruments
|
||||
OPT3001 Ambient Light Sensor.
|
||||
|
||||
If built as a dynamically linked module, it will be called
|
||||
opt3001.
|
||||
|
||||
config PA12203001
|
||||
tristate "TXC PA12203001 light and proximity sensor"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you get support for the TXC PA12203001
|
||||
ambient light and proximity sensor.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called pa12203001.
|
||||
|
||||
config STK3310
|
||||
tristate "STK3310 ALS and proximity sensor"
|
||||
depends on I2C
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ obj-$(CONFIG_ISL29125) += isl29125.o
|
|||
obj-$(CONFIG_JSA1212) += jsa1212.o
|
||||
obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
|
||||
obj-$(CONFIG_LTR501) += ltr501.o
|
||||
obj-$(CONFIG_OPT3001) += opt3001.o
|
||||
obj-$(CONFIG_PA12203001) += pa12203001.o
|
||||
obj-$(CONFIG_RPR0521) += rpr0521.o
|
||||
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
|
||||
obj-$(CONFIG_STK3310) += stk3310.o
|
||||
|
|
|
|||
|
|
@ -65,20 +65,20 @@ static const struct iio_chan_spec acpi_als_channels[] = {
|
|||
* to acpi_als_channels[], the evt_buffer below will grow
|
||||
* automatically.
|
||||
*/
|
||||
#define EVT_NR_SOURCES ARRAY_SIZE(acpi_als_channels)
|
||||
#define EVT_BUFFER_SIZE \
|
||||
(sizeof(s64) + (EVT_NR_SOURCES * sizeof(s32)))
|
||||
#define ACPI_ALS_EVT_NR_SOURCES ARRAY_SIZE(acpi_als_channels)
|
||||
#define ACPI_ALS_EVT_BUFFER_SIZE \
|
||||
(sizeof(s64) + (ACPI_ALS_EVT_NR_SOURCES * sizeof(s32)))
|
||||
|
||||
struct acpi_als {
|
||||
struct acpi_device *device;
|
||||
struct mutex lock;
|
||||
|
||||
s32 evt_buffer[EVT_BUFFER_SIZE];
|
||||
s32 evt_buffer[ACPI_ALS_EVT_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
/*
|
||||
* All types of properties the ACPI0008 block can report. The ALI, ALC, ALT
|
||||
* and ALP can all be handled by als_read_value() below, while the ALR is
|
||||
* and ALP can all be handled by acpi_als_read_value() below, while the ALR is
|
||||
* special.
|
||||
*
|
||||
* The _ALR property returns tables that can be used to fine-tune the values
|
||||
|
|
@ -93,7 +93,7 @@ struct acpi_als {
|
|||
#define ACPI_ALS_POLLING "_ALP"
|
||||
#define ACPI_ALS_TABLES "_ALR"
|
||||
|
||||
static int als_read_value(struct acpi_als *als, char *prop, s32 *val)
|
||||
static int acpi_als_read_value(struct acpi_als *als, char *prop, s32 *val)
|
||||
{
|
||||
unsigned long long temp_val;
|
||||
acpi_status status;
|
||||
|
|
@ -122,11 +122,11 @@ static void acpi_als_notify(struct acpi_device *device, u32 event)
|
|||
|
||||
mutex_lock(&als->lock);
|
||||
|
||||
memset(buffer, 0, EVT_BUFFER_SIZE);
|
||||
memset(buffer, 0, ACPI_ALS_EVT_BUFFER_SIZE);
|
||||
|
||||
switch (event) {
|
||||
case ACPI_ALS_NOTIFY_ILLUMINANCE:
|
||||
ret = als_read_value(als, ACPI_ALS_ILLUMINANCE, &val);
|
||||
ret = acpi_als_read_value(als, ACPI_ALS_ILLUMINANCE, &val);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
*buffer++ = val;
|
||||
|
|
@ -159,7 +159,7 @@ static int acpi_als_read_raw(struct iio_dev *indio_dev,
|
|||
if (chan->type != IIO_LIGHT)
|
||||
return -EINVAL;
|
||||
|
||||
ret = als_read_value(als, ACPI_ALS_ILLUMINANCE, &temp_val);
|
||||
ret = acpi_als_read_value(als, ACPI_ALS_ILLUMINANCE, &temp_val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -353,6 +353,7 @@ static const struct of_device_id cm32181_of_match[] = {
|
|||
{ .compatible = "capella,cm32181" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cm32181_of_match);
|
||||
|
||||
static struct i2c_driver cm32181_driver = {
|
||||
.driver = {
|
||||
|
|
|
|||
|
|
@ -417,6 +417,7 @@ static const struct of_device_id cm3232_of_match[] = {
|
|||
{.compatible = "capella,cm3232"},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cm3232_of_match);
|
||||
|
||||
static struct i2c_driver cm3232_driver = {
|
||||
.driver = {
|
||||
|
|
|
|||
|
|
@ -731,6 +731,7 @@ static const struct of_device_id cm36651_of_match[] = {
|
|||
{ .compatible = "capella,cm36651" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cm36651_of_match);
|
||||
|
||||
static struct i2c_driver cm36651_driver = {
|
||||
.driver = {
|
||||
|
|
|
|||
|
|
@ -1634,6 +1634,7 @@ static const struct of_device_id gp2ap020a00f_of_match[] = {
|
|||
{ .compatible = "sharp,gp2ap020a00f" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, gp2ap020a00f_of_match);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver gp2ap020a00f_driver = {
|
||||
|
|
|
|||
804
drivers/iio/light/opt3001.c
Normal file
804
drivers/iio/light/opt3001.c
Normal file
|
|
@ -0,0 +1,804 @@
|
|||
/**
|
||||
* opt3001.c - Texas Instruments OPT3001 Light Sensor
|
||||
*
|
||||
* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
|
||||
*
|
||||
* Author: Andreas Dannenberg <dannenberg@ti.com>
|
||||
* Based on previous work from: Felipe Balbi <balbi@ti.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 of the License
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/iio/events.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
#define OPT3001_RESULT 0x00
|
||||
#define OPT3001_CONFIGURATION 0x01
|
||||
#define OPT3001_LOW_LIMIT 0x02
|
||||
#define OPT3001_HIGH_LIMIT 0x03
|
||||
#define OPT3001_MANUFACTURER_ID 0x7e
|
||||
#define OPT3001_DEVICE_ID 0x7f
|
||||
|
||||
#define OPT3001_CONFIGURATION_RN_MASK (0xf << 12)
|
||||
#define OPT3001_CONFIGURATION_RN_AUTO (0xc << 12)
|
||||
|
||||
#define OPT3001_CONFIGURATION_CT BIT(11)
|
||||
|
||||
#define OPT3001_CONFIGURATION_M_MASK (3 << 9)
|
||||
#define OPT3001_CONFIGURATION_M_SHUTDOWN (0 << 9)
|
||||
#define OPT3001_CONFIGURATION_M_SINGLE (1 << 9)
|
||||
#define OPT3001_CONFIGURATION_M_CONTINUOUS (2 << 9) /* also 3 << 9 */
|
||||
|
||||
#define OPT3001_CONFIGURATION_OVF BIT(8)
|
||||
#define OPT3001_CONFIGURATION_CRF BIT(7)
|
||||
#define OPT3001_CONFIGURATION_FH BIT(6)
|
||||
#define OPT3001_CONFIGURATION_FL BIT(5)
|
||||
#define OPT3001_CONFIGURATION_L BIT(4)
|
||||
#define OPT3001_CONFIGURATION_POL BIT(3)
|
||||
#define OPT3001_CONFIGURATION_ME BIT(2)
|
||||
|
||||
#define OPT3001_CONFIGURATION_FC_MASK (3 << 0)
|
||||
|
||||
/* The end-of-conversion enable is located in the low-limit register */
|
||||
#define OPT3001_LOW_LIMIT_EOC_ENABLE 0xc000
|
||||
|
||||
#define OPT3001_REG_EXPONENT(n) ((n) >> 12)
|
||||
#define OPT3001_REG_MANTISSA(n) ((n) & 0xfff)
|
||||
|
||||
/*
|
||||
* Time to wait for conversion result to be ready. The device datasheet
|
||||
* worst-case max value is 880ms. Add some slack to be on the safe side.
|
||||
*/
|
||||
#define OPT3001_RESULT_READY_TIMEOUT msecs_to_jiffies(1000)
|
||||
|
||||
struct opt3001 {
|
||||
struct i2c_client *client;
|
||||
struct device *dev;
|
||||
|
||||
struct mutex lock;
|
||||
u16 ok_to_ignore_lock:1;
|
||||
u16 result_ready:1;
|
||||
wait_queue_head_t result_ready_queue;
|
||||
u16 result;
|
||||
|
||||
u32 int_time;
|
||||
u32 mode;
|
||||
|
||||
u16 high_thresh_mantissa;
|
||||
u16 low_thresh_mantissa;
|
||||
|
||||
u8 high_thresh_exp;
|
||||
u8 low_thresh_exp;
|
||||
};
|
||||
|
||||
struct opt3001_scale {
|
||||
int val;
|
||||
int val2;
|
||||
};
|
||||
|
||||
static const struct opt3001_scale opt3001_scales[] = {
|
||||
{
|
||||
.val = 40,
|
||||
.val2 = 950000,
|
||||
},
|
||||
{
|
||||
.val = 81,
|
||||
.val2 = 900000,
|
||||
},
|
||||
{
|
||||
.val = 163,
|
||||
.val2 = 800000,
|
||||
},
|
||||
{
|
||||
.val = 327,
|
||||
.val2 = 600000,
|
||||
},
|
||||
{
|
||||
.val = 655,
|
||||
.val2 = 200000,
|
||||
},
|
||||
{
|
||||
.val = 1310,
|
||||
.val2 = 400000,
|
||||
},
|
||||
{
|
||||
.val = 2620,
|
||||
.val2 = 800000,
|
||||
},
|
||||
{
|
||||
.val = 5241,
|
||||
.val2 = 600000,
|
||||
},
|
||||
{
|
||||
.val = 10483,
|
||||
.val2 = 200000,
|
||||
},
|
||||
{
|
||||
.val = 20966,
|
||||
.val2 = 400000,
|
||||
},
|
||||
{
|
||||
.val = 83865,
|
||||
.val2 = 600000,
|
||||
},
|
||||
};
|
||||
|
||||
static int opt3001_find_scale(const struct opt3001 *opt, int val,
|
||||
int val2, u8 *exponent)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(opt3001_scales); i++) {
|
||||
const struct opt3001_scale *scale = &opt3001_scales[i];
|
||||
|
||||
/*
|
||||
* Combine the integer and micro parts for comparison
|
||||
* purposes. Use milli lux precision to avoid 32-bit integer
|
||||
* overflows.
|
||||
*/
|
||||
if ((val * 1000 + val2 / 1000) <=
|
||||
(scale->val * 1000 + scale->val2 / 1000)) {
|
||||
*exponent = i;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void opt3001_to_iio_ret(struct opt3001 *opt, u8 exponent,
|
||||
u16 mantissa, int *val, int *val2)
|
||||
{
|
||||
int lux;
|
||||
|
||||
lux = 10 * (mantissa << exponent);
|
||||
*val = lux / 1000;
|
||||
*val2 = (lux - (*val * 1000)) * 1000;
|
||||
}
|
||||
|
||||
static void opt3001_set_mode(struct opt3001 *opt, u16 *reg, u16 mode)
|
||||
{
|
||||
*reg &= ~OPT3001_CONFIGURATION_M_MASK;
|
||||
*reg |= mode;
|
||||
opt->mode = mode;
|
||||
}
|
||||
|
||||
static IIO_CONST_ATTR_INT_TIME_AVAIL("0.1 0.8");
|
||||
|
||||
static struct attribute *opt3001_attributes[] = {
|
||||
&iio_const_attr_integration_time_available.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group opt3001_attribute_group = {
|
||||
.attrs = opt3001_attributes,
|
||||
};
|
||||
|
||||
static const struct iio_event_spec opt3001_event_spec[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
},
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec opt3001_channels[] = {
|
||||
{
|
||||
.type = IIO_LIGHT,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
|
||||
BIT(IIO_CHAN_INFO_INT_TIME),
|
||||
.event_spec = opt3001_event_spec,
|
||||
.num_event_specs = ARRAY_SIZE(opt3001_event_spec),
|
||||
},
|
||||
IIO_CHAN_SOFT_TIMESTAMP(1),
|
||||
};
|
||||
|
||||
static int opt3001_get_lux(struct opt3001 *opt, int *val, int *val2)
|
||||
{
|
||||
int ret;
|
||||
u16 mantissa;
|
||||
u16 reg;
|
||||
u8 exponent;
|
||||
u16 value;
|
||||
|
||||
/*
|
||||
* Enable the end-of-conversion interrupt mechanism. Note that doing
|
||||
* so will overwrite the low-level limit value however we will restore
|
||||
* this value later on.
|
||||
*/
|
||||
ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_LOW_LIMIT,
|
||||
OPT3001_LOW_LIMIT_EOC_ENABLE);
|
||||
if (ret < 0) {
|
||||
dev_err(opt->dev, "failed to write register %02x\n",
|
||||
OPT3001_LOW_LIMIT);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Reset data-ready indicator flag (will be set in the IRQ routine) */
|
||||
opt->result_ready = false;
|
||||
|
||||
/* Allow IRQ to access the device despite lock being set */
|
||||
opt->ok_to_ignore_lock = true;
|
||||
|
||||
/* Configure for single-conversion mode and start a new conversion */
|
||||
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
|
||||
if (ret < 0) {
|
||||
dev_err(opt->dev, "failed to read register %02x\n",
|
||||
OPT3001_CONFIGURATION);
|
||||
goto err;
|
||||
}
|
||||
|
||||
reg = ret;
|
||||
opt3001_set_mode(opt, ®, OPT3001_CONFIGURATION_M_SINGLE);
|
||||
|
||||
ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
|
||||
reg);
|
||||
if (ret < 0) {
|
||||
dev_err(opt->dev, "failed to write register %02x\n",
|
||||
OPT3001_CONFIGURATION);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Wait for the IRQ to indicate the conversion is complete */
|
||||
ret = wait_event_timeout(opt->result_ready_queue, opt->result_ready,
|
||||
OPT3001_RESULT_READY_TIMEOUT);
|
||||
|
||||
err:
|
||||
/* Disallow IRQ to access the device while lock is active */
|
||||
opt->ok_to_ignore_lock = false;
|
||||
|
||||
if (ret == 0)
|
||||
return -ETIMEDOUT;
|
||||
else if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Disable the end-of-conversion interrupt mechanism by restoring the
|
||||
* low-level limit value (clearing OPT3001_LOW_LIMIT_EOC_ENABLE). Note
|
||||
* that selectively clearing those enable bits would affect the actual
|
||||
* limit value due to bit-overlap and therefore can't be done.
|
||||
*/
|
||||
value = (opt->low_thresh_exp << 12) | opt->low_thresh_mantissa;
|
||||
ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_LOW_LIMIT,
|
||||
value);
|
||||
if (ret < 0) {
|
||||
dev_err(opt->dev, "failed to write register %02x\n",
|
||||
OPT3001_LOW_LIMIT);
|
||||
return ret;
|
||||
}
|
||||
|
||||
exponent = OPT3001_REG_EXPONENT(opt->result);
|
||||
mantissa = OPT3001_REG_MANTISSA(opt->result);
|
||||
|
||||
opt3001_to_iio_ret(opt, exponent, mantissa, val, val2);
|
||||
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
|
||||
static int opt3001_get_int_time(struct opt3001 *opt, int *val, int *val2)
|
||||
{
|
||||
*val = 0;
|
||||
*val2 = opt->int_time;
|
||||
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
|
||||
static int opt3001_set_int_time(struct opt3001 *opt, int time)
|
||||
{
|
||||
int ret;
|
||||
u16 reg;
|
||||
|
||||
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
|
||||
if (ret < 0) {
|
||||
dev_err(opt->dev, "failed to read register %02x\n",
|
||||
OPT3001_CONFIGURATION);
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg = ret;
|
||||
|
||||
switch (time) {
|
||||
case 100000:
|
||||
reg &= ~OPT3001_CONFIGURATION_CT;
|
||||
opt->int_time = 100000;
|
||||
break;
|
||||
case 800000:
|
||||
reg |= OPT3001_CONFIGURATION_CT;
|
||||
opt->int_time = 800000;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
|
||||
reg);
|
||||
}
|
||||
|
||||
static int opt3001_read_raw(struct iio_dev *iio,
|
||||
struct iio_chan_spec const *chan, int *val, int *val2,
|
||||
long mask)
|
||||
{
|
||||
struct opt3001 *opt = iio_priv(iio);
|
||||
int ret;
|
||||
|
||||
if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS)
|
||||
return -EBUSY;
|
||||
|
||||
if (chan->type != IIO_LIGHT)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&opt->lock);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_PROCESSED:
|
||||
ret = opt3001_get_lux(opt, val, val2);
|
||||
break;
|
||||
case IIO_CHAN_INFO_INT_TIME:
|
||||
ret = opt3001_get_int_time(opt, val, val2);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
mutex_unlock(&opt->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int opt3001_write_raw(struct iio_dev *iio,
|
||||
struct iio_chan_spec const *chan, int val, int val2,
|
||||
long mask)
|
||||
{
|
||||
struct opt3001 *opt = iio_priv(iio);
|
||||
int ret;
|
||||
|
||||
if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS)
|
||||
return -EBUSY;
|
||||
|
||||
if (chan->type != IIO_LIGHT)
|
||||
return -EINVAL;
|
||||
|
||||
if (mask != IIO_CHAN_INFO_INT_TIME)
|
||||
return -EINVAL;
|
||||
|
||||
if (val != 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&opt->lock);
|
||||
ret = opt3001_set_int_time(opt, val2);
|
||||
mutex_unlock(&opt->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int opt3001_read_event_value(struct iio_dev *iio,
|
||||
const struct iio_chan_spec *chan, enum iio_event_type type,
|
||||
enum iio_event_direction dir, enum iio_event_info info,
|
||||
int *val, int *val2)
|
||||
{
|
||||
struct opt3001 *opt = iio_priv(iio);
|
||||
int ret = IIO_VAL_INT_PLUS_MICRO;
|
||||
|
||||
mutex_lock(&opt->lock);
|
||||
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
opt3001_to_iio_ret(opt, opt->high_thresh_exp,
|
||||
opt->high_thresh_mantissa, val, val2);
|
||||
break;
|
||||
case IIO_EV_DIR_FALLING:
|
||||
opt3001_to_iio_ret(opt, opt->low_thresh_exp,
|
||||
opt->low_thresh_mantissa, val, val2);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
mutex_unlock(&opt->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int opt3001_write_event_value(struct iio_dev *iio,
|
||||
const struct iio_chan_spec *chan, enum iio_event_type type,
|
||||
enum iio_event_direction dir, enum iio_event_info info,
|
||||
int val, int val2)
|
||||
{
|
||||
struct opt3001 *opt = iio_priv(iio);
|
||||
int ret;
|
||||
|
||||
u16 mantissa;
|
||||
u16 value;
|
||||
u16 reg;
|
||||
|
||||
u8 exponent;
|
||||
|
||||
if (val < 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&opt->lock);
|
||||
|
||||
ret = opt3001_find_scale(opt, val, val2, &exponent);
|
||||
if (ret < 0) {
|
||||
dev_err(opt->dev, "can't find scale for %d.%06u\n", val, val2);
|
||||
goto err;
|
||||
}
|
||||
|
||||
mantissa = (((val * 1000) + (val2 / 1000)) / 10) >> exponent;
|
||||
value = (exponent << 12) | mantissa;
|
||||
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
reg = OPT3001_HIGH_LIMIT;
|
||||
opt->high_thresh_mantissa = mantissa;
|
||||
opt->high_thresh_exp = exponent;
|
||||
break;
|
||||
case IIO_EV_DIR_FALLING:
|
||||
reg = OPT3001_LOW_LIMIT;
|
||||
opt->low_thresh_mantissa = mantissa;
|
||||
opt->low_thresh_exp = exponent;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_write_word_swapped(opt->client, reg, value);
|
||||
if (ret < 0) {
|
||||
dev_err(opt->dev, "failed to write register %02x\n", reg);
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
mutex_unlock(&opt->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int opt3001_read_event_config(struct iio_dev *iio,
|
||||
const struct iio_chan_spec *chan, enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
struct opt3001 *opt = iio_priv(iio);
|
||||
|
||||
return opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS;
|
||||
}
|
||||
|
||||
static int opt3001_write_event_config(struct iio_dev *iio,
|
||||
const struct iio_chan_spec *chan, enum iio_event_type type,
|
||||
enum iio_event_direction dir, int state)
|
||||
{
|
||||
struct opt3001 *opt = iio_priv(iio);
|
||||
int ret;
|
||||
u16 mode;
|
||||
u16 reg;
|
||||
|
||||
if (state && opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS)
|
||||
return 0;
|
||||
|
||||
if (!state && opt->mode == OPT3001_CONFIGURATION_M_SHUTDOWN)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&opt->lock);
|
||||
|
||||
mode = state ? OPT3001_CONFIGURATION_M_CONTINUOUS
|
||||
: OPT3001_CONFIGURATION_M_SHUTDOWN;
|
||||
|
||||
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
|
||||
if (ret < 0) {
|
||||
dev_err(opt->dev, "failed to read register %02x\n",
|
||||
OPT3001_CONFIGURATION);
|
||||
goto err;
|
||||
}
|
||||
|
||||
reg = ret;
|
||||
opt3001_set_mode(opt, ®, mode);
|
||||
|
||||
ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
|
||||
reg);
|
||||
if (ret < 0) {
|
||||
dev_err(opt->dev, "failed to write register %02x\n",
|
||||
OPT3001_CONFIGURATION);
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
mutex_unlock(&opt->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct iio_info opt3001_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.attrs = &opt3001_attribute_group,
|
||||
.read_raw = opt3001_read_raw,
|
||||
.write_raw = opt3001_write_raw,
|
||||
.read_event_value = opt3001_read_event_value,
|
||||
.write_event_value = opt3001_write_event_value,
|
||||
.read_event_config = opt3001_read_event_config,
|
||||
.write_event_config = opt3001_write_event_config,
|
||||
};
|
||||
|
||||
static int opt3001_read_id(struct opt3001 *opt)
|
||||
{
|
||||
char manufacturer[2];
|
||||
u16 device_id;
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_MANUFACTURER_ID);
|
||||
if (ret < 0) {
|
||||
dev_err(opt->dev, "failed to read register %02x\n",
|
||||
OPT3001_MANUFACTURER_ID);
|
||||
return ret;
|
||||
}
|
||||
|
||||
manufacturer[0] = ret >> 8;
|
||||
manufacturer[1] = ret & 0xff;
|
||||
|
||||
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_DEVICE_ID);
|
||||
if (ret < 0) {
|
||||
dev_err(opt->dev, "failed to read register %02x\n",
|
||||
OPT3001_DEVICE_ID);
|
||||
return ret;
|
||||
}
|
||||
|
||||
device_id = ret;
|
||||
|
||||
dev_info(opt->dev, "Found %c%c OPT%04x\n", manufacturer[0],
|
||||
manufacturer[1], device_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt3001_configure(struct opt3001 *opt)
|
||||
{
|
||||
int ret;
|
||||
u16 reg;
|
||||
|
||||
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
|
||||
if (ret < 0) {
|
||||
dev_err(opt->dev, "failed to read register %02x\n",
|
||||
OPT3001_CONFIGURATION);
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg = ret;
|
||||
|
||||
/* Enable automatic full-scale setting mode */
|
||||
reg &= ~OPT3001_CONFIGURATION_RN_MASK;
|
||||
reg |= OPT3001_CONFIGURATION_RN_AUTO;
|
||||
|
||||
/* Reflect status of the device's integration time setting */
|
||||
if (reg & OPT3001_CONFIGURATION_CT)
|
||||
opt->int_time = 800000;
|
||||
else
|
||||
opt->int_time = 100000;
|
||||
|
||||
/* Ensure device is in shutdown initially */
|
||||
opt3001_set_mode(opt, ®, OPT3001_CONFIGURATION_M_SHUTDOWN);
|
||||
|
||||
/* Configure for latched window-style comparison operation */
|
||||
reg |= OPT3001_CONFIGURATION_L;
|
||||
reg &= ~OPT3001_CONFIGURATION_POL;
|
||||
reg &= ~OPT3001_CONFIGURATION_ME;
|
||||
reg &= ~OPT3001_CONFIGURATION_FC_MASK;
|
||||
|
||||
ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
|
||||
reg);
|
||||
if (ret < 0) {
|
||||
dev_err(opt->dev, "failed to write register %02x\n",
|
||||
OPT3001_CONFIGURATION);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_LOW_LIMIT);
|
||||
if (ret < 0) {
|
||||
dev_err(opt->dev, "failed to read register %02x\n",
|
||||
OPT3001_LOW_LIMIT);
|
||||
return ret;
|
||||
}
|
||||
|
||||
opt->low_thresh_mantissa = OPT3001_REG_MANTISSA(ret);
|
||||
opt->low_thresh_exp = OPT3001_REG_EXPONENT(ret);
|
||||
|
||||
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_HIGH_LIMIT);
|
||||
if (ret < 0) {
|
||||
dev_err(opt->dev, "failed to read register %02x\n",
|
||||
OPT3001_HIGH_LIMIT);
|
||||
return ret;
|
||||
}
|
||||
|
||||
opt->high_thresh_mantissa = OPT3001_REG_MANTISSA(ret);
|
||||
opt->high_thresh_exp = OPT3001_REG_EXPONENT(ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t opt3001_irq(int irq, void *_iio)
|
||||
{
|
||||
struct iio_dev *iio = _iio;
|
||||
struct opt3001 *opt = iio_priv(iio);
|
||||
int ret;
|
||||
|
||||
if (!opt->ok_to_ignore_lock)
|
||||
mutex_lock(&opt->lock);
|
||||
|
||||
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
|
||||
if (ret < 0) {
|
||||
dev_err(opt->dev, "failed to read register %02x\n",
|
||||
OPT3001_CONFIGURATION);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((ret & OPT3001_CONFIGURATION_M_MASK) ==
|
||||
OPT3001_CONFIGURATION_M_CONTINUOUS) {
|
||||
if (ret & OPT3001_CONFIGURATION_FH)
|
||||
iio_push_event(iio,
|
||||
IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING),
|
||||
iio_get_time_ns());
|
||||
if (ret & OPT3001_CONFIGURATION_FL)
|
||||
iio_push_event(iio,
|
||||
IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_FALLING),
|
||||
iio_get_time_ns());
|
||||
} else if (ret & OPT3001_CONFIGURATION_CRF) {
|
||||
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_RESULT);
|
||||
if (ret < 0) {
|
||||
dev_err(opt->dev, "failed to read register %02x\n",
|
||||
OPT3001_RESULT);
|
||||
goto out;
|
||||
}
|
||||
opt->result = ret;
|
||||
opt->result_ready = true;
|
||||
wake_up(&opt->result_ready_queue);
|
||||
}
|
||||
|
||||
out:
|
||||
if (!opt->ok_to_ignore_lock)
|
||||
mutex_unlock(&opt->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int opt3001_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
|
||||
struct iio_dev *iio;
|
||||
struct opt3001 *opt;
|
||||
int irq = client->irq;
|
||||
int ret;
|
||||
|
||||
iio = devm_iio_device_alloc(dev, sizeof(*opt));
|
||||
if (!iio)
|
||||
return -ENOMEM;
|
||||
|
||||
opt = iio_priv(iio);
|
||||
opt->client = client;
|
||||
opt->dev = dev;
|
||||
|
||||
mutex_init(&opt->lock);
|
||||
init_waitqueue_head(&opt->result_ready_queue);
|
||||
i2c_set_clientdata(client, iio);
|
||||
|
||||
ret = opt3001_read_id(opt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = opt3001_configure(opt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
iio->name = client->name;
|
||||
iio->channels = opt3001_channels;
|
||||
iio->num_channels = ARRAY_SIZE(opt3001_channels);
|
||||
iio->dev.parent = dev;
|
||||
iio->modes = INDIO_DIRECT_MODE;
|
||||
iio->info = &opt3001_info;
|
||||
|
||||
ret = devm_iio_device_register(dev, iio);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register IIO device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = request_threaded_irq(irq, NULL, opt3001_irq,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
"opt3001", iio);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to request IRQ #%d\n", irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt3001_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *iio = i2c_get_clientdata(client);
|
||||
struct opt3001 *opt = iio_priv(iio);
|
||||
int ret;
|
||||
u16 reg;
|
||||
|
||||
free_irq(client->irq, iio);
|
||||
|
||||
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
|
||||
if (ret < 0) {
|
||||
dev_err(opt->dev, "failed to read register %02x\n",
|
||||
OPT3001_CONFIGURATION);
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg = ret;
|
||||
opt3001_set_mode(opt, ®, OPT3001_CONFIGURATION_M_SHUTDOWN);
|
||||
|
||||
ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
|
||||
reg);
|
||||
if (ret < 0) {
|
||||
dev_err(opt->dev, "failed to write register %02x\n",
|
||||
OPT3001_CONFIGURATION);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id opt3001_id[] = {
|
||||
{ "opt3001", 0 },
|
||||
{ } /* Terminating Entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, opt3001_id);
|
||||
|
||||
static const struct of_device_id opt3001_of_match[] = {
|
||||
{ .compatible = "ti,opt3001" },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct i2c_driver opt3001_driver = {
|
||||
.probe = opt3001_probe,
|
||||
.remove = opt3001_remove,
|
||||
.id_table = opt3001_id,
|
||||
|
||||
.driver = {
|
||||
.name = "opt3001",
|
||||
.of_match_table = of_match_ptr(opt3001_of_match),
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
module_i2c_driver(opt3001_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Andreas Dannenberg <[email protected]>");
|
||||
MODULE_DESCRIPTION("Texas Instruments OPT3001 Light Sensor Driver");
|
||||
483
drivers/iio/light/pa12203001.c
Normal file
483
drivers/iio/light/pa12203001.c
Normal file
|
|
@ -0,0 +1,483 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Intel Corporation
|
||||
*
|
||||
* Driver for TXC PA12203001 Proximity and Ambient Light Sensor.
|
||||
*
|
||||
* 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.
|
||||
* To do: Interrupt support.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define PA12203001_DRIVER_NAME "pa12203001"
|
||||
|
||||
#define PA12203001_REG_CFG0 0x00
|
||||
#define PA12203001_REG_CFG1 0x01
|
||||
#define PA12203001_REG_CFG2 0x02
|
||||
#define PA12203001_REG_CFG3 0x03
|
||||
|
||||
#define PA12203001_REG_ADL 0x0b
|
||||
#define PA12203001_REG_PDH 0x0e
|
||||
|
||||
#define PA12203001_REG_POFS 0x10
|
||||
#define PA12203001_REG_PSET 0x11
|
||||
|
||||
#define PA12203001_ALS_EN_MASK BIT(0)
|
||||
#define PA12203001_PX_EN_MASK BIT(1)
|
||||
#define PA12203001_PX_NORMAL_MODE_MASK GENMASK(7, 6)
|
||||
#define PA12203001_AFSR_MASK GENMASK(5, 4)
|
||||
#define PA12203001_AFSR_SHIFT 4
|
||||
|
||||
#define PA12203001_PSCAN 0x03
|
||||
|
||||
/* als range 31000, ps, als disabled */
|
||||
#define PA12203001_REG_CFG0_DEFAULT 0x30
|
||||
|
||||
/* led current: 100 mA */
|
||||
#define PA12203001_REG_CFG1_DEFAULT 0x20
|
||||
|
||||
/* ps mode: normal, interrupts not active */
|
||||
#define PA12203001_REG_CFG2_DEFAULT 0xcc
|
||||
|
||||
#define PA12203001_REG_CFG3_DEFAULT 0x00
|
||||
|
||||
#define PA12203001_SLEEP_DELAY_MS 3000
|
||||
|
||||
#define PA12203001_CHIP_ENABLE 0xff
|
||||
#define PA12203001_CHIP_DISABLE 0x00
|
||||
|
||||
/* available scales: corresponding to [500, 4000, 7000, 31000] lux */
|
||||
static const int pa12203001_scales[] = { 7629, 61036, 106813, 473029};
|
||||
|
||||
struct pa12203001_data {
|
||||
struct i2c_client *client;
|
||||
|
||||
/* protect device states */
|
||||
struct mutex lock;
|
||||
|
||||
bool als_enabled;
|
||||
bool px_enabled;
|
||||
bool als_needs_enable;
|
||||
bool px_needs_enable;
|
||||
|
||||
struct regmap *map;
|
||||
};
|
||||
|
||||
static const struct {
|
||||
u8 reg;
|
||||
u8 val;
|
||||
} regvals[] = {
|
||||
{PA12203001_REG_CFG0, PA12203001_REG_CFG0_DEFAULT},
|
||||
{PA12203001_REG_CFG1, PA12203001_REG_CFG1_DEFAULT},
|
||||
{PA12203001_REG_CFG2, PA12203001_REG_CFG2_DEFAULT},
|
||||
{PA12203001_REG_CFG3, PA12203001_REG_CFG3_DEFAULT},
|
||||
{PA12203001_REG_PSET, PA12203001_PSCAN},
|
||||
};
|
||||
|
||||
static IIO_CONST_ATTR(in_illuminance_scale_available,
|
||||
"0.007629 0.061036 0.106813 0.473029");
|
||||
|
||||
static struct attribute *pa12203001_attrs[] = {
|
||||
&iio_const_attr_in_illuminance_scale_available.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group pa12203001_attr_group = {
|
||||
.attrs = pa12203001_attrs,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec pa12203001_channels[] = {
|
||||
{
|
||||
.type = IIO_LIGHT,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
},
|
||||
{
|
||||
.type = IIO_PROXIMITY,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
}
|
||||
};
|
||||
|
||||
static const struct regmap_range pa12203001_volatile_regs_ranges[] = {
|
||||
regmap_reg_range(PA12203001_REG_ADL, PA12203001_REG_ADL + 1),
|
||||
regmap_reg_range(PA12203001_REG_PDH, PA12203001_REG_PDH),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table pa12203001_volatile_regs = {
|
||||
.yes_ranges = pa12203001_volatile_regs_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(pa12203001_volatile_regs_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_config pa12203001_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = PA12203001_REG_PSET,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.volatile_table = &pa12203001_volatile_regs,
|
||||
};
|
||||
|
||||
static inline int pa12203001_als_enable(struct pa12203001_data *data, u8 enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(data->map, PA12203001_REG_CFG0,
|
||||
PA12203001_ALS_EN_MASK, enable);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->als_enabled = !!enable;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int pa12203001_px_enable(struct pa12203001_data *data, u8 enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(data->map, PA12203001_REG_CFG0,
|
||||
PA12203001_PX_EN_MASK, enable);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->px_enabled = !!enable;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pa12203001_set_power_state(struct pa12203001_data *data, bool on,
|
||||
u8 mask)
|
||||
{
|
||||
#ifdef CONFIG_PM
|
||||
int ret;
|
||||
|
||||
if (on && (mask & PA12203001_ALS_EN_MASK)) {
|
||||
mutex_lock(&data->lock);
|
||||
if (data->px_enabled) {
|
||||
ret = pa12203001_als_enable(data,
|
||||
PA12203001_ALS_EN_MASK);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
} else {
|
||||
data->als_needs_enable = true;
|
||||
}
|
||||
mutex_unlock(&data->lock);
|
||||
}
|
||||
|
||||
if (on && (mask & PA12203001_PX_EN_MASK)) {
|
||||
mutex_lock(&data->lock);
|
||||
if (data->als_enabled) {
|
||||
ret = pa12203001_px_enable(data, PA12203001_PX_EN_MASK);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
} else {
|
||||
data->px_needs_enable = true;
|
||||
}
|
||||
mutex_unlock(&data->lock);
|
||||
}
|
||||
|
||||
if (on) {
|
||||
ret = pm_runtime_get_sync(&data->client->dev);
|
||||
if (ret < 0)
|
||||
pm_runtime_put_noidle(&data->client->dev);
|
||||
|
||||
} else {
|
||||
pm_runtime_mark_last_busy(&data->client->dev);
|
||||
ret = pm_runtime_put_autosuspend(&data->client->dev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err:
|
||||
mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pa12203001_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val,
|
||||
int *val2, long mask)
|
||||
{
|
||||
struct pa12203001_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
u8 dev_mask;
|
||||
unsigned int reg_byte;
|
||||
__le16 reg_word;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
switch (chan->type) {
|
||||
case IIO_LIGHT:
|
||||
dev_mask = PA12203001_ALS_EN_MASK;
|
||||
ret = pa12203001_set_power_state(data, true, dev_mask);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/*
|
||||
* ALS ADC value is stored in registers
|
||||
* PA12203001_REG_ADL and in PA12203001_REG_ADL + 1.
|
||||
*/
|
||||
ret = regmap_bulk_read(data->map, PA12203001_REG_ADL,
|
||||
®_word, 2);
|
||||
if (ret < 0)
|
||||
goto reg_err;
|
||||
|
||||
*val = le16_to_cpu(reg_word);
|
||||
ret = pa12203001_set_power_state(data, false, dev_mask);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
case IIO_PROXIMITY:
|
||||
dev_mask = PA12203001_PX_EN_MASK;
|
||||
ret = pa12203001_set_power_state(data, true, dev_mask);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = regmap_read(data->map, PA12203001_REG_PDH,
|
||||
®_byte);
|
||||
if (ret < 0)
|
||||
goto reg_err;
|
||||
|
||||
*val = reg_byte;
|
||||
ret = pa12203001_set_power_state(data, false, dev_mask);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
ret = regmap_read(data->map, PA12203001_REG_CFG0, ®_byte);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = 0;
|
||||
reg_byte = (reg_byte & PA12203001_AFSR_MASK);
|
||||
*val2 = pa12203001_scales[reg_byte >> 4];
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
reg_err:
|
||||
pa12203001_set_power_state(data, false, dev_mask);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pa12203001_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int val,
|
||||
int val2, long mask)
|
||||
{
|
||||
struct pa12203001_data *data = iio_priv(indio_dev);
|
||||
int i, ret, new_val;
|
||||
unsigned int reg_byte;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
ret = regmap_read(data->map, PA12203001_REG_CFG0, ®_byte);
|
||||
if (val != 0 || ret < 0)
|
||||
return -EINVAL;
|
||||
for (i = 0; i < ARRAY_SIZE(pa12203001_scales); i++) {
|
||||
if (val2 == pa12203001_scales[i]) {
|
||||
new_val = i << PA12203001_AFSR_SHIFT;
|
||||
return regmap_update_bits(data->map,
|
||||
PA12203001_REG_CFG0,
|
||||
PA12203001_AFSR_MASK,
|
||||
new_val);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct iio_info pa12203001_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.read_raw = pa12203001_read_raw,
|
||||
.write_raw = pa12203001_write_raw,
|
||||
.attrs = &pa12203001_attr_group,
|
||||
};
|
||||
|
||||
static int pa12203001_init(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct pa12203001_data *data = iio_priv(indio_dev);
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(regvals); i++) {
|
||||
ret = regmap_write(data->map, regvals[i].reg, regvals[i].val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pa12203001_power_chip(struct iio_dev *indio_dev, u8 state)
|
||||
{
|
||||
struct pa12203001_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
ret = pa12203001_als_enable(data, state);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = pa12203001_px_enable(data, state);
|
||||
|
||||
out:
|
||||
mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pa12203001_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct pa12203001_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev,
|
||||
sizeof(struct pa12203001_data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
|
||||
data->map = devm_regmap_init_i2c(client, &pa12203001_regmap_config);
|
||||
if (IS_ERR(data->map))
|
||||
return PTR_ERR(data->map);
|
||||
|
||||
mutex_init(&data->lock);
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->info = &pa12203001_info;
|
||||
indio_dev->name = PA12203001_DRIVER_NAME;
|
||||
indio_dev->channels = pa12203001_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(pa12203001_channels);
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
ret = pa12203001_init(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = pa12203001_power_chip(indio_dev, PA12203001_CHIP_ENABLE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = pm_runtime_set_active(&client->dev);
|
||||
if (ret < 0) {
|
||||
pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pm_runtime_enable(&client->dev);
|
||||
pm_runtime_set_autosuspend_delay(&client->dev,
|
||||
PA12203001_SLEEP_DELAY_MS);
|
||||
pm_runtime_use_autosuspend(&client->dev);
|
||||
|
||||
return iio_device_register(indio_dev);
|
||||
}
|
||||
|
||||
static int pa12203001_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
|
||||
return pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM)
|
||||
static int pa12203001_suspend(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
|
||||
|
||||
return pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int pa12203001_resume(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
|
||||
|
||||
return pa12203001_power_chip(indio_dev, PA12203001_CHIP_ENABLE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int pa12203001_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct pa12203001_data *data;
|
||||
|
||||
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
if (data->als_needs_enable) {
|
||||
pa12203001_als_enable(data, PA12203001_ALS_EN_MASK);
|
||||
data->als_needs_enable = false;
|
||||
}
|
||||
if (data->px_needs_enable) {
|
||||
pa12203001_px_enable(data, PA12203001_PX_EN_MASK);
|
||||
data->px_needs_enable = false;
|
||||
}
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops pa12203001_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pa12203001_suspend, pa12203001_resume)
|
||||
SET_RUNTIME_PM_OPS(pa12203001_suspend, pa12203001_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct acpi_device_id pa12203001_acpi_match[] = {
|
||||
{ "TXCPA122", 0},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(acpi, pa12203001_acpi_match);
|
||||
|
||||
static const struct i2c_device_id pa12203001_id[] = {
|
||||
{"txcpa122", 0},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, pa12203001_id);
|
||||
|
||||
static struct i2c_driver pa12203001_driver = {
|
||||
.driver = {
|
||||
.name = PA12203001_DRIVER_NAME,
|
||||
.pm = &pa12203001_pm_ops,
|
||||
.acpi_match_table = ACPI_PTR(pa12203001_acpi_match),
|
||||
},
|
||||
.probe = pa12203001_probe,
|
||||
.remove = pa12203001_remove,
|
||||
.id_table = pa12203001_id,
|
||||
|
||||
};
|
||||
module_i2c_driver(pa12203001_driver);
|
||||
|
||||
MODULE_AUTHOR("Adriana Reus <[email protected]>");
|
||||
MODULE_DESCRIPTION("Driver for TXC PA12203001 Proximity and Light Sensor");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
@ -676,6 +676,7 @@ static const struct i2c_device_id stk3310_i2c_id[] = {
|
|||
{"STK3311", 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id);
|
||||
|
||||
static const struct acpi_device_id stk3310_acpi_id[] = {
|
||||
{"STK3310", 0},
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@
|
|||
#define BMC150_MAGN_REG_HIGH_THRESH 0x50
|
||||
#define BMC150_MAGN_REG_REP_XY 0x51
|
||||
#define BMC150_MAGN_REG_REP_Z 0x52
|
||||
#define BMC150_MAGN_REG_REP_DATAMASK GENMASK(7, 0)
|
||||
|
||||
#define BMC150_MAGN_REG_TRIM_START 0x5D
|
||||
#define BMC150_MAGN_REG_TRIM_END 0x71
|
||||
|
|
@ -559,7 +560,7 @@ static int bmc150_magn_write_raw(struct iio_dev *indio_dev,
|
|||
}
|
||||
ret = regmap_update_bits(data->regmap,
|
||||
BMC150_MAGN_REG_REP_XY,
|
||||
0xFF,
|
||||
BMC150_MAGN_REG_REP_DATAMASK,
|
||||
BMC150_MAGN_REPXY_TO_REGVAL
|
||||
(val));
|
||||
mutex_unlock(&data->mutex);
|
||||
|
|
@ -575,7 +576,7 @@ static int bmc150_magn_write_raw(struct iio_dev *indio_dev,
|
|||
}
|
||||
ret = regmap_update_bits(data->regmap,
|
||||
BMC150_MAGN_REG_REP_Z,
|
||||
0xFF,
|
||||
BMC150_MAGN_REG_REP_DATAMASK,
|
||||
BMC150_MAGN_REPZ_TO_REGVAL
|
||||
(val));
|
||||
mutex_unlock(&data->mutex);
|
||||
|
|
@ -651,7 +652,9 @@ static const struct iio_info bmc150_magn_info = {
|
|||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const unsigned long bmc150_magn_scan_masks[] = {0x07, 0};
|
||||
static const unsigned long bmc150_magn_scan_masks[] = {
|
||||
BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
|
||||
0};
|
||||
|
||||
static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p)
|
||||
{
|
||||
|
|
@ -662,7 +665,6 @@ static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p)
|
|||
|
||||
mutex_lock(&data->mutex);
|
||||
ret = bmc150_magn_read_xyz(data, data->buffer);
|
||||
mutex_unlock(&data->mutex);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
|
|
@ -670,6 +672,7 @@ static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p)
|
|||
pf->timestamp);
|
||||
|
||||
err:
|
||||
mutex_unlock(&data->mutex);
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
|
@ -781,29 +784,23 @@ static int bmc150_magn_data_rdy_trigger_set_state(struct iio_trigger *trig,
|
|||
if (state == data->dready_trigger_on)
|
||||
goto err_unlock;
|
||||
|
||||
ret = bmc150_magn_set_power_state(data, state);
|
||||
if (ret < 0)
|
||||
goto err_unlock;
|
||||
|
||||
ret = regmap_update_bits(data->regmap, BMC150_MAGN_REG_INT_DRDY,
|
||||
BMC150_MAGN_MASK_DRDY_EN,
|
||||
state << BMC150_MAGN_SHIFT_DRDY_EN);
|
||||
if (ret < 0)
|
||||
goto err_poweroff;
|
||||
goto err_unlock;
|
||||
|
||||
data->dready_trigger_on = state;
|
||||
|
||||
if (state) {
|
||||
ret = bmc150_magn_reset_intr(data);
|
||||
if (ret < 0)
|
||||
goto err_poweroff;
|
||||
goto err_unlock;
|
||||
}
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
err_poweroff:
|
||||
bmc150_magn_set_power_state(data, false);
|
||||
err_unlock:
|
||||
mutex_unlock(&data->mutex);
|
||||
return ret;
|
||||
|
|
@ -1041,6 +1038,9 @@ static int bmc150_magn_runtime_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Should be called with data->mutex held.
|
||||
*/
|
||||
static int bmc150_magn_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
|
||||
|
|
|
|||
|
|
@ -316,31 +316,31 @@ static int mmc35240_read_measurement(struct mmc35240_data *data, __le16 buf[3])
|
|||
static int mmc35240_raw_to_mgauss(struct mmc35240_data *data, int index,
|
||||
__le16 buf[], int *val)
|
||||
{
|
||||
int raw_x, raw_y, raw_z;
|
||||
int sens_x, sens_y, sens_z;
|
||||
int raw[3];
|
||||
int sens[3];
|
||||
int nfo;
|
||||
|
||||
raw_x = le16_to_cpu(buf[AXIS_X]);
|
||||
raw_y = le16_to_cpu(buf[AXIS_Y]);
|
||||
raw_z = le16_to_cpu(buf[AXIS_Z]);
|
||||
raw[AXIS_X] = le16_to_cpu(buf[AXIS_X]);
|
||||
raw[AXIS_Y] = le16_to_cpu(buf[AXIS_Y]);
|
||||
raw[AXIS_Z] = le16_to_cpu(buf[AXIS_Z]);
|
||||
|
||||
sens_x = mmc35240_props_table[data->res].sens[AXIS_X];
|
||||
sens_y = mmc35240_props_table[data->res].sens[AXIS_Y];
|
||||
sens_z = mmc35240_props_table[data->res].sens[AXIS_Z];
|
||||
sens[AXIS_X] = mmc35240_props_table[data->res].sens[AXIS_X];
|
||||
sens[AXIS_Y] = mmc35240_props_table[data->res].sens[AXIS_Y];
|
||||
sens[AXIS_Z] = mmc35240_props_table[data->res].sens[AXIS_Z];
|
||||
|
||||
nfo = mmc35240_props_table[data->res].nfo;
|
||||
|
||||
switch (index) {
|
||||
case AXIS_X:
|
||||
*val = (raw_x - nfo) * 1000 / sens_x;
|
||||
*val = (raw[AXIS_X] - nfo) * 1000 / sens[AXIS_X];
|
||||
break;
|
||||
case AXIS_Y:
|
||||
*val = (raw_y - nfo) * 1000 / sens_y -
|
||||
(raw_z - nfo) * 1000 / sens_z;
|
||||
*val = (raw[AXIS_Y] - nfo) * 1000 / sens[AXIS_Y] -
|
||||
(raw[AXIS_Z] - nfo) * 1000 / sens[AXIS_Z];
|
||||
break;
|
||||
case AXIS_Z:
|
||||
*val = (raw_y - nfo) * 1000 / sens_y +
|
||||
(raw_z - nfo) * 1000 / sens_z;
|
||||
*val = (raw[AXIS_Y] - nfo) * 1000 / sens[AXIS_Y] +
|
||||
(raw[AXIS_Z] - nfo) * 1000 / sens[AXIS_Z];
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
|
@ -559,6 +559,12 @@ static const struct dev_pm_ops mmc35240_pm_ops = {
|
|||
SET_SYSTEM_SLEEP_PM_OPS(mmc35240_suspend, mmc35240_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id mmc35240_of_match[] = {
|
||||
{ .compatible = "memsic,mmc35240", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mmc35240_of_match);
|
||||
|
||||
static const struct acpi_device_id mmc35240_acpi_match[] = {
|
||||
{"MMC35240", 0},
|
||||
{ },
|
||||
|
|
@ -574,6 +580,7 @@ MODULE_DEVICE_TABLE(i2c, mmc35240_id);
|
|||
static struct i2c_driver mmc35240_driver = {
|
||||
.driver = {
|
||||
.name = MMC35240_DRV_NAME,
|
||||
.of_match_table = mmc35240_of_match,
|
||||
.pm = &mmc35240_pm_ops,
|
||||
.acpi_match_table = ACPI_PTR(mmc35240_acpi_match),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#define LSM303DLHC_MAGN_DEV_NAME "lsm303dlhc_magn"
|
||||
#define LSM303DLM_MAGN_DEV_NAME "lsm303dlm_magn"
|
||||
#define LIS3MDL_MAGN_DEV_NAME "lis3mdl"
|
||||
#define LSM303AGR_MAGN_DEV_NAME "lsm303agr_magn"
|
||||
|
||||
int st_magn_common_probe(struct iio_dev *indio_dev);
|
||||
void st_magn_common_remove(struct iio_dev *indio_dev);
|
||||
|
|
@ -25,6 +26,8 @@ void st_magn_common_remove(struct iio_dev *indio_dev);
|
|||
#ifdef CONFIG_IIO_BUFFER
|
||||
int st_magn_allocate_ring(struct iio_dev *indio_dev);
|
||||
void st_magn_deallocate_ring(struct iio_dev *indio_dev);
|
||||
int st_magn_trig_set_state(struct iio_trigger *trig, bool state);
|
||||
#define ST_MAGN_TRIGGER_SET_STATE (&st_magn_trig_set_state)
|
||||
#else /* CONFIG_IIO_BUFFER */
|
||||
static inline int st_magn_probe_trigger(struct iio_dev *indio_dev, int irq)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,6 +23,13 @@
|
|||
#include <linux/iio/common/st_sensors.h>
|
||||
#include "st_magn.h"
|
||||
|
||||
int st_magn_trig_set_state(struct iio_trigger *trig, bool state)
|
||||
{
|
||||
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
|
||||
|
||||
return st_sensors_set_dataready_irq(indio_dev, state);
|
||||
}
|
||||
|
||||
static int st_magn_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
return st_sensors_set_enable(indio_dev, true);
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
#define ST_MAGN_FS_AVL_8000MG 8000
|
||||
#define ST_MAGN_FS_AVL_8100MG 8100
|
||||
#define ST_MAGN_FS_AVL_12000MG 12000
|
||||
#define ST_MAGN_FS_AVL_15000MG 15000
|
||||
#define ST_MAGN_FS_AVL_16000MG 16000
|
||||
|
||||
/* CUSTOM VALUES FOR SENSOR 0 */
|
||||
|
|
@ -157,6 +158,29 @@
|
|||
#define ST_MAGN_2_OUT_Y_L_ADDR 0x2a
|
||||
#define ST_MAGN_2_OUT_Z_L_ADDR 0x2c
|
||||
|
||||
/* CUSTOM VALUES FOR SENSOR 3 */
|
||||
#define ST_MAGN_3_WAI_ADDR 0x4f
|
||||
#define ST_MAGN_3_WAI_EXP 0x40
|
||||
#define ST_MAGN_3_ODR_ADDR 0x60
|
||||
#define ST_MAGN_3_ODR_MASK 0x0c
|
||||
#define ST_MAGN_3_ODR_AVL_10HZ_VAL 0x00
|
||||
#define ST_MAGN_3_ODR_AVL_20HZ_VAL 0x01
|
||||
#define ST_MAGN_3_ODR_AVL_50HZ_VAL 0x02
|
||||
#define ST_MAGN_3_ODR_AVL_100HZ_VAL 0x03
|
||||
#define ST_MAGN_3_PW_ADDR 0x60
|
||||
#define ST_MAGN_3_PW_MASK 0x03
|
||||
#define ST_MAGN_3_PW_ON 0x00
|
||||
#define ST_MAGN_3_PW_OFF 0x03
|
||||
#define ST_MAGN_3_BDU_ADDR 0x62
|
||||
#define ST_MAGN_3_BDU_MASK 0x10
|
||||
#define ST_MAGN_3_DRDY_IRQ_ADDR 0x62
|
||||
#define ST_MAGN_3_DRDY_INT_MASK 0x01
|
||||
#define ST_MAGN_3_FS_AVL_15000_GAIN 1500
|
||||
#define ST_MAGN_3_MULTIREAD_BIT false
|
||||
#define ST_MAGN_3_OUT_X_L_ADDR 0x68
|
||||
#define ST_MAGN_3_OUT_Y_L_ADDR 0x6a
|
||||
#define ST_MAGN_3_OUT_Z_L_ADDR 0x6c
|
||||
|
||||
static const struct iio_chan_spec st_magn_16bit_channels[] = {
|
||||
ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
|
|
@ -189,9 +213,26 @@ static const struct iio_chan_spec st_magn_2_16bit_channels[] = {
|
|||
IIO_CHAN_SOFT_TIMESTAMP(3)
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec st_magn_3_16bit_channels[] = {
|
||||
ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16,
|
||||
ST_MAGN_3_OUT_X_L_ADDR),
|
||||
ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16,
|
||||
ST_MAGN_3_OUT_Y_L_ADDR),
|
||||
ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16,
|
||||
ST_MAGN_3_OUT_Z_L_ADDR),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(3)
|
||||
};
|
||||
|
||||
static const struct st_sensor_settings st_magn_sensors_settings[] = {
|
||||
{
|
||||
.wai = 0, /* This sensor has no valid WhoAmI report 0 */
|
||||
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
|
||||
.sensors_supported = {
|
||||
[0] = LSM303DLH_MAGN_DEV_NAME,
|
||||
},
|
||||
|
|
@ -268,6 +309,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
|
|||
},
|
||||
{
|
||||
.wai = ST_MAGN_1_WAI_EXP,
|
||||
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
|
||||
.sensors_supported = {
|
||||
[0] = LSM303DLHC_MAGN_DEV_NAME,
|
||||
[1] = LSM303DLM_MAGN_DEV_NAME,
|
||||
|
|
@ -346,6 +388,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
|
|||
},
|
||||
{
|
||||
.wai = ST_MAGN_2_WAI_EXP,
|
||||
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
|
||||
.sensors_supported = {
|
||||
[0] = LIS3MDL_MAGN_DEV_NAME,
|
||||
},
|
||||
|
|
@ -399,6 +442,48 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
|
|||
.multi_read_bit = ST_MAGN_2_MULTIREAD_BIT,
|
||||
.bootime = 2,
|
||||
},
|
||||
{
|
||||
.wai = ST_MAGN_3_WAI_EXP,
|
||||
.wai_addr = ST_MAGN_3_WAI_ADDR,
|
||||
.sensors_supported = {
|
||||
[0] = LSM303AGR_MAGN_DEV_NAME,
|
||||
},
|
||||
.ch = (struct iio_chan_spec *)st_magn_3_16bit_channels,
|
||||
.odr = {
|
||||
.addr = ST_MAGN_3_ODR_ADDR,
|
||||
.mask = ST_MAGN_3_ODR_MASK,
|
||||
.odr_avl = {
|
||||
{ 10, ST_MAGN_3_ODR_AVL_10HZ_VAL, },
|
||||
{ 20, ST_MAGN_3_ODR_AVL_20HZ_VAL, },
|
||||
{ 50, ST_MAGN_3_ODR_AVL_50HZ_VAL, },
|
||||
{ 100, ST_MAGN_3_ODR_AVL_100HZ_VAL, },
|
||||
},
|
||||
},
|
||||
.pw = {
|
||||
.addr = ST_MAGN_3_PW_ADDR,
|
||||
.mask = ST_MAGN_3_PW_MASK,
|
||||
.value_on = ST_MAGN_3_PW_ON,
|
||||
.value_off = ST_MAGN_3_PW_OFF,
|
||||
},
|
||||
.fs = {
|
||||
.fs_avl = {
|
||||
[0] = {
|
||||
.num = ST_MAGN_FS_AVL_15000MG,
|
||||
.gain = ST_MAGN_3_FS_AVL_15000_GAIN,
|
||||
},
|
||||
},
|
||||
},
|
||||
.bdu = {
|
||||
.addr = ST_MAGN_3_BDU_ADDR,
|
||||
.mask = ST_MAGN_3_BDU_MASK,
|
||||
},
|
||||
.drdy_irq = {
|
||||
.addr = ST_MAGN_3_DRDY_IRQ_ADDR,
|
||||
.mask_int1 = ST_MAGN_3_DRDY_INT_MASK,
|
||||
},
|
||||
.multi_read_bit = ST_MAGN_3_MULTIREAD_BIT,
|
||||
.bootime = 2,
|
||||
},
|
||||
};
|
||||
|
||||
static int st_magn_read_raw(struct iio_dev *indio_dev,
|
||||
|
|
@ -477,6 +562,16 @@ static const struct iio_info magn_info = {
|
|||
.write_raw = &st_magn_write_raw,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IIO_TRIGGER
|
||||
static const struct iio_trigger_ops st_magn_trigger_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.set_trigger_state = ST_MAGN_TRIGGER_SET_STATE,
|
||||
};
|
||||
#define ST_MAGN_TRIGGER_OPS (&st_magn_trigger_ops)
|
||||
#else
|
||||
#define ST_MAGN_TRIGGER_OPS NULL
|
||||
#endif
|
||||
|
||||
int st_magn_common_probe(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct st_sensor_data *mdata = iio_priv(indio_dev);
|
||||
|
|
@ -513,7 +608,8 @@ int st_magn_common_probe(struct iio_dev *indio_dev)
|
|||
return err;
|
||||
|
||||
if (irq > 0) {
|
||||
err = st_sensors_allocate_trigger(indio_dev, NULL);
|
||||
err = st_sensors_allocate_trigger(indio_dev,
|
||||
ST_MAGN_TRIGGER_OPS);
|
||||
if (err < 0)
|
||||
goto st_magn_probe_trigger_error;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,10 @@ static const struct of_device_id st_magn_of_match[] = {
|
|||
.compatible = "st,lis3mdl-magn",
|
||||
.data = LIS3MDL_MAGN_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm303agr-magn",
|
||||
.data = LSM303AGR_MAGN_DEV_NAME,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st_magn_of_match);
|
||||
|
|
@ -79,6 +83,7 @@ static const struct i2c_device_id st_magn_id_table[] = {
|
|||
{ LSM303DLHC_MAGN_DEV_NAME },
|
||||
{ LSM303DLM_MAGN_DEV_NAME },
|
||||
{ LIS3MDL_MAGN_DEV_NAME },
|
||||
{ LSM303AGR_MAGN_DEV_NAME },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, st_magn_id_table);
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ static const struct spi_device_id st_magn_id_table[] = {
|
|||
{ LSM303DLHC_MAGN_DEV_NAME },
|
||||
{ LSM303DLM_MAGN_DEV_NAME },
|
||||
{ LIS3MDL_MAGN_DEV_NAME },
|
||||
{ LSM303AGR_MAGN_DEV_NAME },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, st_magn_id_table);
|
||||
|
|
|
|||
|
|
@ -178,6 +178,7 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = {
|
|||
static const struct st_sensor_settings st_press_sensors_settings[] = {
|
||||
{
|
||||
.wai = ST_PRESS_LPS331AP_WAI_EXP,
|
||||
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
|
||||
.sensors_supported = {
|
||||
[0] = LPS331AP_PRESS_DEV_NAME,
|
||||
},
|
||||
|
|
@ -225,6 +226,7 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
|
|||
},
|
||||
{
|
||||
.wai = ST_PRESS_LPS001WP_WAI_EXP,
|
||||
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
|
||||
.sensors_supported = {
|
||||
[0] = LPS001WP_PRESS_DEV_NAME,
|
||||
},
|
||||
|
|
@ -260,6 +262,7 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
|
|||
},
|
||||
{
|
||||
.wai = ST_PRESS_LPS25H_WAI_EXP,
|
||||
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
|
||||
.sensors_supported = {
|
||||
[0] = LPS25H_PRESS_DEV_NAME,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -65,6 +65,13 @@
|
|||
|
||||
#define MLX90614_AUTOSLEEP_DELAY 5000 /* default autosleep delay */
|
||||
|
||||
/* Magic constants */
|
||||
#define MLX90614_CONST_OFFSET_DEC -13657 /* decimal part of the Kelvin offset */
|
||||
#define MLX90614_CONST_OFFSET_REM 500000 /* remainder of offset (273.15*50) */
|
||||
#define MLX90614_CONST_SCALE 20 /* Scale in milliKelvin (0.02 * 1000) */
|
||||
#define MLX90614_CONST_RAW_EMISSIVITY_MAX 65535 /* max value for emissivity */
|
||||
#define MLX90614_CONST_EMISSIVITY_RESOLUTION 15259 /* 1/65535 ~ 0.000015259 */
|
||||
|
||||
struct mlx90614_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex lock; /* for EEPROM access only */
|
||||
|
|
@ -204,11 +211,11 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
|
|||
*val = ret;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
*val = -13657;
|
||||
*val2 = 500000;
|
||||
*val = MLX90614_CONST_OFFSET_DEC;
|
||||
*val2 = MLX90614_CONST_OFFSET_REM;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 20;
|
||||
*val = MLX90614_CONST_SCALE;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */
|
||||
mlx90614_power_get(data, false);
|
||||
|
|
@ -221,12 +228,12 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret == 65535) {
|
||||
if (ret == MLX90614_CONST_RAW_EMISSIVITY_MAX) {
|
||||
*val = 1;
|
||||
*val2 = 0;
|
||||
} else {
|
||||
*val = 0;
|
||||
*val2 = ret * 15259; /* 1/65535 ~ 0.000015259 */
|
||||
*val2 = ret * MLX90614_CONST_EMISSIVITY_RESOLUTION;
|
||||
}
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
default:
|
||||
|
|
@ -245,7 +252,8 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev,
|
|||
case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */
|
||||
if (val < 0 || val2 < 0 || val > 1 || (val == 1 && val2 != 0))
|
||||
return -EINVAL;
|
||||
val = val * 65535 + val2 / 15259; /* 1/65535 ~ 0.000015259 */
|
||||
val = val * MLX90614_CONST_RAW_EMISSIVITY_MAX +
|
||||
val2 / MLX90614_CONST_EMISSIVITY_RESOLUTION;
|
||||
|
||||
mlx90614_power_get(data, false);
|
||||
mutex_lock(&data->lock);
|
||||
|
|
|
|||
Loading…
Reference in a new issue