First round of new drivers, cleanups and functionality for IIO in the 4.3 cycle.
Core and tools new stuff * Allow explicit flush of hardware fifo by using an non blocking read. This is needed to support some of the Android requirements for HW fifo devices - also makes sense generally and clarifies a corner of the ABI. * Add some missing modifier names. Mostly these exist for weird and wonderful event types, but should still be present in the name array. * Update iio_event_monitor to cope with new channel types. * generic_buffer gains support for single byte scan elements (no idea how this never got implemented before!) New device support * ROHM rpr0521 light and proximity sensor driver. * bmc150 gains bmc156 support. * ms5611 gains ms5607 temperature and pressure sensor support. Driver functionality * inv-mpu - add scale_available attributes to aid userspace in configuring these devices. * isl29125 - add scale_available attributes. * stk8ba50 - sampling frequency control, triggered buffer support. * stk8312 - sampling frequency control, triggered buffer support. * cc10001 - ensure ADC powered up at probe time if shared by non linux running CPUs. * bmc150-magn - decouple the buffer and trigger allowing other triggers to be used to drive this device's sampling. Documentation * Add some previously missed *scale_available attributes to the ABI docs. Cleanups * Clarify some crazy naming in iio_triggered_buffer_setup that seems to have somehow ended up backwards (dates back a long way). Avoid the top half and bottom half naming entirely given we are how dealing with a handler and a thread in all cases. * Tools cleanup including coding style, variable naming improvements, also a new sanity check on a full event having been read. * stk8ba50 - replace the scale table with a struct for clarity. Also suspend the sensor if an error occurs in init. * hid-sensor-prox - drop uneeded line break. * mma9551 - use size in words for word read / write avoiding accidental sending of an odd number of bytes. * mma9553 - fix code alignment and document the use of a mutex. * light/Kconfig - typo fix in commment. * cm3323 - don't eat an error value, replace an unneeded local variable with a generic local variable with the same use, add some blank lines for clarity. * pressure/Kconfig - typo in Measurement Specialties name. * bmc150-accel - actually use a mask definition rather than repeating the value inline, code style cleanup. * adc/Kconfig - general help description cleanup. * ssp_sensors - drop redundant spi driver bus initialization (done in the spi core) * tmp006 - use genmask rather than hand generated masks. * ms5611 - drop IIO_CHAN_INFO_SCALE as this driver provides a processed output and as such the read only scale adds nothing useful. * kxcjk-1013, adf4350, dummy - drop unwanted blank lines. * Drop all owner assignments from i2c_drivers and this is done in the i2c core. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJVpqGLAAoJEFSFNJnE9BaIeXEP/09wE8m98+cTUn4/cppM1vTL Ypx5ariBNrsbJ3aodD6uOhIY/E8tnOGa5MZmMt7F6XTOTDJIoWt3sJHTYGgC2niS 1rvXpIKcFx473LabhI7Cq6r3Azon7wC3RrEkZZFgpgMAbZLGLLwamWawZKZkgsQx tlWrT3M8BwQoV72mkfUBVrZpRgHwpB5QDZZ7RLVe04QoO1QBZg4HlGO67BdGx3md farmaCVOyB1PehzRk1C4wBgfLa2x/fnnrTlXlwNqKfh5OXhbwzluEbzejS9fk5KZ ox+H1Ns3+prVheaElI9N5svx1vIrviwwyh1a7aE5r32djidVd502qPOlcB1ebr2e xZ0xxzXYzd+XD3g3mGF0B2mIEUL8kj1wX3w/Q2DNoLUaCfPRQbRr8rRf3C7QFcZl F0nZyaL2yZzYrs4nqZ6o3G2huWQNBybaQ7riyswq8dPyJ0vpKyQE7Ihj9FHt2u13 44zpbQ59ct7BZlnsljtSMMQRzJMA2JHnXciB8FYliRoc0QBn4vTP9c+PDCFY2+YW TJ6TB/bVI1h/6Qn8rp6i9Ks+QhPr98ftlfSRPTJ9pMINvyZh1oW0yunGfVr88jdj aEuQ2sQg/QYs0qB2eon7GmgZ1fhM1snoz3X6XPIuo3pC4eJ29K59gxDHAvUpqdhM ANGW8MwFk1lMipobvXIM =0E79 -----END PGP SIGNATURE----- Merge tag 'iio-for-4.3a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next Jonathan writes: First round of new drivers, cleanups and functionality for IIO in the 4.3 cycle. Core and tools new stuff * Allow explicit flush of hardware fifo by using an non blocking read. This is needed to support some of the Android requirements for HW fifo devices - also makes sense generally and clarifies a corner of the ABI. * Add some missing modifier names. Mostly these exist for weird and wonderful event types, but should still be present in the name array. * Update iio_event_monitor to cope with new channel types. * generic_buffer gains support for single byte scan elements (no idea how this never got implemented before!) New device support * ROHM rpr0521 light and proximity sensor driver. * bmc150 gains bmc156 support. * ms5611 gains ms5607 temperature and pressure sensor support. Driver functionality * inv-mpu - add scale_available attributes to aid userspace in configuring these devices. * isl29125 - add scale_available attributes. * stk8ba50 - sampling frequency control, triggered buffer support. * stk8312 - sampling frequency control, triggered buffer support. * cc10001 - ensure ADC powered up at probe time if shared by non linux running CPUs. * bmc150-magn - decouple the buffer and trigger allowing other triggers to be used to drive this device's sampling. Documentation * Add some previously missed *scale_available attributes to the ABI docs. Cleanups * Clarify some crazy naming in iio_triggered_buffer_setup that seems to have somehow ended up backwards (dates back a long way). Avoid the top half and bottom half naming entirely given we are how dealing with a handler and a thread in all cases. * Tools cleanup including coding style, variable naming improvements, also a new sanity check on a full event having been read. * stk8ba50 - replace the scale table with a struct for clarity. Also suspend the sensor if an error occurs in init. * hid-sensor-prox - drop uneeded line break. * mma9551 - use size in words for word read / write avoiding accidental sending of an odd number of bytes. * mma9553 - fix code alignment and document the use of a mutex. * light/Kconfig - typo fix in commment. * cm3323 - don't eat an error value, replace an unneeded local variable with a generic local variable with the same use, add some blank lines for clarity. * pressure/Kconfig - typo in Measurement Specialties name. * bmc150-accel - actually use a mask definition rather than repeating the value inline, code style cleanup. * adc/Kconfig - general help description cleanup. * ssp_sensors - drop redundant spi driver bus initialization (done in the spi core) * tmp006 - use genmask rather than hand generated masks. * ms5611 - drop IIO_CHAN_INFO_SCALE as this driver provides a processed output and as such the read only scale adds nothing useful. * kxcjk-1013, adf4350, dummy - drop unwanted blank lines. * Drop all owner assignments from i2c_drivers and this is done in the i2c core.
This commit is contained in:
commit
e913bfb60b
|
@ -413,6 +413,11 @@ Description:
|
|||
to compute the calories burnt by the user.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_scale_available
|
||||
What: /sys/.../iio:deviceX/in_anglvel_scale_available
|
||||
What: /sys/.../iio:deviceX/in_magn_scale_available
|
||||
What: /sys/.../iio:deviceX/in_illuminance_scale_available
|
||||
What: /sys/.../iio:deviceX/in_intensity_scale_available
|
||||
What: /sys/.../iio:deviceX/in_proximity_scale_available
|
||||
What: /sys/.../iio:deviceX/in_voltageX_scale_available
|
||||
What: /sys/.../iio:deviceX/in_voltage-voltage_scale_available
|
||||
What: /sys/.../iio:deviceX/out_voltageX_scale_available
|
||||
|
|
|
@ -846,7 +846,6 @@ MODULE_DEVICE_TABLE(i2c, bma180_ids);
|
|||
static struct i2c_driver bma180_driver = {
|
||||
.driver = {
|
||||
.name = "bma180",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = BMA180_PM_OPS,
|
||||
},
|
||||
.probe = bma180_probe,
|
||||
|
|
|
@ -241,7 +241,6 @@ static const struct {
|
|||
{500000, BMC150_ACCEL_SLEEP_500_MS},
|
||||
{1000000, BMC150_ACCEL_SLEEP_1_SEC} };
|
||||
|
||||
|
||||
static int bmc150_accel_set_mode(struct bmc150_accel_data *data,
|
||||
enum bmc150_power_modes mode,
|
||||
int dur_us)
|
||||
|
@ -259,8 +258,9 @@ static int bmc150_accel_set_mode(struct bmc150_accel_data *data,
|
|||
dur_val =
|
||||
bmc150_accel_sleep_value_table[i].reg_value;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
dur_val = 0;
|
||||
}
|
||||
|
||||
if (dur_val < 0)
|
||||
return -EINVAL;
|
||||
|
@ -288,7 +288,7 @@ static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val,
|
|||
|
||||
for (i = 0; i < ARRAY_SIZE(bmc150_accel_samp_freq_table); ++i) {
|
||||
if (bmc150_accel_samp_freq_table[i].val == val &&
|
||||
bmc150_accel_samp_freq_table[i].val2 == val2) {
|
||||
bmc150_accel_samp_freq_table[i].val2 == val2) {
|
||||
ret = i2c_smbus_write_byte_data(
|
||||
data->client,
|
||||
BMC150_ACCEL_REG_PMU_BW,
|
||||
|
@ -351,8 +351,7 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
|
|||
|
||||
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");
|
||||
dev_err(&data->client->dev, "Error: Reading chip id\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -376,8 +375,7 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
|
|||
BMC150_ACCEL_REG_PMU_RANGE,
|
||||
BMC150_ACCEL_DEF_RANGE_4G);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev,
|
||||
"Error writing reg_pmu_range\n");
|
||||
dev_err(&data->client->dev, "Error writing reg_pmu_range\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -437,12 +435,13 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (on)
|
||||
if (on) {
|
||||
ret = pm_runtime_get_sync(&data->client->dev);
|
||||
else {
|
||||
} else {
|
||||
pm_runtime_mark_last_busy(&data->client->dev);
|
||||
ret = pm_runtime_put_autosuspend(&data->client->dev);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev,
|
||||
"Failed: bmc150_accel_set_power_state for %d\n", on);
|
||||
|
@ -514,13 +513,13 @@ static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i,
|
|||
}
|
||||
|
||||
/*
|
||||
* We will expect the enable and disable to do operation in
|
||||
* in reverse order. This will happen here anyway as our
|
||||
* resume operation uses sync mode runtime pm calls, the
|
||||
* suspend operation will be delayed by autosuspend delay
|
||||
* So the disable operation will still happen in reverse of
|
||||
* enable operation. When runtime pm is disabled the mode
|
||||
* is always on so sequence doesn't matter
|
||||
* We will expect the enable and disable to do operation in reverse
|
||||
* order. This will happen here anyway, as our resume operation uses
|
||||
* sync mode runtime pm calls. The suspend operation will be delayed
|
||||
* by autosuspend delay.
|
||||
* So the disable operation will still happen in reverse order of
|
||||
* enable operation. When runtime pm is disabled the mode is always on,
|
||||
* so sequence doesn't matter.
|
||||
*/
|
||||
ret = bmc150_accel_set_power_state(data, state);
|
||||
if (ret < 0)
|
||||
|
@ -574,7 +573,6 @@ out_fix_power_state:
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val)
|
||||
{
|
||||
int ret, i;
|
||||
|
@ -674,8 +672,9 @@ static int bmc150_accel_read_raw(struct iio_dev *indio_dev,
|
|||
if (chan->type == IIO_TEMP) {
|
||||
*val = BMC150_ACCEL_TEMP_CENTER_VAL;
|
||||
return IIO_VAL_INT;
|
||||
} else
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 0;
|
||||
switch (chan->type) {
|
||||
|
@ -776,7 +775,7 @@ static int bmc150_accel_write_event(struct iio_dev *indio_dev,
|
|||
|
||||
switch (info) {
|
||||
case IIO_EV_INFO_VALUE:
|
||||
data->slope_thres = val & 0xFF;
|
||||
data->slope_thres = val & BMC150_ACCEL_SLOPE_THRES_MASK;
|
||||
break;
|
||||
case IIO_EV_INFO_PERIOD:
|
||||
data->slope_dur = val & BMC150_ACCEL_SLOPE_DUR_MASK;
|
||||
|
@ -793,7 +792,6 @@ static int bmc150_accel_read_event_config(struct iio_dev *indio_dev,
|
|||
enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
|
||||
struct bmc150_accel_data *data = iio_priv(indio_dev);
|
||||
|
||||
return data->ev_enable_state;
|
||||
|
@ -827,7 +825,7 @@ static int bmc150_accel_write_event_config(struct iio_dev *indio_dev,
|
|||
}
|
||||
|
||||
static int bmc150_accel_validate_trigger(struct iio_dev *indio_dev,
|
||||
struct iio_trigger *trig)
|
||||
struct iio_trigger *trig)
|
||||
{
|
||||
struct bmc150_accel_data *data = iio_priv(indio_dev);
|
||||
int i;
|
||||
|
@ -963,6 +961,7 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
|
|||
u16 buffer[BMC150_ACCEL_FIFO_LENGTH * 3];
|
||||
int64_t tstamp;
|
||||
uint64_t sample_period;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client,
|
||||
BMC150_ACCEL_REG_FIFO_STATUS);
|
||||
if (ret < 0) {
|
||||
|
@ -1255,7 +1254,7 @@ static int bmc150_accel_trig_try_reen(struct iio_trigger *trig)
|
|||
}
|
||||
|
||||
static int bmc150_accel_trigger_set_state(struct iio_trigger *trig,
|
||||
bool state)
|
||||
bool state)
|
||||
{
|
||||
struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig);
|
||||
struct bmc150_accel_data *data = t->data;
|
||||
|
@ -1314,26 +1313,32 @@ static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev)
|
|||
dir = IIO_EV_DIR_RISING;
|
||||
|
||||
if (ret & BMC150_ACCEL_ANY_MOTION_BIT_X)
|
||||
iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL,
|
||||
0,
|
||||
IIO_MOD_X,
|
||||
IIO_EV_TYPE_ROC,
|
||||
dir),
|
||||
data->timestamp);
|
||||
iio_push_event(indio_dev,
|
||||
IIO_MOD_EVENT_CODE(IIO_ACCEL,
|
||||
0,
|
||||
IIO_MOD_X,
|
||||
IIO_EV_TYPE_ROC,
|
||||
dir),
|
||||
data->timestamp);
|
||||
|
||||
if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Y)
|
||||
iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL,
|
||||
0,
|
||||
IIO_MOD_Y,
|
||||
IIO_EV_TYPE_ROC,
|
||||
dir),
|
||||
data->timestamp);
|
||||
iio_push_event(indio_dev,
|
||||
IIO_MOD_EVENT_CODE(IIO_ACCEL,
|
||||
0,
|
||||
IIO_MOD_Y,
|
||||
IIO_EV_TYPE_ROC,
|
||||
dir),
|
||||
data->timestamp);
|
||||
|
||||
if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Z)
|
||||
iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL,
|
||||
0,
|
||||
IIO_MOD_Z,
|
||||
IIO_EV_TYPE_ROC,
|
||||
dir),
|
||||
data->timestamp);
|
||||
iio_push_event(indio_dev,
|
||||
IIO_MOD_EVENT_CODE(IIO_ACCEL,
|
||||
0,
|
||||
IIO_MOD_Z,
|
||||
IIO_EV_TYPE_ROC,
|
||||
dir),
|
||||
data->timestamp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1365,7 +1370,9 @@ static irqreturn_t bmc150_accel_irq_thread_handler(int irq, void *private)
|
|||
BMC150_ACCEL_INT_MODE_LATCH_INT |
|
||||
BMC150_ACCEL_INT_MODE_LATCH_RESET);
|
||||
if (ret)
|
||||
dev_err(&data->client->dev, "Error writing reg_int_rst_latch\n");
|
||||
dev_err(&data->client->dev,
|
||||
"Error writing reg_int_rst_latch\n");
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
} else {
|
||||
ret = IRQ_NONE;
|
||||
|
@ -1412,13 +1419,13 @@ static const char *bmc150_accel_match_acpi_device(struct device *dev, int *data)
|
|||
if (!id)
|
||||
return NULL;
|
||||
|
||||
*data = (int) id->driver_data;
|
||||
*data = (int)id->driver_data;
|
||||
|
||||
return dev_name(dev);
|
||||
}
|
||||
|
||||
static int bmc150_accel_gpio_probe(struct i2c_client *client,
|
||||
struct bmc150_accel_data *data)
|
||||
struct bmc150_accel_data *data)
|
||||
{
|
||||
struct device *dev;
|
||||
struct gpio_desc *gpio;
|
||||
|
|
|
@ -658,10 +658,8 @@ static int kxcjk1013_set_scale(struct kxcjk1013_data *data, int val)
|
|||
int ret, i;
|
||||
enum kxcjk1013_mode store_mode;
|
||||
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(KXCJK1013_scale_table); ++i) {
|
||||
if (KXCJK1013_scale_table[i].scale == val) {
|
||||
|
||||
ret = kxcjk1013_get_mode(data, &store_mode);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -820,7 +818,6 @@ static int kxcjk1013_read_event_config(struct iio_dev *indio_dev,
|
|||
enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
|
||||
struct kxcjk1013_data *data = iio_priv(indio_dev);
|
||||
|
||||
return data->ev_enable_state;
|
||||
|
|
|
@ -297,7 +297,7 @@ EXPORT_SYMBOL(mma9551_read_status_byte);
|
|||
* Returns: 0 on success, negative value on failure.
|
||||
*/
|
||||
int mma9551_read_config_word(struct i2c_client *client, u8 app_id,
|
||||
u16 reg, u16 *val)
|
||||
u16 reg, u16 *val)
|
||||
{
|
||||
int ret;
|
||||
__be16 v;
|
||||
|
@ -328,12 +328,12 @@ EXPORT_SYMBOL(mma9551_read_config_word);
|
|||
* Returns: 0 on success, negative value on failure.
|
||||
*/
|
||||
int mma9551_write_config_word(struct i2c_client *client, u8 app_id,
|
||||
u16 reg, u16 val)
|
||||
u16 reg, u16 val)
|
||||
{
|
||||
__be16 v = cpu_to_be16(val);
|
||||
|
||||
return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg,
|
||||
(u8 *) &v, 2, NULL, 0);
|
||||
(u8 *)&v, 2, NULL, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(mma9551_write_config_word);
|
||||
|
||||
|
@ -373,7 +373,7 @@ EXPORT_SYMBOL(mma9551_read_status_word);
|
|||
* @client: I2C client
|
||||
* @app_id: Application ID
|
||||
* @reg: Application register
|
||||
* @len: Length of array to read in bytes
|
||||
* @len: Length of array to read (in words)
|
||||
* @buf: Array of words to read
|
||||
*
|
||||
* Read multiple configuration registers (word-sized registers).
|
||||
|
@ -385,23 +385,22 @@ EXPORT_SYMBOL(mma9551_read_status_word);
|
|||
* Returns: 0 on success, negative value on failure.
|
||||
*/
|
||||
int mma9551_read_config_words(struct i2c_client *client, u8 app_id,
|
||||
u16 reg, u8 len, u16 *buf)
|
||||
u16 reg, u8 len, u16 *buf)
|
||||
{
|
||||
int ret, i;
|
||||
int len_words = len / sizeof(u16);
|
||||
__be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS / 2];
|
||||
|
||||
if (len_words > ARRAY_SIZE(be_buf)) {
|
||||
if (len > ARRAY_SIZE(be_buf)) {
|
||||
dev_err(&client->dev, "Invalid buffer size %d\n", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
|
||||
reg, NULL, 0, (u8 *) be_buf, len);
|
||||
reg, NULL, 0, (u8 *)be_buf, len * sizeof(u16));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < len_words; i++)
|
||||
for (i = 0; i < len; i++)
|
||||
buf[i] = be16_to_cpu(be_buf[i]);
|
||||
|
||||
return 0;
|
||||
|
@ -413,7 +412,7 @@ EXPORT_SYMBOL(mma9551_read_config_words);
|
|||
* @client: I2C client
|
||||
* @app_id: Application ID
|
||||
* @reg: Application register
|
||||
* @len: Length of array to read in bytes
|
||||
* @len: Length of array to read (in words)
|
||||
* @buf: Array of words to read
|
||||
*
|
||||
* Read multiple status registers (word-sized registers).
|
||||
|
@ -428,20 +427,19 @@ int mma9551_read_status_words(struct i2c_client *client, u8 app_id,
|
|||
u16 reg, u8 len, u16 *buf)
|
||||
{
|
||||
int ret, i;
|
||||
int len_words = len / sizeof(u16);
|
||||
__be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS / 2];
|
||||
|
||||
if (len_words > ARRAY_SIZE(be_buf)) {
|
||||
if (len > ARRAY_SIZE(be_buf)) {
|
||||
dev_err(&client->dev, "Invalid buffer size %d\n", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
|
||||
reg, NULL, 0, (u8 *) be_buf, len);
|
||||
reg, NULL, 0, (u8 *)be_buf, len * sizeof(u16));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < len_words; i++)
|
||||
for (i = 0; i < len; i++)
|
||||
buf[i] = be16_to_cpu(be_buf[i]);
|
||||
|
||||
return 0;
|
||||
|
@ -453,7 +451,7 @@ EXPORT_SYMBOL(mma9551_read_status_words);
|
|||
* @client: I2C client
|
||||
* @app_id: Application ID
|
||||
* @reg: Application register
|
||||
* @len: Length of array to write in bytes
|
||||
* @len: Length of array to write (in words)
|
||||
* @buf: Array of words to write
|
||||
*
|
||||
* Write multiple configuration registers (word-sized registers).
|
||||
|
@ -468,19 +466,18 @@ int mma9551_write_config_words(struct i2c_client *client, u8 app_id,
|
|||
u16 reg, u8 len, u16 *buf)
|
||||
{
|
||||
int i;
|
||||
int len_words = len / sizeof(u16);
|
||||
__be16 be_buf[(MMA9551_MAX_MAILBOX_DATA_REGS - 1) / 2];
|
||||
|
||||
if (len_words > ARRAY_SIZE(be_buf)) {
|
||||
if (len > ARRAY_SIZE(be_buf)) {
|
||||
dev_err(&client->dev, "Invalid buffer size %d\n", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < len_words; i++)
|
||||
for (i = 0; i < len; i++)
|
||||
be_buf[i] = cpu_to_be16(buf[i]);
|
||||
|
||||
return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG,
|
||||
reg, (u8 *) be_buf, len, NULL, 0);
|
||||
reg, (u8 *)be_buf, len * sizeof(u16), NULL, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(mma9551_write_config_words);
|
||||
|
||||
|
|
|
@ -53,13 +53,13 @@ int mma9551_write_config_byte(struct i2c_client *client, u8 app_id,
|
|||
int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
|
||||
u16 reg, u8 *val);
|
||||
int mma9551_read_config_word(struct i2c_client *client, u8 app_id,
|
||||
u16 reg, u16 *val);
|
||||
u16 reg, u16 *val);
|
||||
int mma9551_write_config_word(struct i2c_client *client, u8 app_id,
|
||||
u16 reg, u16 val);
|
||||
u16 reg, u16 val);
|
||||
int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
|
||||
u16 reg, u16 *val);
|
||||
int mma9551_read_config_words(struct i2c_client *client, u8 app_id,
|
||||
u16 reg, u8 len, u16 *buf);
|
||||
u16 reg, u8 len, u16 *buf);
|
||||
int mma9551_read_status_words(struct i2c_client *client, u8 app_id,
|
||||
u16 reg, u8 len, u16 *buf);
|
||||
int mma9551_write_config_words(struct i2c_client *client, u8 app_id,
|
||||
|
|
|
@ -182,6 +182,10 @@ struct mma9553_conf_regs {
|
|||
|
||||
struct mma9553_data {
|
||||
struct i2c_client *client;
|
||||
/*
|
||||
* 1. Serialize access to HW (requested by mma9551_core API).
|
||||
* 2. Serialize sequences that power on/off the device and access HW.
|
||||
*/
|
||||
struct mutex mutex;
|
||||
struct mma9553_conf_regs conf;
|
||||
struct mma9553_event events[MMA9553_EVENTS_INFO_SIZE];
|
||||
|
@ -322,7 +326,8 @@ static int mma9553_read_activity_stepcnt(struct mma9553_data *data,
|
|||
int ret;
|
||||
|
||||
ret = mma9551_read_status_words(data->client, MMA9551_APPID_PEDOMETER,
|
||||
MMA9553_REG_STATUS, sizeof(u32), buf);
|
||||
MMA9553_REG_STATUS, ARRAY_SIZE(buf),
|
||||
buf);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev,
|
||||
"error reading status and stepcnt\n");
|
||||
|
@ -342,10 +347,10 @@ static int mma9553_conf_gpio(struct mma9553_data *data)
|
|||
struct mma9553_event *ev_step_detect;
|
||||
bool activity_enabled;
|
||||
|
||||
activity_enabled =
|
||||
mma9553_is_any_event_enabled(data, true, IIO_ACTIVITY);
|
||||
ev_step_detect =
|
||||
mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, IIO_EV_DIR_NONE);
|
||||
activity_enabled = mma9553_is_any_event_enabled(data, true,
|
||||
IIO_ACTIVITY);
|
||||
ev_step_detect = mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD,
|
||||
IIO_EV_DIR_NONE);
|
||||
|
||||
/*
|
||||
* If both step detector and activity are enabled, use the MRGFL bit.
|
||||
|
@ -371,9 +376,8 @@ static int mma9553_conf_gpio(struct mma9553_data *data)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = mma9551_gpio_config(data->client,
|
||||
MMA9553_DEFAULT_GPIO_PIN,
|
||||
appid, bitnum, MMA9553_DEFAULT_GPIO_POLARITY);
|
||||
ret = mma9551_gpio_config(data->client, MMA9553_DEFAULT_GPIO_PIN, appid,
|
||||
bitnum, MMA9553_DEFAULT_GPIO_POLARITY);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->gpio_bitnum = bitnum;
|
||||
|
@ -394,17 +398,16 @@ static int mma9553_init(struct mma9553_data *data)
|
|||
* a device identification command to differentiate the MMA9553L
|
||||
* from the MMA9550L.
|
||||
*/
|
||||
ret =
|
||||
mma9551_read_config_words(data->client, MMA9551_APPID_PEDOMETER,
|
||||
MMA9553_REG_CONF_SLEEPMIN,
|
||||
sizeof(data->conf), (u16 *) &data->conf);
|
||||
ret = mma9551_read_config_words(data->client, MMA9551_APPID_PEDOMETER,
|
||||
MMA9553_REG_CONF_SLEEPMIN,
|
||||
sizeof(data->conf) / sizeof(u16),
|
||||
(u16 *)&data->conf);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev,
|
||||
"failed to read configuration registers\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Reset GPIO */
|
||||
data->gpio_bitnum = MMA9553_MAX_BITNUM;
|
||||
ret = mma9553_conf_gpio(data);
|
||||
|
@ -419,18 +422,18 @@ static int mma9553_init(struct mma9553_data *data)
|
|||
data->conf.sleepmin = MMA9553_DEFAULT_SLEEPMIN;
|
||||
data->conf.sleepmax = MMA9553_DEFAULT_SLEEPMAX;
|
||||
data->conf.sleepthd = MMA9553_DEFAULT_SLEEPTHD;
|
||||
data->conf.config =
|
||||
mma9553_set_bits(data->conf.config, 1, MMA9553_MASK_CONF_CONFIG);
|
||||
data->conf.config = mma9553_set_bits(data->conf.config, 1,
|
||||
MMA9553_MASK_CONF_CONFIG);
|
||||
/*
|
||||
* Clear the activity debounce counter when the activity level changes,
|
||||
* so that the confidence level applies for any activity level.
|
||||
*/
|
||||
data->conf.config = mma9553_set_bits(data->conf.config, 1,
|
||||
MMA9553_MASK_CONF_ACT_DBCNTM);
|
||||
ret =
|
||||
mma9551_write_config_words(data->client, MMA9551_APPID_PEDOMETER,
|
||||
MMA9553_REG_CONF_SLEEPMIN,
|
||||
sizeof(data->conf), (u16 *) &data->conf);
|
||||
ret = mma9551_write_config_words(data->client, MMA9551_APPID_PEDOMETER,
|
||||
MMA9553_REG_CONF_SLEEPMIN,
|
||||
sizeof(data->conf) / sizeof(u16),
|
||||
(u16 *)&data->conf);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev,
|
||||
"failed to write configuration registers\n");
|
||||
|
@ -567,7 +570,7 @@ static int mma9553_read_raw(struct iio_dev *indio_dev,
|
|||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_CALIBHEIGHT:
|
||||
tmp = mma9553_get_bits(data->conf.height_weight,
|
||||
MMA9553_MASK_CONF_HEIGHT);
|
||||
MMA9553_MASK_CONF_HEIGHT);
|
||||
*val = tmp / 100; /* cm to m */
|
||||
*val2 = (tmp % 100) * 10000;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
|
@ -719,7 +722,6 @@ static int mma9553_read_event_config(struct iio_dev *indio_dev,
|
|||
enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
|
||||
struct mma9553_data *data = iio_priv(indio_dev);
|
||||
struct mma9553_event *event;
|
||||
|
||||
|
@ -1026,22 +1028,22 @@ static irqreturn_t mma9553_event_handler(int irq, void *private)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
ev_prev_activity =
|
||||
mma9553_get_event(data, IIO_ACTIVITY,
|
||||
mma9553_activity_to_mod(data->activity),
|
||||
IIO_EV_DIR_FALLING);
|
||||
ev_activity =
|
||||
mma9553_get_event(data, IIO_ACTIVITY,
|
||||
mma9553_activity_to_mod(activity),
|
||||
IIO_EV_DIR_RISING);
|
||||
ev_step_detect =
|
||||
mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, IIO_EV_DIR_NONE);
|
||||
ev_prev_activity = mma9553_get_event(data, IIO_ACTIVITY,
|
||||
mma9553_activity_to_mod(
|
||||
data->activity),
|
||||
IIO_EV_DIR_FALLING);
|
||||
ev_activity = mma9553_get_event(data, IIO_ACTIVITY,
|
||||
mma9553_activity_to_mod(activity),
|
||||
IIO_EV_DIR_RISING);
|
||||
ev_step_detect = mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD,
|
||||
IIO_EV_DIR_NONE);
|
||||
|
||||
if (ev_step_detect->enabled && (stepcnt != data->stepcnt)) {
|
||||
data->stepcnt = stepcnt;
|
||||
iio_push_event(indio_dev,
|
||||
IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD,
|
||||
IIO_EV_DIR_NONE, IIO_EV_TYPE_CHANGE, 0, 0, 0),
|
||||
IIO_EV_DIR_NONE,
|
||||
IIO_EV_TYPE_CHANGE, 0, 0, 0),
|
||||
data->timestamp);
|
||||
}
|
||||
|
||||
|
@ -1051,17 +1053,19 @@ static irqreturn_t mma9553_event_handler(int irq, void *private)
|
|||
if (ev_prev_activity && ev_prev_activity->enabled)
|
||||
iio_push_event(indio_dev,
|
||||
IIO_EVENT_CODE(IIO_ACTIVITY, 0,
|
||||
ev_prev_activity->info->mod,
|
||||
IIO_EV_DIR_FALLING,
|
||||
IIO_EV_TYPE_THRESH, 0, 0, 0),
|
||||
ev_prev_activity->info->mod,
|
||||
IIO_EV_DIR_FALLING,
|
||||
IIO_EV_TYPE_THRESH, 0, 0,
|
||||
0),
|
||||
data->timestamp);
|
||||
|
||||
if (ev_activity && ev_activity->enabled)
|
||||
iio_push_event(indio_dev,
|
||||
IIO_EVENT_CODE(IIO_ACTIVITY, 0,
|
||||
ev_activity->info->mod,
|
||||
IIO_EV_DIR_RISING,
|
||||
IIO_EV_TYPE_THRESH, 0, 0, 0),
|
||||
ev_activity->info->mod,
|
||||
IIO_EV_DIR_RISING,
|
||||
IIO_EV_TYPE_THRESH, 0, 0,
|
||||
0),
|
||||
data->timestamp);
|
||||
}
|
||||
mutex_unlock(&data->mutex);
|
||||
|
@ -1156,7 +1160,6 @@ static int mma9553_probe(struct i2c_client *client,
|
|||
client->irq);
|
||||
goto out_poweroff;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
|
|
|
@ -122,7 +122,6 @@ MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
|
|||
|
||||
static struct i2c_driver st_accel_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "st-accel-i2c",
|
||||
.of_match_table = of_match_ptr(st_accel_of_match),
|
||||
},
|
||||
|
|
|
@ -11,17 +11,25 @@
|
|||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
|
||||
#define STK8312_REG_XOUT 0x00
|
||||
#define STK8312_REG_YOUT 0x01
|
||||
#define STK8312_REG_ZOUT 0x02
|
||||
#define STK8312_REG_INTSU 0x06
|
||||
#define STK8312_REG_MODE 0x07
|
||||
#define STK8312_REG_SR 0x08
|
||||
#define STK8312_REG_STH 0x13
|
||||
#define STK8312_REG_RESET 0x20
|
||||
#define STK8312_REG_AFECTRL 0x24
|
||||
|
@ -29,14 +37,21 @@
|
|||
#define STK8312_REG_OTPDATA 0x3E
|
||||
#define STK8312_REG_OTPCTRL 0x3F
|
||||
|
||||
#define STK8312_MODE_ACTIVE 1
|
||||
#define STK8312_MODE_STANDBY 0
|
||||
#define STK8312_MODE_MASK 0x01
|
||||
#define STK8312_MODE_ACTIVE 0x01
|
||||
#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_RNG_SHIFT 6
|
||||
#define STK8312_READ_RETRIES 16
|
||||
#define STK8312_ALL_CHANNEL_MASK 7
|
||||
#define STK8312_ALL_CHANNEL_SIZE 3
|
||||
|
||||
#define STK8312_DRIVER_NAME "stk8312"
|
||||
#define STK8312_GPIO "stk8312_gpio"
|
||||
#define STK8312_IRQ_NAME "stk8312_event"
|
||||
|
||||
/*
|
||||
* The accelerometer has two measurement ranges:
|
||||
|
@ -53,32 +68,56 @@ static const int stk8312_scale_table[][2] = {
|
|||
{0, 461600}, {1, 231100}
|
||||
};
|
||||
|
||||
#define STK8312_ACCEL_CHANNEL(reg, axis) { \
|
||||
.type = IIO_ACCEL, \
|
||||
.address = reg, \
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_##axis, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
static const struct {
|
||||
u16 val;
|
||||
u32 val2;
|
||||
} stk8312_samp_freq_table[] = {
|
||||
{400, 0}, {200, 0}, {100, 0}, {50, 0}, {25, 0},
|
||||
{12, 500000}, {6, 250000}, {3, 125000}
|
||||
};
|
||||
|
||||
#define STK8312_ACCEL_CHANNEL(index, reg, axis) { \
|
||||
.type = IIO_ACCEL, \
|
||||
.address = reg, \
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_##axis, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.scan_index = index, \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = 8, \
|
||||
.storagebits = 8, \
|
||||
.endianness = IIO_CPU, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec stk8312_channels[] = {
|
||||
STK8312_ACCEL_CHANNEL(STK8312_REG_XOUT, X),
|
||||
STK8312_ACCEL_CHANNEL(STK8312_REG_YOUT, Y),
|
||||
STK8312_ACCEL_CHANNEL(STK8312_REG_ZOUT, Z),
|
||||
STK8312_ACCEL_CHANNEL(0, STK8312_REG_XOUT, X),
|
||||
STK8312_ACCEL_CHANNEL(1, STK8312_REG_YOUT, Y),
|
||||
STK8312_ACCEL_CHANNEL(2, STK8312_REG_ZOUT, Z),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(3),
|
||||
};
|
||||
|
||||
struct stk8312_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
int range;
|
||||
u8 sample_rate_idx;
|
||||
u8 mode;
|
||||
struct iio_trigger *dready_trig;
|
||||
bool dready_trigger_on;
|
||||
s8 buffer[16]; /* 3x8-bit channels + 5x8 padding + 64-bit timestamp */
|
||||
};
|
||||
|
||||
static IIO_CONST_ATTR(in_accel_scale_available, STK8312_SCALE_AVAIL);
|
||||
|
||||
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("3.125 6.25 12.5 25 50 100 200 400");
|
||||
|
||||
static struct attribute *stk8312_attributes[] = {
|
||||
&iio_const_attr_in_accel_scale_available.dev_attr.attr,
|
||||
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
@ -130,31 +169,19 @@ exit_err:
|
|||
static int stk8312_set_mode(struct stk8312_data *data, u8 mode)
|
||||
{
|
||||
int ret;
|
||||
u8 masked_reg;
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
if (mode > 1)
|
||||
return -EINVAL;
|
||||
else if (mode == data->mode)
|
||||
if (mode == data->mode)
|
||||
return 0;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, STK8312_REG_MODE);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "failed to change sensor mode\n");
|
||||
return ret;
|
||||
}
|
||||
masked_reg = ret & (~STK8312_MODE_MASK);
|
||||
masked_reg |= mode;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client,
|
||||
STK8312_REG_MODE, masked_reg);
|
||||
ret = i2c_smbus_write_byte_data(client, STK8312_REG_MODE, mode);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "failed to change sensor mode\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->mode = mode;
|
||||
if (mode == STK8312_MODE_ACTIVE) {
|
||||
if (mode & STK8312_MODE_ACTIVE) {
|
||||
/* Need to run OTP sequence before entering active mode */
|
||||
usleep_range(1000, 5000);
|
||||
ret = stk8312_otp_init(data);
|
||||
|
@ -163,6 +190,85 @@ static int stk8312_set_mode(struct stk8312_data *data, u8 mode)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int stk8312_set_interrupts(struct stk8312_data *data, u8 int_mask)
|
||||
{
|
||||
int ret;
|
||||
u8 mode;
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
mode = data->mode;
|
||||
/* We need to go in standby mode to modify registers */
|
||||
ret = stk8312_set_mode(data, STK8312_MODE_STANDBY);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, STK8312_REG_INTSU, int_mask);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "failed to set interrupts\n");
|
||||
|
||||
return stk8312_set_mode(data, mode);
|
||||
}
|
||||
|
||||
static int stk8312_data_rdy_trigger_set_state(struct iio_trigger *trig,
|
||||
bool state)
|
||||
{
|
||||
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
|
||||
struct stk8312_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
if (state)
|
||||
ret = stk8312_set_interrupts(data, STK8312_DREADY_BIT);
|
||||
else
|
||||
ret = stk8312_set_interrupts(data, 0x00);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "failed to set trigger state\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->dready_trigger_on = state;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct iio_trigger_ops stk8312_trigger_ops = {
|
||||
.set_trigger_state = stk8312_data_rdy_trigger_set_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int stk8312_set_sample_rate(struct stk8312_data *data, int rate)
|
||||
{
|
||||
int ret;
|
||||
u8 masked_reg;
|
||||
u8 mode;
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
if (rate == data->sample_rate_idx)
|
||||
return 0;
|
||||
|
||||
mode = data->mode;
|
||||
/* We need to go in standby mode to modify registers */
|
||||
ret = stk8312_set_mode(data, STK8312_MODE_STANDBY);
|
||||
if (ret < 0)
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
return stk8312_set_mode(data, mode);
|
||||
}
|
||||
|
||||
static int stk8312_set_range(struct stk8312_data *data, u8 range)
|
||||
{
|
||||
int ret;
|
||||
|
@ -208,12 +314,10 @@ static int stk8312_read_accel(struct stk8312_data *data, u8 address)
|
|||
return -EINVAL;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, address);
|
||||
if (ret < 0) {
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "register read failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return sign_extend32(ret, 7);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stk8312_read_raw(struct iio_dev *indio_dev,
|
||||
|
@ -221,20 +325,37 @@ static int stk8312_read_raw(struct iio_dev *indio_dev,
|
|||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct stk8312_data *data = iio_priv(indio_dev);
|
||||
|
||||
if (chan->type != IIO_ACCEL)
|
||||
return -EINVAL;
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (iio_buffer_enabled(indio_dev))
|
||||
return -EBUSY;
|
||||
mutex_lock(&data->lock);
|
||||
*val = stk8312_read_accel(data, chan->address);
|
||||
ret = stk8312_set_mode(data, data->mode | STK8312_MODE_ACTIVE);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
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;
|
||||
}
|
||||
*val = sign_extend32(ret, 7);
|
||||
stk8312_set_mode(data, data->mode & (~STK8312_MODE_ACTIVE));
|
||||
mutex_unlock(&data->lock);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = stk8312_scale_table[data->range - 1][0];
|
||||
*val2 = stk8312_scale_table[data->range - 1][1];
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*val = stk8312_samp_freq_table[data->sample_rate_idx].val;
|
||||
*val2 = stk8312_samp_freq_table[data->sample_rate_idx].val2;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
@ -264,6 +385,20 @@ static int stk8312_write_raw(struct iio_dev *indio_dev,
|
|||
ret = stk8312_set_range(data, index);
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
for (i = 0; i < ARRAY_SIZE(stk8312_samp_freq_table); i++)
|
||||
if (val == stk8312_samp_freq_table[i].val &&
|
||||
val2 == stk8312_samp_freq_table[i].val2) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
if (index < 0)
|
||||
return -EINVAL;
|
||||
mutex_lock(&data->lock);
|
||||
ret = stk8312_set_sample_rate(data, index);
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -277,6 +412,109 @@ static const struct iio_info stk8312_info = {
|
|||
.attrs = &stk8312_attribute_group,
|
||||
};
|
||||
|
||||
static irqreturn_t stk8312_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = 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);
|
||||
/*
|
||||
* Do a bulk read if all channels are requested,
|
||||
* from 0x00 (XOUT) to 0x02 (ZOUT)
|
||||
*/
|
||||
if (*(indio_dev->active_scan_mask) == STK8312_ALL_CHANNEL_MASK) {
|
||||
ret = i2c_smbus_read_i2c_block_data(data->client,
|
||||
STK8312_REG_XOUT,
|
||||
STK8312_ALL_CHANNEL_SIZE,
|
||||
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) {
|
||||
ret = stk8312_read_accel(data, bit);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->lock);
|
||||
goto err;
|
||||
}
|
||||
data->buffer[i++] = ret;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
pf->timestamp);
|
||||
err:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t stk8312_data_rdy_trig_poll(int irq, void *private)
|
||||
{
|
||||
struct iio_dev *indio_dev = private;
|
||||
struct stk8312_data *data = iio_priv(indio_dev);
|
||||
|
||||
if (data->dready_trigger_on)
|
||||
iio_trigger_poll(data->dready_trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int stk8312_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct stk8312_data *data = iio_priv(indio_dev);
|
||||
|
||||
return stk8312_set_mode(data, data->mode | STK8312_MODE_ACTIVE);
|
||||
}
|
||||
|
||||
static int stk8312_buffer_postdisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct stk8312_data *data = iio_priv(indio_dev);
|
||||
|
||||
return stk8312_set_mode(data, data->mode & (~STK8312_MODE_ACTIVE));
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops stk8312_buffer_setup_ops = {
|
||||
.preenable = stk8312_buffer_preenable,
|
||||
.postenable = iio_triggered_buffer_postenable,
|
||||
.predisable = iio_triggered_buffer_predisable,
|
||||
.postdisable = stk8312_buffer_postdisable,
|
||||
};
|
||||
|
||||
static int stk8312_gpio_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev;
|
||||
struct gpio_desc *gpio;
|
||||
int ret;
|
||||
|
||||
if (!client)
|
||||
return -EINVAL;
|
||||
|
||||
dev = &client->dev;
|
||||
|
||||
/* data ready gpio interrupt pin */
|
||||
gpio = devm_gpiod_get_index(dev, STK8312_GPIO, 0, GPIOD_IN);
|
||||
if (IS_ERR(gpio)) {
|
||||
dev_err(dev, "acpi gpio get index failed\n");
|
||||
return PTR_ERR(gpio);
|
||||
}
|
||||
|
||||
ret = gpiod_to_irq(gpio);
|
||||
dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stk8312_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -308,30 +546,90 @@ static int stk8312_probe(struct i2c_client *client,
|
|||
dev_err(&client->dev, "failed to reset sensor\n");
|
||||
return ret;
|
||||
}
|
||||
data->sample_rate_idx = STK8312_SR_400HZ_IDX;
|
||||
ret = stk8312_set_range(data, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = stk8312_set_mode(data, STK8312_MODE_ACTIVE);
|
||||
ret = stk8312_set_mode(data, STK8312_INT_MODE | STK8312_MODE_ACTIVE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (client->irq < 0)
|
||||
client->irq = stk8312_gpio_probe(client);
|
||||
|
||||
if (client->irq >= 0) {
|
||||
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
stk8312_data_rdy_trig_poll,
|
||||
NULL,
|
||||
IRQF_TRIGGER_RISING |
|
||||
IRQF_ONESHOT,
|
||||
STK8312_IRQ_NAME,
|
||||
indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "request irq %d failed\n",
|
||||
client->irq);
|
||||
goto err_power_off;
|
||||
}
|
||||
|
||||
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
|
||||
"%s-dev%d",
|
||||
indio_dev->name,
|
||||
indio_dev->id);
|
||||
if (!data->dready_trig) {
|
||||
ret = -ENOMEM;
|
||||
goto err_power_off;
|
||||
}
|
||||
|
||||
data->dready_trig->dev.parent = &client->dev;
|
||||
data->dready_trig->ops = &stk8312_trigger_ops;
|
||||
iio_trigger_set_drvdata(data->dready_trig, indio_dev);
|
||||
ret = iio_trigger_register(data->dready_trig);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "iio trigger register failed\n");
|
||||
goto err_power_off;
|
||||
}
|
||||
}
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev,
|
||||
iio_pollfunc_store_time,
|
||||
stk8312_trigger_handler,
|
||||
&stk8312_buffer_setup_ops);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "iio triggered buffer setup failed\n");
|
||||
goto err_trigger_unregister;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "device_register failed\n");
|
||||
stk8312_set_mode(data, STK8312_MODE_STANDBY);
|
||||
goto err_buffer_cleanup;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_buffer_cleanup:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
err_trigger_unregister:
|
||||
if (data->dready_trig)
|
||||
iio_trigger_unregister(data->dready_trig);
|
||||
err_power_off:
|
||||
stk8312_set_mode(data, STK8312_MODE_STANDBY);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stk8312_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
struct stk8312_data *data = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
|
||||
return stk8312_set_mode(iio_priv(indio_dev), STK8312_MODE_STANDBY);
|
||||
if (data->dready_trig)
|
||||
iio_trigger_unregister(data->dready_trig);
|
||||
|
||||
return stk8312_set_mode(data, STK8312_MODE_STANDBY);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
@ -341,7 +639,7 @@ static int stk8312_suspend(struct device *dev)
|
|||
|
||||
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
|
||||
|
||||
return stk8312_set_mode(data, STK8312_MODE_STANDBY);
|
||||
return stk8312_set_mode(data, data->mode & (~STK8312_MODE_ACTIVE));
|
||||
}
|
||||
|
||||
static int stk8312_resume(struct device *dev)
|
||||
|
@ -350,7 +648,7 @@ static int stk8312_resume(struct device *dev)
|
|||
|
||||
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
|
||||
|
||||
return stk8312_set_mode(data, STK8312_MODE_ACTIVE);
|
||||
return stk8312_set_mode(data, data->mode | STK8312_MODE_ACTIVE);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend, stk8312_resume);
|
||||
|
|
|
@ -11,26 +11,42 @@
|
|||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
|
||||
#define STK8BA50_REG_XOUT 0x02
|
||||
#define STK8BA50_REG_YOUT 0x04
|
||||
#define STK8BA50_REG_ZOUT 0x06
|
||||
#define STK8BA50_REG_RANGE 0x0F
|
||||
#define STK8BA50_REG_BWSEL 0x10
|
||||
#define STK8BA50_REG_POWMODE 0x11
|
||||
#define STK8BA50_REG_SWRST 0x14
|
||||
#define STK8BA50_REG_INTEN2 0x17
|
||||
#define STK8BA50_REG_INTMAP2 0x1A
|
||||
|
||||
#define STK8BA50_MODE_NORMAL 0
|
||||
#define STK8BA50_MODE_SUSPEND 1
|
||||
#define STK8BA50_MODE_POWERBIT BIT(7)
|
||||
#define STK8BA50_DATA_SHIFT 6
|
||||
#define STK8BA50_RESET_CMD 0xB6
|
||||
#define STK8BA50_SR_1792HZ_IDX 7
|
||||
#define STK8BA50_DREADY_INT_MASK 0x10
|
||||
#define STK8BA50_DREADY_INT_MAP 0x81
|
||||
#define STK8BA50_ALL_CHANNEL_MASK 7
|
||||
#define STK8BA50_ALL_CHANNEL_SIZE 6
|
||||
|
||||
#define STK8BA50_DRIVER_NAME "stk8ba50"
|
||||
#define STK8BA50_GPIO "stk8ba50_gpio"
|
||||
#define STK8BA50_IRQ_NAME "stk8ba50_event"
|
||||
|
||||
#define STK8BA50_SCALE_AVAIL "0.0384 0.0767 0.1534 0.3069"
|
||||
|
||||
|
@ -50,35 +66,76 @@
|
|||
*
|
||||
* Locally, the range is stored as a table index.
|
||||
*/
|
||||
static const int stk8ba50_scale_table[][2] = {
|
||||
static const struct {
|
||||
u8 reg_val;
|
||||
u32 scale_val;
|
||||
} stk8ba50_scale_table[] = {
|
||||
{3, 38400}, {5, 76700}, {8, 153400}, {12, 306900}
|
||||
};
|
||||
|
||||
/* Sample rates are stored as { <register value>, <Hz value> } */
|
||||
static const struct {
|
||||
u8 reg_val;
|
||||
u16 samp_freq;
|
||||
} stk8ba50_samp_freq_table[] = {
|
||||
{0x08, 14}, {0x09, 25}, {0x0A, 56}, {0x0B, 112},
|
||||
{0x0C, 224}, {0x0D, 448}, {0x0E, 896}, {0x0F, 1792}
|
||||
};
|
||||
|
||||
/* Used to map scan mask bits to their corresponding channel register. */
|
||||
static const int stk8ba50_channel_table[] = {
|
||||
STK8BA50_REG_XOUT,
|
||||
STK8BA50_REG_YOUT,
|
||||
STK8BA50_REG_ZOUT
|
||||
};
|
||||
|
||||
struct stk8ba50_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
int range;
|
||||
u8 sample_rate_idx;
|
||||
struct iio_trigger *dready_trig;
|
||||
bool dready_trigger_on;
|
||||
/*
|
||||
* 3 x 16-bit channels (10-bit data, 6-bit padding) +
|
||||
* 1 x 16 padding +
|
||||
* 4 x 16 64-bit timestamp
|
||||
*/
|
||||
s16 buffer[8];
|
||||
};
|
||||
|
||||
#define STK8BA50_ACCEL_CHANNEL(reg, axis) { \
|
||||
.type = IIO_ACCEL, \
|
||||
.address = reg, \
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_##axis, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
#define STK8BA50_ACCEL_CHANNEL(index, reg, axis) { \
|
||||
.type = IIO_ACCEL, \
|
||||
.address = reg, \
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_##axis, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.scan_index = index, \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = 10, \
|
||||
.storagebits = 16, \
|
||||
.shift = STK8BA50_DATA_SHIFT, \
|
||||
.endianness = IIO_CPU, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec stk8ba50_channels[] = {
|
||||
STK8BA50_ACCEL_CHANNEL(STK8BA50_REG_XOUT, X),
|
||||
STK8BA50_ACCEL_CHANNEL(STK8BA50_REG_YOUT, Y),
|
||||
STK8BA50_ACCEL_CHANNEL(STK8BA50_REG_ZOUT, Z),
|
||||
STK8BA50_ACCEL_CHANNEL(0, STK8BA50_REG_XOUT, X),
|
||||
STK8BA50_ACCEL_CHANNEL(1, STK8BA50_REG_YOUT, Y),
|
||||
STK8BA50_ACCEL_CHANNEL(2, STK8BA50_REG_ZOUT, Z),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(3),
|
||||
};
|
||||
|
||||
static IIO_CONST_ATTR(in_accel_scale_available, STK8BA50_SCALE_AVAIL);
|
||||
|
||||
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("14 25 56 112 224 448 896 1792");
|
||||
|
||||
static struct attribute *stk8ba50_attributes[] = {
|
||||
&iio_const_attr_in_accel_scale_available.dev_attr.attr,
|
||||
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
@ -97,72 +154,34 @@ static int stk8ba50_read_accel(struct stk8ba50_data *data, u8 reg)
|
|||
return ret;
|
||||
}
|
||||
|
||||
return sign_extend32(ret >> STK8BA50_DATA_SHIFT, 9);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stk8ba50_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
static int stk8ba50_data_rdy_trigger_set_state(struct iio_trigger *trig,
|
||||
bool state)
|
||||
{
|
||||
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
|
||||
struct stk8ba50_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
mutex_lock(&data->lock);
|
||||
*val = stk8ba50_read_accel(data, chan->address);
|
||||
mutex_unlock(&data->lock);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 0;
|
||||
*val2 = stk8ba50_scale_table[data->range][1];
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int stk8ba50_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
int index = -1;
|
||||
struct stk8ba50_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
if (val != 0)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(stk8ba50_scale_table); i++)
|
||||
if (val2 == stk8ba50_scale_table[i][1]) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
if (index < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (state)
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
STK8BA50_REG_RANGE,
|
||||
stk8ba50_scale_table[index][0]);
|
||||
if (ret < 0)
|
||||
dev_err(&data->client->dev,
|
||||
"failed to set measurement range\n");
|
||||
else
|
||||
data->range = index;
|
||||
STK8BA50_REG_INTEN2, STK8BA50_DREADY_INT_MASK);
|
||||
else
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
STK8BA50_REG_INTEN2, 0x00);
|
||||
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
dev_err(&data->client->dev, "failed to set trigger state\n");
|
||||
else
|
||||
data->dready_trigger_on = state;
|
||||
|
||||
return -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct iio_info stk8ba50_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.read_raw = stk8ba50_read_raw,
|
||||
.write_raw = stk8ba50_write_raw,
|
||||
.attrs = &stk8ba50_attribute_group,
|
||||
static const struct iio_trigger_ops stk8ba50_trigger_ops = {
|
||||
.set_trigger_state = stk8ba50_data_rdy_trigger_set_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int stk8ba50_set_power(struct stk8ba50_data *data, bool mode)
|
||||
|
@ -192,6 +211,207 @@ exit_err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int stk8ba50_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct stk8ba50_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (iio_buffer_enabled(indio_dev))
|
||||
return -EBUSY;
|
||||
mutex_lock(&data->lock);
|
||||
ret = stk8ba50_set_power(data, STK8BA50_MODE_NORMAL);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = stk8ba50_read_accel(data, chan->address);
|
||||
if (ret < 0) {
|
||||
stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND);
|
||||
mutex_unlock(&data->lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
*val = sign_extend32(ret >> STK8BA50_DATA_SHIFT, 9);
|
||||
stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND);
|
||||
mutex_unlock(&data->lock);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 0;
|
||||
*val2 = stk8ba50_scale_table[data->range].scale_val;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*val = stk8ba50_samp_freq_table
|
||||
[data->sample_rate_idx].samp_freq;
|
||||
*val2 = 0;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int stk8ba50_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
int index = -1;
|
||||
struct stk8ba50_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
if (val != 0)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(stk8ba50_scale_table); i++)
|
||||
if (val2 == stk8ba50_scale_table[i].scale_val) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
if (index < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
STK8BA50_REG_RANGE,
|
||||
stk8ba50_scale_table[index].reg_val);
|
||||
if (ret < 0)
|
||||
dev_err(&data->client->dev,
|
||||
"failed to set measurement range\n");
|
||||
else
|
||||
data->range = index;
|
||||
|
||||
return ret;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
for (i = 0; i < ARRAY_SIZE(stk8ba50_samp_freq_table); i++)
|
||||
if (val == stk8ba50_samp_freq_table[i].samp_freq) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
if (index < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
STK8BA50_REG_BWSEL,
|
||||
stk8ba50_samp_freq_table[index].reg_val);
|
||||
if (ret < 0)
|
||||
dev_err(&data->client->dev,
|
||||
"failed to set sampling rate\n");
|
||||
else
|
||||
data->sample_rate_idx = index;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct iio_info stk8ba50_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.read_raw = stk8ba50_read_raw,
|
||||
.write_raw = stk8ba50_write_raw,
|
||||
.attrs = &stk8ba50_attribute_group,
|
||||
};
|
||||
|
||||
static irqreturn_t stk8ba50_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct stk8ba50_data *data = iio_priv(indio_dev);
|
||||
int bit, ret, i = 0;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
/*
|
||||
* Do a bulk read if all channels are requested,
|
||||
* from 0x02 (XOUT1) to 0x07 (ZOUT2)
|
||||
*/
|
||||
if (*(indio_dev->active_scan_mask) == STK8BA50_ALL_CHANNEL_MASK) {
|
||||
ret = i2c_smbus_read_i2c_block_data(data->client,
|
||||
STK8BA50_REG_XOUT,
|
||||
STK8BA50_ALL_CHANNEL_SIZE,
|
||||
(u8 *)data->buffer);
|
||||
if (ret < STK8BA50_ALL_CHANNEL_SIZE) {
|
||||
dev_err(&data->client->dev, "register read failed\n");
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
ret = stk8ba50_read_accel(data,
|
||||
stk8ba50_channel_table[bit]);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
data->buffer[i++] = ret;
|
||||
}
|
||||
}
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
pf->timestamp);
|
||||
err:
|
||||
mutex_unlock(&data->lock);
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t stk8ba50_data_rdy_trig_poll(int irq, void *private)
|
||||
{
|
||||
struct iio_dev *indio_dev = private;
|
||||
struct stk8ba50_data *data = iio_priv(indio_dev);
|
||||
|
||||
if (data->dready_trigger_on)
|
||||
iio_trigger_poll(data->dready_trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int stk8ba50_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct stk8ba50_data *data = iio_priv(indio_dev);
|
||||
|
||||
return stk8ba50_set_power(data, STK8BA50_MODE_NORMAL);
|
||||
}
|
||||
|
||||
static int stk8ba50_buffer_postdisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct stk8ba50_data *data = iio_priv(indio_dev);
|
||||
|
||||
return stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND);
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops stk8ba50_buffer_setup_ops = {
|
||||
.preenable = stk8ba50_buffer_preenable,
|
||||
.postenable = iio_triggered_buffer_postenable,
|
||||
.predisable = iio_triggered_buffer_predisable,
|
||||
.postdisable = stk8ba50_buffer_postdisable,
|
||||
};
|
||||
|
||||
static int stk8ba50_gpio_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev;
|
||||
struct gpio_desc *gpio;
|
||||
int ret;
|
||||
|
||||
if (!client)
|
||||
return -EINVAL;
|
||||
|
||||
dev = &client->dev;
|
||||
|
||||
/* data ready gpio interrupt pin */
|
||||
gpio = devm_gpiod_get_index(dev, STK8BA50_GPIO, 0, GPIOD_IN);
|
||||
if (IS_ERR(gpio)) {
|
||||
dev_err(dev, "acpi gpio get index failed\n");
|
||||
return PTR_ERR(gpio);
|
||||
}
|
||||
|
||||
ret = gpiod_to_irq(gpio);
|
||||
dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stk8ba50_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -222,28 +442,104 @@ static int stk8ba50_probe(struct i2c_client *client,
|
|||
STK8BA50_REG_SWRST, STK8BA50_RESET_CMD);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "failed to reset sensor\n");
|
||||
return ret;
|
||||
goto err_power_off;
|
||||
}
|
||||
|
||||
/* The default range is +/-2g */
|
||||
data->range = 0;
|
||||
|
||||
/* The default sampling rate is 1792 Hz (maximum) */
|
||||
data->sample_rate_idx = STK8BA50_SR_1792HZ_IDX;
|
||||
|
||||
/* Set up interrupts */
|
||||
ret = i2c_smbus_write_byte_data(client,
|
||||
STK8BA50_REG_INTEN2, STK8BA50_DREADY_INT_MASK);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "failed to set up interrupts\n");
|
||||
goto err_power_off;
|
||||
}
|
||||
ret = i2c_smbus_write_byte_data(client,
|
||||
STK8BA50_REG_INTMAP2, STK8BA50_DREADY_INT_MAP);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "failed to set up interrupts\n");
|
||||
goto err_power_off;
|
||||
}
|
||||
|
||||
if (client->irq < 0)
|
||||
client->irq = stk8ba50_gpio_probe(client);
|
||||
|
||||
if (client->irq >= 0) {
|
||||
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
stk8ba50_data_rdy_trig_poll,
|
||||
NULL,
|
||||
IRQF_TRIGGER_RISING |
|
||||
IRQF_ONESHOT,
|
||||
STK8BA50_IRQ_NAME,
|
||||
indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "request irq %d failed\n",
|
||||
client->irq);
|
||||
goto err_power_off;
|
||||
}
|
||||
|
||||
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
|
||||
"%s-dev%d",
|
||||
indio_dev->name,
|
||||
indio_dev->id);
|
||||
if (!data->dready_trig) {
|
||||
ret = -ENOMEM;
|
||||
goto err_power_off;
|
||||
}
|
||||
|
||||
data->dready_trig->dev.parent = &client->dev;
|
||||
data->dready_trig->ops = &stk8ba50_trigger_ops;
|
||||
iio_trigger_set_drvdata(data->dready_trig, indio_dev);
|
||||
ret = iio_trigger_register(data->dready_trig);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "iio trigger register failed\n");
|
||||
goto err_power_off;
|
||||
}
|
||||
}
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev,
|
||||
iio_pollfunc_store_time,
|
||||
stk8ba50_trigger_handler,
|
||||
&stk8ba50_buffer_setup_ops);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "iio triggered buffer setup failed\n");
|
||||
goto err_trigger_unregister;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "device_register failed\n");
|
||||
stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND);
|
||||
goto err_buffer_cleanup;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_buffer_cleanup:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
err_trigger_unregister:
|
||||
if (data->dready_trig)
|
||||
iio_trigger_unregister(data->dready_trig);
|
||||
err_power_off:
|
||||
stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stk8ba50_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
struct stk8ba50_data *data = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
|
||||
return stk8ba50_set_power(iio_priv(indio_dev), STK8BA50_MODE_SUSPEND);
|
||||
if (data->dready_trig)
|
||||
iio_trigger_unregister(data->dready_trig);
|
||||
|
||||
return stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
|
|
@ -20,6 +20,9 @@ config AD7266
|
|||
Say yes here to build support for Analog Devices AD7265 and AD7266
|
||||
ADCs.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called ad7266.
|
||||
|
||||
config AD7291
|
||||
tristate "Analog Devices AD7291 ADC driver"
|
||||
depends on I2C
|
||||
|
@ -52,8 +55,6 @@ config AD7476
|
|||
AD7277, AD7278, AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468,
|
||||
AD7495, AD7910, AD7920, AD7920 SPI analog to digital converters (ADC).
|
||||
|
||||
If unsure, say N (but it's safe to say "Y").
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ad7476.
|
||||
|
||||
|
@ -63,8 +64,7 @@ config AD7791
|
|||
select AD_SIGMA_DELTA
|
||||
help
|
||||
Say yes here to build support for Analog Devices AD7787, AD7788, AD7789,
|
||||
AD7790 and AD7791 SPI analog to digital converters (ADC). If unsure, say
|
||||
N (but it is safe to say "Y").
|
||||
AD7790 and AD7791 SPI analog to digital converters (ADC).
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called ad7791.
|
||||
|
@ -76,7 +76,6 @@ config AD7793
|
|||
help
|
||||
Say yes here to build support for Analog Devices AD7785, AD7792, AD7793,
|
||||
AD7794 and AD7795 SPI analog to digital converters (ADC).
|
||||
If unsure, say N (but it's safe to say "Y").
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called AD7793.
|
||||
|
@ -89,7 +88,6 @@ config AD7887
|
|||
help
|
||||
Say yes here to build support for Analog Devices
|
||||
AD7887 SPI analog to digital converter (ADC).
|
||||
If unsure, say N (but it's safe to say "Y").
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ad7887.
|
||||
|
@ -117,6 +115,9 @@ config AD799X
|
|||
i2c analog to digital converters (ADC). Provides direct access
|
||||
via sysfs.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called ad799x.
|
||||
|
||||
config AT91_ADC
|
||||
tristate "Atmel AT91 ADC"
|
||||
depends on ARCH_AT91
|
||||
|
@ -127,6 +128,9 @@ config AT91_ADC
|
|||
help
|
||||
Say yes here to build support for Atmel AT91 ADC.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called at91_adc.
|
||||
|
||||
config AXP288_ADC
|
||||
tristate "X-Powers AXP288 ADC driver"
|
||||
depends on MFD_AXP20X
|
||||
|
@ -135,6 +139,9 @@ config AXP288_ADC
|
|||
device. Depending on platform configuration, this general purpose ADC can
|
||||
be used for sampling sensors such as thermal resistors.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called axp288_adc.
|
||||
|
||||
config BERLIN2_ADC
|
||||
tristate "Marvell Berlin2 ADC driver"
|
||||
depends on ARCH_BERLIN
|
||||
|
@ -151,6 +158,9 @@ config DA9150_GPADC
|
|||
This driver can also be built as a module. If chosen, the module name
|
||||
will be da9150-gpadc.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called berlin2-adc.
|
||||
|
||||
config CC10001_ADC
|
||||
tristate "Cosmic Circuits 10001 ADC driver"
|
||||
depends on HAVE_CLK || REGULATOR
|
||||
|
@ -171,12 +181,18 @@ config EXYNOS_ADC
|
|||
of SoCs for drivers such as the touchscreen and hwmon to use to share
|
||||
this resource.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called exynos_adc.
|
||||
|
||||
config LP8788_ADC
|
||||
tristate "LP8788 ADC driver"
|
||||
depends on MFD_LP8788
|
||||
help
|
||||
Say yes here to build support for TI LP8788 ADC.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called lp8788_adc.
|
||||
|
||||
config MAX1027
|
||||
tristate "Maxim max1027 ADC driver"
|
||||
depends on SPI
|
||||
|
@ -186,6 +202,9 @@ config MAX1027
|
|||
Say yes here to build support for Maxim SPI ADC models
|
||||
max1027, max1029 and max1031.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called max1027.
|
||||
|
||||
config MAX1363
|
||||
tristate "Maxim max1363 ADC driver"
|
||||
depends on I2C
|
||||
|
@ -202,6 +221,9 @@ config MAX1363
|
|||
max11646, max11647) Provides direct access via sysfs and buffered
|
||||
data via the iio dev interface.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called max1363.
|
||||
|
||||
config MCP320X
|
||||
tristate "Microchip Technology MCP3x01/02/04/08"
|
||||
depends on SPI
|
||||
|
@ -310,15 +332,18 @@ config TI_AM335X_ADC
|
|||
Say yes here to build support for Texas Instruments ADC
|
||||
driver which is also a MFD client.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called ti_am335x_adc.
|
||||
|
||||
config TWL4030_MADC
|
||||
tristate "TWL4030 MADC (Monitoring A/D Converter)"
|
||||
depends on TWL4030_CORE
|
||||
help
|
||||
This driver provides support for Triton TWL4030-MADC. The
|
||||
driver supports both RT and SW conversion methods.
|
||||
This driver provides support for Triton TWL4030-MADC. The
|
||||
driver supports both RT and SW conversion methods.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called twl4030-madc.
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called twl4030-madc.
|
||||
|
||||
config TWL6030_GPADC
|
||||
tristate "TWL6030 GPADC (General Purpose A/D Converter) Support"
|
||||
|
@ -351,6 +376,9 @@ config VIPERBOARD_ADC
|
|||
Say yes here to access the ADC part of the Nano River
|
||||
Technologies Viperboard.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called viperboard_adc.
|
||||
|
||||
config XILINX_XADC
|
||||
tristate "Xilinx XADC driver"
|
||||
depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST
|
||||
|
|
|
@ -62,6 +62,7 @@ struct cc10001_adc_device {
|
|||
struct regulator *reg;
|
||||
u16 *buf;
|
||||
|
||||
bool shared;
|
||||
struct mutex lock;
|
||||
unsigned int start_delay_ns;
|
||||
unsigned int eoc_delay_ns;
|
||||
|
@ -153,7 +154,8 @@ static irqreturn_t cc10001_adc_trigger_h(int irq, void *p)
|
|||
|
||||
mutex_lock(&adc_dev->lock);
|
||||
|
||||
cc10001_adc_power_up(adc_dev);
|
||||
if (!adc_dev->shared)
|
||||
cc10001_adc_power_up(adc_dev);
|
||||
|
||||
/* Calculate delay step for eoc and sampled data */
|
||||
delay_ns = adc_dev->eoc_delay_ns / CC10001_MAX_POLL_COUNT;
|
||||
|
@ -177,7 +179,8 @@ static irqreturn_t cc10001_adc_trigger_h(int irq, void *p)
|
|||
}
|
||||
|
||||
done:
|
||||
cc10001_adc_power_down(adc_dev);
|
||||
if (!adc_dev->shared)
|
||||
cc10001_adc_power_down(adc_dev);
|
||||
|
||||
mutex_unlock(&adc_dev->lock);
|
||||
|
||||
|
@ -196,7 +199,8 @@ static u16 cc10001_adc_read_raw_voltage(struct iio_dev *indio_dev,
|
|||
unsigned int delay_ns;
|
||||
u16 val;
|
||||
|
||||
cc10001_adc_power_up(adc_dev);
|
||||
if (!adc_dev->shared)
|
||||
cc10001_adc_power_up(adc_dev);
|
||||
|
||||
/* Calculate delay step for eoc and sampled data */
|
||||
delay_ns = adc_dev->eoc_delay_ns / CC10001_MAX_POLL_COUNT;
|
||||
|
@ -205,7 +209,8 @@ static u16 cc10001_adc_read_raw_voltage(struct iio_dev *indio_dev,
|
|||
|
||||
val = cc10001_adc_poll_done(indio_dev, chan->channel, delay_ns);
|
||||
|
||||
cc10001_adc_power_down(adc_dev);
|
||||
if (!adc_dev->shared)
|
||||
cc10001_adc_power_down(adc_dev);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
@ -322,8 +327,10 @@ static int cc10001_adc_probe(struct platform_device *pdev)
|
|||
adc_dev = iio_priv(indio_dev);
|
||||
|
||||
channel_map = GENMASK(CC10001_ADC_NUM_CHANNELS - 1, 0);
|
||||
if (!of_property_read_u32(node, "adc-reserved-channels", &ret))
|
||||
if (!of_property_read_u32(node, "adc-reserved-channels", &ret)) {
|
||||
adc_dev->shared = true;
|
||||
channel_map &= ~ret;
|
||||
}
|
||||
|
||||
adc_dev->reg = devm_regulator_get(&pdev->dev, "vref");
|
||||
if (IS_ERR(adc_dev->reg))
|
||||
|
@ -368,6 +375,14 @@ static int cc10001_adc_probe(struct platform_device *pdev)
|
|||
adc_dev->eoc_delay_ns = NSEC_PER_SEC / adc_clk_rate;
|
||||
adc_dev->start_delay_ns = adc_dev->eoc_delay_ns * CC10001_WAIT_CYCLES;
|
||||
|
||||
/*
|
||||
* There is only one register to power-up/power-down the AUX ADC.
|
||||
* If the ADC is shared among multiple CPUs, always power it up here.
|
||||
* If the ADC is used only by the MIPS, power-up/power-down at runtime.
|
||||
*/
|
||||
if (adc_dev->shared)
|
||||
cc10001_adc_power_up(adc_dev);
|
||||
|
||||
/* Setup the ADC channels available on the device */
|
||||
ret = cc10001_adc_channel_init(indio_dev, channel_map);
|
||||
if (ret < 0)
|
||||
|
@ -402,6 +417,7 @@ static int cc10001_adc_remove(struct platform_device *pdev)
|
|||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
struct cc10001_adc_device *adc_dev = iio_priv(indio_dev);
|
||||
|
||||
cc10001_adc_power_down(adc_dev);
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
clk_disable_unprepare(adc_dev->adc_clk);
|
||||
|
|
|
@ -404,7 +404,6 @@ MODULE_DEVICE_TABLE(of, mcp3422_of_match);
|
|||
static struct i2c_driver mcp3422_driver = {
|
||||
.driver = {
|
||||
.name = "mcp3422",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(mcp3422_of_match),
|
||||
},
|
||||
.probe = mcp3422_probe,
|
||||
|
|
|
@ -140,7 +140,6 @@ MODULE_DEVICE_TABLE(of, adc081c_of_match);
|
|||
static struct i2c_driver adc081c_driver = {
|
||||
.driver = {
|
||||
.name = "adc081c",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(adc081c_of_match),
|
||||
},
|
||||
.probe = adc081c_probe,
|
||||
|
|
|
@ -700,7 +700,6 @@ static struct spi_driver ssp_driver = {
|
|||
.remove = ssp_remove,
|
||||
.driver = {
|
||||
.pm = &ssp_pm_ops,
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(ssp_of_match),
|
||||
.name = "sensorhub"
|
||||
|
|
|
@ -630,7 +630,6 @@ MODULE_DEVICE_TABLE(i2c, ad5064_i2c_ids);
|
|||
static struct i2c_driver ad5064_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ad5064",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ad5064_i2c_probe,
|
||||
.remove = ad5064_i2c_remove,
|
||||
|
|
|
@ -593,7 +593,6 @@ MODULE_DEVICE_TABLE(i2c, ad5380_i2c_ids);
|
|||
static struct i2c_driver ad5380_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ad5380",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ad5380_i2c_probe,
|
||||
.remove = ad5380_i2c_remove,
|
||||
|
|
|
@ -569,7 +569,6 @@ MODULE_DEVICE_TABLE(i2c, ad5446_i2c_ids);
|
|||
static struct i2c_driver ad5446_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ad5446",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ad5446_i2c_probe,
|
||||
.remove = ad5446_i2c_remove,
|
||||
|
|
|
@ -392,7 +392,6 @@ static struct i2c_driver max5821_driver = {
|
|||
.driver = {
|
||||
.name = "max5821",
|
||||
.pm = MAX5821_PM_OPS,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = max5821_probe,
|
||||
.remove = max5821_remove,
|
||||
|
|
|
@ -72,7 +72,6 @@ static int adf4350_sync_config(struct adf4350_state *st)
|
|||
for (i = ADF4350_REG5; i >= ADF4350_REG0; i--) {
|
||||
if ((st->regs_hw[i] != st->regs[i]) ||
|
||||
((i == ADF4350_REG0) && doublebuf)) {
|
||||
|
||||
switch (i) {
|
||||
case ADF4350_REG1:
|
||||
case ADF4350_REG4:
|
||||
|
|
|
@ -379,7 +379,6 @@ MODULE_DEVICE_TABLE(i2c, itg3200_id);
|
|||
|
||||
static struct i2c_driver itg3200_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "itg3200",
|
||||
.pm = &itg3200_pm_ops,
|
||||
},
|
||||
|
|
|
@ -99,7 +99,6 @@ MODULE_DEVICE_TABLE(i2c, st_gyro_id_table);
|
|||
|
||||
static struct i2c_driver st_gyro_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "st-gyro-i2c",
|
||||
.of_match_table = of_match_ptr(st_gyro_of_match),
|
||||
},
|
||||
|
|
|
@ -177,7 +177,6 @@ MODULE_DEVICE_TABLE(i2c, si7005_id);
|
|||
static struct i2c_driver si7005_driver = {
|
||||
.driver = {
|
||||
.name = "si7005",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = si7005_probe,
|
||||
.id_table = si7005_id,
|
||||
|
|
|
@ -673,6 +673,10 @@ static const struct iio_chan_spec inv_mpu_channels[] = {
|
|||
|
||||
/* constant IIO attribute */
|
||||
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("10 20 50 100 200 500");
|
||||
static IIO_CONST_ATTR(in_anglvel_scale_available,
|
||||
"0.000133090 0.000266181 0.000532362 0.001064724");
|
||||
static IIO_CONST_ATTR(in_accel_scale_available,
|
||||
"0.000598 0.001196 0.002392 0.004785");
|
||||
static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, inv_fifo_rate_show,
|
||||
inv_mpu6050_fifo_rate_store);
|
||||
static IIO_DEVICE_ATTR(in_gyro_matrix, S_IRUGO, inv_attr_show, NULL,
|
||||
|
@ -685,6 +689,8 @@ static struct attribute *inv_attributes[] = {
|
|||
&iio_dev_attr_in_accel_matrix.dev_attr.attr,
|
||||
&iio_dev_attr_sampling_frequency.dev_attr.attr,
|
||||
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
|
||||
&iio_const_attr_in_accel_scale_available.dev_attr.attr,
|
||||
&iio_const_attr_in_anglvel_scale_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
@ -903,7 +909,6 @@ static struct i2c_driver inv_mpu_driver = {
|
|||
.remove = inv_mpu_remove,
|
||||
.id_table = inv_mpu_id,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "inv-mpu6050",
|
||||
.pm = INV_MPU6050_PMOPS,
|
||||
.acpi_match_table = ACPI_PTR(inv_acpi_match),
|
||||
|
|
|
@ -71,8 +71,9 @@ static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf,
|
|||
|
||||
if (avail >= to_wait) {
|
||||
/* force a flush for non-blocking reads */
|
||||
if (!to_wait && !avail && to_flush)
|
||||
iio_buffer_flush_hwfifo(indio_dev, buf, to_flush);
|
||||
if (!to_wait && avail < to_flush)
|
||||
iio_buffer_flush_hwfifo(indio_dev, buf,
|
||||
to_flush - avail);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -100,8 +101,7 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
|
|||
struct iio_dev *indio_dev = filp->private_data;
|
||||
struct iio_buffer *rb = indio_dev->buffer;
|
||||
size_t datum_size;
|
||||
size_t to_wait = 0;
|
||||
size_t to_read;
|
||||
size_t to_wait;
|
||||
int ret;
|
||||
|
||||
if (!indio_dev->info)
|
||||
|
@ -119,14 +119,14 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
|
|||
if (!datum_size)
|
||||
return 0;
|
||||
|
||||
to_read = min_t(size_t, n / datum_size, rb->watermark);
|
||||
|
||||
if (!(filp->f_flags & O_NONBLOCK))
|
||||
to_wait = to_read;
|
||||
if (filp->f_flags & O_NONBLOCK)
|
||||
to_wait = 0;
|
||||
else
|
||||
to_wait = min_t(size_t, n / datum_size, rb->watermark);
|
||||
|
||||
do {
|
||||
ret = wait_event_interruptible(rb->pollq,
|
||||
iio_buffer_ready(indio_dev, rb, to_wait, to_read));
|
||||
iio_buffer_ready(indio_dev, rb, to_wait, n / datum_size));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -81,6 +81,14 @@ static const char * const iio_modifier_names[] = {
|
|||
[IIO_MOD_X] = "x",
|
||||
[IIO_MOD_Y] = "y",
|
||||
[IIO_MOD_Z] = "z",
|
||||
[IIO_MOD_X_AND_Y] = "x&y",
|
||||
[IIO_MOD_X_AND_Z] = "x&z",
|
||||
[IIO_MOD_Y_AND_Z] = "y&z",
|
||||
[IIO_MOD_X_AND_Y_AND_Z] = "x&y&z",
|
||||
[IIO_MOD_X_OR_Y] = "x|y",
|
||||
[IIO_MOD_X_OR_Z] = "x|z",
|
||||
[IIO_MOD_Y_OR_Z] = "y|z",
|
||||
[IIO_MOD_X_OR_Y_OR_Z] = "x|y|z",
|
||||
[IIO_MOD_ROOT_SUM_SQUARED_X_Y] = "sqrt(x^2+y^2)",
|
||||
[IIO_MOD_SUM_SQUARED_X_Y_Z] = "x^2+y^2+z^2",
|
||||
[IIO_MOD_LIGHT_BOTH] = "both",
|
||||
|
|
|
@ -24,8 +24,8 @@ static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
|
|||
/**
|
||||
* iio_triggered_buffer_setup() - Setup triggered buffer and pollfunc
|
||||
* @indio_dev: IIO device structure
|
||||
* @pollfunc_bh: Function which will be used as pollfunc bottom half
|
||||
* @pollfunc_th: Function which will be used as pollfunc top half
|
||||
* @h: Function which will be used as pollfunc top half
|
||||
* @thread: Function which will be used as pollfunc bottom half
|
||||
* @setup_ops: Buffer setup functions to use for this device.
|
||||
* If NULL the default setup functions for triggered
|
||||
* buffers will be used.
|
||||
|
@ -42,8 +42,8 @@ static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
|
|||
* iio_triggered_buffer_cleanup().
|
||||
*/
|
||||
int iio_triggered_buffer_setup(struct iio_dev *indio_dev,
|
||||
irqreturn_t (*pollfunc_bh)(int irq, void *p),
|
||||
irqreturn_t (*pollfunc_th)(int irq, void *p),
|
||||
irqreturn_t (*h)(int irq, void *p),
|
||||
irqreturn_t (*thread)(int irq, void *p),
|
||||
const struct iio_buffer_setup_ops *setup_ops)
|
||||
{
|
||||
struct iio_buffer *buffer;
|
||||
|
@ -57,8 +57,8 @@ int iio_triggered_buffer_setup(struct iio_dev *indio_dev,
|
|||
|
||||
iio_device_attach_buffer(indio_dev, buffer);
|
||||
|
||||
indio_dev->pollfunc = iio_alloc_pollfunc(pollfunc_bh,
|
||||
pollfunc_th,
|
||||
indio_dev->pollfunc = iio_alloc_pollfunc(h,
|
||||
thread,
|
||||
IRQF_ONESHOT,
|
||||
indio_dev,
|
||||
"%s_consumer%d",
|
||||
|
|
|
@ -86,7 +86,7 @@ config CM3323
|
|||
depends on I2C
|
||||
tristate "Capella CM3323 color light sensor"
|
||||
help
|
||||
Say Y here if you want to build a driver for Capela CM3323
|
||||
Say Y here if you want to build a driver for Capella CM3323
|
||||
color sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
|
@ -168,6 +168,17 @@ config JSA1212
|
|||
To compile this driver as a module, choose M here:
|
||||
the module will be called jsa1212.
|
||||
|
||||
config RPR0521
|
||||
tristate "ROHM RPR0521 ALS and proximity sensor driver"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say Y here if you want to build support for ROHM's RPR0521
|
||||
ambient light and proximity sensor device.
|
||||
|
||||
To compile this driver as a module, choose M here:
|
||||
the module will be called rpr0521.
|
||||
|
||||
config SENSORS_LM3533
|
||||
tristate "LM3533 ambient light sensor"
|
||||
depends on MFD_LM3533
|
||||
|
|
|
@ -19,6 +19,7 @@ obj-$(CONFIG_ISL29125) += isl29125.o
|
|||
obj-$(CONFIG_JSA1212) += jsa1212.o
|
||||
obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
|
||||
obj-$(CONFIG_LTR501) += ltr501.o
|
||||
obj-$(CONFIG_RPR0521) += rpr0521.o
|
||||
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
|
||||
obj-$(CONFIG_STK3310) += stk3310.o
|
||||
obj-$(CONFIG_TCS3414) += tcs3414.o
|
||||
|
|
|
@ -515,7 +515,6 @@ MODULE_DEVICE_TABLE(i2c, apds9300_id);
|
|||
static struct i2c_driver apds9300_driver = {
|
||||
.driver = {
|
||||
.name = APDS9300_DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = APDS9300_PM_OPS,
|
||||
},
|
||||
.probe = apds9300_probe,
|
||||
|
|
|
@ -319,7 +319,6 @@ MODULE_DEVICE_TABLE(i2c, bh1750_id);
|
|||
static struct i2c_driver bh1750_driver = {
|
||||
.driver = {
|
||||
.name = "bh1750",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = BH1750_PM_OPS,
|
||||
},
|
||||
.probe = bh1750_probe,
|
||||
|
|
|
@ -358,7 +358,6 @@ static struct i2c_driver cm32181_driver = {
|
|||
.driver = {
|
||||
.name = "cm32181",
|
||||
.of_match_table = of_match_ptr(cm32181_of_match),
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.id_table = cm32181_id,
|
||||
.probe = cm32181_probe,
|
||||
|
|
|
@ -421,7 +421,6 @@ static const struct of_device_id cm3232_of_match[] = {
|
|||
static struct i2c_driver cm3232_driver = {
|
||||
.driver = {
|
||||
.name = "cm3232",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(cm3232_of_match),
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.pm = &cm3232_pm_ops,
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
#define CM3323_CONF_SD_BIT BIT(0) /* sensor disable */
|
||||
#define CM3323_CONF_AF_BIT BIT(1) /* auto/manual force mode */
|
||||
#define CM3323_CONF_IT_MASK (BIT(4) | BIT(5) | BIT(6))
|
||||
#define CM3323_CONF_IT_MASK GENMASK(6, 4)
|
||||
#define CM3323_CONF_IT_SHIFT 4
|
||||
|
||||
#define CM3323_INT_TIME_AVAILABLE "0.04 0.08 0.16 0.32 0.64 1.28"
|
||||
|
@ -133,9 +133,11 @@ static int cm3323_set_it_bits(struct cm3323_data *data, int val, int val2)
|
|||
return ret;
|
||||
|
||||
data->reg_conf = reg_conf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -148,6 +150,7 @@ static int cm3323_get_it_bits(struct cm3323_data *data)
|
|||
|
||||
if (bits >= ARRAY_SIZE(cm3323_int_time))
|
||||
return -EINVAL;
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
|
@ -155,7 +158,7 @@ static int cm3323_read_raw(struct iio_dev *indio_dev,
|
|||
struct iio_chan_spec const *chan, int *val,
|
||||
int *val2, long mask)
|
||||
{
|
||||
int i, ret;
|
||||
int ret;
|
||||
struct cm3323_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
|
@ -172,14 +175,14 @@ static int cm3323_read_raw(struct iio_dev *indio_dev,
|
|||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_INT_TIME:
|
||||
mutex_lock(&data->mutex);
|
||||
i = cm3323_get_it_bits(data);
|
||||
if (i < 0) {
|
||||
ret = cm3323_get_it_bits(data);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->mutex);
|
||||
return -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
*val = cm3323_int_time[i].val;
|
||||
*val2 = cm3323_int_time[i].val2;
|
||||
*val = cm3323_int_time[ret].val;
|
||||
*val2 = cm3323_int_time[ret].val2;
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
|
@ -243,11 +246,13 @@ static int cm3323_probe(struct i2c_client *client,
|
|||
dev_err(&client->dev, "cm3323 chip init failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "failed to register iio dev\n");
|
||||
goto err_init;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_init:
|
||||
cm3323_disable(indio_dev);
|
||||
|
|
|
@ -736,7 +736,6 @@ static struct i2c_driver cm36651_driver = {
|
|||
.driver = {
|
||||
.name = "cm36651",
|
||||
.of_match_table = cm36651_of_match,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = cm36651_probe,
|
||||
.remove = cm36651_remove,
|
||||
|
|
|
@ -1640,7 +1640,6 @@ static struct i2c_driver gp2ap020a00f_driver = {
|
|||
.driver = {
|
||||
.name = GP2A_I2C_NAME,
|
||||
.of_match_table = of_match_ptr(gp2ap020a00f_of_match),
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = gp2ap020a00f_probe,
|
||||
.remove = gp2ap020a00f_remove,
|
||||
|
|
|
@ -284,8 +284,7 @@ static int hid_prox_probe(struct platform_device *pdev)
|
|||
goto error_free_dev_mem;
|
||||
}
|
||||
|
||||
indio_dev->num_channels =
|
||||
ARRAY_SIZE(prox_channels);
|
||||
indio_dev->num_channels = ARRAY_SIZE(prox_channels);
|
||||
indio_dev->dev.parent = &pdev->dev;
|
||||
indio_dev->info = &prox_info;
|
||||
indio_dev->name = name;
|
||||
|
|
|
@ -197,9 +197,21 @@ done:
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static IIO_CONST_ATTR(scale_available, "0.005722 0.152590");
|
||||
|
||||
static struct attribute *isl29125_attributes[] = {
|
||||
&iio_const_attr_scale_available.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group isl29125_attribute_group = {
|
||||
.attrs = isl29125_attributes,
|
||||
};
|
||||
|
||||
static const struct iio_info isl29125_info = {
|
||||
.read_raw = isl29125_read_raw,
|
||||
.write_raw = isl29125_write_raw,
|
||||
.attrs = &isl29125_attribute_group,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
@ -334,7 +346,6 @@ static struct i2c_driver isl29125_driver = {
|
|||
.driver = {
|
||||
.name = ISL29125_DRV_NAME,
|
||||
.pm = &isl29125_pm_ops,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = isl29125_probe,
|
||||
.remove = isl29125_remove,
|
||||
|
|
|
@ -457,7 +457,6 @@ static struct i2c_driver jsa1212_driver = {
|
|||
.driver = {
|
||||
.name = JSA1212_DRIVER_NAME,
|
||||
.pm = JSA1212_PM_OPS,
|
||||
.owner = THIS_MODULE,
|
||||
.acpi_match_table = ACPI_PTR(jsa1212_acpi_match),
|
||||
},
|
||||
.probe = jsa1212_probe,
|
||||
|
|
|
@ -1551,7 +1551,6 @@ static struct i2c_driver ltr501_driver = {
|
|||
.name = LTR501_DRV_NAME,
|
||||
.pm = <r501_pm_ops,
|
||||
.acpi_match_table = ACPI_PTR(ltr_acpi_match),
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ltr501_probe,
|
||||
.remove = ltr501_remove,
|
||||
|
|
|
@ -0,0 +1,615 @@
|
|||
/*
|
||||
* RPR-0521 ROHM Ambient Light and Proximity Sensor
|
||||
*
|
||||
* Copyright (c) 2015, Intel Corporation.
|
||||
*
|
||||
* This file is subject to the terms and conditions of version 2 of
|
||||
* the GNU General Public License. See the file COPYING in the main
|
||||
* directory of this archive for more details.
|
||||
*
|
||||
* IIO driver for RPR-0521RS (7-bit I2C slave address 0x38).
|
||||
*
|
||||
* TODO: illuminance channel, PM support, buffer
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#define RPR0521_REG_SYSTEM_CTRL 0x40
|
||||
#define RPR0521_REG_MODE_CTRL 0x41
|
||||
#define RPR0521_REG_ALS_CTRL 0x42
|
||||
#define RPR0521_REG_PXS_CTRL 0x43
|
||||
#define RPR0521_REG_PXS_DATA 0x44 /* 16-bit, little endian */
|
||||
#define RPR0521_REG_ALS_DATA0 0x46 /* 16-bit, little endian */
|
||||
#define RPR0521_REG_ALS_DATA1 0x48 /* 16-bit, little endian */
|
||||
#define RPR0521_REG_ID 0x92
|
||||
|
||||
#define RPR0521_MODE_ALS_MASK BIT(7)
|
||||
#define RPR0521_MODE_PXS_MASK BIT(6)
|
||||
#define RPR0521_MODE_MEAS_TIME_MASK GENMASK(3, 0)
|
||||
#define RPR0521_ALS_DATA0_GAIN_MASK GENMASK(5, 4)
|
||||
#define RPR0521_ALS_DATA0_GAIN_SHIFT 4
|
||||
#define RPR0521_ALS_DATA1_GAIN_MASK GENMASK(3, 2)
|
||||
#define RPR0521_ALS_DATA1_GAIN_SHIFT 2
|
||||
#define RPR0521_PXS_GAIN_MASK GENMASK(5, 4)
|
||||
#define RPR0521_PXS_GAIN_SHIFT 4
|
||||
|
||||
#define RPR0521_MODE_ALS_ENABLE BIT(7)
|
||||
#define RPR0521_MODE_ALS_DISABLE 0x00
|
||||
#define RPR0521_MODE_PXS_ENABLE BIT(6)
|
||||
#define RPR0521_MODE_PXS_DISABLE 0x00
|
||||
|
||||
#define RPR0521_MANUFACT_ID 0xE0
|
||||
#define RPR0521_DEFAULT_MEAS_TIME 0x06 /* ALS - 100ms, PXS - 100ms */
|
||||
|
||||
#define RPR0521_DRV_NAME "RPR0521"
|
||||
#define RPR0521_REGMAP_NAME "rpr0521_regmap"
|
||||
|
||||
#define RPR0521_SLEEP_DELAY_MS 2000
|
||||
|
||||
#define RPR0521_ALS_SCALE_AVAIL "0.007812 0.015625 0.5 1"
|
||||
#define RPR0521_PXS_SCALE_AVAIL "0.125 0.5 1"
|
||||
|
||||
struct rpr0521_gain {
|
||||
int scale;
|
||||
int uscale;
|
||||
};
|
||||
|
||||
static const struct rpr0521_gain rpr0521_als_gain[4] = {
|
||||
{1, 0}, /* x1 */
|
||||
{0, 500000}, /* x2 */
|
||||
{0, 15625}, /* x64 */
|
||||
{0, 7812}, /* x128 */
|
||||
};
|
||||
|
||||
static const struct rpr0521_gain rpr0521_pxs_gain[3] = {
|
||||
{1, 0}, /* x1 */
|
||||
{0, 500000}, /* x2 */
|
||||
{0, 125000}, /* x4 */
|
||||
};
|
||||
|
||||
enum rpr0521_channel {
|
||||
RPR0521_CHAN_ALS_DATA0,
|
||||
RPR0521_CHAN_ALS_DATA1,
|
||||
RPR0521_CHAN_PXS,
|
||||
};
|
||||
|
||||
struct rpr0521_reg_desc {
|
||||
u8 address;
|
||||
u8 device_mask;
|
||||
};
|
||||
|
||||
static const struct rpr0521_reg_desc rpr0521_data_reg[] = {
|
||||
[RPR0521_CHAN_ALS_DATA0] = {
|
||||
.address = RPR0521_REG_ALS_DATA0,
|
||||
.device_mask = RPR0521_MODE_ALS_MASK,
|
||||
},
|
||||
[RPR0521_CHAN_ALS_DATA1] = {
|
||||
.address = RPR0521_REG_ALS_DATA1,
|
||||
.device_mask = RPR0521_MODE_ALS_MASK,
|
||||
},
|
||||
[RPR0521_CHAN_PXS] = {
|
||||
.address = RPR0521_REG_PXS_DATA,
|
||||
.device_mask = RPR0521_MODE_PXS_MASK,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct rpr0521_gain_info {
|
||||
u8 reg;
|
||||
u8 mask;
|
||||
u8 shift;
|
||||
const struct rpr0521_gain *gain;
|
||||
int size;
|
||||
} rpr0521_gain[] = {
|
||||
[RPR0521_CHAN_ALS_DATA0] = {
|
||||
.reg = RPR0521_REG_ALS_CTRL,
|
||||
.mask = RPR0521_ALS_DATA0_GAIN_MASK,
|
||||
.shift = RPR0521_ALS_DATA0_GAIN_SHIFT,
|
||||
.gain = rpr0521_als_gain,
|
||||
.size = ARRAY_SIZE(rpr0521_als_gain),
|
||||
},
|
||||
[RPR0521_CHAN_ALS_DATA1] = {
|
||||
.reg = RPR0521_REG_ALS_CTRL,
|
||||
.mask = RPR0521_ALS_DATA1_GAIN_MASK,
|
||||
.shift = RPR0521_ALS_DATA1_GAIN_SHIFT,
|
||||
.gain = rpr0521_als_gain,
|
||||
.size = ARRAY_SIZE(rpr0521_als_gain),
|
||||
},
|
||||
[RPR0521_CHAN_PXS] = {
|
||||
.reg = RPR0521_REG_PXS_CTRL,
|
||||
.mask = RPR0521_PXS_GAIN_MASK,
|
||||
.shift = RPR0521_PXS_GAIN_SHIFT,
|
||||
.gain = rpr0521_pxs_gain,
|
||||
.size = ARRAY_SIZE(rpr0521_pxs_gain),
|
||||
},
|
||||
};
|
||||
|
||||
struct rpr0521_data {
|
||||
struct i2c_client *client;
|
||||
|
||||
/* protect device params updates (e.g state, gain) */
|
||||
struct mutex lock;
|
||||
|
||||
/* device active status */
|
||||
bool als_dev_en;
|
||||
bool pxs_dev_en;
|
||||
|
||||
/* optimize runtime pm ops - enable device only if needed */
|
||||
bool als_ps_need_en;
|
||||
bool pxs_ps_need_en;
|
||||
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static IIO_CONST_ATTR(in_intensity_scale_available, RPR0521_ALS_SCALE_AVAIL);
|
||||
static IIO_CONST_ATTR(in_proximity_scale_available, RPR0521_PXS_SCALE_AVAIL);
|
||||
|
||||
static struct attribute *rpr0521_attributes[] = {
|
||||
&iio_const_attr_in_intensity_scale_available.dev_attr.attr,
|
||||
&iio_const_attr_in_proximity_scale_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group rpr0521_attribute_group = {
|
||||
.attrs = rpr0521_attributes,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec rpr0521_channels[] = {
|
||||
{
|
||||
.type = IIO_INTENSITY,
|
||||
.modified = 1,
|
||||
.address = RPR0521_CHAN_ALS_DATA0,
|
||||
.channel2 = IIO_MOD_LIGHT_BOTH,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
},
|
||||
{
|
||||
.type = IIO_INTENSITY,
|
||||
.modified = 1,
|
||||
.address = RPR0521_CHAN_ALS_DATA1,
|
||||
.channel2 = IIO_MOD_LIGHT_IR,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
},
|
||||
{
|
||||
.type = IIO_PROXIMITY,
|
||||
.address = RPR0521_CHAN_PXS,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
}
|
||||
};
|
||||
|
||||
static int rpr0521_als_enable(struct rpr0521_data *data, u8 status)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL,
|
||||
RPR0521_MODE_ALS_MASK,
|
||||
status);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->als_dev_en = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rpr0521_pxs_enable(struct rpr0521_data *data, u8 status)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL,
|
||||
RPR0521_MODE_PXS_MASK,
|
||||
status);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->pxs_dev_en = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* rpr0521_set_power_state - handles runtime PM state and sensors enabled status
|
||||
*
|
||||
* @data: rpr0521 device private data
|
||||
* @on: state to be set for devices in @device_mask
|
||||
* @device_mask: bitmask specifying for which device we need to update @on state
|
||||
*
|
||||
* We rely on rpr0521_runtime_resume to enable our @device_mask devices, but
|
||||
* if (for example) PXS was enabled (pxs_dev_en = true) by a previous call to
|
||||
* rpr0521_runtime_resume and we want to enable ALS we MUST set ALS enable
|
||||
* bit of RPR0521_REG_MODE_CTRL here because rpr0521_runtime_resume will not
|
||||
* be called twice.
|
||||
*/
|
||||
static int rpr0521_set_power_state(struct rpr0521_data *data, bool on,
|
||||
u8 device_mask)
|
||||
{
|
||||
#ifdef CONFIG_PM
|
||||
int ret;
|
||||
u8 update_mask = 0;
|
||||
|
||||
if (device_mask & RPR0521_MODE_ALS_MASK) {
|
||||
if (on && !data->als_ps_need_en && data->pxs_dev_en)
|
||||
update_mask |= RPR0521_MODE_ALS_MASK;
|
||||
else
|
||||
data->als_ps_need_en = on;
|
||||
}
|
||||
|
||||
if (device_mask & RPR0521_MODE_PXS_MASK) {
|
||||
if (on && !data->pxs_ps_need_en && data->als_dev_en)
|
||||
update_mask |= RPR0521_MODE_PXS_MASK;
|
||||
else
|
||||
data->pxs_ps_need_en = on;
|
||||
}
|
||||
|
||||
if (update_mask) {
|
||||
ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL,
|
||||
update_mask, update_mask);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (on) {
|
||||
ret = pm_runtime_get_sync(&data->client->dev);
|
||||
} else {
|
||||
pm_runtime_mark_last_busy(&data->client->dev);
|
||||
ret = pm_runtime_put_autosuspend(&data->client->dev);
|
||||
}
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev,
|
||||
"Failed: rpr0521_set_power_state for %d, ret %d\n",
|
||||
on, ret);
|
||||
if (on)
|
||||
pm_runtime_put_noidle(&data->client->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rpr0521_get_gain(struct rpr0521_data *data, int chan,
|
||||
int *val, int *val2)
|
||||
{
|
||||
int ret, reg, idx;
|
||||
|
||||
ret = regmap_read(data->regmap, rpr0521_gain[chan].reg, ®);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
idx = (rpr0521_gain[chan].mask & reg) >> rpr0521_gain[chan].shift;
|
||||
*val = rpr0521_gain[chan].gain[idx].scale;
|
||||
*val2 = rpr0521_gain[chan].gain[idx].uscale;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rpr0521_set_gain(struct rpr0521_data *data, int chan,
|
||||
int val, int val2)
|
||||
{
|
||||
int i, idx = -EINVAL;
|
||||
|
||||
/* get gain index */
|
||||
for (i = 0; i < rpr0521_gain[chan].size; i++)
|
||||
if (val == rpr0521_gain[chan].gain[i].scale &&
|
||||
val2 == rpr0521_gain[chan].gain[i].uscale) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (idx < 0)
|
||||
return idx;
|
||||
|
||||
return regmap_update_bits(data->regmap, rpr0521_gain[chan].reg,
|
||||
rpr0521_gain[chan].mask,
|
||||
idx << rpr0521_gain[chan].shift);
|
||||
}
|
||||
|
||||
static int rpr0521_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val,
|
||||
int *val2, long mask)
|
||||
{
|
||||
struct rpr0521_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
u8 device_mask;
|
||||
__le16 raw_data;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (chan->type != IIO_INTENSITY && chan->type != IIO_PROXIMITY)
|
||||
return -EINVAL;
|
||||
|
||||
device_mask = rpr0521_data_reg[chan->address].device_mask;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
ret = rpr0521_set_power_state(data, true, device_mask);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_bulk_read(data->regmap,
|
||||
rpr0521_data_reg[chan->address].address,
|
||||
&raw_data, 2);
|
||||
if (ret < 0) {
|
||||
rpr0521_set_power_state(data, false, device_mask);
|
||||
mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = rpr0521_set_power_state(data, false, device_mask);
|
||||
mutex_unlock(&data->lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = le16_to_cpu(raw_data);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
mutex_lock(&data->lock);
|
||||
ret = rpr0521_get_gain(data, chan->address, val, val2);
|
||||
mutex_unlock(&data->lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int rpr0521_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int val,
|
||||
int val2, long mask)
|
||||
{
|
||||
struct rpr0521_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
mutex_lock(&data->lock);
|
||||
ret = rpr0521_set_gain(data, chan->address, val, val2);
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_info rpr0521_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.read_raw = rpr0521_read_raw,
|
||||
.write_raw = rpr0521_write_raw,
|
||||
.attrs = &rpr0521_attribute_group,
|
||||
};
|
||||
|
||||
static int rpr0521_init(struct rpr0521_data *data)
|
||||
{
|
||||
int ret;
|
||||
int id;
|
||||
|
||||
ret = regmap_read(data->regmap, RPR0521_REG_ID, &id);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Failed to read REG_ID register\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (id != RPR0521_MANUFACT_ID) {
|
||||
dev_err(&data->client->dev, "Wrong id, got %x, expected %x\n",
|
||||
id, RPR0521_MANUFACT_ID);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* set default measurement time - 100 ms for both ALS and PS */
|
||||
ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL,
|
||||
RPR0521_MODE_MEAS_TIME_MASK,
|
||||
RPR0521_DEFAULT_MEAS_TIME);
|
||||
if (ret) {
|
||||
pr_err("regmap_update_bits returned %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = rpr0521_pxs_enable(data, RPR0521_MODE_PXS_ENABLE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rpr0521_poweroff(struct rpr0521_data *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL,
|
||||
RPR0521_MODE_ALS_MASK |
|
||||
RPR0521_MODE_PXS_MASK,
|
||||
RPR0521_MODE_ALS_DISABLE |
|
||||
RPR0521_MODE_PXS_DISABLE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->als_dev_en = false;
|
||||
data->pxs_dev_en = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool rpr0521_is_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case RPR0521_REG_MODE_CTRL:
|
||||
case RPR0521_REG_ALS_CTRL:
|
||||
case RPR0521_REG_PXS_CTRL:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config rpr0521_regmap_config = {
|
||||
.name = RPR0521_REGMAP_NAME,
|
||||
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = RPR0521_REG_ID,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.volatile_reg = rpr0521_is_volatile_reg,
|
||||
};
|
||||
|
||||
static int rpr0521_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct rpr0521_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
struct regmap *regmap;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, &rpr0521_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&client->dev, "regmap_init failed!\n");
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
data->regmap = regmap;
|
||||
|
||||
mutex_init(&data->lock);
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->info = &rpr0521_info;
|
||||
indio_dev->name = RPR0521_DRV_NAME;
|
||||
indio_dev->channels = rpr0521_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(rpr0521_channels);
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
ret = rpr0521_init(data);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "rpr0521 chip init failed\n");
|
||||
return ret;
|
||||
}
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = pm_runtime_set_active(&client->dev);
|
||||
if (ret < 0)
|
||||
goto err_iio_unregister;
|
||||
|
||||
pm_runtime_enable(&client->dev);
|
||||
pm_runtime_set_autosuspend_delay(&client->dev, RPR0521_SLEEP_DELAY_MS);
|
||||
pm_runtime_use_autosuspend(&client->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_iio_unregister:
|
||||
iio_device_unregister(indio_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rpr0521_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
rpr0521_poweroff(iio_priv(indio_dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int rpr0521_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
|
||||
struct rpr0521_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
/* disable channels and sets {als,pxs}_dev_en to false */
|
||||
mutex_lock(&data->lock);
|
||||
ret = rpr0521_poweroff(data);
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rpr0521_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
|
||||
struct rpr0521_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
if (data->als_ps_need_en) {
|
||||
ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->als_ps_need_en = false;
|
||||
}
|
||||
|
||||
if (data->pxs_ps_need_en) {
|
||||
ret = rpr0521_pxs_enable(data, RPR0521_MODE_PXS_ENABLE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->pxs_ps_need_en = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops rpr0521_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(rpr0521_runtime_suspend,
|
||||
rpr0521_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct acpi_device_id rpr0521_acpi_match[] = {
|
||||
{"RPR0521", 0},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, rpr0521_acpi_match);
|
||||
|
||||
static const struct i2c_device_id rpr0521_id[] = {
|
||||
{"rpr0521", 0},
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, rpr0521_id);
|
||||
|
||||
static struct i2c_driver rpr0521_driver = {
|
||||
.driver = {
|
||||
.name = RPR0521_DRV_NAME,
|
||||
.pm = &rpr0521_pm_ops,
|
||||
.acpi_match_table = ACPI_PTR(rpr0521_acpi_match),
|
||||
},
|
||||
.probe = rpr0521_probe,
|
||||
.remove = rpr0521_remove,
|
||||
.id_table = rpr0521_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(rpr0521_driver);
|
||||
|
||||
MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
|
||||
MODULE_DESCRIPTION("RPR0521 ROHM Ambient Light and Proximity Sensor driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -392,7 +392,6 @@ static struct i2c_driver tcs3414_driver = {
|
|||
.driver = {
|
||||
.name = TCS3414_DRV_NAME,
|
||||
.pm = &tcs3414_pm_ops,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = tcs3414_probe,
|
||||
.remove = tcs3414_remove,
|
||||
|
|
|
@ -366,7 +366,6 @@ static struct i2c_driver tcs3472_driver = {
|
|||
.driver = {
|
||||
.name = TCS3472_DRV_NAME,
|
||||
.pm = &tcs3472_pm_ops,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = tcs3472_probe,
|
||||
.remove = tcs3472_remove,
|
||||
|
|
|
@ -247,7 +247,6 @@ static struct i2c_driver tsl4531_driver = {
|
|||
.driver = {
|
||||
.name = TSL4531_DRV_NAME,
|
||||
.pm = TSL4531_PM_OPS,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = tsl4531_probe,
|
||||
.remove = tsl4531_remove,
|
||||
|
|
|
@ -185,7 +185,6 @@ static int vcnl4000_probe(struct i2c_client *client,
|
|||
static struct i2c_driver vcnl4000_driver = {
|
||||
.driver = {
|
||||
.name = VCNL4000_DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = vcnl4000_probe,
|
||||
.id_table = vcnl4000_id,
|
||||
|
|
|
@ -588,17 +588,6 @@ static int bmc150_magn_write_raw(struct iio_dev *indio_dev,
|
|||
}
|
||||
}
|
||||
|
||||
static int bmc150_magn_validate_trigger(struct iio_dev *indio_dev,
|
||||
struct iio_trigger *trig)
|
||||
{
|
||||
struct bmc150_magn_data *data = iio_priv(indio_dev);
|
||||
|
||||
if (data->dready_trig != trig)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t bmc150_magn_show_samp_freq_avail(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
|
@ -659,7 +648,6 @@ static const struct iio_info bmc150_magn_info = {
|
|||
.attrs = &bmc150_magn_attrs_group,
|
||||
.read_raw = bmc150_magn_read_raw,
|
||||
.write_raw = bmc150_magn_write_raw,
|
||||
.validate_trigger = bmc150_magn_validate_trigger,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
@ -682,7 +670,7 @@ static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p)
|
|||
pf->timestamp);
|
||||
|
||||
err:
|
||||
iio_trigger_notify_done(data->dready_trig);
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -827,6 +815,27 @@ static const struct iio_trigger_ops bmc150_magn_trigger_ops = {
|
|||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int bmc150_magn_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct bmc150_magn_data *data = iio_priv(indio_dev);
|
||||
|
||||
return bmc150_magn_set_power_state(data, true);
|
||||
}
|
||||
|
||||
static int bmc150_magn_buffer_postdisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct bmc150_magn_data *data = iio_priv(indio_dev);
|
||||
|
||||
return bmc150_magn_set_power_state(data, false);
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops bmc150_magn_buffer_setup_ops = {
|
||||
.preenable = bmc150_magn_buffer_preenable,
|
||||
.postenable = iio_triggered_buffer_postenable,
|
||||
.predisable = iio_triggered_buffer_predisable,
|
||||
.postdisable = bmc150_magn_buffer_postdisable,
|
||||
};
|
||||
|
||||
static int bmc150_magn_gpio_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev;
|
||||
|
@ -932,16 +941,6 @@ static int bmc150_magn_probe(struct i2c_client *client,
|
|||
goto err_poweroff;
|
||||
}
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev,
|
||||
&iio_pollfunc_store_time,
|
||||
bmc150_magn_trigger_handler,
|
||||
NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev,
|
||||
"iio triggered buffer setup failed\n");
|
||||
goto err_trigger_unregister;
|
||||
}
|
||||
|
||||
ret = request_threaded_irq(client->irq,
|
||||
iio_trigger_generic_data_rdy_poll,
|
||||
NULL,
|
||||
|
@ -951,14 +950,24 @@ static int bmc150_magn_probe(struct i2c_client *client,
|
|||
if (ret < 0) {
|
||||
dev_err(&client->dev, "request irq %d failed\n",
|
||||
client->irq);
|
||||
goto err_buffer_cleanup;
|
||||
goto err_trigger_unregister;
|
||||
}
|
||||
}
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev,
|
||||
iio_pollfunc_store_time,
|
||||
bmc150_magn_trigger_handler,
|
||||
&bmc150_magn_buffer_setup_ops);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev,
|
||||
"iio triggered buffer setup failed\n");
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "unable to register iio device\n");
|
||||
goto err_free_irq;
|
||||
goto err_buffer_cleanup;
|
||||
}
|
||||
|
||||
ret = pm_runtime_set_active(&client->dev);
|
||||
|
@ -976,12 +985,11 @@ static int bmc150_magn_probe(struct i2c_client *client,
|
|||
|
||||
err_iio_unregister:
|
||||
iio_device_unregister(indio_dev);
|
||||
err_buffer_cleanup:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
err_free_irq:
|
||||
if (client->irq > 0)
|
||||
free_irq(client->irq, data->dready_trig);
|
||||
err_buffer_cleanup:
|
||||
if (data->dready_trig)
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
err_trigger_unregister:
|
||||
if (data->dready_trig)
|
||||
iio_trigger_unregister(data->dready_trig);
|
||||
|
@ -1000,14 +1008,13 @@ static int bmc150_magn_remove(struct i2c_client *client)
|
|||
pm_runtime_put_noidle(&client->dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
|
||||
if (client->irq > 0)
|
||||
free_irq(data->client->irq, data->dready_trig);
|
||||
|
||||
if (data->dready_trig) {
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
if (data->dready_trig)
|
||||
iio_trigger_unregister(data->dready_trig);
|
||||
}
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, true);
|
||||
|
@ -1082,12 +1089,14 @@ static const struct dev_pm_ops bmc150_magn_pm_ops = {
|
|||
|
||||
static const struct acpi_device_id bmc150_magn_acpi_match[] = {
|
||||
{"BMC150B", 0},
|
||||
{"BMC156B", 0},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, bmc150_magn_acpi_match);
|
||||
|
||||
static const struct i2c_device_id bmc150_magn_id[] = {
|
||||
{"bmc150_magn", 0},
|
||||
{"bmc156_magn", 0},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, bmc150_magn_id);
|
||||
|
|
|
@ -85,7 +85,6 @@ MODULE_DEVICE_TABLE(i2c, st_magn_id_table);
|
|||
|
||||
static struct i2c_driver st_magn_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "st-magn-i2c",
|
||||
.of_match_table = of_match_ptr(st_magn_of_match),
|
||||
},
|
||||
|
|
|
@ -53,10 +53,10 @@ config MPL3115
|
|||
will be called mpl3115.
|
||||
|
||||
config MS5611
|
||||
tristate "Measurement Specialities MS5611 pressure sensor driver"
|
||||
tristate "Measurement Specialties MS5611 pressure sensor driver"
|
||||
help
|
||||
Say Y here to build support for the Measurement Specialities
|
||||
MS5611 pressure and temperature sensor.
|
||||
Say Y here to build support for the Measurement Specialties
|
||||
MS5611, MS5607 pressure and temperature sensors.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called ms5611_core.
|
||||
|
|
|
@ -27,6 +27,18 @@
|
|||
|
||||
#define MS5611_PROM_WORDS_NB 8
|
||||
|
||||
enum {
|
||||
MS5611,
|
||||
MS5607,
|
||||
};
|
||||
|
||||
struct ms5611_chip_info {
|
||||
u16 prom[MS5611_PROM_WORDS_NB];
|
||||
|
||||
int (*temp_and_pressure_compensate)(struct ms5611_chip_info *chip_info,
|
||||
s32 *temp, s32 *pressure);
|
||||
};
|
||||
|
||||
struct ms5611_state {
|
||||
void *client;
|
||||
struct mutex lock;
|
||||
|
@ -36,9 +48,9 @@ struct ms5611_state {
|
|||
int (*read_adc_temp_and_pressure)(struct device *dev,
|
||||
s32 *temp, s32 *pressure);
|
||||
|
||||
u16 prom[MS5611_PROM_WORDS_NB];
|
||||
struct ms5611_chip_info *chip_info;
|
||||
};
|
||||
|
||||
int ms5611_probe(struct iio_dev *indio_dev, struct device *dev);
|
||||
int ms5611_probe(struct iio_dev *indio_dev, struct device *dev, int type);
|
||||
|
||||
#endif /* _MS5611_H */
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*
|
||||
* Data sheet:
|
||||
* http://www.meas-spec.com/downloads/MS5611-01BA03.pdf
|
||||
* http://www.meas-spec.com/downloads/MS5607-02BA03.pdf
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -50,7 +51,8 @@ static int ms5611_read_prom(struct iio_dev *indio_dev)
|
|||
struct ms5611_state *st = iio_priv(indio_dev);
|
||||
|
||||
for (i = 0; i < MS5611_PROM_WORDS_NB; i++) {
|
||||
ret = st->read_prom_word(&indio_dev->dev, i, &st->prom[i]);
|
||||
ret = st->read_prom_word(&indio_dev->dev,
|
||||
i, &st->chip_info->prom[i]);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"failed to read prom at %d\n", i);
|
||||
|
@ -58,7 +60,7 @@ static int ms5611_read_prom(struct iio_dev *indio_dev)
|
|||
}
|
||||
}
|
||||
|
||||
if (!ms5611_prom_is_valid(st->prom, MS5611_PROM_WORDS_NB)) {
|
||||
if (!ms5611_prom_is_valid(st->chip_info->prom, MS5611_PROM_WORDS_NB)) {
|
||||
dev_err(&indio_dev->dev, "PROM integrity check failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -70,22 +72,30 @@ static int ms5611_read_temp_and_pressure(struct iio_dev *indio_dev,
|
|||
s32 *temp, s32 *pressure)
|
||||
{
|
||||
int ret;
|
||||
s32 t, p;
|
||||
s64 off, sens, dt;
|
||||
struct ms5611_state *st = iio_priv(indio_dev);
|
||||
|
||||
ret = st->read_adc_temp_and_pressure(&indio_dev->dev, &t, &p);
|
||||
ret = st->read_adc_temp_and_pressure(&indio_dev->dev, temp, pressure);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"failed to read temperature and pressure\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dt = t - (st->prom[5] << 8);
|
||||
off = ((s64)st->prom[2] << 16) + ((st->prom[4] * dt) >> 7);
|
||||
sens = ((s64)st->prom[1] << 15) + ((st->prom[3] * dt) >> 8);
|
||||
return st->chip_info->temp_and_pressure_compensate(st->chip_info,
|
||||
temp, pressure);
|
||||
}
|
||||
|
||||
t = 2000 + ((st->prom[6] * dt) >> 23);
|
||||
static int ms5611_temp_and_pressure_compensate(struct ms5611_chip_info *chip_info,
|
||||
s32 *temp, s32 *pressure)
|
||||
{
|
||||
s32 t = *temp, p = *pressure;
|
||||
s64 off, sens, dt;
|
||||
|
||||
dt = t - (chip_info->prom[5] << 8);
|
||||
off = ((s64)chip_info->prom[2] << 16) + ((chip_info->prom[4] * dt) >> 7);
|
||||
sens = ((s64)chip_info->prom[1] << 15) + ((chip_info->prom[3] * dt) >> 8);
|
||||
|
||||
t = 2000 + ((chip_info->prom[6] * dt) >> 23);
|
||||
if (t < 2000) {
|
||||
s64 off2, sens2, t2;
|
||||
|
||||
|
@ -111,6 +121,42 @@ static int ms5611_read_temp_and_pressure(struct iio_dev *indio_dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ms5607_temp_and_pressure_compensate(struct ms5611_chip_info *chip_info,
|
||||
s32 *temp, s32 *pressure)
|
||||
{
|
||||
s32 t = *temp, p = *pressure;
|
||||
s64 off, sens, dt;
|
||||
|
||||
dt = t - (chip_info->prom[5] << 8);
|
||||
off = ((s64)chip_info->prom[2] << 17) + ((chip_info->prom[4] * dt) >> 6);
|
||||
sens = ((s64)chip_info->prom[1] << 16) + ((chip_info->prom[3] * dt) >> 7);
|
||||
|
||||
t = 2000 + ((chip_info->prom[6] * dt) >> 23);
|
||||
if (t < 2000) {
|
||||
s64 off2, sens2, t2;
|
||||
|
||||
t2 = (dt * dt) >> 31;
|
||||
off2 = (61 * (t - 2000) * (t - 2000)) >> 4;
|
||||
sens2 = off2 << 1;
|
||||
|
||||
if (t < -1500) {
|
||||
s64 tmp = (t + 1500) * (t + 1500);
|
||||
|
||||
off2 += 15 * tmp;
|
||||
sens2 += (8 * tmp);
|
||||
}
|
||||
|
||||
t -= t2;
|
||||
off -= off2;
|
||||
sens -= sens2;
|
||||
}
|
||||
|
||||
*temp = t;
|
||||
*pressure = (((p * sens) >> 21) - off) >> 15;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ms5611_reset(struct iio_dev *indio_dev)
|
||||
{
|
||||
int ret;
|
||||
|
@ -160,16 +206,23 @@ static int ms5611_read_raw(struct iio_dev *indio_dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct ms5611_chip_info chip_info_tbl[] = {
|
||||
[MS5611] = {
|
||||
.temp_and_pressure_compensate = ms5611_temp_and_pressure_compensate,
|
||||
},
|
||||
[MS5607] = {
|
||||
.temp_and_pressure_compensate = ms5607_temp_and_pressure_compensate,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ms5611_channels[] = {
|
||||
{
|
||||
.type = IIO_PRESSURE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
|
||||
BIT(IIO_CHAN_INFO_SCALE)
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
|
||||
},
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
|
||||
BIT(IIO_CHAN_INFO_SCALE)
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -189,12 +242,13 @@ static int ms5611_init(struct iio_dev *indio_dev)
|
|||
return ms5611_read_prom(indio_dev);
|
||||
}
|
||||
|
||||
int ms5611_probe(struct iio_dev *indio_dev, struct device *dev)
|
||||
int ms5611_probe(struct iio_dev *indio_dev, struct device *dev, int type)
|
||||
{
|
||||
int ret;
|
||||
struct ms5611_state *st = iio_priv(indio_dev);
|
||||
|
||||
mutex_init(&st->lock);
|
||||
st->chip_info = &chip_info_tbl[type];
|
||||
indio_dev->dev.parent = dev;
|
||||
indio_dev->name = dev->driver->name;
|
||||
indio_dev->info = &ms5611_info;
|
||||
|
|
|
@ -104,11 +104,12 @@ static int ms5611_i2c_probe(struct i2c_client *client,
|
|||
st->read_adc_temp_and_pressure = ms5611_i2c_read_adc_temp_and_pressure;
|
||||
st->client = client;
|
||||
|
||||
return ms5611_probe(indio_dev, &client->dev);
|
||||
return ms5611_probe(indio_dev, &client->dev, id->driver_data);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ms5611_id[] = {
|
||||
{ "ms5611", 0 },
|
||||
{ "ms5611", MS5611 },
|
||||
{ "ms5607", MS5607 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ms5611_id);
|
||||
|
@ -116,7 +117,6 @@ MODULE_DEVICE_TABLE(i2c, ms5611_id);
|
|||
static struct i2c_driver ms5611_driver = {
|
||||
.driver = {
|
||||
.name = "ms5611",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.id_table = ms5611_id,
|
||||
.probe = ms5611_i2c_probe,
|
||||
|
|
|
@ -103,11 +103,13 @@ static int ms5611_spi_probe(struct spi_device *spi)
|
|||
st->read_adc_temp_and_pressure = ms5611_spi_read_adc_temp_and_pressure;
|
||||
st->client = spi;
|
||||
|
||||
return ms5611_probe(indio_dev, &spi->dev);
|
||||
return ms5611_probe(indio_dev, &spi->dev,
|
||||
spi_get_device_id(spi)->driver_data);
|
||||
}
|
||||
|
||||
static const struct spi_device_id ms5611_id[] = {
|
||||
{ "ms5611", 0 },
|
||||
{ "ms5611", MS5611 },
|
||||
{ "ms5607", MS5607 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ms5611_id);
|
||||
|
|
|
@ -79,7 +79,6 @@ MODULE_DEVICE_TABLE(i2c, st_press_id_table);
|
|||
|
||||
static struct i2c_driver st_press_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "st-press-i2c",
|
||||
.of_match_table = of_match_ptr(st_press_of_match),
|
||||
},
|
||||
|
|
|
@ -551,7 +551,6 @@ static const struct dev_pm_ops mlx90614_pm_ops = {
|
|||
static struct i2c_driver mlx90614_driver = {
|
||||
.driver = {
|
||||
.name = "mlx90614",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &mlx90614_pm_ops,
|
||||
},
|
||||
.probe = mlx90614_probe,
|
||||
|
|
|
@ -36,9 +36,9 @@
|
|||
#define TMP006_CONFIG_DRDY_EN BIT(8)
|
||||
#define TMP006_CONFIG_DRDY BIT(7)
|
||||
|
||||
#define TMP006_CONFIG_MOD_MASK 0x7000
|
||||
#define TMP006_CONFIG_MOD_MASK GENMASK(14, 12)
|
||||
|
||||
#define TMP006_CONFIG_CR_MASK 0x0e00
|
||||
#define TMP006_CONFIG_CR_MASK GENMASK(11, 9)
|
||||
#define TMP006_CONFIG_CR_SHIFT 9
|
||||
|
||||
#define TMP006_MANUFACTURER_MAGIC 0x5449
|
||||
|
@ -277,7 +277,6 @@ static struct i2c_driver tmp006_driver = {
|
|||
.driver = {
|
||||
.name = "tmp006",
|
||||
.pm = &tmp006_pm_ops,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = tmp006_probe,
|
||||
.remove = tmp006_remove,
|
||||
|
|
|
@ -124,7 +124,6 @@ static struct i2c_driver adt7316_driver = {
|
|||
.driver = {
|
||||
.name = "adt7316",
|
||||
.pm = ADT7316_PM_OPS,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = adt7316_i2c_probe,
|
||||
.id_table = adt7316_i2c_id,
|
||||
|
|
|
@ -214,6 +214,7 @@ static struct device iio_evgen_dev = {
|
|||
.groups = iio_evgen_groups,
|
||||
.release = &iio_evgen_release,
|
||||
};
|
||||
|
||||
static __init int iio_dummy_evgen_init(void)
|
||||
{
|
||||
int ret = iio_dummy_evgen_create();
|
||||
|
|
|
@ -611,7 +611,6 @@ static int iio_dummy_probe(int index)
|
|||
*/
|
||||
iio_dummy_devs[index] = indio_dev;
|
||||
|
||||
|
||||
/*
|
||||
* Set the device name.
|
||||
*
|
||||
|
@ -675,7 +674,6 @@ static void iio_dummy_remove(int index)
|
|||
*/
|
||||
struct iio_dev *indio_dev = iio_dummy_devs[index];
|
||||
|
||||
|
||||
/* Unregister the device */
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
|
|
|
@ -119,6 +119,7 @@ static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
|
|||
{
|
||||
return 0;
|
||||
};
|
||||
|
||||
static inline
|
||||
void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev)
|
||||
{};
|
||||
|
|
|
@ -32,6 +32,7 @@ static const s16 fakedata[] = {
|
|||
[diffvoltage3m4] = -2,
|
||||
[accelx] = 344,
|
||||
};
|
||||
|
||||
/**
|
||||
* iio_simple_dummy_trigger_h() - the trigger handler function
|
||||
* @irq: the interrupt number
|
||||
|
@ -178,7 +179,6 @@ error_free_buffer:
|
|||
iio_kfifo_free(indio_dev->buffer);
|
||||
error_ret:
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -838,7 +838,6 @@ static struct i2c_driver isl29018_driver = {
|
|||
.name = "isl29018",
|
||||
.acpi_match_table = ACPI_PTR(isl29018_acpi_match),
|
||||
.pm = ISL29018_PM_OPS,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = isl29018_of_match,
|
||||
},
|
||||
.probe = isl29018_probe,
|
||||
|
|
|
@ -547,7 +547,6 @@ static struct i2c_driver isl29028_driver = {
|
|||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "isl29028",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = isl29028_of_match,
|
||||
},
|
||||
.probe = isl29028_probe,
|
||||
|
|
|
@ -7,8 +7,8 @@ struct iio_dev;
|
|||
struct iio_buffer_setup_ops;
|
||||
|
||||
int iio_triggered_buffer_setup(struct iio_dev *indio_dev,
|
||||
irqreturn_t (*pollfunc_bh)(int irq, void *p),
|
||||
irqreturn_t (*pollfunc_th)(int irq, void *p),
|
||||
irqreturn_t (*h)(int irq, void *p),
|
||||
irqreturn_t (*thread)(int irq, void *p),
|
||||
const struct iio_buffer_setup_ops *setup_ops);
|
||||
void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev);
|
||||
|
||||
|
|
|
@ -51,14 +51,33 @@ int size_from_channelarray(struct iio_channel_info *channels, int num_channels)
|
|||
if (bytes % channels[i].bytes == 0)
|
||||
channels[i].location = bytes;
|
||||
else
|
||||
channels[i].location = bytes - bytes%channels[i].bytes
|
||||
+ channels[i].bytes;
|
||||
channels[i].location = bytes - bytes % channels[i].bytes
|
||||
+ channels[i].bytes;
|
||||
|
||||
bytes = channels[i].location + channels[i].bytes;
|
||||
i++;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void print1byte(uint8_t input, struct iio_channel_info *info)
|
||||
{
|
||||
/*
|
||||
* Shift before conversion to avoid sign extension
|
||||
* of left aligned data
|
||||
*/
|
||||
input >>= info->shift;
|
||||
input &= info->mask;
|
||||
if (info->is_signed) {
|
||||
int8_t val = (int8_t)(input << (8 - info->bits_used)) >>
|
||||
(8 - info->bits_used);
|
||||
printf("%05f ", ((float)val + info->offset) * info->scale);
|
||||
} else {
|
||||
printf("%05f ", ((float)input + info->offset) * info->scale);
|
||||
}
|
||||
}
|
||||
|
||||
void print2byte(uint16_t input, struct iio_channel_info *info)
|
||||
{
|
||||
/* First swap if incorrect endian */
|
||||
|
@ -136,9 +155,9 @@ void print8byte(uint64_t input, struct iio_channel_info *info)
|
|||
/**
|
||||
* process_scan() - print out the values in SI units
|
||||
* @data: pointer to the start of the scan
|
||||
* @channels: information about the channels. Note
|
||||
* size_from_channelarray must have been called first to fill the
|
||||
* location offsets.
|
||||
* @channels: information about the channels.
|
||||
* Note: size_from_channelarray must have been called first
|
||||
* to fill the location offsets.
|
||||
* @num_channels: number of channels
|
||||
**/
|
||||
void process_scan(char *data,
|
||||
|
@ -150,6 +169,10 @@ void process_scan(char *data,
|
|||
for (k = 0; k < num_channels; k++)
|
||||
switch (channels[k].bytes) {
|
||||
/* only a few cases implemented so far */
|
||||
case 1:
|
||||
print1byte(*(uint8_t *)(data + channels[k].location),
|
||||
&channels[k]);
|
||||
break;
|
||||
case 2:
|
||||
print2byte(*(uint16_t *)(data + channels[k].location),
|
||||
&channels[k]);
|
||||
|
@ -213,6 +236,7 @@ int main(int argc, char **argv)
|
|||
num_loops = strtoul(optarg, &dummy, 10);
|
||||
if (errno)
|
||||
return -errno;
|
||||
|
||||
break;
|
||||
case 'e':
|
||||
noevents = 1;
|
||||
|
@ -225,6 +249,7 @@ int main(int argc, char **argv)
|
|||
buf_len = strtoul(optarg, &dummy, 10);
|
||||
if (errno)
|
||||
return -errno;
|
||||
|
||||
break;
|
||||
case 'n':
|
||||
device_name = optarg;
|
||||
|
@ -257,6 +282,7 @@ int main(int argc, char **argv)
|
|||
printf("Failed to find the %s\n", device_name);
|
||||
return dev_num;
|
||||
}
|
||||
|
||||
printf("iio device number being used is %d\n", dev_num);
|
||||
|
||||
ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num);
|
||||
|
@ -285,9 +311,11 @@ int main(int argc, char **argv)
|
|||
ret = trig_num;
|
||||
goto error_free_triggername;
|
||||
}
|
||||
|
||||
printf("iio trigger number being used is %d\n", trig_num);
|
||||
} else
|
||||
} else {
|
||||
printf("trigger-less mode selected\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the files in scan_elements to identify what channels are
|
||||
|
@ -314,8 +342,10 @@ int main(int argc, char **argv)
|
|||
|
||||
if (!notrigger) {
|
||||
printf("%s %s\n", dev_dir_name, trigger_name);
|
||||
/* Set the device trigger to be the data ready trigger found
|
||||
* above */
|
||||
/*
|
||||
* Set the device trigger to be the data ready trigger found
|
||||
* above
|
||||
*/
|
||||
ret = write_sysfs_string_and_verify("trigger/current_trigger",
|
||||
dev_dir_name,
|
||||
trigger_name);
|
||||
|
@ -334,8 +364,9 @@ int main(int argc, char **argv)
|
|||
ret = write_sysfs_int("enable", buf_dir_name, 1);
|
||||
if (ret < 0)
|
||||
goto error_free_buf_dir_name;
|
||||
|
||||
scan_size = size_from_channelarray(channels, num_channels);
|
||||
data = malloc(scan_size*buf_len);
|
||||
data = malloc(scan_size * buf_len);
|
||||
if (!data) {
|
||||
ret = -ENOMEM;
|
||||
goto error_free_buf_dir_name;
|
||||
|
@ -349,13 +380,12 @@ int main(int argc, char **argv)
|
|||
|
||||
/* Attempt to open non blocking the access dev */
|
||||
fp = open(buffer_access, O_RDONLY | O_NONBLOCK);
|
||||
if (fp == -1) { /* If it isn't there make the node */
|
||||
if (fp == -1) { /* TODO: If it isn't there make the node */
|
||||
ret = -errno;
|
||||
printf("Failed to open %s\n", buffer_access);
|
||||
goto error_free_buffer_access;
|
||||
}
|
||||
|
||||
/* Wait for events 10 times */
|
||||
for (j = 0; j < num_loops; j++) {
|
||||
if (!noevents) {
|
||||
struct pollfd pfd = {
|
||||
|
@ -372,25 +402,22 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
toread = buf_len;
|
||||
|
||||
} else {
|
||||
usleep(timedelay);
|
||||
toread = 64;
|
||||
}
|
||||
|
||||
read_size = read(fp,
|
||||
data,
|
||||
toread*scan_size);
|
||||
read_size = read(fp, data, toread * scan_size);
|
||||
if (read_size < 0) {
|
||||
if (errno == EAGAIN) {
|
||||
printf("nothing available\n");
|
||||
continue;
|
||||
} else
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < read_size/scan_size; i++)
|
||||
process_scan(data + scan_size*i,
|
||||
channels,
|
||||
for (i = 0; i < read_size / scan_size; i++)
|
||||
process_scan(data + scan_size * i, channels,
|
||||
num_channels);
|
||||
}
|
||||
|
||||
|
@ -409,6 +436,7 @@ int main(int argc, char **argv)
|
|||
error_close_buffer_access:
|
||||
if (close(fp) == -1)
|
||||
perror("Failed to close buffer");
|
||||
|
||||
error_free_buffer_access:
|
||||
free(buffer_access);
|
||||
error_free_data:
|
||||
|
@ -424,6 +452,7 @@ error_free_channels:
|
|||
error_free_triggername:
|
||||
if (datardytrigger)
|
||||
free(trigger_name);
|
||||
|
||||
error_free_dev_dir_name:
|
||||
free(dev_dir_name);
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
*
|
||||
* Usage:
|
||||
* iio_event_monitor <device_name>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
|
@ -51,6 +50,9 @@ static const char * const iio_chan_type_name_spec[] = {
|
|||
[IIO_HUMIDITYRELATIVE] = "humidityrelative",
|
||||
[IIO_ACTIVITY] = "activity",
|
||||
[IIO_STEPS] = "steps",
|
||||
[IIO_ENERGY] = "energy",
|
||||
[IIO_DISTANCE] = "distance",
|
||||
[IIO_VELOCITY] = "velocity",
|
||||
};
|
||||
|
||||
static const char * const iio_ev_type_text[] = {
|
||||
|
@ -99,6 +101,7 @@ static const char * const iio_modifier_names[] = {
|
|||
[IIO_MOD_JOGGING] = "jogging",
|
||||
[IIO_MOD_WALKING] = "walking",
|
||||
[IIO_MOD_STILL] = "still",
|
||||
[IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z] = "sqrt(x^2+y^2+z^2)",
|
||||
};
|
||||
|
||||
static bool event_is_known(struct iio_event_data *event)
|
||||
|
@ -130,6 +133,9 @@ static bool event_is_known(struct iio_event_data *event)
|
|||
case IIO_HUMIDITYRELATIVE:
|
||||
case IIO_ACTIVITY:
|
||||
case IIO_STEPS:
|
||||
case IIO_ENERGY:
|
||||
case IIO_DISTANCE:
|
||||
case IIO_VELOCITY:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
@ -167,6 +173,7 @@ static bool event_is_known(struct iio_event_data *event)
|
|||
case IIO_MOD_JOGGING:
|
||||
case IIO_MOD_WALKING:
|
||||
case IIO_MOD_STILL:
|
||||
case IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
@ -209,7 +216,8 @@ static void print_event(struct iio_event_data *event)
|
|||
|
||||
if (!event_is_known(event)) {
|
||||
printf("Unknown event: time: %lld, id: %llx\n",
|
||||
event->timestamp, event->id);
|
||||
event->timestamp, event->id);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -229,6 +237,7 @@ static void print_event(struct iio_event_data *event)
|
|||
|
||||
if (dir != IIO_EV_DIR_NONE)
|
||||
printf(", direction: %s", iio_ev_dir_text[dir]);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
@ -251,14 +260,16 @@ int main(int argc, char **argv)
|
|||
dev_num = find_type_by_name(device_name, "iio:device");
|
||||
if (dev_num >= 0) {
|
||||
printf("Found IIO device with name %s with device number %d\n",
|
||||
device_name, dev_num);
|
||||
device_name, dev_num);
|
||||
ret = asprintf(&chrdev_name, "/dev/iio:device%d", dev_num);
|
||||
if (ret < 0) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
} else {
|
||||
/* If we can't find a IIO device by name assume device_name is a
|
||||
IIO chrdev */
|
||||
/*
|
||||
* If we can't find an IIO device by name assume device_name is
|
||||
* an IIO chrdev
|
||||
*/
|
||||
chrdev_name = strdup(device_name);
|
||||
if (!chrdev_name)
|
||||
return -ENOMEM;
|
||||
|
@ -299,6 +310,12 @@ int main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
if (ret != sizeof(event)) {
|
||||
printf("Reading event failed!\n");
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
print_event(&event);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,8 +32,7 @@ static char * const iio_direction[] = {
|
|||
*
|
||||
* Returns 0 on success, or a negative error code if string extraction failed.
|
||||
**/
|
||||
int iioutils_break_up_name(const char *full_name,
|
||||
char **generic_name)
|
||||
int iioutils_break_up_name(const char *full_name, char **generic_name)
|
||||
{
|
||||
char *current;
|
||||
char *w, *r;
|
||||
|
@ -65,6 +64,7 @@ int iioutils_break_up_name(const char *full_name,
|
|||
*w = *r;
|
||||
w++;
|
||||
}
|
||||
|
||||
r++;
|
||||
}
|
||||
*w = '\0';
|
||||
|
@ -88,15 +88,10 @@ int iioutils_break_up_name(const char *full_name,
|
|||
*
|
||||
* Returns a value >= 0 on success, otherwise a negative error code.
|
||||
**/
|
||||
int iioutils_get_type(unsigned *is_signed,
|
||||
unsigned *bytes,
|
||||
unsigned *bits_used,
|
||||
unsigned *shift,
|
||||
uint64_t *mask,
|
||||
unsigned *be,
|
||||
const char *device_dir,
|
||||
const char *name,
|
||||
const char *generic_name)
|
||||
int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
|
||||
unsigned *shift, uint64_t *mask, unsigned *be,
|
||||
const char *device_dir, const char *name,
|
||||
const char *generic_name)
|
||||
{
|
||||
FILE *sysfsfp;
|
||||
int ret;
|
||||
|
@ -126,6 +121,7 @@ int iioutils_get_type(unsigned *is_signed,
|
|||
ret = -errno;
|
||||
goto error_free_builtname_generic;
|
||||
}
|
||||
|
||||
ret = -ENOENT;
|
||||
while (ent = readdir(dp), ent != NULL)
|
||||
/*
|
||||
|
@ -140,6 +136,7 @@ int iioutils_get_type(unsigned *is_signed,
|
|||
ret = -ENOMEM;
|
||||
goto error_closedir;
|
||||
}
|
||||
|
||||
sysfsfp = fopen(filename, "r");
|
||||
if (sysfsfp == NULL) {
|
||||
ret = -errno;
|
||||
|
@ -162,12 +159,14 @@ int iioutils_get_type(unsigned *is_signed,
|
|||
printf("scan type description didn't match\n");
|
||||
goto error_close_sysfsfp;
|
||||
}
|
||||
|
||||
*be = (endianchar == 'b');
|
||||
*bytes = padint / 8;
|
||||
if (*bits_used == 64)
|
||||
*mask = ~0;
|
||||
else
|
||||
*mask = (1 << *bits_used) - 1;
|
||||
|
||||
*is_signed = (signchar == 's');
|
||||
if (fclose(sysfsfp)) {
|
||||
ret = -errno;
|
||||
|
@ -177,9 +176,9 @@ int iioutils_get_type(unsigned *is_signed,
|
|||
|
||||
sysfsfp = 0;
|
||||
free(filename);
|
||||
|
||||
filename = 0;
|
||||
}
|
||||
|
||||
error_close_sysfsfp:
|
||||
if (sysfsfp)
|
||||
if (fclose(sysfsfp))
|
||||
|
@ -188,6 +187,7 @@ error_close_sysfsfp:
|
|||
error_free_filename:
|
||||
if (filename)
|
||||
free(filename);
|
||||
|
||||
error_closedir:
|
||||
if (closedir(dp) == -1)
|
||||
perror("iioutils_get_type(): Failed to close directory");
|
||||
|
@ -212,11 +212,9 @@ error_free_scan_el_dir:
|
|||
*
|
||||
* Returns a value >= 0 on success, otherwise a negative error code.
|
||||
**/
|
||||
int iioutils_get_param_float(float *output,
|
||||
const char *param_name,
|
||||
const char *device_dir,
|
||||
const char *name,
|
||||
const char *generic_name)
|
||||
int iioutils_get_param_float(float *output, const char *param_name,
|
||||
const char *device_dir, const char *name,
|
||||
const char *generic_name)
|
||||
{
|
||||
FILE *sysfsfp;
|
||||
int ret;
|
||||
|
@ -235,11 +233,13 @@ int iioutils_get_param_float(float *output,
|
|||
ret = -ENOMEM;
|
||||
goto error_free_builtname;
|
||||
}
|
||||
|
||||
dp = opendir(device_dir);
|
||||
if (dp == NULL) {
|
||||
ret = -errno;
|
||||
goto error_free_builtname_generic;
|
||||
}
|
||||
|
||||
ret = -ENOENT;
|
||||
while (ent = readdir(dp), ent != NULL)
|
||||
if ((strcmp(builtname, ent->d_name) == 0) ||
|
||||
|
@ -250,11 +250,13 @@ int iioutils_get_param_float(float *output,
|
|||
ret = -ENOMEM;
|
||||
goto error_closedir;
|
||||
}
|
||||
|
||||
sysfsfp = fopen(filename, "r");
|
||||
if (!sysfsfp) {
|
||||
ret = -errno;
|
||||
goto error_free_filename;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
if (fscanf(sysfsfp, "%f", output) != 1)
|
||||
ret = errno ? -errno : -ENODATA;
|
||||
|
@ -264,6 +266,7 @@ int iioutils_get_param_float(float *output,
|
|||
error_free_filename:
|
||||
if (filename)
|
||||
free(filename);
|
||||
|
||||
error_closedir:
|
||||
if (closedir(dp) == -1)
|
||||
perror("iioutils_get_param_float(): Failed to close directory");
|
||||
|
@ -282,16 +285,14 @@ error_free_builtname:
|
|||
* @cnt: the amount of array elements
|
||||
**/
|
||||
|
||||
void bsort_channel_array_by_index(struct iio_channel_info **ci_array,
|
||||
int cnt)
|
||||
void bsort_channel_array_by_index(struct iio_channel_info **ci_array, int cnt)
|
||||
{
|
||||
|
||||
struct iio_channel_info temp;
|
||||
int x, y;
|
||||
|
||||
for (x = 0; x < cnt; x++)
|
||||
for (y = 0; y < (cnt - 1); y++)
|
||||
if ((*ci_array)[y].index > (*ci_array)[y+1].index) {
|
||||
if ((*ci_array)[y].index > (*ci_array)[y + 1].index) {
|
||||
temp = (*ci_array)[y + 1];
|
||||
(*ci_array)[y + 1] = (*ci_array)[y];
|
||||
(*ci_array)[y] = temp;
|
||||
|
@ -307,8 +308,7 @@ void bsort_channel_array_by_index(struct iio_channel_info **ci_array,
|
|||
* Returns 0 on success, otherwise a negative error code.
|
||||
**/
|
||||
int build_channel_array(const char *device_dir,
|
||||
struct iio_channel_info **ci_array,
|
||||
int *counter)
|
||||
struct iio_channel_info **ci_array, int *counter)
|
||||
{
|
||||
DIR *dp;
|
||||
FILE *sysfsfp;
|
||||
|
@ -329,6 +329,7 @@ int build_channel_array(const char *device_dir,
|
|||
ret = -errno;
|
||||
goto error_free_name;
|
||||
}
|
||||
|
||||
while (ent = readdir(dp), ent != NULL)
|
||||
if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
|
||||
"_en") == 0) {
|
||||
|
@ -338,12 +339,14 @@ int build_channel_array(const char *device_dir,
|
|||
ret = -ENOMEM;
|
||||
goto error_close_dir;
|
||||
}
|
||||
|
||||
sysfsfp = fopen(filename, "r");
|
||||
if (sysfsfp == NULL) {
|
||||
ret = -errno;
|
||||
free(filename);
|
||||
goto error_close_dir;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
if (fscanf(sysfsfp, "%i", &ret) != 1) {
|
||||
ret = errno ? -errno : -ENODATA;
|
||||
|
@ -353,9 +356,9 @@ int build_channel_array(const char *device_dir,
|
|||
free(filename);
|
||||
goto error_close_dir;
|
||||
}
|
||||
|
||||
if (ret == 1)
|
||||
(*counter)++;
|
||||
|
||||
if (fclose(sysfsfp)) {
|
||||
ret = -errno;
|
||||
free(filename);
|
||||
|
@ -364,11 +367,13 @@ int build_channel_array(const char *device_dir,
|
|||
|
||||
free(filename);
|
||||
}
|
||||
|
||||
*ci_array = malloc(sizeof(**ci_array) * (*counter));
|
||||
if (*ci_array == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error_close_dir;
|
||||
}
|
||||
|
||||
seekdir(dp, 0);
|
||||
while (ent = readdir(dp), ent != NULL) {
|
||||
if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
|
||||
|
@ -384,6 +389,7 @@ int build_channel_array(const char *device_dir,
|
|||
count--;
|
||||
goto error_cleanup_array;
|
||||
}
|
||||
|
||||
sysfsfp = fopen(filename, "r");
|
||||
if (sysfsfp == NULL) {
|
||||
ret = -errno;
|
||||
|
@ -391,6 +397,7 @@ int build_channel_array(const char *device_dir,
|
|||
count--;
|
||||
goto error_cleanup_array;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
if (fscanf(sysfsfp, "%i", ¤t_enabled) != 1) {
|
||||
ret = errno ? -errno : -ENODATA;
|
||||
|
@ -423,6 +430,7 @@ int build_channel_array(const char *device_dir,
|
|||
count--;
|
||||
goto error_cleanup_array;
|
||||
}
|
||||
|
||||
/* Get the generic and specific name elements */
|
||||
ret = iioutils_break_up_name(current->name,
|
||||
¤t->generic_name);
|
||||
|
@ -432,6 +440,7 @@ int build_channel_array(const char *device_dir,
|
|||
count--;
|
||||
goto error_cleanup_array;
|
||||
}
|
||||
|
||||
ret = asprintf(&filename,
|
||||
"%s/%s_index",
|
||||
scan_el_dir,
|
||||
|
@ -441,6 +450,7 @@ int build_channel_array(const char *device_dir,
|
|||
ret = -ENOMEM;
|
||||
goto error_cleanup_array;
|
||||
}
|
||||
|
||||
sysfsfp = fopen(filename, "r");
|
||||
if (sysfsfp == NULL) {
|
||||
ret = -errno;
|
||||
|
@ -474,6 +484,7 @@ int build_channel_array(const char *device_dir,
|
|||
current->generic_name);
|
||||
if (ret < 0)
|
||||
goto error_cleanup_array;
|
||||
|
||||
ret = iioutils_get_param_float(¤t->offset,
|
||||
"offset",
|
||||
device_dir,
|
||||
|
@ -481,6 +492,7 @@ int build_channel_array(const char *device_dir,
|
|||
current->generic_name);
|
||||
if (ret < 0)
|
||||
goto error_cleanup_array;
|
||||
|
||||
ret = iioutils_get_type(¤t->is_signed,
|
||||
¤t->bytes,
|
||||
¤t->bits_used,
|
||||
|
@ -549,7 +561,7 @@ int find_type_by_name(const char *name, const char *type)
|
|||
const struct dirent *ent;
|
||||
int number, numstrlen, ret;
|
||||
|
||||
FILE *nameFile;
|
||||
FILE *namefp;
|
||||
DIR *dp;
|
||||
char thisname[IIO_MAX_NAME_LENGTH];
|
||||
char *filename;
|
||||
|
@ -562,9 +574,9 @@ int find_type_by_name(const char *name, const char *type)
|
|||
|
||||
while (ent = readdir(dp), ent != NULL) {
|
||||
if (strcmp(ent->d_name, ".") != 0 &&
|
||||
strcmp(ent->d_name, "..") != 0 &&
|
||||
strlen(ent->d_name) > strlen(type) &&
|
||||
strncmp(ent->d_name, type, strlen(type)) == 0) {
|
||||
strcmp(ent->d_name, "..") != 0 &&
|
||||
strlen(ent->d_name) > strlen(type) &&
|
||||
strncmp(ent->d_name, type, strlen(type)) == 0) {
|
||||
errno = 0;
|
||||
ret = sscanf(ent->d_name + strlen(type), "%d", &number);
|
||||
if (ret < 0) {
|
||||
|
@ -580,12 +592,9 @@ int find_type_by_name(const char *name, const char *type)
|
|||
numstrlen = calc_digits(number);
|
||||
/* verify the next character is not a colon */
|
||||
if (strncmp(ent->d_name + strlen(type) + numstrlen,
|
||||
":",
|
||||
1) != 0) {
|
||||
filename = malloc(strlen(iio_dir)
|
||||
+ strlen(type)
|
||||
+ numstrlen
|
||||
+ 6);
|
||||
":", 1) != 0) {
|
||||
filename = malloc(strlen(iio_dir) + strlen(type)
|
||||
+ numstrlen + 6);
|
||||
if (filename == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error_close_dir;
|
||||
|
@ -598,19 +607,20 @@ int find_type_by_name(const char *name, const char *type)
|
|||
goto error_close_dir;
|
||||
}
|
||||
|
||||
nameFile = fopen(filename, "r");
|
||||
if (!nameFile) {
|
||||
namefp = fopen(filename, "r");
|
||||
if (!namefp) {
|
||||
free(filename);
|
||||
continue;
|
||||
}
|
||||
|
||||
free(filename);
|
||||
errno = 0;
|
||||
if (fscanf(nameFile, "%s", thisname) != 1) {
|
||||
if (fscanf(namefp, "%s", thisname) != 1) {
|
||||
ret = errno ? -errno : -ENODATA;
|
||||
goto error_close_dir;
|
||||
}
|
||||
|
||||
if (fclose(nameFile)) {
|
||||
if (fclose(namefp)) {
|
||||
ret = -errno;
|
||||
goto error_close_dir;
|
||||
}
|
||||
|
@ -618,6 +628,7 @@ int find_type_by_name(const char *name, const char *type)
|
|||
if (strcmp(name, thisname) == 0) {
|
||||
if (closedir(dp) == -1)
|
||||
return -errno;
|
||||
|
||||
return number;
|
||||
}
|
||||
}
|
||||
|
@ -631,6 +642,7 @@ int find_type_by_name(const char *name, const char *type)
|
|||
error_close_dir:
|
||||
if (closedir(dp) == -1)
|
||||
perror("find_type_by_name(): Failed to close directory");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -644,6 +656,7 @@ static int _write_sysfs_int(const char *filename, const char *basedir, int val,
|
|||
|
||||
if (temp == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = sprintf(temp, "%s/%s", basedir, filename);
|
||||
if (ret < 0)
|
||||
goto error_free;
|
||||
|
@ -654,6 +667,7 @@ static int _write_sysfs_int(const char *filename, const char *basedir, int val,
|
|||
printf("failed to open %s\n", temp);
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
ret = fprintf(sysfsfp, "%d", val);
|
||||
if (ret < 0) {
|
||||
if (fclose(sysfsfp))
|
||||
|
@ -674,6 +688,7 @@ static int _write_sysfs_int(const char *filename, const char *basedir, int val,
|
|||
printf("failed to open %s\n", temp);
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
if (fscanf(sysfsfp, "%d", &test) != 1) {
|
||||
ret = errno ? -errno : -ENODATA;
|
||||
if (fclose(sysfsfp))
|
||||
|
@ -688,13 +703,12 @@ static int _write_sysfs_int(const char *filename, const char *basedir, int val,
|
|||
}
|
||||
|
||||
if (test != val) {
|
||||
printf("Possible failure in int write %d to %s%s\n",
|
||||
val,
|
||||
basedir,
|
||||
filename);
|
||||
printf("Possible failure in int write %d to %s/%s\n",
|
||||
val, basedir, filename);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
error_free:
|
||||
free(temp);
|
||||
return ret;
|
||||
|
@ -739,6 +753,7 @@ static int _write_sysfs_string(const char *filename, const char *basedir,
|
|||
printf("Memory allocation failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = sprintf(temp, "%s/%s", basedir, filename);
|
||||
if (ret < 0)
|
||||
goto error_free;
|
||||
|
@ -749,6 +764,7 @@ static int _write_sysfs_string(const char *filename, const char *basedir,
|
|||
printf("Could not open %s\n", temp);
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
ret = fprintf(sysfsfp, "%s", val);
|
||||
if (ret < 0) {
|
||||
if (fclose(sysfsfp))
|
||||
|
@ -766,9 +782,10 @@ static int _write_sysfs_string(const char *filename, const char *basedir,
|
|||
sysfsfp = fopen(temp, "r");
|
||||
if (sysfsfp == NULL) {
|
||||
ret = -errno;
|
||||
printf("could not open file to verify\n");
|
||||
printf("Could not open file to verify\n");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
if (fscanf(sysfsfp, "%s", temp) != 1) {
|
||||
ret = errno ? -errno : -ENODATA;
|
||||
if (fclose(sysfsfp))
|
||||
|
@ -784,15 +801,12 @@ static int _write_sysfs_string(const char *filename, const char *basedir,
|
|||
|
||||
if (strcmp(temp, val) != 0) {
|
||||
printf("Possible failure in string write of %s "
|
||||
"Should be %s "
|
||||
"written to %s\%s\n",
|
||||
temp,
|
||||
val,
|
||||
basedir,
|
||||
filename);
|
||||
"Should be %s written to %s/%s\n", temp, val,
|
||||
basedir, filename);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
error_free:
|
||||
free(temp);
|
||||
|
||||
|
@ -845,6 +859,7 @@ int read_sysfs_posint(const char *filename, const char *basedir)
|
|||
printf("Memory allocation failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = sprintf(temp, "%s/%s", basedir, filename);
|
||||
if (ret < 0)
|
||||
goto error_free;
|
||||
|
@ -854,6 +869,7 @@ int read_sysfs_posint(const char *filename, const char *basedir)
|
|||
ret = -errno;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
if (fscanf(sysfsfp, "%d\n", &ret) != 1) {
|
||||
ret = errno ? -errno : -ENODATA;
|
||||
|
@ -868,6 +884,7 @@ int read_sysfs_posint(const char *filename, const char *basedir)
|
|||
|
||||
error_free:
|
||||
free(temp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -889,6 +906,7 @@ int read_sysfs_float(const char *filename, const char *basedir, float *val)
|
|||
printf("Memory allocation failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = sprintf(temp, "%s/%s", basedir, filename);
|
||||
if (ret < 0)
|
||||
goto error_free;
|
||||
|
@ -898,6 +916,7 @@ int read_sysfs_float(const char *filename, const char *basedir, float *val)
|
|||
ret = -errno;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
if (fscanf(sysfsfp, "%f\n", val) != 1) {
|
||||
ret = errno ? -errno : -ENODATA;
|
||||
|
@ -912,6 +931,7 @@ int read_sysfs_float(const char *filename, const char *basedir, float *val)
|
|||
|
||||
error_free:
|
||||
free(temp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -933,6 +953,7 @@ int read_sysfs_string(const char *filename, const char *basedir, char *str)
|
|||
printf("Memory allocation failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = sprintf(temp, "%s/%s", basedir, filename);
|
||||
if (ret < 0)
|
||||
goto error_free;
|
||||
|
@ -942,6 +963,7 @@ int read_sysfs_string(const char *filename, const char *basedir, char *str)
|
|||
ret = -errno;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
if (fscanf(sysfsfp, "%s\n", str) != 1) {
|
||||
ret = errno ? -errno : -ENODATA;
|
||||
|
@ -956,6 +978,7 @@ int read_sysfs_string(const char *filename, const char *basedir, char *str)
|
|||
|
||||
error_free:
|
||||
free(temp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -51,17 +51,16 @@ struct iio_channel_info {
|
|||
};
|
||||
|
||||
int iioutils_break_up_name(const char *full_name, char **generic_name);
|
||||
int iioutils_get_type(unsigned *is_signed, unsigned *bytes,
|
||||
unsigned *bits_used, unsigned *shift,
|
||||
uint64_t *mask, unsigned *be,
|
||||
const char *device_dir, const char *name,
|
||||
const char *generic_name);
|
||||
int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
|
||||
unsigned *shift, uint64_t *mask, unsigned *be,
|
||||
const char *device_dir, const char *name,
|
||||
const char *generic_name);
|
||||
int iioutils_get_param_float(float *output, const char *param_name,
|
||||
const char *device_dir, const char *name,
|
||||
const char *generic_name);
|
||||
const char *device_dir, const char *name,
|
||||
const char *generic_name);
|
||||
void bsort_channel_array_by_index(struct iio_channel_info **ci_array, int cnt);
|
||||
int build_channel_array(const char *device_dir,
|
||||
struct iio_channel_info **ci_array, int *counter);
|
||||
struct iio_channel_info **ci_array, int *counter);
|
||||
int find_type_by_name(const char *name, const char *type);
|
||||
int write_sysfs_int(const char *filename, const char *basedir, int val);
|
||||
int write_sysfs_int_and_verify(const char *filename, const char *basedir,
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include <sys/dir.h>
|
||||
#include "iio_utils.h"
|
||||
|
||||
|
||||
static enum verbosity {
|
||||
VERBLEVEL_DEFAULT, /* 0 gives lspci behaviour */
|
||||
VERBLEVEL_SENSORS, /* 1 lists sensors */
|
||||
|
@ -29,17 +28,16 @@ static enum verbosity {
|
|||
const char *type_device = "iio:device";
|
||||
const char *type_trigger = "trigger";
|
||||
|
||||
|
||||
static inline int check_prefix(const char *str, const char *prefix)
|
||||
{
|
||||
return strlen(str) > strlen(prefix) &&
|
||||
strncmp(str, prefix, strlen(prefix)) == 0;
|
||||
strncmp(str, prefix, strlen(prefix)) == 0;
|
||||
}
|
||||
|
||||
static inline int check_postfix(const char *str, const char *postfix)
|
||||
{
|
||||
return strlen(str) > strlen(postfix) &&
|
||||
strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
|
||||
strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
|
||||
}
|
||||
|
||||
static int dump_channels(const char *dev_dir_name)
|
||||
|
@ -50,11 +48,11 @@ static int dump_channels(const char *dev_dir_name)
|
|||
dp = opendir(dev_dir_name);
|
||||
if (dp == NULL)
|
||||
return -errno;
|
||||
|
||||
while (ent = readdir(dp), ent != NULL)
|
||||
if (check_prefix(ent->d_name, "in_") &&
|
||||
check_postfix(ent->d_name, "_raw")) {
|
||||
check_postfix(ent->d_name, "_raw"))
|
||||
printf(" %-10s\n", ent->d_name);
|
||||
}
|
||||
|
||||
return (closedir(dp) == -1) ? -errno : 0;
|
||||
}
|
||||
|
@ -63,20 +61,22 @@ static int dump_one_device(const char *dev_dir_name)
|
|||
{
|
||||
char name[IIO_MAX_NAME_LENGTH];
|
||||
int dev_idx;
|
||||
int retval;
|
||||
int ret;
|
||||
|
||||
retval = sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_device),
|
||||
"%i", &dev_idx);
|
||||
if (retval != 1)
|
||||
ret = sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_device), "%i",
|
||||
&dev_idx);
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
retval = read_sysfs_string("name", dev_dir_name, name);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ret = read_sysfs_string("name", dev_dir_name, name);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
printf("Device %03d: %s\n", dev_idx, name);
|
||||
|
||||
if (verblevel >= VERBLEVEL_SENSORS)
|
||||
return dump_channels(dev_dir_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -84,17 +84,19 @@ static int dump_one_trigger(const char *dev_dir_name)
|
|||
{
|
||||
char name[IIO_MAX_NAME_LENGTH];
|
||||
int dev_idx;
|
||||
int retval;
|
||||
int ret;
|
||||
|
||||
retval = sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_trigger),
|
||||
"%i", &dev_idx);
|
||||
if (retval != 1)
|
||||
ret = sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_trigger),
|
||||
"%i", &dev_idx);
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
retval = read_sysfs_string("name", dev_dir_name, name);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ret = read_sysfs_string("name", dev_dir_name, name);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
printf("Trigger %03d: %s\n", dev_idx, name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -151,6 +153,7 @@ static int dump_devices(void)
|
|||
free(dev_dir_name);
|
||||
}
|
||||
}
|
||||
|
||||
return (closedir(dp) == -1) ? -errno : 0;
|
||||
|
||||
error_close_dir:
|
||||
|
|
Loading…
Reference in New Issue