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:
Greg Kroah-Hartman 2015-07-15 12:32:09 -07:00
commit e913bfb60b
68 changed files with 1872 additions and 454 deletions

View File

@ -413,6 +413,11 @@ Description:
to compute the calories burnt by the user. to compute the calories burnt by the user.
What: /sys/bus/iio/devices/iio:deviceX/in_accel_scale_available 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_voltageX_scale_available
What: /sys/.../iio:deviceX/in_voltage-voltage_scale_available What: /sys/.../iio:deviceX/in_voltage-voltage_scale_available
What: /sys/.../iio:deviceX/out_voltageX_scale_available What: /sys/.../iio:deviceX/out_voltageX_scale_available

View File

@ -846,7 +846,6 @@ MODULE_DEVICE_TABLE(i2c, bma180_ids);
static struct i2c_driver bma180_driver = { static struct i2c_driver bma180_driver = {
.driver = { .driver = {
.name = "bma180", .name = "bma180",
.owner = THIS_MODULE,
.pm = BMA180_PM_OPS, .pm = BMA180_PM_OPS,
}, },
.probe = bma180_probe, .probe = bma180_probe,

View File

@ -241,7 +241,6 @@ static const struct {
{500000, BMC150_ACCEL_SLEEP_500_MS}, {500000, BMC150_ACCEL_SLEEP_500_MS},
{1000000, BMC150_ACCEL_SLEEP_1_SEC} }; {1000000, BMC150_ACCEL_SLEEP_1_SEC} };
static int bmc150_accel_set_mode(struct bmc150_accel_data *data, static int bmc150_accel_set_mode(struct bmc150_accel_data *data,
enum bmc150_power_modes mode, enum bmc150_power_modes mode,
int dur_us) int dur_us)
@ -259,8 +258,9 @@ static int bmc150_accel_set_mode(struct bmc150_accel_data *data,
dur_val = dur_val =
bmc150_accel_sleep_value_table[i].reg_value; bmc150_accel_sleep_value_table[i].reg_value;
} }
} else } else {
dur_val = 0; dur_val = 0;
}
if (dur_val < 0) if (dur_val < 0)
return -EINVAL; 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) { for (i = 0; i < ARRAY_SIZE(bmc150_accel_samp_freq_table); ++i) {
if (bmc150_accel_samp_freq_table[i].val == val && 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( ret = i2c_smbus_write_byte_data(
data->client, data->client,
BMC150_ACCEL_REG_PMU_BW, 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); ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID);
if (ret < 0) { if (ret < 0) {
dev_err(&data->client->dev, dev_err(&data->client->dev, "Error: Reading chip id\n");
"Error: Reading chip id\n");
return ret; return ret;
} }
@ -376,8 +375,7 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
BMC150_ACCEL_REG_PMU_RANGE, BMC150_ACCEL_REG_PMU_RANGE,
BMC150_ACCEL_DEF_RANGE_4G); BMC150_ACCEL_DEF_RANGE_4G);
if (ret < 0) { if (ret < 0) {
dev_err(&data->client->dev, dev_err(&data->client->dev, "Error writing reg_pmu_range\n");
"Error writing reg_pmu_range\n");
return ret; return ret;
} }
@ -437,12 +435,13 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
{ {
int ret; int ret;
if (on) if (on) {
ret = pm_runtime_get_sync(&data->client->dev); ret = pm_runtime_get_sync(&data->client->dev);
else { } else {
pm_runtime_mark_last_busy(&data->client->dev); pm_runtime_mark_last_busy(&data->client->dev);
ret = pm_runtime_put_autosuspend(&data->client->dev); ret = pm_runtime_put_autosuspend(&data->client->dev);
} }
if (ret < 0) { if (ret < 0) {
dev_err(&data->client->dev, dev_err(&data->client->dev,
"Failed: bmc150_accel_set_power_state for %d\n", on); "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 * We will expect the enable and disable to do operation in reverse
* in reverse order. This will happen here anyway as our * order. This will happen here anyway, as our resume operation uses
* resume operation uses sync mode runtime pm calls, the * sync mode runtime pm calls. The suspend operation will be delayed
* suspend operation will be delayed by autosuspend delay * by autosuspend delay.
* So the disable operation will still happen in reverse of * So the disable operation will still happen in reverse order of
* enable operation. When runtime pm is disabled the mode * enable operation. When runtime pm is disabled the mode is always on,
* is always on so sequence doesn't matter * so sequence doesn't matter.
*/ */
ret = bmc150_accel_set_power_state(data, state); ret = bmc150_accel_set_power_state(data, state);
if (ret < 0) if (ret < 0)
@ -574,7 +573,6 @@ out_fix_power_state:
return ret; return ret;
} }
static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val) static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val)
{ {
int ret, i; int ret, i;
@ -674,8 +672,9 @@ static int bmc150_accel_read_raw(struct iio_dev *indio_dev,
if (chan->type == IIO_TEMP) { if (chan->type == IIO_TEMP) {
*val = BMC150_ACCEL_TEMP_CENTER_VAL; *val = BMC150_ACCEL_TEMP_CENTER_VAL;
return IIO_VAL_INT; return IIO_VAL_INT;
} else } else {
return -EINVAL; return -EINVAL;
}
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
*val = 0; *val = 0;
switch (chan->type) { switch (chan->type) {
@ -776,7 +775,7 @@ static int bmc150_accel_write_event(struct iio_dev *indio_dev,
switch (info) { switch (info) {
case IIO_EV_INFO_VALUE: case IIO_EV_INFO_VALUE:
data->slope_thres = val & 0xFF; data->slope_thres = val & BMC150_ACCEL_SLOPE_THRES_MASK;
break; break;
case IIO_EV_INFO_PERIOD: case IIO_EV_INFO_PERIOD:
data->slope_dur = val & BMC150_ACCEL_SLOPE_DUR_MASK; 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_type type,
enum iio_event_direction dir) enum iio_event_direction dir)
{ {
struct bmc150_accel_data *data = iio_priv(indio_dev); struct bmc150_accel_data *data = iio_priv(indio_dev);
return data->ev_enable_state; 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, 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); struct bmc150_accel_data *data = iio_priv(indio_dev);
int i; int i;
@ -963,6 +961,7 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
u16 buffer[BMC150_ACCEL_FIFO_LENGTH * 3]; u16 buffer[BMC150_ACCEL_FIFO_LENGTH * 3];
int64_t tstamp; int64_t tstamp;
uint64_t sample_period; uint64_t sample_period;
ret = i2c_smbus_read_byte_data(data->client, ret = i2c_smbus_read_byte_data(data->client,
BMC150_ACCEL_REG_FIFO_STATUS); BMC150_ACCEL_REG_FIFO_STATUS);
if (ret < 0) { 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, 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_trigger *t = iio_trigger_get_drvdata(trig);
struct bmc150_accel_data *data = t->data; 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; dir = IIO_EV_DIR_RISING;
if (ret & BMC150_ACCEL_ANY_MOTION_BIT_X) if (ret & BMC150_ACCEL_ANY_MOTION_BIT_X)
iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, iio_push_event(indio_dev,
0, IIO_MOD_EVENT_CODE(IIO_ACCEL,
IIO_MOD_X, 0,
IIO_EV_TYPE_ROC, IIO_MOD_X,
dir), IIO_EV_TYPE_ROC,
data->timestamp); dir),
data->timestamp);
if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Y) if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Y)
iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, iio_push_event(indio_dev,
0, IIO_MOD_EVENT_CODE(IIO_ACCEL,
IIO_MOD_Y, 0,
IIO_EV_TYPE_ROC, IIO_MOD_Y,
dir), IIO_EV_TYPE_ROC,
data->timestamp); dir),
data->timestamp);
if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Z) if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Z)
iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, iio_push_event(indio_dev,
0, IIO_MOD_EVENT_CODE(IIO_ACCEL,
IIO_MOD_Z, 0,
IIO_EV_TYPE_ROC, IIO_MOD_Z,
dir), IIO_EV_TYPE_ROC,
data->timestamp); dir),
data->timestamp);
return ret; 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_INT |
BMC150_ACCEL_INT_MODE_LATCH_RESET); BMC150_ACCEL_INT_MODE_LATCH_RESET);
if (ret) 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; ret = IRQ_HANDLED;
} else { } else {
ret = IRQ_NONE; ret = IRQ_NONE;
@ -1412,13 +1419,13 @@ static const char *bmc150_accel_match_acpi_device(struct device *dev, int *data)
if (!id) if (!id)
return NULL; return NULL;
*data = (int) id->driver_data; *data = (int)id->driver_data;
return dev_name(dev); return dev_name(dev);
} }
static int bmc150_accel_gpio_probe(struct i2c_client *client, static int bmc150_accel_gpio_probe(struct i2c_client *client,
struct bmc150_accel_data *data) struct bmc150_accel_data *data)
{ {
struct device *dev; struct device *dev;
struct gpio_desc *gpio; struct gpio_desc *gpio;

View File

@ -658,10 +658,8 @@ static int kxcjk1013_set_scale(struct kxcjk1013_data *data, int val)
int ret, i; int ret, i;
enum kxcjk1013_mode store_mode; enum kxcjk1013_mode store_mode;
for (i = 0; i < ARRAY_SIZE(KXCJK1013_scale_table); ++i) { for (i = 0; i < ARRAY_SIZE(KXCJK1013_scale_table); ++i) {
if (KXCJK1013_scale_table[i].scale == val) { if (KXCJK1013_scale_table[i].scale == val) {
ret = kxcjk1013_get_mode(data, &store_mode); ret = kxcjk1013_get_mode(data, &store_mode);
if (ret < 0) if (ret < 0)
return ret; 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_type type,
enum iio_event_direction dir) enum iio_event_direction dir)
{ {
struct kxcjk1013_data *data = iio_priv(indio_dev); struct kxcjk1013_data *data = iio_priv(indio_dev);
return data->ev_enable_state; return data->ev_enable_state;

View File

@ -297,7 +297,7 @@ EXPORT_SYMBOL(mma9551_read_status_byte);
* Returns: 0 on success, negative value on failure. * Returns: 0 on success, negative value on failure.
*/ */
int mma9551_read_config_word(struct i2c_client *client, u8 app_id, int mma9551_read_config_word(struct i2c_client *client, u8 app_id,
u16 reg, u16 *val) u16 reg, u16 *val)
{ {
int ret; int ret;
__be16 v; __be16 v;
@ -328,12 +328,12 @@ EXPORT_SYMBOL(mma9551_read_config_word);
* Returns: 0 on success, negative value on failure. * Returns: 0 on success, negative value on failure.
*/ */
int mma9551_write_config_word(struct i2c_client *client, u8 app_id, 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); __be16 v = cpu_to_be16(val);
return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg, 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); EXPORT_SYMBOL(mma9551_write_config_word);
@ -373,7 +373,7 @@ EXPORT_SYMBOL(mma9551_read_status_word);
* @client: I2C client * @client: I2C client
* @app_id: Application ID * @app_id: Application ID
* @reg: Application register * @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 * @buf: Array of words to read
* *
* Read multiple configuration registers (word-sized registers). * 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. * Returns: 0 on success, negative value on failure.
*/ */
int mma9551_read_config_words(struct i2c_client *client, u8 app_id, 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 ret, i;
int len_words = len / sizeof(u16);
__be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS / 2]; __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); dev_err(&client->dev, "Invalid buffer size %d\n", len);
return -EINVAL; return -EINVAL;
} }
ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG, 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) if (ret < 0)
return ret; return ret;
for (i = 0; i < len_words; i++) for (i = 0; i < len; i++)
buf[i] = be16_to_cpu(be_buf[i]); buf[i] = be16_to_cpu(be_buf[i]);
return 0; return 0;
@ -413,7 +412,7 @@ EXPORT_SYMBOL(mma9551_read_config_words);
* @client: I2C client * @client: I2C client
* @app_id: Application ID * @app_id: Application ID
* @reg: Application register * @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 * @buf: Array of words to read
* *
* Read multiple status registers (word-sized registers). * 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) u16 reg, u8 len, u16 *buf)
{ {
int ret, i; int ret, i;
int len_words = len / sizeof(u16);
__be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS / 2]; __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); dev_err(&client->dev, "Invalid buffer size %d\n", len);
return -EINVAL; return -EINVAL;
} }
ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS, 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) if (ret < 0)
return ret; return ret;
for (i = 0; i < len_words; i++) for (i = 0; i < len; i++)
buf[i] = be16_to_cpu(be_buf[i]); buf[i] = be16_to_cpu(be_buf[i]);
return 0; return 0;
@ -453,7 +451,7 @@ EXPORT_SYMBOL(mma9551_read_status_words);
* @client: I2C client * @client: I2C client
* @app_id: Application ID * @app_id: Application ID
* @reg: Application register * @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 * @buf: Array of words to write
* *
* Write multiple configuration registers (word-sized registers). * 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) u16 reg, u8 len, u16 *buf)
{ {
int i; int i;
int len_words = len / sizeof(u16);
__be16 be_buf[(MMA9551_MAX_MAILBOX_DATA_REGS - 1) / 2]; __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); dev_err(&client->dev, "Invalid buffer size %d\n", len);
return -EINVAL; return -EINVAL;
} }
for (i = 0; i < len_words; i++) for (i = 0; i < len; i++)
be_buf[i] = cpu_to_be16(buf[i]); be_buf[i] = cpu_to_be16(buf[i]);
return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, 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); EXPORT_SYMBOL(mma9551_write_config_words);

View File

@ -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, int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
u16 reg, u8 *val); u16 reg, u8 *val);
int mma9551_read_config_word(struct i2c_client *client, u8 app_id, 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, 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, int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
u16 reg, u16 *val); u16 reg, u16 *val);
int mma9551_read_config_words(struct i2c_client *client, u8 app_id, 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, int mma9551_read_status_words(struct i2c_client *client, u8 app_id,
u16 reg, u8 len, u16 *buf); u16 reg, u8 len, u16 *buf);
int mma9551_write_config_words(struct i2c_client *client, u8 app_id, int mma9551_write_config_words(struct i2c_client *client, u8 app_id,

View File

@ -182,6 +182,10 @@ struct mma9553_conf_regs {
struct mma9553_data { struct mma9553_data {
struct i2c_client *client; 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 mutex mutex;
struct mma9553_conf_regs conf; struct mma9553_conf_regs conf;
struct mma9553_event events[MMA9553_EVENTS_INFO_SIZE]; struct mma9553_event events[MMA9553_EVENTS_INFO_SIZE];
@ -322,7 +326,8 @@ static int mma9553_read_activity_stepcnt(struct mma9553_data *data,
int ret; int ret;
ret = mma9551_read_status_words(data->client, MMA9551_APPID_PEDOMETER, 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) { if (ret < 0) {
dev_err(&data->client->dev, dev_err(&data->client->dev,
"error reading status and stepcnt\n"); "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; struct mma9553_event *ev_step_detect;
bool activity_enabled; bool activity_enabled;
activity_enabled = activity_enabled = mma9553_is_any_event_enabled(data, true,
mma9553_is_any_event_enabled(data, true, IIO_ACTIVITY); IIO_ACTIVITY);
ev_step_detect = ev_step_detect = mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD,
mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, IIO_EV_DIR_NONE); IIO_EV_DIR_NONE);
/* /*
* If both step detector and activity are enabled, use the MRGFL bit. * 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; return ret;
} }
ret = mma9551_gpio_config(data->client, ret = mma9551_gpio_config(data->client, MMA9553_DEFAULT_GPIO_PIN, appid,
MMA9553_DEFAULT_GPIO_PIN, bitnum, MMA9553_DEFAULT_GPIO_POLARITY);
appid, bitnum, MMA9553_DEFAULT_GPIO_POLARITY);
if (ret < 0) if (ret < 0)
return ret; return ret;
data->gpio_bitnum = bitnum; data->gpio_bitnum = bitnum;
@ -394,17 +398,16 @@ static int mma9553_init(struct mma9553_data *data)
* a device identification command to differentiate the MMA9553L * a device identification command to differentiate the MMA9553L
* from the MMA9550L. * from the MMA9550L.
*/ */
ret = ret = mma9551_read_config_words(data->client, MMA9551_APPID_PEDOMETER,
mma9551_read_config_words(data->client, MMA9551_APPID_PEDOMETER, MMA9553_REG_CONF_SLEEPMIN,
MMA9553_REG_CONF_SLEEPMIN, sizeof(data->conf) / sizeof(u16),
sizeof(data->conf), (u16 *) &data->conf); (u16 *)&data->conf);
if (ret < 0) { if (ret < 0) {
dev_err(&data->client->dev, dev_err(&data->client->dev,
"failed to read configuration registers\n"); "failed to read configuration registers\n");
return ret; return ret;
} }
/* Reset GPIO */ /* Reset GPIO */
data->gpio_bitnum = MMA9553_MAX_BITNUM; data->gpio_bitnum = MMA9553_MAX_BITNUM;
ret = mma9553_conf_gpio(data); 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.sleepmin = MMA9553_DEFAULT_SLEEPMIN;
data->conf.sleepmax = MMA9553_DEFAULT_SLEEPMAX; data->conf.sleepmax = MMA9553_DEFAULT_SLEEPMAX;
data->conf.sleepthd = MMA9553_DEFAULT_SLEEPTHD; data->conf.sleepthd = MMA9553_DEFAULT_SLEEPTHD;
data->conf.config = data->conf.config = mma9553_set_bits(data->conf.config, 1,
mma9553_set_bits(data->conf.config, 1, MMA9553_MASK_CONF_CONFIG); MMA9553_MASK_CONF_CONFIG);
/* /*
* Clear the activity debounce counter when the activity level changes, * Clear the activity debounce counter when the activity level changes,
* so that the confidence level applies for any activity level. * so that the confidence level applies for any activity level.
*/ */
data->conf.config = mma9553_set_bits(data->conf.config, 1, data->conf.config = mma9553_set_bits(data->conf.config, 1,
MMA9553_MASK_CONF_ACT_DBCNTM); MMA9553_MASK_CONF_ACT_DBCNTM);
ret = ret = mma9551_write_config_words(data->client, MMA9551_APPID_PEDOMETER,
mma9551_write_config_words(data->client, MMA9551_APPID_PEDOMETER, MMA9553_REG_CONF_SLEEPMIN,
MMA9553_REG_CONF_SLEEPMIN, sizeof(data->conf) / sizeof(u16),
sizeof(data->conf), (u16 *) &data->conf); (u16 *)&data->conf);
if (ret < 0) { if (ret < 0) {
dev_err(&data->client->dev, dev_err(&data->client->dev,
"failed to write configuration registers\n"); "failed to write configuration registers\n");
@ -567,7 +570,7 @@ static int mma9553_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT; return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBHEIGHT: case IIO_CHAN_INFO_CALIBHEIGHT:
tmp = mma9553_get_bits(data->conf.height_weight, tmp = mma9553_get_bits(data->conf.height_weight,
MMA9553_MASK_CONF_HEIGHT); MMA9553_MASK_CONF_HEIGHT);
*val = tmp / 100; /* cm to m */ *val = tmp / 100; /* cm to m */
*val2 = (tmp % 100) * 10000; *val2 = (tmp % 100) * 10000;
return IIO_VAL_INT_PLUS_MICRO; 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_type type,
enum iio_event_direction dir) enum iio_event_direction dir)
{ {
struct mma9553_data *data = iio_priv(indio_dev); struct mma9553_data *data = iio_priv(indio_dev);
struct mma9553_event *event; struct mma9553_event *event;
@ -1026,22 +1028,22 @@ static irqreturn_t mma9553_event_handler(int irq, void *private)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
ev_prev_activity = ev_prev_activity = mma9553_get_event(data, IIO_ACTIVITY,
mma9553_get_event(data, IIO_ACTIVITY, mma9553_activity_to_mod(
mma9553_activity_to_mod(data->activity), data->activity),
IIO_EV_DIR_FALLING); IIO_EV_DIR_FALLING);
ev_activity = ev_activity = mma9553_get_event(data, IIO_ACTIVITY,
mma9553_get_event(data, IIO_ACTIVITY, mma9553_activity_to_mod(activity),
mma9553_activity_to_mod(activity), IIO_EV_DIR_RISING);
IIO_EV_DIR_RISING); ev_step_detect = mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD,
ev_step_detect = IIO_EV_DIR_NONE);
mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, IIO_EV_DIR_NONE);
if (ev_step_detect->enabled && (stepcnt != data->stepcnt)) { if (ev_step_detect->enabled && (stepcnt != data->stepcnt)) {
data->stepcnt = stepcnt; data->stepcnt = stepcnt;
iio_push_event(indio_dev, iio_push_event(indio_dev,
IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD, 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); data->timestamp);
} }
@ -1051,17 +1053,19 @@ static irqreturn_t mma9553_event_handler(int irq, void *private)
if (ev_prev_activity && ev_prev_activity->enabled) if (ev_prev_activity && ev_prev_activity->enabled)
iio_push_event(indio_dev, iio_push_event(indio_dev,
IIO_EVENT_CODE(IIO_ACTIVITY, 0, IIO_EVENT_CODE(IIO_ACTIVITY, 0,
ev_prev_activity->info->mod, ev_prev_activity->info->mod,
IIO_EV_DIR_FALLING, IIO_EV_DIR_FALLING,
IIO_EV_TYPE_THRESH, 0, 0, 0), IIO_EV_TYPE_THRESH, 0, 0,
0),
data->timestamp); data->timestamp);
if (ev_activity && ev_activity->enabled) if (ev_activity && ev_activity->enabled)
iio_push_event(indio_dev, iio_push_event(indio_dev,
IIO_EVENT_CODE(IIO_ACTIVITY, 0, IIO_EVENT_CODE(IIO_ACTIVITY, 0,
ev_activity->info->mod, ev_activity->info->mod,
IIO_EV_DIR_RISING, IIO_EV_DIR_RISING,
IIO_EV_TYPE_THRESH, 0, 0, 0), IIO_EV_TYPE_THRESH, 0, 0,
0),
data->timestamp); data->timestamp);
} }
mutex_unlock(&data->mutex); mutex_unlock(&data->mutex);
@ -1156,7 +1160,6 @@ static int mma9553_probe(struct i2c_client *client,
client->irq); client->irq);
goto out_poweroff; goto out_poweroff;
} }
} }
ret = iio_device_register(indio_dev); ret = iio_device_register(indio_dev);

View File

@ -122,7 +122,6 @@ MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
static struct i2c_driver st_accel_driver = { static struct i2c_driver st_accel_driver = {
.driver = { .driver = {
.owner = THIS_MODULE,
.name = "st-accel-i2c", .name = "st-accel-i2c",
.of_match_table = of_match_ptr(st_accel_of_match), .of_match_table = of_match_ptr(st_accel_of_match),
}, },

View File

@ -11,17 +11,25 @@
*/ */
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/sysfs.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_XOUT 0x00
#define STK8312_REG_YOUT 0x01 #define STK8312_REG_YOUT 0x01
#define STK8312_REG_ZOUT 0x02 #define STK8312_REG_ZOUT 0x02
#define STK8312_REG_INTSU 0x06
#define STK8312_REG_MODE 0x07 #define STK8312_REG_MODE 0x07
#define STK8312_REG_SR 0x08
#define STK8312_REG_STH 0x13 #define STK8312_REG_STH 0x13
#define STK8312_REG_RESET 0x20 #define STK8312_REG_RESET 0x20
#define STK8312_REG_AFECTRL 0x24 #define STK8312_REG_AFECTRL 0x24
@ -29,14 +37,21 @@
#define STK8312_REG_OTPDATA 0x3E #define STK8312_REG_OTPDATA 0x3E
#define STK8312_REG_OTPCTRL 0x3F #define STK8312_REG_OTPCTRL 0x3F
#define STK8312_MODE_ACTIVE 1 #define STK8312_MODE_ACTIVE 0x01
#define STK8312_MODE_STANDBY 0 #define STK8312_MODE_STANDBY 0x00
#define STK8312_MODE_MASK 0x01 #define STK8312_DREADY_BIT 0x10
#define STK8312_INT_MODE 0xC0
#define STK8312_RNG_MASK 0xC0 #define STK8312_RNG_MASK 0xC0
#define STK8312_SR_MASK 0x07
#define STK8312_SR_400HZ_IDX 0
#define STK8312_RNG_SHIFT 6 #define STK8312_RNG_SHIFT 6
#define STK8312_READ_RETRIES 16 #define STK8312_READ_RETRIES 16
#define STK8312_ALL_CHANNEL_MASK 7
#define STK8312_ALL_CHANNEL_SIZE 3
#define STK8312_DRIVER_NAME "stk8312" #define STK8312_DRIVER_NAME "stk8312"
#define STK8312_GPIO "stk8312_gpio"
#define STK8312_IRQ_NAME "stk8312_event"
/* /*
* The accelerometer has two measurement ranges: * The accelerometer has two measurement ranges:
@ -53,32 +68,56 @@ static const int stk8312_scale_table[][2] = {
{0, 461600}, {1, 231100} {0, 461600}, {1, 231100}
}; };
#define STK8312_ACCEL_CHANNEL(reg, axis) { \ static const struct {
.type = IIO_ACCEL, \ u16 val;
.address = reg, \ u32 val2;
.modified = 1, \ } stk8312_samp_freq_table[] = {
.channel2 = IIO_MOD_##axis, \ {400, 0}, {200, 0}, {100, 0}, {50, 0}, {25, 0},
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ {12, 500000}, {6, 250000}, {3, 125000}
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ };
#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[] = { static const struct iio_chan_spec stk8312_channels[] = {
STK8312_ACCEL_CHANNEL(STK8312_REG_XOUT, X), STK8312_ACCEL_CHANNEL(0, STK8312_REG_XOUT, X),
STK8312_ACCEL_CHANNEL(STK8312_REG_YOUT, Y), STK8312_ACCEL_CHANNEL(1, STK8312_REG_YOUT, Y),
STK8312_ACCEL_CHANNEL(STK8312_REG_ZOUT, Z), STK8312_ACCEL_CHANNEL(2, STK8312_REG_ZOUT, Z),
IIO_CHAN_SOFT_TIMESTAMP(3),
}; };
struct stk8312_data { struct stk8312_data {
struct i2c_client *client; struct i2c_client *client;
struct mutex lock; struct mutex lock;
int range; int range;
u8 sample_rate_idx;
u8 mode; 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(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[] = { static struct attribute *stk8312_attributes[] = {
&iio_const_attr_in_accel_scale_available.dev_attr.attr, &iio_const_attr_in_accel_scale_available.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
NULL, NULL,
}; };
@ -130,31 +169,19 @@ exit_err:
static int stk8312_set_mode(struct stk8312_data *data, u8 mode) static int stk8312_set_mode(struct stk8312_data *data, u8 mode)
{ {
int ret; int ret;
u8 masked_reg;
struct i2c_client *client = data->client; struct i2c_client *client = data->client;
if (mode > 1) if (mode == data->mode)
return -EINVAL;
else if (mode == data->mode)
return 0; return 0;
ret = i2c_smbus_read_byte_data(client, STK8312_REG_MODE); 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;
}
masked_reg = ret & (~STK8312_MODE_MASK);
masked_reg |= mode;
ret = i2c_smbus_write_byte_data(client,
STK8312_REG_MODE, masked_reg);
if (ret < 0) { if (ret < 0) {
dev_err(&client->dev, "failed to change sensor mode\n"); dev_err(&client->dev, "failed to change sensor mode\n");
return ret; return ret;
} }
data->mode = mode; data->mode = mode;
if (mode == STK8312_MODE_ACTIVE) { if (mode & STK8312_MODE_ACTIVE) {
/* Need to run OTP sequence before entering active mode */ /* Need to run OTP sequence before entering active mode */
usleep_range(1000, 5000); usleep_range(1000, 5000);
ret = stk8312_otp_init(data); ret = stk8312_otp_init(data);
@ -163,6 +190,85 @@ static int stk8312_set_mode(struct stk8312_data *data, u8 mode)
return ret; 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) static int stk8312_set_range(struct stk8312_data *data, u8 range)
{ {
int ret; int ret;
@ -208,12 +314,10 @@ static int stk8312_read_accel(struct stk8312_data *data, u8 address)
return -EINVAL; return -EINVAL;
ret = i2c_smbus_read_byte_data(client, address); ret = i2c_smbus_read_byte_data(client, address);
if (ret < 0) { if (ret < 0)
dev_err(&client->dev, "register read failed\n"); 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, 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) int *val, int *val2, long mask)
{ {
struct stk8312_data *data = iio_priv(indio_dev); struct stk8312_data *data = iio_priv(indio_dev);
int ret;
if (chan->type != IIO_ACCEL)
return -EINVAL;
switch (mask) { switch (mask) {
case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_RAW:
if (iio_buffer_enabled(indio_dev))
return -EBUSY;
mutex_lock(&data->lock); 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); mutex_unlock(&data->lock);
return IIO_VAL_INT; return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
*val = stk8312_scale_table[data->range - 1][0]; *val = stk8312_scale_table[data->range - 1][0];
*val2 = stk8312_scale_table[data->range - 1][1]; *val2 = stk8312_scale_table[data->range - 1][1];
return IIO_VAL_INT_PLUS_MICRO; 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; return -EINVAL;
@ -264,6 +385,20 @@ static int stk8312_write_raw(struct iio_dev *indio_dev,
ret = stk8312_set_range(data, index); ret = stk8312_set_range(data, index);
mutex_unlock(&data->lock); 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; return ret;
} }
@ -277,6 +412,109 @@ static const struct iio_info stk8312_info = {
.attrs = &stk8312_attribute_group, .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, static int stk8312_probe(struct i2c_client *client,
const struct i2c_device_id *id) 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"); dev_err(&client->dev, "failed to reset sensor\n");
return ret; return ret;
} }
data->sample_rate_idx = STK8312_SR_400HZ_IDX;
ret = stk8312_set_range(data, 1); ret = stk8312_set_range(data, 1);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = stk8312_set_mode(data, STK8312_MODE_ACTIVE); ret = stk8312_set_mode(data, STK8312_INT_MODE | STK8312_MODE_ACTIVE);
if (ret < 0) if (ret < 0)
return ret; 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); ret = iio_device_register(indio_dev);
if (ret < 0) { if (ret < 0) {
dev_err(&client->dev, "device_register failed\n"); dev_err(&client->dev, "device_register failed\n");
stk8312_set_mode(data, STK8312_MODE_STANDBY); goto err_buffer_cleanup;
} }
return ret; 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) static int stk8312_remove(struct i2c_client *client)
{ {
struct iio_dev *indio_dev = i2c_get_clientdata(client); struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct stk8312_data *data = iio_priv(indio_dev);
iio_device_unregister(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 #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))); 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) 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))); 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); static SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend, stk8312_resume);

View File

@ -11,26 +11,42 @@
*/ */
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/sysfs.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_XOUT 0x02
#define STK8BA50_REG_YOUT 0x04 #define STK8BA50_REG_YOUT 0x04
#define STK8BA50_REG_ZOUT 0x06 #define STK8BA50_REG_ZOUT 0x06
#define STK8BA50_REG_RANGE 0x0F #define STK8BA50_REG_RANGE 0x0F
#define STK8BA50_REG_BWSEL 0x10
#define STK8BA50_REG_POWMODE 0x11 #define STK8BA50_REG_POWMODE 0x11
#define STK8BA50_REG_SWRST 0x14 #define STK8BA50_REG_SWRST 0x14
#define STK8BA50_REG_INTEN2 0x17
#define STK8BA50_REG_INTMAP2 0x1A
#define STK8BA50_MODE_NORMAL 0 #define STK8BA50_MODE_NORMAL 0
#define STK8BA50_MODE_SUSPEND 1 #define STK8BA50_MODE_SUSPEND 1
#define STK8BA50_MODE_POWERBIT BIT(7) #define STK8BA50_MODE_POWERBIT BIT(7)
#define STK8BA50_DATA_SHIFT 6 #define STK8BA50_DATA_SHIFT 6
#define STK8BA50_RESET_CMD 0xB6 #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_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" #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. * 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} {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 stk8ba50_data {
struct i2c_client *client; struct i2c_client *client;
struct mutex lock; struct mutex lock;
int range; 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) { \ #define STK8BA50_ACCEL_CHANNEL(index, reg, axis) { \
.type = IIO_ACCEL, \ .type = IIO_ACCEL, \
.address = reg, \ .address = reg, \
.modified = 1, \ .modified = 1, \
.channel2 = IIO_MOD_##axis, \ .channel2 = IIO_MOD_##axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .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[] = { static const struct iio_chan_spec stk8ba50_channels[] = {
STK8BA50_ACCEL_CHANNEL(STK8BA50_REG_XOUT, X), STK8BA50_ACCEL_CHANNEL(0, STK8BA50_REG_XOUT, X),
STK8BA50_ACCEL_CHANNEL(STK8BA50_REG_YOUT, Y), STK8BA50_ACCEL_CHANNEL(1, STK8BA50_REG_YOUT, Y),
STK8BA50_ACCEL_CHANNEL(STK8BA50_REG_ZOUT, Z), 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(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[] = { static struct attribute *stk8ba50_attributes[] = {
&iio_const_attr_in_accel_scale_available.dev_attr.attr, &iio_const_attr_in_accel_scale_available.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
NULL, NULL,
}; };
@ -97,72 +154,34 @@ static int stk8ba50_read_accel(struct stk8ba50_data *data, u8 reg)
return ret; return ret;
} }
return sign_extend32(ret >> STK8BA50_DATA_SHIFT, 9); return ret;
} }
static int stk8ba50_read_raw(struct iio_dev *indio_dev, static int stk8ba50_data_rdy_trigger_set_state(struct iio_trigger *trig,
struct iio_chan_spec const *chan, bool state)
int *val, int *val2, long mask)
{ {
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct stk8ba50_data *data = iio_priv(indio_dev); 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 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, ret = i2c_smbus_write_byte_data(data->client,
STK8BA50_REG_RANGE, STK8BA50_REG_INTEN2, STK8BA50_DREADY_INT_MASK);
stk8ba50_scale_table[index][0]); else
if (ret < 0) ret = i2c_smbus_write_byte_data(data->client,
dev_err(&data->client->dev, STK8BA50_REG_INTEN2, 0x00);
"failed to set measurement range\n");
else
data->range = index;
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 = { static const struct iio_trigger_ops stk8ba50_trigger_ops = {
.driver_module = THIS_MODULE, .set_trigger_state = stk8ba50_data_rdy_trigger_set_state,
.read_raw = stk8ba50_read_raw, .owner = THIS_MODULE,
.write_raw = stk8ba50_write_raw,
.attrs = &stk8ba50_attribute_group,
}; };
static int stk8ba50_set_power(struct stk8ba50_data *data, bool mode) static int stk8ba50_set_power(struct stk8ba50_data *data, bool mode)
@ -192,6 +211,207 @@ exit_err:
return ret; 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, static int stk8ba50_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
@ -222,28 +442,104 @@ static int stk8ba50_probe(struct i2c_client *client,
STK8BA50_REG_SWRST, STK8BA50_RESET_CMD); STK8BA50_REG_SWRST, STK8BA50_RESET_CMD);
if (ret < 0) { if (ret < 0) {
dev_err(&client->dev, "failed to reset sensor\n"); dev_err(&client->dev, "failed to reset sensor\n");
return ret; goto err_power_off;
} }
/* The default range is +/-2g */ /* The default range is +/-2g */
data->range = 0; 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); ret = iio_device_register(indio_dev);
if (ret < 0) { if (ret < 0) {
dev_err(&client->dev, "device_register failed\n"); dev_err(&client->dev, "device_register failed\n");
stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND); goto err_buffer_cleanup;
} }
return ret; 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) static int stk8ba50_remove(struct i2c_client *client)
{ {
struct iio_dev *indio_dev = i2c_get_clientdata(client); struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct stk8ba50_data *data = iio_priv(indio_dev);
iio_device_unregister(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 #ifdef CONFIG_PM_SLEEP

View File

@ -20,6 +20,9 @@ config AD7266
Say yes here to build support for Analog Devices AD7265 and AD7266 Say yes here to build support for Analog Devices AD7265 and AD7266
ADCs. ADCs.
To compile this driver as a module, choose M here: the module will be
called ad7266.
config AD7291 config AD7291
tristate "Analog Devices AD7291 ADC driver" tristate "Analog Devices AD7291 ADC driver"
depends on I2C depends on I2C
@ -52,8 +55,6 @@ config AD7476
AD7277, AD7278, AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468, AD7277, AD7278, AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468,
AD7495, AD7910, AD7920, AD7920 SPI analog to digital converters (ADC). 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 To compile this driver as a module, choose M here: the
module will be called ad7476. module will be called ad7476.
@ -63,8 +64,7 @@ config AD7791
select AD_SIGMA_DELTA select AD_SIGMA_DELTA
help help
Say yes here to build support for Analog Devices AD7787, AD7788, AD7789, Say yes here to build support for Analog Devices AD7787, AD7788, AD7789,
AD7790 and AD7791 SPI analog to digital converters (ADC). If unsure, say AD7790 and AD7791 SPI analog to digital converters (ADC).
N (but it is safe to say "Y").
To compile this driver as a module, choose M here: the module will be To compile this driver as a module, choose M here: the module will be
called ad7791. called ad7791.
@ -76,7 +76,6 @@ config AD7793
help help
Say yes here to build support for Analog Devices AD7785, AD7792, AD7793, Say yes here to build support for Analog Devices AD7785, AD7792, AD7793,
AD7794 and AD7795 SPI analog to digital converters (ADC). 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 To compile this driver as a module, choose M here: the
module will be called AD7793. module will be called AD7793.
@ -89,7 +88,6 @@ config AD7887
help help
Say yes here to build support for Analog Devices Say yes here to build support for Analog Devices
AD7887 SPI analog to digital converter (ADC). 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 To compile this driver as a module, choose M here: the
module will be called ad7887. module will be called ad7887.
@ -117,6 +115,9 @@ config AD799X
i2c analog to digital converters (ADC). Provides direct access i2c analog to digital converters (ADC). Provides direct access
via sysfs. via sysfs.
To compile this driver as a module, choose M here: the module will be
called ad799x.
config AT91_ADC config AT91_ADC
tristate "Atmel AT91 ADC" tristate "Atmel AT91 ADC"
depends on ARCH_AT91 depends on ARCH_AT91
@ -127,6 +128,9 @@ config AT91_ADC
help help
Say yes here to build support for Atmel AT91 ADC. 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 config AXP288_ADC
tristate "X-Powers AXP288 ADC driver" tristate "X-Powers AXP288 ADC driver"
depends on MFD_AXP20X depends on MFD_AXP20X
@ -135,6 +139,9 @@ config AXP288_ADC
device. Depending on platform configuration, this general purpose ADC can device. Depending on platform configuration, this general purpose ADC can
be used for sampling sensors such as thermal resistors. 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 config BERLIN2_ADC
tristate "Marvell Berlin2 ADC driver" tristate "Marvell Berlin2 ADC driver"
depends on ARCH_BERLIN 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 This driver can also be built as a module. If chosen, the module name
will be da9150-gpadc. will be da9150-gpadc.
To compile this driver as a module, choose M here: the module will be
called berlin2-adc.
config CC10001_ADC config CC10001_ADC
tristate "Cosmic Circuits 10001 ADC driver" tristate "Cosmic Circuits 10001 ADC driver"
depends on HAVE_CLK || REGULATOR 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 of SoCs for drivers such as the touchscreen and hwmon to use to share
this resource. this resource.
To compile this driver as a module, choose M here: the module will be
called exynos_adc.
config LP8788_ADC config LP8788_ADC
tristate "LP8788 ADC driver" tristate "LP8788 ADC driver"
depends on MFD_LP8788 depends on MFD_LP8788
help help
Say yes here to build support for TI LP8788 ADC. 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 config MAX1027
tristate "Maxim max1027 ADC driver" tristate "Maxim max1027 ADC driver"
depends on SPI depends on SPI
@ -186,6 +202,9 @@ config MAX1027
Say yes here to build support for Maxim SPI ADC models Say yes here to build support for Maxim SPI ADC models
max1027, max1029 and max1031. max1027, max1029 and max1031.
To compile this driver as a module, choose M here: the module will be
called max1027.
config MAX1363 config MAX1363
tristate "Maxim max1363 ADC driver" tristate "Maxim max1363 ADC driver"
depends on I2C depends on I2C
@ -202,6 +221,9 @@ config MAX1363
max11646, max11647) Provides direct access via sysfs and buffered max11646, max11647) Provides direct access via sysfs and buffered
data via the iio dev interface. data via the iio dev interface.
To compile this driver as a module, choose M here: the module will be
called max1363.
config MCP320X config MCP320X
tristate "Microchip Technology MCP3x01/02/04/08" tristate "Microchip Technology MCP3x01/02/04/08"
depends on SPI depends on SPI
@ -310,15 +332,18 @@ config TI_AM335X_ADC
Say yes here to build support for Texas Instruments ADC Say yes here to build support for Texas Instruments ADC
driver which is also a MFD client. 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 config TWL4030_MADC
tristate "TWL4030 MADC (Monitoring A/D Converter)" tristate "TWL4030 MADC (Monitoring A/D Converter)"
depends on TWL4030_CORE depends on TWL4030_CORE
help help
This driver provides support for Triton TWL4030-MADC. The This driver provides support for Triton TWL4030-MADC. The
driver supports both RT and SW conversion methods. driver supports both RT and SW conversion methods.
This driver can also be built as a module. If so, the module will be This driver can also be built as a module. If so, the module will be
called twl4030-madc. called twl4030-madc.
config TWL6030_GPADC config TWL6030_GPADC
tristate "TWL6030 GPADC (General Purpose A/D Converter) Support" 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 Say yes here to access the ADC part of the Nano River
Technologies Viperboard. Technologies Viperboard.
To compile this driver as a module, choose M here: the module will be
called viperboard_adc.
config XILINX_XADC config XILINX_XADC
tristate "Xilinx XADC driver" tristate "Xilinx XADC driver"
depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST

View File

@ -62,6 +62,7 @@ struct cc10001_adc_device {
struct regulator *reg; struct regulator *reg;
u16 *buf; u16 *buf;
bool shared;
struct mutex lock; struct mutex lock;
unsigned int start_delay_ns; unsigned int start_delay_ns;
unsigned int eoc_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); 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 */ /* Calculate delay step for eoc and sampled data */
delay_ns = adc_dev->eoc_delay_ns / CC10001_MAX_POLL_COUNT; 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: done:
cc10001_adc_power_down(adc_dev); if (!adc_dev->shared)
cc10001_adc_power_down(adc_dev);
mutex_unlock(&adc_dev->lock); 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; unsigned int delay_ns;
u16 val; 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 */ /* Calculate delay step for eoc and sampled data */
delay_ns = adc_dev->eoc_delay_ns / CC10001_MAX_POLL_COUNT; 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); 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; return val;
} }
@ -322,8 +327,10 @@ static int cc10001_adc_probe(struct platform_device *pdev)
adc_dev = iio_priv(indio_dev); adc_dev = iio_priv(indio_dev);
channel_map = GENMASK(CC10001_ADC_NUM_CHANNELS - 1, 0); 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; channel_map &= ~ret;
}
adc_dev->reg = devm_regulator_get(&pdev->dev, "vref"); adc_dev->reg = devm_regulator_get(&pdev->dev, "vref");
if (IS_ERR(adc_dev->reg)) 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->eoc_delay_ns = NSEC_PER_SEC / adc_clk_rate;
adc_dev->start_delay_ns = adc_dev->eoc_delay_ns * CC10001_WAIT_CYCLES; 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 */ /* Setup the ADC channels available on the device */
ret = cc10001_adc_channel_init(indio_dev, channel_map); ret = cc10001_adc_channel_init(indio_dev, channel_map);
if (ret < 0) 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 iio_dev *indio_dev = platform_get_drvdata(pdev);
struct cc10001_adc_device *adc_dev = iio_priv(indio_dev); struct cc10001_adc_device *adc_dev = iio_priv(indio_dev);
cc10001_adc_power_down(adc_dev);
iio_device_unregister(indio_dev); iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev); iio_triggered_buffer_cleanup(indio_dev);
clk_disable_unprepare(adc_dev->adc_clk); clk_disable_unprepare(adc_dev->adc_clk);

View File

@ -404,7 +404,6 @@ MODULE_DEVICE_TABLE(of, mcp3422_of_match);
static struct i2c_driver mcp3422_driver = { static struct i2c_driver mcp3422_driver = {
.driver = { .driver = {
.name = "mcp3422", .name = "mcp3422",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(mcp3422_of_match), .of_match_table = of_match_ptr(mcp3422_of_match),
}, },
.probe = mcp3422_probe, .probe = mcp3422_probe,

View File

@ -140,7 +140,6 @@ MODULE_DEVICE_TABLE(of, adc081c_of_match);
static struct i2c_driver adc081c_driver = { static struct i2c_driver adc081c_driver = {
.driver = { .driver = {
.name = "adc081c", .name = "adc081c",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(adc081c_of_match), .of_match_table = of_match_ptr(adc081c_of_match),
}, },
.probe = adc081c_probe, .probe = adc081c_probe,

View File

@ -700,7 +700,6 @@ static struct spi_driver ssp_driver = {
.remove = ssp_remove, .remove = ssp_remove,
.driver = { .driver = {
.pm = &ssp_pm_ops, .pm = &ssp_pm_ops,
.bus = &spi_bus_type,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(ssp_of_match), .of_match_table = of_match_ptr(ssp_of_match),
.name = "sensorhub" .name = "sensorhub"

View File

@ -630,7 +630,6 @@ MODULE_DEVICE_TABLE(i2c, ad5064_i2c_ids);
static struct i2c_driver ad5064_i2c_driver = { static struct i2c_driver ad5064_i2c_driver = {
.driver = { .driver = {
.name = "ad5064", .name = "ad5064",
.owner = THIS_MODULE,
}, },
.probe = ad5064_i2c_probe, .probe = ad5064_i2c_probe,
.remove = ad5064_i2c_remove, .remove = ad5064_i2c_remove,

View File

@ -593,7 +593,6 @@ MODULE_DEVICE_TABLE(i2c, ad5380_i2c_ids);
static struct i2c_driver ad5380_i2c_driver = { static struct i2c_driver ad5380_i2c_driver = {
.driver = { .driver = {
.name = "ad5380", .name = "ad5380",
.owner = THIS_MODULE,
}, },
.probe = ad5380_i2c_probe, .probe = ad5380_i2c_probe,
.remove = ad5380_i2c_remove, .remove = ad5380_i2c_remove,

View File

@ -569,7 +569,6 @@ MODULE_DEVICE_TABLE(i2c, ad5446_i2c_ids);
static struct i2c_driver ad5446_i2c_driver = { static struct i2c_driver ad5446_i2c_driver = {
.driver = { .driver = {
.name = "ad5446", .name = "ad5446",
.owner = THIS_MODULE,
}, },
.probe = ad5446_i2c_probe, .probe = ad5446_i2c_probe,
.remove = ad5446_i2c_remove, .remove = ad5446_i2c_remove,

View File

@ -392,7 +392,6 @@ static struct i2c_driver max5821_driver = {
.driver = { .driver = {
.name = "max5821", .name = "max5821",
.pm = MAX5821_PM_OPS, .pm = MAX5821_PM_OPS,
.owner = THIS_MODULE,
}, },
.probe = max5821_probe, .probe = max5821_probe,
.remove = max5821_remove, .remove = max5821_remove,

View File

@ -72,7 +72,6 @@ static int adf4350_sync_config(struct adf4350_state *st)
for (i = ADF4350_REG5; i >= ADF4350_REG0; i--) { for (i = ADF4350_REG5; i >= ADF4350_REG0; i--) {
if ((st->regs_hw[i] != st->regs[i]) || if ((st->regs_hw[i] != st->regs[i]) ||
((i == ADF4350_REG0) && doublebuf)) { ((i == ADF4350_REG0) && doublebuf)) {
switch (i) { switch (i) {
case ADF4350_REG1: case ADF4350_REG1:
case ADF4350_REG4: case ADF4350_REG4:

View File

@ -379,7 +379,6 @@ MODULE_DEVICE_TABLE(i2c, itg3200_id);
static struct i2c_driver itg3200_driver = { static struct i2c_driver itg3200_driver = {
.driver = { .driver = {
.owner = THIS_MODULE,
.name = "itg3200", .name = "itg3200",
.pm = &itg3200_pm_ops, .pm = &itg3200_pm_ops,
}, },

View File

@ -99,7 +99,6 @@ MODULE_DEVICE_TABLE(i2c, st_gyro_id_table);
static struct i2c_driver st_gyro_driver = { static struct i2c_driver st_gyro_driver = {
.driver = { .driver = {
.owner = THIS_MODULE,
.name = "st-gyro-i2c", .name = "st-gyro-i2c",
.of_match_table = of_match_ptr(st_gyro_of_match), .of_match_table = of_match_ptr(st_gyro_of_match),
}, },

View File

@ -177,7 +177,6 @@ MODULE_DEVICE_TABLE(i2c, si7005_id);
static struct i2c_driver si7005_driver = { static struct i2c_driver si7005_driver = {
.driver = { .driver = {
.name = "si7005", .name = "si7005",
.owner = THIS_MODULE,
}, },
.probe = si7005_probe, .probe = si7005_probe,
.id_table = si7005_id, .id_table = si7005_id,

View File

@ -673,6 +673,10 @@ static const struct iio_chan_spec inv_mpu_channels[] = {
/* constant IIO attribute */ /* constant IIO attribute */
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("10 20 50 100 200 500"); 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, static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, inv_fifo_rate_show,
inv_mpu6050_fifo_rate_store); inv_mpu6050_fifo_rate_store);
static IIO_DEVICE_ATTR(in_gyro_matrix, S_IRUGO, inv_attr_show, NULL, 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_in_accel_matrix.dev_attr.attr,
&iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.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, NULL,
}; };
@ -903,7 +909,6 @@ static struct i2c_driver inv_mpu_driver = {
.remove = inv_mpu_remove, .remove = inv_mpu_remove,
.id_table = inv_mpu_id, .id_table = inv_mpu_id,
.driver = { .driver = {
.owner = THIS_MODULE,
.name = "inv-mpu6050", .name = "inv-mpu6050",
.pm = INV_MPU6050_PMOPS, .pm = INV_MPU6050_PMOPS,
.acpi_match_table = ACPI_PTR(inv_acpi_match), .acpi_match_table = ACPI_PTR(inv_acpi_match),

View File

@ -71,8 +71,9 @@ static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf,
if (avail >= to_wait) { if (avail >= to_wait) {
/* force a flush for non-blocking reads */ /* force a flush for non-blocking reads */
if (!to_wait && !avail && to_flush) if (!to_wait && avail < to_flush)
iio_buffer_flush_hwfifo(indio_dev, buf, to_flush); iio_buffer_flush_hwfifo(indio_dev, buf,
to_flush - avail);
return true; 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_dev *indio_dev = filp->private_data;
struct iio_buffer *rb = indio_dev->buffer; struct iio_buffer *rb = indio_dev->buffer;
size_t datum_size; size_t datum_size;
size_t to_wait = 0; size_t to_wait;
size_t to_read;
int ret; int ret;
if (!indio_dev->info) 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) if (!datum_size)
return 0; return 0;
to_read = min_t(size_t, n / datum_size, rb->watermark); if (filp->f_flags & O_NONBLOCK)
to_wait = 0;
if (!(filp->f_flags & O_NONBLOCK)) else
to_wait = to_read; to_wait = min_t(size_t, n / datum_size, rb->watermark);
do { do {
ret = wait_event_interruptible(rb->pollq, 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) if (ret)
return ret; return ret;

View File

@ -81,6 +81,14 @@ static const char * const iio_modifier_names[] = {
[IIO_MOD_X] = "x", [IIO_MOD_X] = "x",
[IIO_MOD_Y] = "y", [IIO_MOD_Y] = "y",
[IIO_MOD_Z] = "z", [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_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_SUM_SQUARED_X_Y_Z] = "x^2+y^2+z^2",
[IIO_MOD_LIGHT_BOTH] = "both", [IIO_MOD_LIGHT_BOTH] = "both",

View File

@ -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 * iio_triggered_buffer_setup() - Setup triggered buffer and pollfunc
* @indio_dev: IIO device structure * @indio_dev: IIO device structure
* @pollfunc_bh: Function which will be used as pollfunc bottom half * @h: Function which will be used as pollfunc top half
* @pollfunc_th: 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. * @setup_ops: Buffer setup functions to use for this device.
* If NULL the default setup functions for triggered * If NULL the default setup functions for triggered
* buffers will be used. * buffers will be used.
@ -42,8 +42,8 @@ static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
* iio_triggered_buffer_cleanup(). * iio_triggered_buffer_cleanup().
*/ */
int iio_triggered_buffer_setup(struct iio_dev *indio_dev, int iio_triggered_buffer_setup(struct iio_dev *indio_dev,
irqreturn_t (*pollfunc_bh)(int irq, void *p), irqreturn_t (*h)(int irq, void *p),
irqreturn_t (*pollfunc_th)(int irq, void *p), irqreturn_t (*thread)(int irq, void *p),
const struct iio_buffer_setup_ops *setup_ops) const struct iio_buffer_setup_ops *setup_ops)
{ {
struct iio_buffer *buffer; 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); iio_device_attach_buffer(indio_dev, buffer);
indio_dev->pollfunc = iio_alloc_pollfunc(pollfunc_bh, indio_dev->pollfunc = iio_alloc_pollfunc(h,
pollfunc_th, thread,
IRQF_ONESHOT, IRQF_ONESHOT,
indio_dev, indio_dev,
"%s_consumer%d", "%s_consumer%d",

View File

@ -86,7 +86,7 @@ config CM3323
depends on I2C depends on I2C
tristate "Capella CM3323 color light sensor" tristate "Capella CM3323 color light sensor"
help 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. color sensor.
To compile this driver as a module, choose M here: the module will 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: To compile this driver as a module, choose M here:
the module will be called jsa1212. 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 config SENSORS_LM3533
tristate "LM3533 ambient light sensor" tristate "LM3533 ambient light sensor"
depends on MFD_LM3533 depends on MFD_LM3533

View File

@ -19,6 +19,7 @@ obj-$(CONFIG_ISL29125) += isl29125.o
obj-$(CONFIG_JSA1212) += jsa1212.o obj-$(CONFIG_JSA1212) += jsa1212.o
obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
obj-$(CONFIG_LTR501) += ltr501.o obj-$(CONFIG_LTR501) += ltr501.o
obj-$(CONFIG_RPR0521) += rpr0521.o
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_STK3310) += stk3310.o obj-$(CONFIG_STK3310) += stk3310.o
obj-$(CONFIG_TCS3414) += tcs3414.o obj-$(CONFIG_TCS3414) += tcs3414.o

View File

@ -515,7 +515,6 @@ MODULE_DEVICE_TABLE(i2c, apds9300_id);
static struct i2c_driver apds9300_driver = { static struct i2c_driver apds9300_driver = {
.driver = { .driver = {
.name = APDS9300_DRV_NAME, .name = APDS9300_DRV_NAME,
.owner = THIS_MODULE,
.pm = APDS9300_PM_OPS, .pm = APDS9300_PM_OPS,
}, },
.probe = apds9300_probe, .probe = apds9300_probe,

View File

@ -319,7 +319,6 @@ MODULE_DEVICE_TABLE(i2c, bh1750_id);
static struct i2c_driver bh1750_driver = { static struct i2c_driver bh1750_driver = {
.driver = { .driver = {
.name = "bh1750", .name = "bh1750",
.owner = THIS_MODULE,
.pm = BH1750_PM_OPS, .pm = BH1750_PM_OPS,
}, },
.probe = bh1750_probe, .probe = bh1750_probe,

View File

@ -358,7 +358,6 @@ static struct i2c_driver cm32181_driver = {
.driver = { .driver = {
.name = "cm32181", .name = "cm32181",
.of_match_table = of_match_ptr(cm32181_of_match), .of_match_table = of_match_ptr(cm32181_of_match),
.owner = THIS_MODULE,
}, },
.id_table = cm32181_id, .id_table = cm32181_id,
.probe = cm32181_probe, .probe = cm32181_probe,

View File

@ -421,7 +421,6 @@ static const struct of_device_id cm3232_of_match[] = {
static struct i2c_driver cm3232_driver = { static struct i2c_driver cm3232_driver = {
.driver = { .driver = {
.name = "cm3232", .name = "cm3232",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(cm3232_of_match), .of_match_table = of_match_ptr(cm3232_of_match),
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
.pm = &cm3232_pm_ops, .pm = &cm3232_pm_ops,

View File

@ -29,7 +29,7 @@
#define CM3323_CONF_SD_BIT BIT(0) /* sensor disable */ #define CM3323_CONF_SD_BIT BIT(0) /* sensor disable */
#define CM3323_CONF_AF_BIT BIT(1) /* auto/manual force mode */ #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_CONF_IT_SHIFT 4
#define CM3323_INT_TIME_AVAILABLE "0.04 0.08 0.16 0.32 0.64 1.28" #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; return ret;
data->reg_conf = reg_conf; data->reg_conf = reg_conf;
return 0; return 0;
} }
} }
return -EINVAL; return -EINVAL;
} }
@ -148,6 +150,7 @@ static int cm3323_get_it_bits(struct cm3323_data *data)
if (bits >= ARRAY_SIZE(cm3323_int_time)) if (bits >= ARRAY_SIZE(cm3323_int_time))
return -EINVAL; return -EINVAL;
return bits; return bits;
} }
@ -155,7 +158,7 @@ static int cm3323_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, struct iio_chan_spec const *chan, int *val,
int *val2, long mask) int *val2, long mask)
{ {
int i, ret; int ret;
struct cm3323_data *data = iio_priv(indio_dev); struct cm3323_data *data = iio_priv(indio_dev);
switch (mask) { switch (mask) {
@ -172,14 +175,14 @@ static int cm3323_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT; return IIO_VAL_INT;
case IIO_CHAN_INFO_INT_TIME: case IIO_CHAN_INFO_INT_TIME:
mutex_lock(&data->mutex); mutex_lock(&data->mutex);
i = cm3323_get_it_bits(data); ret = cm3323_get_it_bits(data);
if (i < 0) { if (ret < 0) {
mutex_unlock(&data->mutex); mutex_unlock(&data->mutex);
return -EINVAL; return ret;
} }
*val = cm3323_int_time[i].val; *val = cm3323_int_time[ret].val;
*val2 = cm3323_int_time[i].val2; *val2 = cm3323_int_time[ret].val2;
mutex_unlock(&data->mutex); mutex_unlock(&data->mutex);
return IIO_VAL_INT_PLUS_MICRO; 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"); dev_err(&client->dev, "cm3323 chip init failed\n");
return ret; return ret;
} }
ret = iio_device_register(indio_dev); ret = iio_device_register(indio_dev);
if (ret < 0) { if (ret < 0) {
dev_err(&client->dev, "failed to register iio dev\n"); dev_err(&client->dev, "failed to register iio dev\n");
goto err_init; goto err_init;
} }
return 0; return 0;
err_init: err_init:
cm3323_disable(indio_dev); cm3323_disable(indio_dev);

View File

@ -736,7 +736,6 @@ static struct i2c_driver cm36651_driver = {
.driver = { .driver = {
.name = "cm36651", .name = "cm36651",
.of_match_table = cm36651_of_match, .of_match_table = cm36651_of_match,
.owner = THIS_MODULE,
}, },
.probe = cm36651_probe, .probe = cm36651_probe,
.remove = cm36651_remove, .remove = cm36651_remove,

View File

@ -1640,7 +1640,6 @@ static struct i2c_driver gp2ap020a00f_driver = {
.driver = { .driver = {
.name = GP2A_I2C_NAME, .name = GP2A_I2C_NAME,
.of_match_table = of_match_ptr(gp2ap020a00f_of_match), .of_match_table = of_match_ptr(gp2ap020a00f_of_match),
.owner = THIS_MODULE,
}, },
.probe = gp2ap020a00f_probe, .probe = gp2ap020a00f_probe,
.remove = gp2ap020a00f_remove, .remove = gp2ap020a00f_remove,

View File

@ -284,8 +284,7 @@ static int hid_prox_probe(struct platform_device *pdev)
goto error_free_dev_mem; goto error_free_dev_mem;
} }
indio_dev->num_channels = indio_dev->num_channels = ARRAY_SIZE(prox_channels);
ARRAY_SIZE(prox_channels);
indio_dev->dev.parent = &pdev->dev; indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &prox_info; indio_dev->info = &prox_info;
indio_dev->name = name; indio_dev->name = name;

View File

@ -197,9 +197,21 @@ done:
return IRQ_HANDLED; 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 = { static const struct iio_info isl29125_info = {
.read_raw = isl29125_read_raw, .read_raw = isl29125_read_raw,
.write_raw = isl29125_write_raw, .write_raw = isl29125_write_raw,
.attrs = &isl29125_attribute_group,
.driver_module = THIS_MODULE, .driver_module = THIS_MODULE,
}; };
@ -334,7 +346,6 @@ static struct i2c_driver isl29125_driver = {
.driver = { .driver = {
.name = ISL29125_DRV_NAME, .name = ISL29125_DRV_NAME,
.pm = &isl29125_pm_ops, .pm = &isl29125_pm_ops,
.owner = THIS_MODULE,
}, },
.probe = isl29125_probe, .probe = isl29125_probe,
.remove = isl29125_remove, .remove = isl29125_remove,

View File

@ -457,7 +457,6 @@ static struct i2c_driver jsa1212_driver = {
.driver = { .driver = {
.name = JSA1212_DRIVER_NAME, .name = JSA1212_DRIVER_NAME,
.pm = JSA1212_PM_OPS, .pm = JSA1212_PM_OPS,
.owner = THIS_MODULE,
.acpi_match_table = ACPI_PTR(jsa1212_acpi_match), .acpi_match_table = ACPI_PTR(jsa1212_acpi_match),
}, },
.probe = jsa1212_probe, .probe = jsa1212_probe,

View File

@ -1551,7 +1551,6 @@ static struct i2c_driver ltr501_driver = {
.name = LTR501_DRV_NAME, .name = LTR501_DRV_NAME,
.pm = &ltr501_pm_ops, .pm = &ltr501_pm_ops,
.acpi_match_table = ACPI_PTR(ltr_acpi_match), .acpi_match_table = ACPI_PTR(ltr_acpi_match),
.owner = THIS_MODULE,
}, },
.probe = ltr501_probe, .probe = ltr501_probe,
.remove = ltr501_remove, .remove = ltr501_remove,

615
drivers/iio/light/rpr0521.c Normal file
View File

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

View File

@ -392,7 +392,6 @@ static struct i2c_driver tcs3414_driver = {
.driver = { .driver = {
.name = TCS3414_DRV_NAME, .name = TCS3414_DRV_NAME,
.pm = &tcs3414_pm_ops, .pm = &tcs3414_pm_ops,
.owner = THIS_MODULE,
}, },
.probe = tcs3414_probe, .probe = tcs3414_probe,
.remove = tcs3414_remove, .remove = tcs3414_remove,

View File

@ -366,7 +366,6 @@ static struct i2c_driver tcs3472_driver = {
.driver = { .driver = {
.name = TCS3472_DRV_NAME, .name = TCS3472_DRV_NAME,
.pm = &tcs3472_pm_ops, .pm = &tcs3472_pm_ops,
.owner = THIS_MODULE,
}, },
.probe = tcs3472_probe, .probe = tcs3472_probe,
.remove = tcs3472_remove, .remove = tcs3472_remove,

View File

@ -247,7 +247,6 @@ static struct i2c_driver tsl4531_driver = {
.driver = { .driver = {
.name = TSL4531_DRV_NAME, .name = TSL4531_DRV_NAME,
.pm = TSL4531_PM_OPS, .pm = TSL4531_PM_OPS,
.owner = THIS_MODULE,
}, },
.probe = tsl4531_probe, .probe = tsl4531_probe,
.remove = tsl4531_remove, .remove = tsl4531_remove,

View File

@ -185,7 +185,6 @@ static int vcnl4000_probe(struct i2c_client *client,
static struct i2c_driver vcnl4000_driver = { static struct i2c_driver vcnl4000_driver = {
.driver = { .driver = {
.name = VCNL4000_DRV_NAME, .name = VCNL4000_DRV_NAME,
.owner = THIS_MODULE,
}, },
.probe = vcnl4000_probe, .probe = vcnl4000_probe,
.id_table = vcnl4000_id, .id_table = vcnl4000_id,

View File

@ -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, static ssize_t bmc150_magn_show_samp_freq_avail(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
@ -659,7 +648,6 @@ static const struct iio_info bmc150_magn_info = {
.attrs = &bmc150_magn_attrs_group, .attrs = &bmc150_magn_attrs_group,
.read_raw = bmc150_magn_read_raw, .read_raw = bmc150_magn_read_raw,
.write_raw = bmc150_magn_write_raw, .write_raw = bmc150_magn_write_raw,
.validate_trigger = bmc150_magn_validate_trigger,
.driver_module = THIS_MODULE, .driver_module = THIS_MODULE,
}; };
@ -682,7 +670,7 @@ static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p)
pf->timestamp); pf->timestamp);
err: err:
iio_trigger_notify_done(data->dready_trig); iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -827,6 +815,27 @@ static const struct iio_trigger_ops bmc150_magn_trigger_ops = {
.owner = THIS_MODULE, .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) static int bmc150_magn_gpio_probe(struct i2c_client *client)
{ {
struct device *dev; struct device *dev;
@ -932,16 +941,6 @@ static int bmc150_magn_probe(struct i2c_client *client,
goto err_poweroff; 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, ret = request_threaded_irq(client->irq,
iio_trigger_generic_data_rdy_poll, iio_trigger_generic_data_rdy_poll,
NULL, NULL,
@ -951,14 +950,24 @@ static int bmc150_magn_probe(struct i2c_client *client,
if (ret < 0) { if (ret < 0) {
dev_err(&client->dev, "request irq %d failed\n", dev_err(&client->dev, "request irq %d failed\n",
client->irq); 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); ret = iio_device_register(indio_dev);
if (ret < 0) { if (ret < 0) {
dev_err(&client->dev, "unable to register iio device\n"); 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); ret = pm_runtime_set_active(&client->dev);
@ -976,12 +985,11 @@ static int bmc150_magn_probe(struct i2c_client *client,
err_iio_unregister: err_iio_unregister:
iio_device_unregister(indio_dev); iio_device_unregister(indio_dev);
err_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
err_free_irq: err_free_irq:
if (client->irq > 0) if (client->irq > 0)
free_irq(client->irq, data->dready_trig); free_irq(client->irq, data->dready_trig);
err_buffer_cleanup:
if (data->dready_trig)
iio_triggered_buffer_cleanup(indio_dev);
err_trigger_unregister: err_trigger_unregister:
if (data->dready_trig) if (data->dready_trig)
iio_trigger_unregister(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); pm_runtime_put_noidle(&client->dev);
iio_device_unregister(indio_dev); iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
if (client->irq > 0) if (client->irq > 0)
free_irq(data->client->irq, data->dready_trig); free_irq(data->client->irq, data->dready_trig);
if (data->dready_trig) { if (data->dready_trig)
iio_triggered_buffer_cleanup(indio_dev);
iio_trigger_unregister(data->dready_trig); iio_trigger_unregister(data->dready_trig);
}
mutex_lock(&data->mutex); mutex_lock(&data->mutex);
bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, true); 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[] = { static const struct acpi_device_id bmc150_magn_acpi_match[] = {
{"BMC150B", 0}, {"BMC150B", 0},
{"BMC156B", 0},
{}, {},
}; };
MODULE_DEVICE_TABLE(acpi, bmc150_magn_acpi_match); MODULE_DEVICE_TABLE(acpi, bmc150_magn_acpi_match);
static const struct i2c_device_id bmc150_magn_id[] = { static const struct i2c_device_id bmc150_magn_id[] = {
{"bmc150_magn", 0}, {"bmc150_magn", 0},
{"bmc156_magn", 0},
{}, {},
}; };
MODULE_DEVICE_TABLE(i2c, bmc150_magn_id); MODULE_DEVICE_TABLE(i2c, bmc150_magn_id);

View File

@ -85,7 +85,6 @@ MODULE_DEVICE_TABLE(i2c, st_magn_id_table);
static struct i2c_driver st_magn_driver = { static struct i2c_driver st_magn_driver = {
.driver = { .driver = {
.owner = THIS_MODULE,
.name = "st-magn-i2c", .name = "st-magn-i2c",
.of_match_table = of_match_ptr(st_magn_of_match), .of_match_table = of_match_ptr(st_magn_of_match),
}, },

View File

@ -53,10 +53,10 @@ config MPL3115
will be called mpl3115. will be called mpl3115.
config MS5611 config MS5611
tristate "Measurement Specialities MS5611 pressure sensor driver" tristate "Measurement Specialties MS5611 pressure sensor driver"
help help
Say Y here to build support for the Measurement Specialities Say Y here to build support for the Measurement Specialties
MS5611 pressure and temperature sensor. MS5611, MS5607 pressure and temperature sensors.
To compile this driver as a module, choose M here: the module will To compile this driver as a module, choose M here: the module will
be called ms5611_core. be called ms5611_core.

View File

@ -27,6 +27,18 @@
#define MS5611_PROM_WORDS_NB 8 #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 { struct ms5611_state {
void *client; void *client;
struct mutex lock; struct mutex lock;
@ -36,9 +48,9 @@ struct ms5611_state {
int (*read_adc_temp_and_pressure)(struct device *dev, int (*read_adc_temp_and_pressure)(struct device *dev,
s32 *temp, s32 *pressure); 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 */ #endif /* _MS5611_H */

View File

@ -9,6 +9,7 @@
* *
* Data sheet: * Data sheet:
* http://www.meas-spec.com/downloads/MS5611-01BA03.pdf * 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); struct ms5611_state *st = iio_priv(indio_dev);
for (i = 0; i < MS5611_PROM_WORDS_NB; i++) { 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) { if (ret < 0) {
dev_err(&indio_dev->dev, dev_err(&indio_dev->dev,
"failed to read prom at %d\n", i); "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"); dev_err(&indio_dev->dev, "PROM integrity check failed\n");
return -ENODEV; return -ENODEV;
} }
@ -70,22 +72,30 @@ static int ms5611_read_temp_and_pressure(struct iio_dev *indio_dev,
s32 *temp, s32 *pressure) s32 *temp, s32 *pressure)
{ {
int ret; int ret;
s32 t, p;
s64 off, sens, dt;
struct ms5611_state *st = iio_priv(indio_dev); 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) { if (ret < 0) {
dev_err(&indio_dev->dev, dev_err(&indio_dev->dev,
"failed to read temperature and pressure\n"); "failed to read temperature and pressure\n");
return ret; return ret;
} }
dt = t - (st->prom[5] << 8); return st->chip_info->temp_and_pressure_compensate(st->chip_info,
off = ((s64)st->prom[2] << 16) + ((st->prom[4] * dt) >> 7); temp, pressure);
sens = ((s64)st->prom[1] << 15) + ((st->prom[3] * dt) >> 8); }
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) { if (t < 2000) {
s64 off2, sens2, t2; s64 off2, sens2, t2;
@ -111,6 +121,42 @@ static int ms5611_read_temp_and_pressure(struct iio_dev *indio_dev,
return 0; 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) static int ms5611_reset(struct iio_dev *indio_dev)
{ {
int ret; int ret;
@ -160,16 +206,23 @@ static int ms5611_read_raw(struct iio_dev *indio_dev,
return -EINVAL; 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[] = { static const struct iio_chan_spec ms5611_channels[] = {
{ {
.type = IIO_PRESSURE, .type = IIO_PRESSURE,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
BIT(IIO_CHAN_INFO_SCALE)
}, },
{ {
.type = IIO_TEMP, .type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
BIT(IIO_CHAN_INFO_SCALE)
} }
}; };
@ -189,12 +242,13 @@ static int ms5611_init(struct iio_dev *indio_dev)
return ms5611_read_prom(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; int ret;
struct ms5611_state *st = iio_priv(indio_dev); struct ms5611_state *st = iio_priv(indio_dev);
mutex_init(&st->lock); mutex_init(&st->lock);
st->chip_info = &chip_info_tbl[type];
indio_dev->dev.parent = dev; indio_dev->dev.parent = dev;
indio_dev->name = dev->driver->name; indio_dev->name = dev->driver->name;
indio_dev->info = &ms5611_info; indio_dev->info = &ms5611_info;

View File

@ -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->read_adc_temp_and_pressure = ms5611_i2c_read_adc_temp_and_pressure;
st->client = client; 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[] = { static const struct i2c_device_id ms5611_id[] = {
{ "ms5611", 0 }, { "ms5611", MS5611 },
{ "ms5607", MS5607 },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, ms5611_id); MODULE_DEVICE_TABLE(i2c, ms5611_id);
@ -116,7 +117,6 @@ MODULE_DEVICE_TABLE(i2c, ms5611_id);
static struct i2c_driver ms5611_driver = { static struct i2c_driver ms5611_driver = {
.driver = { .driver = {
.name = "ms5611", .name = "ms5611",
.owner = THIS_MODULE,
}, },
.id_table = ms5611_id, .id_table = ms5611_id,
.probe = ms5611_i2c_probe, .probe = ms5611_i2c_probe,

View File

@ -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->read_adc_temp_and_pressure = ms5611_spi_read_adc_temp_and_pressure;
st->client = spi; 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[] = { static const struct spi_device_id ms5611_id[] = {
{ "ms5611", 0 }, { "ms5611", MS5611 },
{ "ms5607", MS5607 },
{ } { }
}; };
MODULE_DEVICE_TABLE(spi, ms5611_id); MODULE_DEVICE_TABLE(spi, ms5611_id);

View File

@ -79,7 +79,6 @@ MODULE_DEVICE_TABLE(i2c, st_press_id_table);
static struct i2c_driver st_press_driver = { static struct i2c_driver st_press_driver = {
.driver = { .driver = {
.owner = THIS_MODULE,
.name = "st-press-i2c", .name = "st-press-i2c",
.of_match_table = of_match_ptr(st_press_of_match), .of_match_table = of_match_ptr(st_press_of_match),
}, },

View File

@ -551,7 +551,6 @@ static const struct dev_pm_ops mlx90614_pm_ops = {
static struct i2c_driver mlx90614_driver = { static struct i2c_driver mlx90614_driver = {
.driver = { .driver = {
.name = "mlx90614", .name = "mlx90614",
.owner = THIS_MODULE,
.pm = &mlx90614_pm_ops, .pm = &mlx90614_pm_ops,
}, },
.probe = mlx90614_probe, .probe = mlx90614_probe,

View File

@ -36,9 +36,9 @@
#define TMP006_CONFIG_DRDY_EN BIT(8) #define TMP006_CONFIG_DRDY_EN BIT(8)
#define TMP006_CONFIG_DRDY BIT(7) #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_CONFIG_CR_SHIFT 9
#define TMP006_MANUFACTURER_MAGIC 0x5449 #define TMP006_MANUFACTURER_MAGIC 0x5449
@ -277,7 +277,6 @@ static struct i2c_driver tmp006_driver = {
.driver = { .driver = {
.name = "tmp006", .name = "tmp006",
.pm = &tmp006_pm_ops, .pm = &tmp006_pm_ops,
.owner = THIS_MODULE,
}, },
.probe = tmp006_probe, .probe = tmp006_probe,
.remove = tmp006_remove, .remove = tmp006_remove,

View File

@ -124,7 +124,6 @@ static struct i2c_driver adt7316_driver = {
.driver = { .driver = {
.name = "adt7316", .name = "adt7316",
.pm = ADT7316_PM_OPS, .pm = ADT7316_PM_OPS,
.owner = THIS_MODULE,
}, },
.probe = adt7316_i2c_probe, .probe = adt7316_i2c_probe,
.id_table = adt7316_i2c_id, .id_table = adt7316_i2c_id,

View File

@ -214,6 +214,7 @@ static struct device iio_evgen_dev = {
.groups = iio_evgen_groups, .groups = iio_evgen_groups,
.release = &iio_evgen_release, .release = &iio_evgen_release,
}; };
static __init int iio_dummy_evgen_init(void) static __init int iio_dummy_evgen_init(void)
{ {
int ret = iio_dummy_evgen_create(); int ret = iio_dummy_evgen_create();

View File

@ -611,7 +611,6 @@ static int iio_dummy_probe(int index)
*/ */
iio_dummy_devs[index] = indio_dev; iio_dummy_devs[index] = indio_dev;
/* /*
* Set the device name. * Set the device name.
* *
@ -675,7 +674,6 @@ static void iio_dummy_remove(int index)
*/ */
struct iio_dev *indio_dev = iio_dummy_devs[index]; struct iio_dev *indio_dev = iio_dummy_devs[index];
/* Unregister the device */ /* Unregister the device */
iio_device_unregister(indio_dev); iio_device_unregister(indio_dev);

View File

@ -119,6 +119,7 @@ static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
{ {
return 0; return 0;
}; };
static inline static inline
void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev) void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev)
{}; {};

View File

@ -32,6 +32,7 @@ static const s16 fakedata[] = {
[diffvoltage3m4] = -2, [diffvoltage3m4] = -2,
[accelx] = 344, [accelx] = 344,
}; };
/** /**
* iio_simple_dummy_trigger_h() - the trigger handler function * iio_simple_dummy_trigger_h() - the trigger handler function
* @irq: the interrupt number * @irq: the interrupt number
@ -178,7 +179,6 @@ error_free_buffer:
iio_kfifo_free(indio_dev->buffer); iio_kfifo_free(indio_dev->buffer);
error_ret: error_ret:
return ret; return ret;
} }
/** /**

View File

@ -838,7 +838,6 @@ static struct i2c_driver isl29018_driver = {
.name = "isl29018", .name = "isl29018",
.acpi_match_table = ACPI_PTR(isl29018_acpi_match), .acpi_match_table = ACPI_PTR(isl29018_acpi_match),
.pm = ISL29018_PM_OPS, .pm = ISL29018_PM_OPS,
.owner = THIS_MODULE,
.of_match_table = isl29018_of_match, .of_match_table = isl29018_of_match,
}, },
.probe = isl29018_probe, .probe = isl29018_probe,

View File

@ -547,7 +547,6 @@ static struct i2c_driver isl29028_driver = {
.class = I2C_CLASS_HWMON, .class = I2C_CLASS_HWMON,
.driver = { .driver = {
.name = "isl29028", .name = "isl29028",
.owner = THIS_MODULE,
.of_match_table = isl29028_of_match, .of_match_table = isl29028_of_match,
}, },
.probe = isl29028_probe, .probe = isl29028_probe,

View File

@ -7,8 +7,8 @@ struct iio_dev;
struct iio_buffer_setup_ops; struct iio_buffer_setup_ops;
int iio_triggered_buffer_setup(struct iio_dev *indio_dev, int iio_triggered_buffer_setup(struct iio_dev *indio_dev,
irqreturn_t (*pollfunc_bh)(int irq, void *p), irqreturn_t (*h)(int irq, void *p),
irqreturn_t (*pollfunc_th)(int irq, void *p), irqreturn_t (*thread)(int irq, void *p),
const struct iio_buffer_setup_ops *setup_ops); const struct iio_buffer_setup_ops *setup_ops);
void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev); void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev);

View File

@ -51,14 +51,33 @@ int size_from_channelarray(struct iio_channel_info *channels, int num_channels)
if (bytes % channels[i].bytes == 0) if (bytes % channels[i].bytes == 0)
channels[i].location = bytes; channels[i].location = bytes;
else else
channels[i].location = bytes - bytes%channels[i].bytes channels[i].location = bytes - bytes % channels[i].bytes
+ channels[i].bytes; + channels[i].bytes;
bytes = channels[i].location + channels[i].bytes; bytes = channels[i].location + channels[i].bytes;
i++; i++;
} }
return bytes; 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) void print2byte(uint16_t input, struct iio_channel_info *info)
{ {
/* First swap if incorrect endian */ /* 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 * process_scan() - print out the values in SI units
* @data: pointer to the start of the scan * @data: pointer to the start of the scan
* @channels: information about the channels. Note * @channels: information about the channels.
* size_from_channelarray must have been called first to fill the * Note: size_from_channelarray must have been called first
* location offsets. * to fill the location offsets.
* @num_channels: number of channels * @num_channels: number of channels
**/ **/
void process_scan(char *data, void process_scan(char *data,
@ -150,6 +169,10 @@ void process_scan(char *data,
for (k = 0; k < num_channels; k++) for (k = 0; k < num_channels; k++)
switch (channels[k].bytes) { switch (channels[k].bytes) {
/* only a few cases implemented so far */ /* only a few cases implemented so far */
case 1:
print1byte(*(uint8_t *)(data + channels[k].location),
&channels[k]);
break;
case 2: case 2:
print2byte(*(uint16_t *)(data + channels[k].location), print2byte(*(uint16_t *)(data + channels[k].location),
&channels[k]); &channels[k]);
@ -213,6 +236,7 @@ int main(int argc, char **argv)
num_loops = strtoul(optarg, &dummy, 10); num_loops = strtoul(optarg, &dummy, 10);
if (errno) if (errno)
return -errno; return -errno;
break; break;
case 'e': case 'e':
noevents = 1; noevents = 1;
@ -225,6 +249,7 @@ int main(int argc, char **argv)
buf_len = strtoul(optarg, &dummy, 10); buf_len = strtoul(optarg, &dummy, 10);
if (errno) if (errno)
return -errno; return -errno;
break; break;
case 'n': case 'n':
device_name = optarg; device_name = optarg;
@ -257,6 +282,7 @@ int main(int argc, char **argv)
printf("Failed to find the %s\n", device_name); printf("Failed to find the %s\n", device_name);
return dev_num; return dev_num;
} }
printf("iio device number being used is %d\n", 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); 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; ret = trig_num;
goto error_free_triggername; goto error_free_triggername;
} }
printf("iio trigger number being used is %d\n", trig_num); printf("iio trigger number being used is %d\n", trig_num);
} else } else {
printf("trigger-less mode selected\n"); printf("trigger-less mode selected\n");
}
/* /*
* Parse the files in scan_elements to identify what channels are * Parse the files in scan_elements to identify what channels are
@ -314,8 +342,10 @@ int main(int argc, char **argv)
if (!notrigger) { if (!notrigger) {
printf("%s %s\n", dev_dir_name, trigger_name); 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", ret = write_sysfs_string_and_verify("trigger/current_trigger",
dev_dir_name, dev_dir_name,
trigger_name); trigger_name);
@ -334,8 +364,9 @@ int main(int argc, char **argv)
ret = write_sysfs_int("enable", buf_dir_name, 1); ret = write_sysfs_int("enable", buf_dir_name, 1);
if (ret < 0) if (ret < 0)
goto error_free_buf_dir_name; goto error_free_buf_dir_name;
scan_size = size_from_channelarray(channels, num_channels); scan_size = size_from_channelarray(channels, num_channels);
data = malloc(scan_size*buf_len); data = malloc(scan_size * buf_len);
if (!data) { if (!data) {
ret = -ENOMEM; ret = -ENOMEM;
goto error_free_buf_dir_name; goto error_free_buf_dir_name;
@ -349,13 +380,12 @@ int main(int argc, char **argv)
/* Attempt to open non blocking the access dev */ /* Attempt to open non blocking the access dev */
fp = open(buffer_access, O_RDONLY | O_NONBLOCK); 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; ret = -errno;
printf("Failed to open %s\n", buffer_access); printf("Failed to open %s\n", buffer_access);
goto error_free_buffer_access; goto error_free_buffer_access;
} }
/* Wait for events 10 times */
for (j = 0; j < num_loops; j++) { for (j = 0; j < num_loops; j++) {
if (!noevents) { if (!noevents) {
struct pollfd pfd = { struct pollfd pfd = {
@ -372,25 +402,22 @@ int main(int argc, char **argv)
} }
toread = buf_len; toread = buf_len;
} else { } else {
usleep(timedelay); usleep(timedelay);
toread = 64; toread = 64;
} }
read_size = read(fp, read_size = read(fp, data, toread * scan_size);
data,
toread*scan_size);
if (read_size < 0) { if (read_size < 0) {
if (errno == EAGAIN) { if (errno == EAGAIN) {
printf("nothing available\n"); printf("nothing available\n");
continue; continue;
} else } else {
break; break;
}
} }
for (i = 0; i < read_size/scan_size; i++) for (i = 0; i < read_size / scan_size; i++)
process_scan(data + scan_size*i, process_scan(data + scan_size * i, channels,
channels,
num_channels); num_channels);
} }
@ -409,6 +436,7 @@ int main(int argc, char **argv)
error_close_buffer_access: error_close_buffer_access:
if (close(fp) == -1) if (close(fp) == -1)
perror("Failed to close buffer"); perror("Failed to close buffer");
error_free_buffer_access: error_free_buffer_access:
free(buffer_access); free(buffer_access);
error_free_data: error_free_data:
@ -424,6 +452,7 @@ error_free_channels:
error_free_triggername: error_free_triggername:
if (datardytrigger) if (datardytrigger)
free(trigger_name); free(trigger_name);
error_free_dev_dir_name: error_free_dev_dir_name:
free(dev_dir_name); free(dev_dir_name);

View File

@ -13,7 +13,6 @@
* *
* Usage: * Usage:
* iio_event_monitor <device_name> * iio_event_monitor <device_name>
*
*/ */
#include <unistd.h> #include <unistd.h>
@ -51,6 +50,9 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_HUMIDITYRELATIVE] = "humidityrelative", [IIO_HUMIDITYRELATIVE] = "humidityrelative",
[IIO_ACTIVITY] = "activity", [IIO_ACTIVITY] = "activity",
[IIO_STEPS] = "steps", [IIO_STEPS] = "steps",
[IIO_ENERGY] = "energy",
[IIO_DISTANCE] = "distance",
[IIO_VELOCITY] = "velocity",
}; };
static const char * const iio_ev_type_text[] = { 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_JOGGING] = "jogging",
[IIO_MOD_WALKING] = "walking", [IIO_MOD_WALKING] = "walking",
[IIO_MOD_STILL] = "still", [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) 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_HUMIDITYRELATIVE:
case IIO_ACTIVITY: case IIO_ACTIVITY:
case IIO_STEPS: case IIO_STEPS:
case IIO_ENERGY:
case IIO_DISTANCE:
case IIO_VELOCITY:
break; break;
default: default:
return false; return false;
@ -167,6 +173,7 @@ static bool event_is_known(struct iio_event_data *event)
case IIO_MOD_JOGGING: case IIO_MOD_JOGGING:
case IIO_MOD_WALKING: case IIO_MOD_WALKING:
case IIO_MOD_STILL: case IIO_MOD_STILL:
case IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z:
break; break;
default: default:
return false; return false;
@ -209,7 +216,8 @@ static void print_event(struct iio_event_data *event)
if (!event_is_known(event)) { if (!event_is_known(event)) {
printf("Unknown event: time: %lld, id: %llx\n", printf("Unknown event: time: %lld, id: %llx\n",
event->timestamp, event->id); event->timestamp, event->id);
return; return;
} }
@ -229,6 +237,7 @@ static void print_event(struct iio_event_data *event)
if (dir != IIO_EV_DIR_NONE) if (dir != IIO_EV_DIR_NONE)
printf(", direction: %s", iio_ev_dir_text[dir]); printf(", direction: %s", iio_ev_dir_text[dir]);
printf("\n"); printf("\n");
} }
@ -251,14 +260,16 @@ int main(int argc, char **argv)
dev_num = find_type_by_name(device_name, "iio:device"); dev_num = find_type_by_name(device_name, "iio:device");
if (dev_num >= 0) { if (dev_num >= 0) {
printf("Found IIO device with name %s with device number %d\n", 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); ret = asprintf(&chrdev_name, "/dev/iio:device%d", dev_num);
if (ret < 0) { if (ret < 0) {
return -ENOMEM; return -ENOMEM;
} }
} else { } 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); chrdev_name = strdup(device_name);
if (!chrdev_name) if (!chrdev_name)
return -ENOMEM; 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); print_event(&event);
} }

View File

@ -32,8 +32,7 @@ static char * const iio_direction[] = {
* *
* Returns 0 on success, or a negative error code if string extraction failed. * Returns 0 on success, or a negative error code if string extraction failed.
**/ **/
int iioutils_break_up_name(const char *full_name, int iioutils_break_up_name(const char *full_name, char **generic_name)
char **generic_name)
{ {
char *current; char *current;
char *w, *r; char *w, *r;
@ -65,6 +64,7 @@ int iioutils_break_up_name(const char *full_name,
*w = *r; *w = *r;
w++; w++;
} }
r++; r++;
} }
*w = '\0'; *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. * Returns a value >= 0 on success, otherwise a negative error code.
**/ **/
int iioutils_get_type(unsigned *is_signed, int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
unsigned *bytes, unsigned *shift, uint64_t *mask, unsigned *be,
unsigned *bits_used, const char *device_dir, const char *name,
unsigned *shift, const char *generic_name)
uint64_t *mask,
unsigned *be,
const char *device_dir,
const char *name,
const char *generic_name)
{ {
FILE *sysfsfp; FILE *sysfsfp;
int ret; int ret;
@ -126,6 +121,7 @@ int iioutils_get_type(unsigned *is_signed,
ret = -errno; ret = -errno;
goto error_free_builtname_generic; goto error_free_builtname_generic;
} }
ret = -ENOENT; ret = -ENOENT;
while (ent = readdir(dp), ent != NULL) while (ent = readdir(dp), ent != NULL)
/* /*
@ -140,6 +136,7 @@ int iioutils_get_type(unsigned *is_signed,
ret = -ENOMEM; ret = -ENOMEM;
goto error_closedir; goto error_closedir;
} }
sysfsfp = fopen(filename, "r"); sysfsfp = fopen(filename, "r");
if (sysfsfp == NULL) { if (sysfsfp == NULL) {
ret = -errno; ret = -errno;
@ -162,12 +159,14 @@ int iioutils_get_type(unsigned *is_signed,
printf("scan type description didn't match\n"); printf("scan type description didn't match\n");
goto error_close_sysfsfp; goto error_close_sysfsfp;
} }
*be = (endianchar == 'b'); *be = (endianchar == 'b');
*bytes = padint / 8; *bytes = padint / 8;
if (*bits_used == 64) if (*bits_used == 64)
*mask = ~0; *mask = ~0;
else else
*mask = (1 << *bits_used) - 1; *mask = (1 << *bits_used) - 1;
*is_signed = (signchar == 's'); *is_signed = (signchar == 's');
if (fclose(sysfsfp)) { if (fclose(sysfsfp)) {
ret = -errno; ret = -errno;
@ -177,9 +176,9 @@ int iioutils_get_type(unsigned *is_signed,
sysfsfp = 0; sysfsfp = 0;
free(filename); free(filename);
filename = 0; filename = 0;
} }
error_close_sysfsfp: error_close_sysfsfp:
if (sysfsfp) if (sysfsfp)
if (fclose(sysfsfp)) if (fclose(sysfsfp))
@ -188,6 +187,7 @@ error_close_sysfsfp:
error_free_filename: error_free_filename:
if (filename) if (filename)
free(filename); free(filename);
error_closedir: error_closedir:
if (closedir(dp) == -1) if (closedir(dp) == -1)
perror("iioutils_get_type(): Failed to close directory"); 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. * Returns a value >= 0 on success, otherwise a negative error code.
**/ **/
int iioutils_get_param_float(float *output, int iioutils_get_param_float(float *output, const char *param_name,
const char *param_name, const char *device_dir, const char *name,
const char *device_dir, const char *generic_name)
const char *name,
const char *generic_name)
{ {
FILE *sysfsfp; FILE *sysfsfp;
int ret; int ret;
@ -235,11 +233,13 @@ int iioutils_get_param_float(float *output,
ret = -ENOMEM; ret = -ENOMEM;
goto error_free_builtname; goto error_free_builtname;
} }
dp = opendir(device_dir); dp = opendir(device_dir);
if (dp == NULL) { if (dp == NULL) {
ret = -errno; ret = -errno;
goto error_free_builtname_generic; goto error_free_builtname_generic;
} }
ret = -ENOENT; ret = -ENOENT;
while (ent = readdir(dp), ent != NULL) while (ent = readdir(dp), ent != NULL)
if ((strcmp(builtname, ent->d_name) == 0) || if ((strcmp(builtname, ent->d_name) == 0) ||
@ -250,11 +250,13 @@ int iioutils_get_param_float(float *output,
ret = -ENOMEM; ret = -ENOMEM;
goto error_closedir; goto error_closedir;
} }
sysfsfp = fopen(filename, "r"); sysfsfp = fopen(filename, "r");
if (!sysfsfp) { if (!sysfsfp) {
ret = -errno; ret = -errno;
goto error_free_filename; goto error_free_filename;
} }
errno = 0; errno = 0;
if (fscanf(sysfsfp, "%f", output) != 1) if (fscanf(sysfsfp, "%f", output) != 1)
ret = errno ? -errno : -ENODATA; ret = errno ? -errno : -ENODATA;
@ -264,6 +266,7 @@ int iioutils_get_param_float(float *output,
error_free_filename: error_free_filename:
if (filename) if (filename)
free(filename); free(filename);
error_closedir: error_closedir:
if (closedir(dp) == -1) if (closedir(dp) == -1)
perror("iioutils_get_param_float(): Failed to close directory"); perror("iioutils_get_param_float(): Failed to close directory");
@ -282,16 +285,14 @@ error_free_builtname:
* @cnt: the amount of array elements * @cnt: the amount of array elements
**/ **/
void bsort_channel_array_by_index(struct iio_channel_info **ci_array, void bsort_channel_array_by_index(struct iio_channel_info **ci_array, int cnt)
int cnt)
{ {
struct iio_channel_info temp; struct iio_channel_info temp;
int x, y; int x, y;
for (x = 0; x < cnt; x++) for (x = 0; x < cnt; x++)
for (y = 0; y < (cnt - 1); y++) 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]; temp = (*ci_array)[y + 1];
(*ci_array)[y + 1] = (*ci_array)[y]; (*ci_array)[y + 1] = (*ci_array)[y];
(*ci_array)[y] = temp; (*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. * Returns 0 on success, otherwise a negative error code.
**/ **/
int build_channel_array(const char *device_dir, int build_channel_array(const char *device_dir,
struct iio_channel_info **ci_array, struct iio_channel_info **ci_array, int *counter)
int *counter)
{ {
DIR *dp; DIR *dp;
FILE *sysfsfp; FILE *sysfsfp;
@ -329,6 +329,7 @@ int build_channel_array(const char *device_dir,
ret = -errno; ret = -errno;
goto error_free_name; goto error_free_name;
} }
while (ent = readdir(dp), ent != NULL) while (ent = readdir(dp), ent != NULL)
if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
"_en") == 0) { "_en") == 0) {
@ -338,12 +339,14 @@ int build_channel_array(const char *device_dir,
ret = -ENOMEM; ret = -ENOMEM;
goto error_close_dir; goto error_close_dir;
} }
sysfsfp = fopen(filename, "r"); sysfsfp = fopen(filename, "r");
if (sysfsfp == NULL) { if (sysfsfp == NULL) {
ret = -errno; ret = -errno;
free(filename); free(filename);
goto error_close_dir; goto error_close_dir;
} }
errno = 0; errno = 0;
if (fscanf(sysfsfp, "%i", &ret) != 1) { if (fscanf(sysfsfp, "%i", &ret) != 1) {
ret = errno ? -errno : -ENODATA; ret = errno ? -errno : -ENODATA;
@ -353,9 +356,9 @@ int build_channel_array(const char *device_dir,
free(filename); free(filename);
goto error_close_dir; goto error_close_dir;
} }
if (ret == 1) if (ret == 1)
(*counter)++; (*counter)++;
if (fclose(sysfsfp)) { if (fclose(sysfsfp)) {
ret = -errno; ret = -errno;
free(filename); free(filename);
@ -364,11 +367,13 @@ int build_channel_array(const char *device_dir,
free(filename); free(filename);
} }
*ci_array = malloc(sizeof(**ci_array) * (*counter)); *ci_array = malloc(sizeof(**ci_array) * (*counter));
if (*ci_array == NULL) { if (*ci_array == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto error_close_dir; goto error_close_dir;
} }
seekdir(dp, 0); seekdir(dp, 0);
while (ent = readdir(dp), ent != NULL) { while (ent = readdir(dp), ent != NULL) {
if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
@ -384,6 +389,7 @@ int build_channel_array(const char *device_dir,
count--; count--;
goto error_cleanup_array; goto error_cleanup_array;
} }
sysfsfp = fopen(filename, "r"); sysfsfp = fopen(filename, "r");
if (sysfsfp == NULL) { if (sysfsfp == NULL) {
ret = -errno; ret = -errno;
@ -391,6 +397,7 @@ int build_channel_array(const char *device_dir,
count--; count--;
goto error_cleanup_array; goto error_cleanup_array;
} }
errno = 0; errno = 0;
if (fscanf(sysfsfp, "%i", &current_enabled) != 1) { if (fscanf(sysfsfp, "%i", &current_enabled) != 1) {
ret = errno ? -errno : -ENODATA; ret = errno ? -errno : -ENODATA;
@ -423,6 +430,7 @@ int build_channel_array(const char *device_dir,
count--; count--;
goto error_cleanup_array; goto error_cleanup_array;
} }
/* Get the generic and specific name elements */ /* Get the generic and specific name elements */
ret = iioutils_break_up_name(current->name, ret = iioutils_break_up_name(current->name,
&current->generic_name); &current->generic_name);
@ -432,6 +440,7 @@ int build_channel_array(const char *device_dir,
count--; count--;
goto error_cleanup_array; goto error_cleanup_array;
} }
ret = asprintf(&filename, ret = asprintf(&filename,
"%s/%s_index", "%s/%s_index",
scan_el_dir, scan_el_dir,
@ -441,6 +450,7 @@ int build_channel_array(const char *device_dir,
ret = -ENOMEM; ret = -ENOMEM;
goto error_cleanup_array; goto error_cleanup_array;
} }
sysfsfp = fopen(filename, "r"); sysfsfp = fopen(filename, "r");
if (sysfsfp == NULL) { if (sysfsfp == NULL) {
ret = -errno; ret = -errno;
@ -474,6 +484,7 @@ int build_channel_array(const char *device_dir,
current->generic_name); current->generic_name);
if (ret < 0) if (ret < 0)
goto error_cleanup_array; goto error_cleanup_array;
ret = iioutils_get_param_float(&current->offset, ret = iioutils_get_param_float(&current->offset,
"offset", "offset",
device_dir, device_dir,
@ -481,6 +492,7 @@ int build_channel_array(const char *device_dir,
current->generic_name); current->generic_name);
if (ret < 0) if (ret < 0)
goto error_cleanup_array; goto error_cleanup_array;
ret = iioutils_get_type(&current->is_signed, ret = iioutils_get_type(&current->is_signed,
&current->bytes, &current->bytes,
&current->bits_used, &current->bits_used,
@ -549,7 +561,7 @@ int find_type_by_name(const char *name, const char *type)
const struct dirent *ent; const struct dirent *ent;
int number, numstrlen, ret; int number, numstrlen, ret;
FILE *nameFile; FILE *namefp;
DIR *dp; DIR *dp;
char thisname[IIO_MAX_NAME_LENGTH]; char thisname[IIO_MAX_NAME_LENGTH];
char *filename; char *filename;
@ -562,9 +574,9 @@ int find_type_by_name(const char *name, const char *type)
while (ent = readdir(dp), ent != NULL) { while (ent = readdir(dp), ent != NULL) {
if (strcmp(ent->d_name, ".") != 0 && if (strcmp(ent->d_name, ".") != 0 &&
strcmp(ent->d_name, "..") != 0 && strcmp(ent->d_name, "..") != 0 &&
strlen(ent->d_name) > strlen(type) && strlen(ent->d_name) > strlen(type) &&
strncmp(ent->d_name, type, strlen(type)) == 0) { strncmp(ent->d_name, type, strlen(type)) == 0) {
errno = 0; errno = 0;
ret = sscanf(ent->d_name + strlen(type), "%d", &number); ret = sscanf(ent->d_name + strlen(type), "%d", &number);
if (ret < 0) { if (ret < 0) {
@ -580,12 +592,9 @@ int find_type_by_name(const char *name, const char *type)
numstrlen = calc_digits(number); numstrlen = calc_digits(number);
/* verify the next character is not a colon */ /* verify the next character is not a colon */
if (strncmp(ent->d_name + strlen(type) + numstrlen, if (strncmp(ent->d_name + strlen(type) + numstrlen,
":", ":", 1) != 0) {
1) != 0) { filename = malloc(strlen(iio_dir) + strlen(type)
filename = malloc(strlen(iio_dir) + numstrlen + 6);
+ strlen(type)
+ numstrlen
+ 6);
if (filename == NULL) { if (filename == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto error_close_dir; goto error_close_dir;
@ -598,19 +607,20 @@ int find_type_by_name(const char *name, const char *type)
goto error_close_dir; goto error_close_dir;
} }
nameFile = fopen(filename, "r"); namefp = fopen(filename, "r");
if (!nameFile) { if (!namefp) {
free(filename); free(filename);
continue; continue;
} }
free(filename); free(filename);
errno = 0; errno = 0;
if (fscanf(nameFile, "%s", thisname) != 1) { if (fscanf(namefp, "%s", thisname) != 1) {
ret = errno ? -errno : -ENODATA; ret = errno ? -errno : -ENODATA;
goto error_close_dir; goto error_close_dir;
} }
if (fclose(nameFile)) { if (fclose(namefp)) {
ret = -errno; ret = -errno;
goto error_close_dir; 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 (strcmp(name, thisname) == 0) {
if (closedir(dp) == -1) if (closedir(dp) == -1)
return -errno; return -errno;
return number; return number;
} }
} }
@ -631,6 +642,7 @@ int find_type_by_name(const char *name, const char *type)
error_close_dir: error_close_dir:
if (closedir(dp) == -1) if (closedir(dp) == -1)
perror("find_type_by_name(): Failed to close directory"); perror("find_type_by_name(): Failed to close directory");
return ret; return ret;
} }
@ -644,6 +656,7 @@ static int _write_sysfs_int(const char *filename, const char *basedir, int val,
if (temp == NULL) if (temp == NULL)
return -ENOMEM; return -ENOMEM;
ret = sprintf(temp, "%s/%s", basedir, filename); ret = sprintf(temp, "%s/%s", basedir, filename);
if (ret < 0) if (ret < 0)
goto error_free; 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); printf("failed to open %s\n", temp);
goto error_free; goto error_free;
} }
ret = fprintf(sysfsfp, "%d", val); ret = fprintf(sysfsfp, "%d", val);
if (ret < 0) { if (ret < 0) {
if (fclose(sysfsfp)) 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); printf("failed to open %s\n", temp);
goto error_free; goto error_free;
} }
if (fscanf(sysfsfp, "%d", &test) != 1) { if (fscanf(sysfsfp, "%d", &test) != 1) {
ret = errno ? -errno : -ENODATA; ret = errno ? -errno : -ENODATA;
if (fclose(sysfsfp)) if (fclose(sysfsfp))
@ -688,13 +703,12 @@ static int _write_sysfs_int(const char *filename, const char *basedir, int val,
} }
if (test != val) { if (test != val) {
printf("Possible failure in int write %d to %s%s\n", printf("Possible failure in int write %d to %s/%s\n",
val, val, basedir, filename);
basedir,
filename);
ret = -1; ret = -1;
} }
} }
error_free: error_free:
free(temp); free(temp);
return ret; return ret;
@ -739,6 +753,7 @@ static int _write_sysfs_string(const char *filename, const char *basedir,
printf("Memory allocation failed\n"); printf("Memory allocation failed\n");
return -ENOMEM; return -ENOMEM;
} }
ret = sprintf(temp, "%s/%s", basedir, filename); ret = sprintf(temp, "%s/%s", basedir, filename);
if (ret < 0) if (ret < 0)
goto error_free; 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); printf("Could not open %s\n", temp);
goto error_free; goto error_free;
} }
ret = fprintf(sysfsfp, "%s", val); ret = fprintf(sysfsfp, "%s", val);
if (ret < 0) { if (ret < 0) {
if (fclose(sysfsfp)) if (fclose(sysfsfp))
@ -766,9 +782,10 @@ static int _write_sysfs_string(const char *filename, const char *basedir,
sysfsfp = fopen(temp, "r"); sysfsfp = fopen(temp, "r");
if (sysfsfp == NULL) { if (sysfsfp == NULL) {
ret = -errno; ret = -errno;
printf("could not open file to verify\n"); printf("Could not open file to verify\n");
goto error_free; goto error_free;
} }
if (fscanf(sysfsfp, "%s", temp) != 1) { if (fscanf(sysfsfp, "%s", temp) != 1) {
ret = errno ? -errno : -ENODATA; ret = errno ? -errno : -ENODATA;
if (fclose(sysfsfp)) if (fclose(sysfsfp))
@ -784,15 +801,12 @@ static int _write_sysfs_string(const char *filename, const char *basedir,
if (strcmp(temp, val) != 0) { if (strcmp(temp, val) != 0) {
printf("Possible failure in string write of %s " printf("Possible failure in string write of %s "
"Should be %s " "Should be %s written to %s/%s\n", temp, val,
"written to %s\%s\n", basedir, filename);
temp,
val,
basedir,
filename);
ret = -1; ret = -1;
} }
} }
error_free: error_free:
free(temp); free(temp);
@ -845,6 +859,7 @@ int read_sysfs_posint(const char *filename, const char *basedir)
printf("Memory allocation failed"); printf("Memory allocation failed");
return -ENOMEM; return -ENOMEM;
} }
ret = sprintf(temp, "%s/%s", basedir, filename); ret = sprintf(temp, "%s/%s", basedir, filename);
if (ret < 0) if (ret < 0)
goto error_free; goto error_free;
@ -854,6 +869,7 @@ int read_sysfs_posint(const char *filename, const char *basedir)
ret = -errno; ret = -errno;
goto error_free; goto error_free;
} }
errno = 0; errno = 0;
if (fscanf(sysfsfp, "%d\n", &ret) != 1) { if (fscanf(sysfsfp, "%d\n", &ret) != 1) {
ret = errno ? -errno : -ENODATA; ret = errno ? -errno : -ENODATA;
@ -868,6 +884,7 @@ int read_sysfs_posint(const char *filename, const char *basedir)
error_free: error_free:
free(temp); free(temp);
return ret; return ret;
} }
@ -889,6 +906,7 @@ int read_sysfs_float(const char *filename, const char *basedir, float *val)
printf("Memory allocation failed"); printf("Memory allocation failed");
return -ENOMEM; return -ENOMEM;
} }
ret = sprintf(temp, "%s/%s", basedir, filename); ret = sprintf(temp, "%s/%s", basedir, filename);
if (ret < 0) if (ret < 0)
goto error_free; goto error_free;
@ -898,6 +916,7 @@ int read_sysfs_float(const char *filename, const char *basedir, float *val)
ret = -errno; ret = -errno;
goto error_free; goto error_free;
} }
errno = 0; errno = 0;
if (fscanf(sysfsfp, "%f\n", val) != 1) { if (fscanf(sysfsfp, "%f\n", val) != 1) {
ret = errno ? -errno : -ENODATA; ret = errno ? -errno : -ENODATA;
@ -912,6 +931,7 @@ int read_sysfs_float(const char *filename, const char *basedir, float *val)
error_free: error_free:
free(temp); free(temp);
return ret; return ret;
} }
@ -933,6 +953,7 @@ int read_sysfs_string(const char *filename, const char *basedir, char *str)
printf("Memory allocation failed"); printf("Memory allocation failed");
return -ENOMEM; return -ENOMEM;
} }
ret = sprintf(temp, "%s/%s", basedir, filename); ret = sprintf(temp, "%s/%s", basedir, filename);
if (ret < 0) if (ret < 0)
goto error_free; goto error_free;
@ -942,6 +963,7 @@ int read_sysfs_string(const char *filename, const char *basedir, char *str)
ret = -errno; ret = -errno;
goto error_free; goto error_free;
} }
errno = 0; errno = 0;
if (fscanf(sysfsfp, "%s\n", str) != 1) { if (fscanf(sysfsfp, "%s\n", str) != 1) {
ret = errno ? -errno : -ENODATA; ret = errno ? -errno : -ENODATA;
@ -956,6 +978,7 @@ int read_sysfs_string(const char *filename, const char *basedir, char *str)
error_free: error_free:
free(temp); free(temp);
return ret; return ret;
} }

View File

@ -51,17 +51,16 @@ struct iio_channel_info {
}; };
int iioutils_break_up_name(const char *full_name, char **generic_name); int iioutils_break_up_name(const char *full_name, char **generic_name);
int iioutils_get_type(unsigned *is_signed, unsigned *bytes, int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
unsigned *bits_used, unsigned *shift, unsigned *shift, uint64_t *mask, unsigned *be,
uint64_t *mask, unsigned *be, const char *device_dir, const char *name,
const char *device_dir, const char *name, const char *generic_name);
const char *generic_name);
int iioutils_get_param_float(float *output, const char *param_name, int iioutils_get_param_float(float *output, const char *param_name,
const char *device_dir, const char *name, const char *device_dir, const char *name,
const char *generic_name); const char *generic_name);
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);
int build_channel_array(const char *device_dir, 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 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(const char *filename, const char *basedir, int val);
int write_sysfs_int_and_verify(const char *filename, const char *basedir, int write_sysfs_int_and_verify(const char *filename, const char *basedir,

View File

@ -20,7 +20,6 @@
#include <sys/dir.h> #include <sys/dir.h>
#include "iio_utils.h" #include "iio_utils.h"
static enum verbosity { static enum verbosity {
VERBLEVEL_DEFAULT, /* 0 gives lspci behaviour */ VERBLEVEL_DEFAULT, /* 0 gives lspci behaviour */
VERBLEVEL_SENSORS, /* 1 lists sensors */ VERBLEVEL_SENSORS, /* 1 lists sensors */
@ -29,17 +28,16 @@ static enum verbosity {
const char *type_device = "iio:device"; const char *type_device = "iio:device";
const char *type_trigger = "trigger"; const char *type_trigger = "trigger";
static inline int check_prefix(const char *str, const char *prefix) static inline int check_prefix(const char *str, const char *prefix)
{ {
return strlen(str) > strlen(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) static inline int check_postfix(const char *str, const char *postfix)
{ {
return strlen(str) > strlen(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) 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); dp = opendir(dev_dir_name);
if (dp == NULL) if (dp == NULL)
return -errno; return -errno;
while (ent = readdir(dp), ent != NULL) while (ent = readdir(dp), ent != NULL)
if (check_prefix(ent->d_name, "in_") && 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); printf(" %-10s\n", ent->d_name);
}
return (closedir(dp) == -1) ? -errno : 0; 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]; char name[IIO_MAX_NAME_LENGTH];
int dev_idx; int dev_idx;
int retval; int ret;
retval = sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_device), ret = sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_device), "%i",
"%i", &dev_idx); &dev_idx);
if (retval != 1) if (ret != 1)
return -EINVAL; return -EINVAL;
retval = read_sysfs_string("name", dev_dir_name, name);
if (retval) ret = read_sysfs_string("name", dev_dir_name, name);
return retval; if (ret)
return ret;
printf("Device %03d: %s\n", dev_idx, name); printf("Device %03d: %s\n", dev_idx, name);
if (verblevel >= VERBLEVEL_SENSORS) if (verblevel >= VERBLEVEL_SENSORS)
return dump_channels(dev_dir_name); return dump_channels(dev_dir_name);
return 0; return 0;
} }
@ -84,17 +84,19 @@ static int dump_one_trigger(const char *dev_dir_name)
{ {
char name[IIO_MAX_NAME_LENGTH]; char name[IIO_MAX_NAME_LENGTH];
int dev_idx; int dev_idx;
int retval; int ret;
retval = sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_trigger), ret = sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_trigger),
"%i", &dev_idx); "%i", &dev_idx);
if (retval != 1) if (ret != 1)
return -EINVAL; return -EINVAL;
retval = read_sysfs_string("name", dev_dir_name, name);
if (retval) ret = read_sysfs_string("name", dev_dir_name, name);
return retval; if (ret)
return ret;
printf("Trigger %03d: %s\n", dev_idx, name); printf("Trigger %03d: %s\n", dev_idx, name);
return 0; return 0;
} }
@ -151,6 +153,7 @@ static int dump_devices(void)
free(dev_dir_name); free(dev_dir_name);
} }
} }
return (closedir(dp) == -1) ? -errno : 0; return (closedir(dp) == -1) ? -errno : 0;
error_close_dir: error_close_dir: