summaryrefslogtreecommitdiff
path: root/drivers/iio/light
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/light')
-rw-r--r--drivers/iio/light/adux1020.c4
-rw-r--r--drivers/iio/light/apds9160.c7
-rw-r--r--drivers/iio/light/apds9300.c4
-rw-r--r--drivers/iio/light/apds9306.c11
-rw-r--r--drivers/iio/light/apds9960.c4
-rw-r--r--drivers/iio/light/bh1745.c3
-rw-r--r--drivers/iio/light/cm32181.c2
-rw-r--r--drivers/iio/light/cm3323.c17
-rw-r--r--drivers/iio/light/cm3605.c5
-rw-r--r--drivers/iio/light/gp2ap002.c29
-rw-r--r--drivers/iio/light/hid-sensor-als.c74
-rw-r--r--drivers/iio/light/hid-sensor-prox.c49
-rw-r--r--drivers/iio/light/isl29028.c22
-rw-r--r--drivers/iio/light/ltr390.c3
-rw-r--r--drivers/iio/light/ltr501.c5
-rw-r--r--drivers/iio/light/ltrf216a.c3
-rw-r--r--drivers/iio/light/opt3001.c539
-rw-r--r--drivers/iio/light/opt4001.c37
-rw-r--r--drivers/iio/light/opt4060.c11
-rw-r--r--drivers/iio/light/rpr0521.c10
-rw-r--r--drivers/iio/light/si1145.c4
-rw-r--r--drivers/iio/light/st_uvis25_core.c5
-rw-r--r--drivers/iio/light/st_uvis25_spi.c2
-rw-r--r--drivers/iio/light/stk3310.c5
-rw-r--r--drivers/iio/light/tcs3472.c319
-rw-r--r--drivers/iio/light/tsl2563.c2
-rw-r--r--drivers/iio/light/tsl2583.c44
-rw-r--r--drivers/iio/light/tsl2772.c7
-rw-r--r--drivers/iio/light/vcnl4000.c16
-rw-r--r--drivers/iio/light/vcnl4035.c23
-rw-r--r--drivers/iio/light/veml6030.c4
-rw-r--r--drivers/iio/light/vl6180.c2
32 files changed, 729 insertions, 543 deletions
diff --git a/drivers/iio/light/adux1020.c b/drivers/iio/light/adux1020.c
index 633a105fd7f0..0ea282ecc99a 100644
--- a/drivers/iio/light/adux1020.c
+++ b/drivers/iio/light/adux1020.c
@@ -808,10 +808,8 @@ static int adux1020_probe(struct i2c_client *client)
NULL, adux1020_interrupt_handler,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
ADUX1020_DRV_NAME, indio_dev);
- if (ret) {
- dev_err(&client->dev, "irq request error %d\n", -ret);
+ if (ret)
return ret;
- }
}
return devm_iio_device_register(&client->dev, indio_dev);
diff --git a/drivers/iio/light/apds9160.c b/drivers/iio/light/apds9160.c
index 8dacb1730429..d7e0924b8106 100644
--- a/drivers/iio/light/apds9160.c
+++ b/drivers/iio/light/apds9160.c
@@ -1545,11 +1545,8 @@ static int apds9160_probe(struct i2c_client *client)
apds9160_irq_handler,
IRQF_ONESHOT, "apds9160_event",
indio_dev);
- if (ret) {
- return dev_err_probe(dev, ret,
- "request irq (%d) failed\n",
- client->irq);
- }
+ if (ret)
+ return ret;
} else {
indio_dev->info = &apds9160_info_no_events;
indio_dev->channels = apds9160_channels_without_events;
diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c
index d60ade1209f3..f0abbc4a862a 100644
--- a/drivers/iio/light/apds9300.c
+++ b/drivers/iio/light/apds9300.c
@@ -432,10 +432,8 @@ static int apds9300_probe(struct i2c_client *client)
NULL, apds9300_interrupt_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"apds9300_event", indio_dev);
- if (ret) {
- dev_err(&client->dev, "irq request error %d\n", -ret);
+ if (ret)
goto err;
- }
}
ret = iio_device_register(indio_dev);
diff --git a/drivers/iio/light/apds9306.c b/drivers/iio/light/apds9306.c
index 5ca4c87524fe..f681b02e4922 100644
--- a/drivers/iio/light/apds9306.c
+++ b/drivers/iio/light/apds9306.c
@@ -469,9 +469,9 @@ static int apds9306_read_data(struct apds9306_data *data, int *val, int reg)
int status = 0;
u8 buff[3];
- ret = pm_runtime_resume_and_get(data->dev);
- if (ret)
- return ret;
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(data->dev, pm);
+ if (PM_RUNTIME_ACQUIRE_ERR(&pm))
+ return PM_RUNTIME_ACQUIRE_ERR(&pm);
ret = regmap_field_read(rf->intg_time, &intg_time_idx);
if (ret)
@@ -535,8 +535,6 @@ static int apds9306_read_data(struct apds9306_data *data, int *val, int reg)
*val = get_unaligned_le24(&buff);
- pm_runtime_put_autosuspend(data->dev);
-
return 0;
}
@@ -1286,8 +1284,7 @@ static int apds9306_probe(struct i2c_client *client)
apds9306_irq_handler, IRQF_ONESHOT,
"apds9306_event", indio_dev);
if (ret)
- return dev_err_probe(dev, ret,
- "failed to assign interrupt.\n");
+ return ret;
} else {
indio_dev->info = &apds9306_info_no_events;
indio_dev->channels = apds9306_channels_without_events;
diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c
index 2686c3b0c03b..afe520de60e2 100644
--- a/drivers/iio/light/apds9960.c
+++ b/drivers/iio/light/apds9960.c
@@ -1098,10 +1098,8 @@ static int apds9960_probe(struct i2c_client *client)
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"apds9960_event",
indio_dev);
- if (ret) {
- dev_err(&client->dev, "request irq (%d) failed\n", client->irq);
+ if (ret)
goto error_power_down;
- }
ret = iio_device_register(indio_dev);
if (ret)
diff --git a/drivers/iio/light/bh1745.c b/drivers/iio/light/bh1745.c
index 0aa8e5cc6c56..2b8ff36071b8 100644
--- a/drivers/iio/light/bh1745.c
+++ b/drivers/iio/light/bh1745.c
@@ -784,8 +784,7 @@ static int bh1745_setup_triggered_buffer(struct iio_dev *indio_dev,
IRQF_ONESHOT,
"bh1745_interrupt", indio_dev);
if (ret)
- return dev_err_probe(dev, ret,
- "Request for IRQ failed\n");
+ return ret;
}
return 0;
diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index 2590fc8fd154..b32a94028f09 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -368,7 +368,7 @@ static int cm32181_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_CALIBSCALE:
cm32181->calibscale = val;
- return val;
+ return 0;
case IIO_CHAN_INFO_INT_TIME:
ret = cm32181_write_als_it(cm32181, val2);
return ret;
diff --git a/drivers/iio/light/cm3323.c b/drivers/iio/light/cm3323.c
index fbb9e0a13733..506c91f44f43 100644
--- a/drivers/iio/light/cm3323.c
+++ b/drivers/iio/light/cm3323.c
@@ -80,22 +80,19 @@ static int cm3323_init(struct iio_dev *indio_dev)
{
int ret;
struct cm3323_data *data = iio_priv(indio_dev);
+ struct device *dev = &data->client->dev;
ret = i2c_smbus_read_word_data(data->client, CM3323_CMD_CONF);
- if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_conf\n");
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Error reading reg_conf\n");
/* enable sensor and set auto force mode */
ret &= ~(CM3323_CONF_SD_BIT | CM3323_CONF_AF_BIT);
data->reg_conf = ret;
ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF, data->reg_conf);
- if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_conf\n");
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Error writing reg_conf\n");
return 0;
}
@@ -236,10 +233,8 @@ static int cm3323_probe(struct i2c_client *client)
indio_dev->modes = INDIO_DIRECT_MODE;
ret = cm3323_init(indio_dev);
- if (ret < 0) {
- dev_err(&client->dev, "cm3323 chip init failed\n");
+ if (ret < 0)
return ret;
- }
ret = devm_add_action_or_reset(&client->dev, cm3323_disable, indio_dev);
if (ret < 0)
diff --git a/drivers/iio/light/cm3605.c b/drivers/iio/light/cm3605.c
index 98c84f33db60..34c127593947 100644
--- a/drivers/iio/light/cm3605.c
+++ b/drivers/iio/light/cm3605.c
@@ -232,10 +232,8 @@ static int cm3605_probe(struct platform_device *pdev)
ret = devm_request_threaded_irq(dev, irq, cm3605_prox_irq,
NULL, 0, "cm3605", indio_dev);
- if (ret) {
- dev_err(dev, "unable to request IRQ\n");
+ if (ret)
goto out_disable_aset;
- }
/* Just name the trigger the same as the driver */
led_trigger_register_simple("cm3605", &cm3605->led);
@@ -324,3 +322,4 @@ module_platform_driver(cm3605_driver);
MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
MODULE_DESCRIPTION("CM3605 ambient light and proximity sensor driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c
index a8db514cca5e..1fd40d60182e 100644
--- a/drivers/iio/light/gp2ap002.c
+++ b/drivers/iio/light/gp2ap002.c
@@ -342,6 +342,10 @@ static int gp2ap002_write_event_config(struct iio_dev *indio_dev,
bool state)
{
struct gp2ap002 *gp2ap002 = iio_priv(indio_dev);
+ int ret;
+
+ if (state == gp2ap002->enabled)
+ return 0;
if (state) {
/*
@@ -349,13 +353,16 @@ static int gp2ap002_write_event_config(struct iio_dev *indio_dev,
* already) and reintialize the sensor by using runtime_pm
* callbacks.
*/
- pm_runtime_get_sync(gp2ap002->dev);
- gp2ap002->enabled = true;
+ ret = pm_runtime_resume_and_get(gp2ap002->dev);
+ if (ret)
+ return ret;
+
} else {
pm_runtime_put_autosuspend(gp2ap002->dev);
- gp2ap002->enabled = false;
}
+ gp2ap002->enabled = state;
+
return 0;
}
@@ -573,10 +580,8 @@ static int gp2ap002_probe(struct i2c_client *client)
ret = devm_request_threaded_irq(dev, client->irq, NULL,
gp2ap002_prox_irq, IRQF_ONESHOT,
"gp2ap002", indio_dev);
- if (ret) {
- dev_err(dev, "unable to request IRQ\n");
+ if (ret)
goto out_put_pm;
- }
gp2ap002->irq = client->irq;
/*
@@ -642,6 +647,7 @@ static int gp2ap002_runtime_suspend(struct device *dev)
/* Disable chip and IRQ, everything off */
ret = regmap_write(gp2ap002->map, GP2AP002_OPMOD, 0x00);
if (ret) {
+ enable_irq(gp2ap002->irq);
dev_err(gp2ap002->dev, "error setting up operation mode\n");
return ret;
}
@@ -669,7 +675,7 @@ static int gp2ap002_runtime_resume(struct device *dev)
ret = regulator_enable(gp2ap002->vio);
if (ret) {
dev_err(dev, "failed to enable VIO regulator in resume path\n");
- return ret;
+ goto out_disable_vdd;
}
msleep(20);
@@ -677,13 +683,19 @@ static int gp2ap002_runtime_resume(struct device *dev)
ret = gp2ap002_init(gp2ap002);
if (ret) {
dev_err(dev, "re-initialization failed\n");
- return ret;
+ goto out_disable_vio;
}
/* Re-activate the IRQ */
enable_irq(gp2ap002->irq);
return 0;
+
+out_disable_vio:
+ regulator_disable(gp2ap002->vio);
+out_disable_vdd:
+ regulator_disable(gp2ap002->vdd);
+ return ret;
}
static DEFINE_RUNTIME_DEV_PM_OPS(gp2ap002_dev_pm_ops, gp2ap002_runtime_suspend,
@@ -717,3 +729,4 @@ module_i2c_driver(gp2ap002_driver);
MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
MODULE_DESCRIPTION("GP2AP002 ambient light and proximity sensor driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index 6bf1bc9a38fe..929343e42d83 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -33,9 +33,9 @@ struct als_state {
u32 illum[CHANNEL_SCAN_INDEX_MAX];
aligned_s64 timestamp;
} scan;
- int scale_pre_decml;
- int scale_post_decml;
- int scale_precision;
+ int scale_pre_decml[CHANNEL_SCAN_INDEX_MAX];
+ int scale_post_decml[CHANNEL_SCAN_INDEX_MAX];
+ int scale_precision[CHANNEL_SCAN_INDEX_MAX];
int value_offset;
int num_channels;
s64 timestamp;
@@ -119,9 +119,8 @@ static const struct iio_chan_spec als_channels[] = {
/* Channel read_raw handler */
static int als_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct als_state *als_state = iio_priv(indio_dev);
struct hid_sensor_hub_device *hsdev = als_state->common_attributes.hsdev;
@@ -162,12 +161,12 @@ static int als_read_raw(struct iio_dev *indio_dev,
}
if (report_id >= 0) {
hid_sensor_power_state(&als_state->common_attributes,
- true);
+ true);
*val = sensor_hub_input_attr_get_raw_value(
hsdev, hsdev->usage, address, report_id,
SENSOR_HUB_SYNC, min < 0);
hid_sensor_power_state(&als_state->common_attributes,
- false);
+ false);
} else {
*val = 0;
return -EINVAL;
@@ -175,9 +174,11 @@ static int als_read_raw(struct iio_dev *indio_dev,
ret_type = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
- *val = als_state->scale_pre_decml;
- *val2 = als_state->scale_post_decml;
- ret_type = als_state->scale_precision;
+ if (chan->scan_index >= CHANNEL_SCAN_INDEX_MAX)
+ return -EINVAL;
+ *val = als_state->scale_pre_decml[chan->scan_index];
+ *val2 = als_state->scale_post_decml[chan->scan_index];
+ ret_type = als_state->scale_precision[chan->scan_index];
break;
case IIO_CHAN_INFO_OFFSET:
*val = als_state->value_offset;
@@ -205,10 +206,8 @@ static int als_read_raw(struct iio_dev *indio_dev,
/* Channel write_raw handler */
static int als_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct als_state *als_state = iio_priv(indio_dev);
int ret = 0;
@@ -240,8 +239,7 @@ static const struct iio_info als_info = {
/* Callback handler to send event after all samples are received and captured */
static int als_proc_event(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- void *priv)
+ u32 usage_id, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct als_state *als_state = iio_priv(indio_dev);
@@ -262,9 +260,9 @@ static int als_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int als_capture_sample(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- size_t raw_len, char *raw_data,
- void *priv)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct als_state *als_state = iio_priv(indio_dev);
@@ -303,9 +301,9 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev,
/* Parse report which is specific to an usage id*/
static int als_parse_report(struct platform_device *pdev,
- struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- struct als_state *st)
+ struct hid_sensor_hub_device *hsdev,
+ u32 usage_id,
+ struct als_state *st)
{
struct iio_chan_spec *channels;
int ret, index = 0;
@@ -331,6 +329,10 @@ static int als_parse_report(struct platform_device *pdev,
};
++index;
+ st->scale_precision[i] = hid_sensor_format_scale(usage_id,
+ &st->als[i], &st->scale_pre_decml[i],
+ &st->scale_post_decml[i]);
+
dev_dbg(&pdev->dev, "als %x:%x\n", st->als[i].index,
st->als[i].report_id);
}
@@ -340,10 +342,6 @@ static int als_parse_report(struct platform_device *pdev,
if (index)
ret = 0;
- st->scale_precision = hid_sensor_format_scale(usage_id,
- &st->als[CHANNEL_SCAN_INDEX_INTENSITY],
- &st->scale_pre_decml, &st->scale_post_decml);
-
return ret;
}
@@ -399,31 +397,31 @@ static int hid_als_probe(struct platform_device *pdev)
atomic_set(&als_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &als_state->common_attributes);
+ &als_state->common_attributes);
if (ret < 0) {
dev_err(&pdev->dev, "trigger setup failed\n");
return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "device register failed\n");
- goto error_remove_trigger;
- }
-
als_state->callbacks.send_event = als_proc_event;
als_state->callbacks.capture_sample = als_capture_sample;
als_state->callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, hsdev->usage, &als_state->callbacks);
if (ret < 0) {
dev_err(&pdev->dev, "callback reg failed\n");
- goto error_iio_unreg;
+ goto error_remove_trigger;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_callback;
}
return ret;
-error_iio_unreg:
- iio_device_unregister(indio_dev);
+error_remove_callback:
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
return ret;
@@ -436,8 +434,8 @@ static void hid_als_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct als_state *als_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
}
diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c
index 95bf2bfd86ee..63fd3eff171c 100644
--- a/drivers/iio/light/hid-sensor-prox.c
+++ b/drivers/iio/light/hid-sensor-prox.c
@@ -69,9 +69,8 @@ static const struct iio_chan_spec prox_channels[] = {
/* Channel read_raw handler */
static int prox_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct prox_state *prox_state = iio_priv(indio_dev);
struct hid_sensor_hub_device *hsdev;
@@ -134,10 +133,8 @@ static int prox_read_raw(struct iio_dev *indio_dev,
/* Channel write_raw handler */
static int prox_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct prox_state *prox_state = iio_priv(indio_dev);
int ret = 0;
@@ -165,8 +162,7 @@ static const struct iio_info prox_info = {
/* Callback handler to send event after all samples are received and captured */
static int prox_proc_event(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- void *priv)
+ u32 usage_id, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct prox_state *prox_state = iio_priv(indio_dev);
@@ -182,9 +178,9 @@ static int prox_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int prox_capture_sample(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- size_t raw_len, char *raw_data,
- void *priv)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct prox_state *prox_state = iio_priv(indio_dev);
@@ -217,8 +213,8 @@ static int prox_capture_sample(struct hid_sensor_hub_device *hsdev,
/* Parse report which is specific to an usage id*/
static int prox_parse_report(struct platform_device *pdev,
- struct hid_sensor_hub_device *hsdev,
- struct prox_state *st)
+ struct hid_sensor_hub_device *hsdev,
+ struct prox_state *st)
{
struct iio_chan_spec *channels = st->channels;
int index = 0;
@@ -270,8 +266,7 @@ static int hid_prox_probe(struct platform_device *pdev)
struct iio_dev *indio_dev;
struct prox_state *prox_state;
- indio_dev = devm_iio_device_alloc(&pdev->dev,
- sizeof(struct prox_state));
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct prox_state));
if (!indio_dev)
return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
@@ -305,18 +300,12 @@ static int hid_prox_probe(struct platform_device *pdev)
atomic_set(&prox_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &prox_state->common_attributes);
+ &prox_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "trigger setup failed\n");
return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "device register failed\n");
- goto error_remove_trigger;
- }
-
prox_state->callbacks.send_event = prox_proc_event;
prox_state->callbacks.capture_sample = prox_capture_sample;
prox_state->callbacks.pdev = pdev;
@@ -324,13 +313,19 @@ static int hid_prox_probe(struct platform_device *pdev)
&prox_state->callbacks);
if (ret < 0) {
dev_err(&pdev->dev, "callback reg failed\n");
- goto error_iio_unreg;
+ goto error_remove_trigger;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_callback;
}
return ret;
-error_iio_unreg:
- iio_device_unregister(indio_dev);
+error_remove_callback:
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes);
return ret;
@@ -343,8 +338,8 @@ static void hid_prox_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct prox_state *prox_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes);
}
diff --git a/drivers/iio/light/isl29028.c b/drivers/iio/light/isl29028.c
index b88e7c4eae3e..33deb1726689 100644
--- a/drivers/iio/light/isl29028.c
+++ b/drivers/iio/light/isl29028.c
@@ -333,16 +333,6 @@ static int isl29028_ir_get(struct isl29028_chip *chip, int *ir_data)
return isl29028_read_als_ir(chip, ir_data);
}
-static int isl29028_set_pm_runtime_busy(struct isl29028_chip *chip, bool on)
-{
- struct device *dev = regmap_get_device(chip->regmap);
-
- if (on)
- return pm_runtime_resume_and_get(dev);
-
- return pm_runtime_put_autosuspend(dev);
-}
-
/* Channel IO */
static int isl29028_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
@@ -352,7 +342,7 @@ static int isl29028_write_raw(struct iio_dev *indio_dev,
struct device *dev = regmap_get_device(chip->regmap);
int ret;
- ret = isl29028_set_pm_runtime_busy(chip, true);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
return ret;
@@ -405,11 +395,11 @@ static int isl29028_write_raw(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
- ret = isl29028_set_pm_runtime_busy(chip, false);
+ ret = pm_runtime_put_autosuspend(dev);
if (ret < 0)
return ret;
- return ret;
+ return 0;
}
static int isl29028_read_raw(struct iio_dev *indio_dev,
@@ -420,7 +410,7 @@ static int isl29028_read_raw(struct iio_dev *indio_dev,
struct device *dev = regmap_get_device(chip->regmap);
int ret, pm_ret;
- ret = isl29028_set_pm_runtime_busy(chip, true);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
return ret;
@@ -476,10 +466,10 @@ static int isl29028_read_raw(struct iio_dev *indio_dev,
/**
* Preserve the ret variable if the call to
- * isl29028_set_pm_runtime_busy() is successful so the reading
+ * pm_runtime_put_autosuspend() is successful so the reading
* (if applicable) is returned to user space.
*/
- pm_ret = isl29028_set_pm_runtime_busy(chip, false);
+ pm_ret = pm_runtime_put_autosuspend(dev);
if (pm_ret < 0)
return pm_ret;
diff --git a/drivers/iio/light/ltr390.c b/drivers/iio/light/ltr390.c
index bdc74b8226c8..bc031f2c3141 100644
--- a/drivers/iio/light/ltr390.c
+++ b/drivers/iio/light/ltr390.c
@@ -838,8 +838,7 @@ static int ltr390_probe(struct i2c_client *client)
"ltr390_thresh_event",
indio_dev);
if (ret)
- return dev_err_probe(dev, ret,
- "request irq (%d) failed\n", client->irq);
+ return ret;
}
ret = ltr390_pm_init(data);
diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c
index 7d045be78c6d..fa0d16890c8b 100644
--- a/drivers/iio/light/ltr501.c
+++ b/drivers/iio/light/ltr501.c
@@ -1537,11 +1537,8 @@ static int ltr501_probe(struct i2c_client *client)
IRQF_ONESHOT,
"ltr501_thresh_event",
indio_dev);
- if (ret) {
- dev_err(&client->dev, "request irq (%d) failed\n",
- client->irq);
+ if (ret)
return ret;
- }
} else {
indio_dev->info = data->chip_info->info_no_irq;
}
diff --git a/drivers/iio/light/ltrf216a.c b/drivers/iio/light/ltrf216a.c
index 3f34ddc911b4..0a8851342039 100644
--- a/drivers/iio/light/ltrf216a.c
+++ b/drivers/iio/light/ltrf216a.c
@@ -247,11 +247,10 @@ static int ltrf216a_get_lux(struct ltrf216a_data *data)
return ret;
greendata = ltrf216a_read_data(data, LTRF216A_ALS_DATA_0);
+ ltrf216a_set_power_state(data, false);
if (greendata < 0)
return greendata;
- ltrf216a_set_power_state(data, false);
-
lux = greendata * data->info->lux_multiplier * LTRF216A_WIN_FAC;
return lux;
diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c
index c5bd7fa23fb7..a948353014ac 100644
--- a/drivers/iio/light/opt3001.c
+++ b/drivers/iio/light/opt3001.c
@@ -10,6 +10,7 @@
#include <linux/array_size.h>
#include <linux/bits.h>
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/dev_printk.h>
#include <linux/errno.h>
@@ -100,9 +101,14 @@ struct opt3001_chip_info {
struct opt3001 {
struct i2c_client *client;
- struct device *dev;
+ /*
+ * Ensure data capture and read-modify-write sequences are
+ * not interrupted.
+ */
struct mutex lock;
+
+ /* Allows for IRQs to bypass locking mechanism */
bool ok_to_ignore_lock;
bool result_ready;
wait_queue_head_t result_ready_queue;
@@ -223,11 +229,10 @@ static const struct opt3001_scale opt3002_scales[] = {
},
};
-static int opt3001_find_scale(const struct opt3001 *opt, int val,
- int val2, u8 *exponent)
+static int opt3001_find_scale(const struct opt3001 *opt, int val, int val2,
+ u8 *exponent)
{
- int i;
- for (i = 0; i < ARRAY_SIZE(*opt->chip_info->scales); i++) {
+ for (unsigned int i = 0; i < ARRAY_SIZE(*opt->chip_info->scales); i++) {
const struct opt3001_scale *scale = &(*opt->chip_info->scales)[i];
/*
* Compare the integer and micro parts to determine value scale.
@@ -242,8 +247,8 @@ static int opt3001_find_scale(const struct opt3001 *opt, int val,
return -EINVAL;
}
-static void opt3001_to_iio_ret(struct opt3001 *opt, u8 exponent,
- u16 mantissa, int *val, int *val2)
+static void opt3001_to_iio_ret(struct opt3001 *opt, u8 exponent, u16 mantissa,
+ int *val, int *val2)
{
int ret;
int whole = opt->chip_info->factor_whole;
@@ -310,123 +315,143 @@ static const struct iio_chan_spec opt3002_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(1),
};
-static int opt3001_get_processed(struct opt3001 *opt, int *val, int *val2)
+static int opt3001_start_conversion(struct opt3001 *opt)
{
- int ret;
- u16 mantissa;
+ struct i2c_client *client = opt->client;
+ struct device *dev = &client->dev;
u16 reg;
- u8 exponent;
- u16 value;
- long timeout;
-
- if (opt->use_irq) {
- /*
- * Enable the end-of-conversion interrupt mechanism. Note that
- * doing so will overwrite the low-level limit value however we
- * will restore this value later on.
- */
- ret = i2c_smbus_write_word_swapped(opt->client,
- OPT3001_LOW_LIMIT,
- OPT3001_LOW_LIMIT_EOC_ENABLE);
- if (ret < 0) {
- dev_err(opt->dev, "failed to write register %02x\n",
- OPT3001_LOW_LIMIT);
- return ret;
- }
-
- /* Allow IRQ to access the device despite lock being set */
- opt->ok_to_ignore_lock = true;
- }
+ int ret;
/* Reset data-ready indicator flag */
opt->result_ready = false;
/* Configure for single-conversion mode and start a new conversion */
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION);
if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_CONFIGURATION);
- goto err;
+ dev_err(dev, "failed to read register %02x\n",
+ OPT3001_CONFIGURATION);
+ return ret;
}
reg = ret;
opt3001_set_mode(opt, &reg, OPT3001_CONFIGURATION_M_SINGLE);
- ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
- reg);
+ ret = i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION, reg);
+ if (ret)
+ dev_err(dev, "failed to write register %02x\n",
+ OPT3001_CONFIGURATION);
+
+ return ret;
+}
+
+static int opt3001_get_processed_irq(struct opt3001 *opt)
+{
+ struct i2c_client *client = opt->client;
+ struct device *dev = &client->dev;
+ u16 value;
+ int ret;
+
+ /*
+ * Enable the end-of-conversion interrupt mechanism. Note that doing so
+ * will overwrite the low-level limit value however we will restore this
+ * value later on.
+ */
+ ret = i2c_smbus_write_word_swapped(client,
+ OPT3001_LOW_LIMIT,
+ OPT3001_LOW_LIMIT_EOC_ENABLE);
if (ret < 0) {
- dev_err(opt->dev, "failed to write register %02x\n",
- OPT3001_CONFIGURATION);
- goto err;
+ dev_err(dev, "failed to write register %02x\n",
+ OPT3001_LOW_LIMIT);
+ return ret;
}
- if (opt->use_irq) {
- /* Wait for the IRQ to indicate the conversion is complete */
- ret = wait_event_timeout(opt->result_ready_queue,
- opt->result_ready,
- msecs_to_jiffies(OPT3001_RESULT_READY_LONG));
- if (ret == 0) {
- ret = -ETIMEDOUT;
- goto err;
- }
- } else {
- /* Sleep for result ready time */
- timeout = (opt->int_time == OPT3001_INT_TIME_SHORT) ?
- OPT3001_RESULT_READY_SHORT : OPT3001_RESULT_READY_LONG;
- msleep(timeout);
-
- /* Check result ready flag */
- ret = i2c_smbus_read_word_swapped(opt->client,
- OPT3001_CONFIGURATION);
- if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_CONFIGURATION);
- goto err;
- }
+ /* Allow IRQ to access the device despite lock being set */
+ opt->ok_to_ignore_lock = true;
- if (!(ret & OPT3001_CONFIGURATION_CRF)) {
- ret = -ETIMEDOUT;
- goto err;
- }
+ ret = opt3001_start_conversion(opt);
+ if (ret)
+ goto err;
- /* Obtain value */
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_RESULT);
- if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_RESULT);
- goto err;
- }
- opt->result = ret;
- opt->result_ready = true;
- }
+ if (wait_event_timeout(opt->result_ready_queue, opt->result_ready,
+ msecs_to_jiffies(OPT3001_RESULT_READY_LONG)))
+ ret = 0;
+ else
+ ret = -ETIMEDOUT;
err:
- if (opt->use_irq)
- /* Disallow IRQ to access the device while lock is active */
- opt->ok_to_ignore_lock = false;
+ opt->ok_to_ignore_lock = false;
if (ret < 0)
return ret;
- if (opt->use_irq) {
- /*
- * Disable the end-of-conversion interrupt mechanism by
- * restoring the low-level limit value (clearing
- * OPT3001_LOW_LIMIT_EOC_ENABLE). Note that selectively clearing
- * those enable bits would affect the actual limit value due to
- * bit-overlap and therefore can't be done.
- */
- value = (opt->low_thresh_exp << 12) | opt->low_thresh_mantissa;
- ret = i2c_smbus_write_word_swapped(opt->client,
- OPT3001_LOW_LIMIT,
- value);
- if (ret < 0) {
- dev_err(opt->dev, "failed to write register %02x\n",
- OPT3001_LOW_LIMIT);
- return ret;
- }
+ /*
+ * Disable the end-of-conversion interrupt mechanism by restoring the
+ * low-level limit value (clearing OPT3001_LOW_LIMIT_EOC_ENABLE). Note
+ * that selectively clearing those enable bits would affect the actual
+ * limit value due to bit-overlap and therefore can't be done.
+ */
+ value = (opt->low_thresh_exp << 12) | opt->low_thresh_mantissa;
+ ret = i2c_smbus_write_word_swapped(client, OPT3001_LOW_LIMIT, value);
+ if (ret)
+ dev_err(dev, "failed to write register %02x\n",
+ OPT3001_LOW_LIMIT);
+
+ return ret;
+}
+
+static int opt3001_get_processed_noirq(struct opt3001 *opt)
+{
+ struct i2c_client *client = opt->client;
+ struct device *dev = &client->dev;
+ int ret;
+
+ ret = opt3001_start_conversion(opt);
+ if (ret)
+ return ret;
+
+ if (opt->int_time == OPT3001_INT_TIME_SHORT)
+ msleep(OPT3001_RESULT_READY_SHORT);
+ else
+ msleep(OPT3001_RESULT_READY_LONG);
+
+ /* Check result ready flag */
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION);
+ if (ret < 0) {
+ dev_err(dev, "failed to read register %02x\n",
+ OPT3001_CONFIGURATION);
+ return ret;
}
+ if (!(ret & OPT3001_CONFIGURATION_CRF))
+ return -ETIMEDOUT;
+
+ /* Obtain value */
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_RESULT);
+ if (ret < 0) {
+ dev_err(dev, "failed to read register %02x\n",
+ OPT3001_RESULT);
+ return ret;
+ }
+
+ opt->result = ret;
+ opt->result_ready = true;
+
+ return 0;
+}
+
+static int opt3001_get_processed(struct opt3001 *opt, int *val, int *val2)
+{
+ u16 mantissa;
+ u8 exponent;
+ int ret;
+
+ if (opt->use_irq)
+ ret = opt3001_get_processed_irq(opt);
+ else
+ ret = opt3001_get_processed_noirq(opt);
+ if (ret)
+ return ret;
+
exponent = OPT3001_REG_EXPONENT(opt->result);
mantissa = OPT3001_REG_MANTISSA(opt->result);
@@ -445,13 +470,15 @@ static int opt3001_get_int_time(struct opt3001 *opt, int *val, int *val2)
static int opt3001_set_int_time(struct opt3001 *opt, int time)
{
+ struct i2c_client *client = opt->client;
+ struct device *dev = &client->dev;
int ret;
u16 reg;
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION);
if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_CONFIGURATION);
+ dev_err(dev, "failed to read register %02x\n",
+ OPT3001_CONFIGURATION);
return ret;
}
@@ -470,16 +497,14 @@ static int opt3001_set_int_time(struct opt3001 *opt, int time)
return -EINVAL;
}
- return i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
- reg);
+ return i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION, reg);
}
static int opt3001_read_raw(struct iio_dev *iio,
- struct iio_chan_spec const *chan, int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct opt3001 *opt = iio_priv(iio);
- int ret;
if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS)
return -EBUSY;
@@ -487,31 +512,24 @@ static int opt3001_read_raw(struct iio_dev *iio,
if (chan->type != opt->chip_info->chan_type)
return -EINVAL;
- mutex_lock(&opt->lock);
+ guard(mutex)(&opt->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_PROCESSED:
- ret = opt3001_get_processed(opt, val, val2);
- break;
+ return opt3001_get_processed(opt, val, val2);
case IIO_CHAN_INFO_INT_TIME:
- ret = opt3001_get_int_time(opt, val, val2);
- break;
+ return opt3001_get_int_time(opt, val, val2);
default:
- ret = -EINVAL;
+ return -EINVAL;
}
-
- mutex_unlock(&opt->lock);
-
- return ret;
}
static int opt3001_write_raw(struct iio_dev *iio,
- struct iio_chan_spec const *chan, int val, int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct opt3001 *opt = iio_priv(iio);
- int ret;
if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS)
return -EBUSY;
@@ -525,47 +543,46 @@ static int opt3001_write_raw(struct iio_dev *iio,
if (val != 0)
return -EINVAL;
- mutex_lock(&opt->lock);
- ret = opt3001_set_int_time(opt, val2);
- mutex_unlock(&opt->lock);
+ guard(mutex)(&opt->lock);
- return ret;
+ return opt3001_set_int_time(opt, val2);
}
static int opt3001_read_event_value(struct iio_dev *iio,
- const struct iio_chan_spec *chan, enum iio_event_type type,
- enum iio_event_direction dir, enum iio_event_info info,
- int *val, int *val2)
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
{
struct opt3001 *opt = iio_priv(iio);
- int ret = IIO_VAL_INT_PLUS_MICRO;
- mutex_lock(&opt->lock);
+ guard(mutex)(&opt->lock);
switch (dir) {
case IIO_EV_DIR_RISING:
opt3001_to_iio_ret(opt, opt->high_thresh_exp,
- opt->high_thresh_mantissa, val, val2);
- break;
+ opt->high_thresh_mantissa, val, val2);
+ return IIO_VAL_INT_PLUS_MICRO;
case IIO_EV_DIR_FALLING:
opt3001_to_iio_ret(opt, opt->low_thresh_exp,
- opt->low_thresh_mantissa, val, val2);
- break;
+ opt->low_thresh_mantissa, val, val2);
+ return IIO_VAL_INT_PLUS_MICRO;
default:
- ret = -EINVAL;
+ return -EINVAL;
}
-
- mutex_unlock(&opt->lock);
-
- return ret;
}
static int opt3001_write_event_value(struct iio_dev *iio,
- const struct iio_chan_spec *chan, enum iio_event_type type,
- enum iio_event_direction dir, enum iio_event_info info,
- int val, int val2)
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
{
struct opt3001 *opt = iio_priv(iio);
+ struct i2c_client *client = opt->client;
+ struct device *dev = &client->dev;
int ret;
int whole;
int integer;
@@ -580,12 +597,12 @@ static int opt3001_write_event_value(struct iio_dev *iio,
if (val < 0)
return -EINVAL;
- mutex_lock(&opt->lock);
+ guard(mutex)(&opt->lock);
ret = opt3001_find_scale(opt, val, val2, &exponent);
if (ret < 0) {
- dev_err(opt->dev, "can't find scale for %d.%06u\n", val, val2);
- goto err;
+ dev_err(dev, "can't find scale for %d.%06u\n", val, val2);
+ return ret;
}
whole = opt->chip_info->factor_whole;
@@ -608,25 +625,22 @@ static int opt3001_write_event_value(struct iio_dev *iio,
opt->low_thresh_exp = exponent;
break;
default:
- ret = -EINVAL;
- goto err;
+ return -EINVAL;
}
- ret = i2c_smbus_write_word_swapped(opt->client, reg, value);
+ ret = i2c_smbus_write_word_swapped(client, reg, value);
if (ret < 0) {
- dev_err(opt->dev, "failed to write register %02x\n", reg);
- goto err;
+ dev_err(dev, "failed to write register %02x\n", reg);
+ return ret;
}
-err:
- mutex_unlock(&opt->lock);
-
- return ret;
+ return 0;
}
static int opt3001_read_event_config(struct iio_dev *iio,
- const struct iio_chan_spec *chan, enum iio_event_type type,
- enum iio_event_direction dir)
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
{
struct opt3001 *opt = iio_priv(iio);
@@ -634,10 +648,14 @@ static int opt3001_read_event_config(struct iio_dev *iio,
}
static int opt3001_write_event_config(struct iio_dev *iio,
- const struct iio_chan_spec *chan, enum iio_event_type type,
- enum iio_event_direction dir, bool state)
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ bool state)
{
struct opt3001 *opt = iio_priv(iio);
+ struct i2c_client *client = opt->client;
+ struct device *dev = &client->dev;
int ret;
u16 mode;
u16 reg;
@@ -648,33 +666,29 @@ static int opt3001_write_event_config(struct iio_dev *iio,
if (!state && opt->mode == OPT3001_CONFIGURATION_M_SHUTDOWN)
return 0;
- mutex_lock(&opt->lock);
+ guard(mutex)(&opt->lock);
mode = state ? OPT3001_CONFIGURATION_M_CONTINUOUS
: OPT3001_CONFIGURATION_M_SHUTDOWN;
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION);
if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_CONFIGURATION);
- goto err;
+ dev_err(dev, "failed to read register %02x\n",
+ OPT3001_CONFIGURATION);
+ return ret;
}
reg = ret;
opt3001_set_mode(opt, &reg, mode);
- ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
- reg);
+ ret = i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION, reg);
if (ret < 0) {
- dev_err(opt->dev, "failed to write register %02x\n",
- OPT3001_CONFIGURATION);
- goto err;
+ dev_err(dev, "failed to write register %02x\n",
+ OPT3001_CONFIGURATION);
+ return ret;
}
-err:
- mutex_unlock(&opt->lock);
-
- return ret;
+ return 0;
}
static const struct iio_info opt3001_info = {
@@ -689,47 +703,69 @@ static const struct iio_info opt3001_info = {
static int opt3001_read_id(struct opt3001 *opt)
{
+ struct i2c_client *client = opt->client;
+ struct device *dev = &client->dev;
char manufacturer[2];
u16 device_id;
int ret;
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_MANUFACTURER_ID);
- if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_MANUFACTURER_ID);
- return ret;
- }
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_MANUFACTURER_ID);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to read register %02x\n",
+ OPT3001_MANUFACTURER_ID);
manufacturer[0] = ret >> 8;
manufacturer[1] = ret & 0xff;
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_DEVICE_ID);
- if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_DEVICE_ID);
- return ret;
- }
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_DEVICE_ID);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to read register %02x\n",
+ OPT3001_DEVICE_ID);
device_id = ret;
- dev_info(opt->dev, "Found %c%c OPT%04x\n", manufacturer[0],
- manufacturer[1], device_id);
+ dev_info(dev, "Found %c%c OPT%04x\n", manufacturer[0], manufacturer[1],
+ device_id);
return 0;
}
-static int opt3001_configure(struct opt3001 *opt)
+static void opt3001_power_off(void *data)
{
+ struct opt3001 *opt = data;
+ struct i2c_client *client = opt->client;
+ struct device *dev = &client->dev;
+ u16 reg_val;
int ret;
- u16 reg;
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION);
if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_CONFIGURATION);
- return ret;
+ dev_err(dev, "failed to read register %02x\n",
+ OPT3001_CONFIGURATION);
+ return;
}
+ reg_val = ret;
+ opt3001_set_mode(opt, &reg_val, OPT3001_CONFIGURATION_M_SHUTDOWN);
+
+ ret = i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION, reg_val);
+ if (ret < 0)
+ dev_err(dev, "failed to write to register %02x\n",
+ OPT3001_CONFIGURATION);
+}
+
+static int opt3001_configure(struct opt3001 *opt)
+{
+ struct i2c_client *client = opt->client;
+ struct device *dev = &client->dev;
+ int ret;
+ u16 reg;
+
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to read register %02x\n",
+ OPT3001_CONFIGURATION);
+
reg = ret;
/* Enable automatic full-scale setting mode */
@@ -751,30 +787,28 @@ static int opt3001_configure(struct opt3001 *opt)
reg &= ~OPT3001_CONFIGURATION_ME;
reg &= ~OPT3001_CONFIGURATION_FC_MASK;
- ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
- reg);
- if (ret < 0) {
- dev_err(opt->dev, "failed to write register %02x\n",
- OPT3001_CONFIGURATION);
- return ret;
- }
+ ret = i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION, reg);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to write register %02x\n",
+ OPT3001_CONFIGURATION);
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_LOW_LIMIT);
- if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_LOW_LIMIT);
- return ret;
- }
+ ret = devm_add_action_or_reset(dev, opt3001_power_off, opt);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to register power off function\n");
+
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_LOW_LIMIT);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to read register %02x\n",
+ OPT3001_LOW_LIMIT);
opt->low_thresh_mantissa = OPT3001_REG_MANTISSA(ret);
opt->low_thresh_exp = OPT3001_REG_EXPONENT(ret);
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_HIGH_LIMIT);
- if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_HIGH_LIMIT);
- return ret;
- }
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_HIGH_LIMIT);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to read register %02x\n",
+ OPT3001_HIGH_LIMIT);
opt->high_thresh_mantissa = OPT3001_REG_MANTISSA(ret);
opt->high_thresh_exp = OPT3001_REG_EXPONENT(ret);
@@ -786,6 +820,8 @@ static irqreturn_t opt3001_irq(int irq, void *_iio)
{
struct iio_dev *iio = _iio;
struct opt3001 *opt = iio_priv(iio);
+ struct i2c_client *client = opt->client;
+ struct device *dev = &client->dev;
int ret;
bool wake_result_ready_queue = false;
enum iio_chan_type chan_type = opt->chip_info->chan_type;
@@ -794,10 +830,10 @@ static irqreturn_t opt3001_irq(int irq, void *_iio)
if (!ok_to_ignore_lock)
mutex_lock(&opt->lock);
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION);
if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_CONFIGURATION);
+ dev_err(dev, "failed to read register %02x\n",
+ OPT3001_CONFIGURATION);
goto out;
}
@@ -805,21 +841,21 @@ static irqreturn_t opt3001_irq(int irq, void *_iio)
OPT3001_CONFIGURATION_M_CONTINUOUS) {
if (ret & OPT3001_CONFIGURATION_FH)
iio_push_event(iio,
- IIO_UNMOD_EVENT_CODE(chan_type, 0,
- IIO_EV_TYPE_THRESH,
- IIO_EV_DIR_RISING),
- iio_get_time_ns(iio));
+ IIO_UNMOD_EVENT_CODE(chan_type, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING),
+ iio_get_time_ns(iio));
if (ret & OPT3001_CONFIGURATION_FL)
iio_push_event(iio,
- IIO_UNMOD_EVENT_CODE(chan_type, 0,
- IIO_EV_TYPE_THRESH,
- IIO_EV_DIR_FALLING),
- iio_get_time_ns(iio));
+ IIO_UNMOD_EVENT_CODE(chan_type, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_FALLING),
+ iio_get_time_ns(iio));
} else if (ret & OPT3001_CONFIGURATION_CRF) {
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_RESULT);
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_RESULT);
if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_RESULT);
+ dev_err(dev, "failed to read register %02x\n",
+ OPT3001_RESULT);
goto out;
}
opt->result = ret;
@@ -852,12 +888,13 @@ static int opt3001_probe(struct i2c_client *client)
opt = iio_priv(iio);
opt->client = client;
- opt->dev = dev;
opt->chip_info = i2c_get_match_data(client);
- mutex_init(&opt->lock);
+ ret = devm_mutex_init(dev, &opt->lock);
+ if (ret)
+ return ret;
+
init_waitqueue_head(&opt->result_ready_queue);
- i2c_set_clientdata(client, iio);
if (opt->chip_info->has_id) {
ret = opt3001_read_id(opt);
@@ -875,55 +912,20 @@ static int opt3001_probe(struct i2c_client *client)
iio->modes = INDIO_DIRECT_MODE;
iio->info = &opt3001_info;
- ret = devm_iio_device_register(dev, iio);
- if (ret) {
- dev_err(dev, "failed to register IIO device\n");
- return ret;
- }
-
/* Make use of INT pin only if valid IRQ no. is given */
if (irq > 0) {
- ret = request_threaded_irq(irq, NULL, opt3001_irq,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- "opt3001", iio);
- if (ret) {
- dev_err(dev, "failed to request IRQ #%d\n", irq);
+ ret = devm_request_threaded_irq(dev, irq, NULL, opt3001_irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "opt3001", iio);
+ if (ret)
return ret;
- }
+
opt->use_irq = true;
} else {
- dev_dbg(opt->dev, "enabling interrupt-less operation\n");
- }
-
- return 0;
-}
-
-static void opt3001_remove(struct i2c_client *client)
-{
- struct iio_dev *iio = i2c_get_clientdata(client);
- struct opt3001 *opt = iio_priv(iio);
- int ret;
- u16 reg;
-
- if (opt->use_irq)
- free_irq(client->irq, iio);
-
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
- if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_CONFIGURATION);
- return;
+ dev_dbg(dev, "enabling interrupt-less operation\n");
}
- reg = ret;
- opt3001_set_mode(opt, &reg, OPT3001_CONFIGURATION_M_SHUTDOWN);
-
- ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
- reg);
- if (ret < 0) {
- dev_err(opt->dev, "failed to write register %02x\n",
- OPT3001_CONFIGURATION);
- }
+ return devm_iio_device_register(dev, iio);
}
static const struct opt3001_chip_info opt3001_chip_information = {
@@ -964,7 +966,6 @@ MODULE_DEVICE_TABLE(of, opt3001_of_match);
static struct i2c_driver opt3001_driver = {
.probe = opt3001_probe,
- .remove = opt3001_remove,
.id_table = opt3001_id,
.driver = {
diff --git a/drivers/iio/light/opt4001.c b/drivers/iio/light/opt4001.c
index dd152d921b48..aa3d87995b7c 100644
--- a/drivers/iio/light/opt4001.c
+++ b/drivers/iio/light/opt4001.c
@@ -39,7 +39,7 @@
#define OPT4001_CTRL_OPER_MODE_MASK GENMASK(5, 4)
#define OPT4001_CTRL_LATCH_MASK GENMASK(3, 3)
#define OPT4001_CTRL_INT_POL_MASK GENMASK(2, 2)
-#define OPT4001_CTRL_FAULT_COUNT GENMASK(0, 1)
+#define OPT4001_CTRL_FAULT_COUNT_MASK GENMASK(1, 0)
/* OPT4001 constants */
#define OPT4001_DEVICE_ID_VAL 0x121
@@ -173,6 +173,7 @@ static int opt4001_read_lux_value(struct iio_dev *indio_dev,
u8 crc;
u8 calc_crc;
u64 lux_raw;
+ u32 rem;
int ret;
ret = regmap_read(chip->regmap, OPT4001_LIGHT1_MSB, &light1);
@@ -199,8 +200,8 @@ static int opt4001_read_lux_value(struct iio_dev *indio_dev,
lux_raw = lux_raw << exp;
lux_raw = lux_raw * chip->chip_info->mul;
- *val = div_u64_rem(lux_raw, chip->chip_info->div, val2);
- *val2 = *val2 * 100;
+ *val = div_u64_rem(lux_raw, chip->chip_info->div, &rem);
+ *val2 = rem * 100;
return IIO_VAL_INT_PLUS_NANO;
}
@@ -222,33 +223,14 @@ static int opt4001_set_conf(struct opt4001_chip *chip)
return ret;
}
-static int opt4001_power_down(struct opt4001_chip *chip)
-{
- struct device *dev = &chip->client->dev;
- int ret;
- unsigned int reg;
-
- ret = regmap_read(chip->regmap, OPT4001_DEVICE_ID, &reg);
- if (ret) {
- dev_err(dev, "Failed to read configuration\n");
- return ret;
- }
-
- /* MODE_OFF is 0x0 so just set bits to 0 */
- reg &= ~OPT4001_CTRL_OPER_MODE_MASK;
-
- ret = regmap_write(chip->regmap, OPT4001_CTRL, reg);
- if (ret)
- dev_err(dev, "Failed to set configuration to power down\n");
-
- return ret;
-}
-
static void opt4001_chip_off_action(void *data)
{
struct opt4001_chip *chip = data;
+ int ret;
- opt4001_power_down(chip);
+ ret = regmap_clear_bits(chip->regmap, OPT4001_CTRL, OPT4001_CTRL_OPER_MODE_MASK);
+ if (ret)
+ dev_err(&chip->client->dev, "Failed to power down\n");
}
static const struct iio_chan_spec opt4001_channels[] = {
@@ -287,6 +269,9 @@ static int opt4001_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_INT_TIME:
+ if (val)
+ return -EINVAL;
+
int_time = opt4001_als_time_to_index(val2);
if (int_time < 0)
return int_time;
diff --git a/drivers/iio/light/opt4060.c b/drivers/iio/light/opt4060.c
index c391ad3271c6..8253a6a8bee4 100644
--- a/drivers/iio/light/opt4060.c
+++ b/drivers/iio/light/opt4060.c
@@ -632,6 +632,9 @@ static int opt4060_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_INT_TIME:
+ if (val)
+ return -EINVAL;
+
int_time = opt4060_als_time_to_index(val2);
if (int_time < 0)
return int_time;
@@ -710,6 +713,7 @@ static ssize_t opt4060_read_ev_period(struct opt4060_chip *chip, int *val,
{
int ret, pers, fault_count, int_time;
u64 uval;
+ u32 rem;
int_time = opt4060_int_time_reg[chip->int_time][0];
@@ -735,7 +739,8 @@ static ssize_t opt4060_read_ev_period(struct opt4060_chip *chip, int *val,
}
uval = mul_u32_u32(int_time, pers);
- *val = div_u64_rem(uval, MICRO, val2);
+ *val = div_u64_rem(uval, MICRO, &rem);
+ *val2 = rem;
return IIO_VAL_INT_PLUS_MICRO;
}
@@ -805,7 +810,7 @@ static int opt4060_get_thresholds(struct opt4060_chip *chip, u32 *th_lo, u32 *th
ret = regmap_read(chip->regmap, OPT4060_THRESHOLD_HIGH, &regval);
if (ret) {
- dev_err(chip->dev, "Failed to read THRESHOLD_LOW.\n");
+ dev_err(chip->dev, "Failed to read THRESHOLD_HIGH.\n");
return ret;
}
*th_hi = opt4060_calc_val_from_th_reg(regval);
@@ -1200,7 +1205,7 @@ static int opt4060_setup_trigger(struct opt4060_chip *chip, struct iio_dev *idev
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
name, idev);
if (ret)
- return dev_err_probe(chip->dev, ret, "Could not request IRQ\n");
+ return ret;
init_completion(&chip->completion);
diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c
index f961973892f2..7d82efc31f3a 100644
--- a/drivers/iio/light/rpr0521.c
+++ b/drivers/iio/light/rpr0521.c
@@ -987,11 +987,8 @@ static int rpr0521_probe(struct i2c_client *client)
rpr0521_drdy_irq_handler, rpr0521_drdy_irq_thread,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"rpr0521_event", indio_dev);
- if (ret < 0) {
- dev_err(&client->dev, "request irq %d for trigger0 failed\n",
- client->irq);
+ if (ret)
goto err_pm_disable;
- }
ret = devm_iio_trigger_register(indio_dev->dev.parent,
data->drdy_trigger0);
@@ -1071,7 +1068,10 @@ static int rpr0521_runtime_resume(struct device *dev)
struct rpr0521_data *data = iio_priv(indio_dev);
int ret;
- regcache_sync(data->regmap);
+ ret = regcache_sync(data->regmap);
+ if (ret < 0)
+ return ret;
+
if (data->als_ps_need_en) {
ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE);
if (ret < 0)
diff --git a/drivers/iio/light/si1145.c b/drivers/iio/light/si1145.c
index 4601ae5d2009..bb7c99041819 100644
--- a/drivers/iio/light/si1145.c
+++ b/drivers/iio/light/si1145.c
@@ -1251,10 +1251,8 @@ static int si1145_probe_trigger(struct iio_dev *indio_dev)
IRQF_TRIGGER_FALLING | IRQF_NO_THREAD,
"si1145_irq",
trig);
- if (ret < 0) {
- dev_err(&client->dev, "irq request failed\n");
+ if (ret)
return ret;
- }
ret = devm_iio_trigger_register(&client->dev, trig);
if (ret)
diff --git a/drivers/iio/light/st_uvis25_core.c b/drivers/iio/light/st_uvis25_core.c
index bcd729a9924e..94d5261b2663 100644
--- a/drivers/iio/light/st_uvis25_core.c
+++ b/drivers/iio/light/st_uvis25_core.c
@@ -196,11 +196,8 @@ static int st_uvis25_allocate_trigger(struct iio_dev *iio_dev)
st_uvis25_trigger_handler_thread,
irq_type | IRQF_ONESHOT,
iio_dev->name, hw);
- if (err) {
- dev_err(dev, "failed to request trigger irq %d\n",
- hw->irq);
+ if (err)
return err;
- }
hw->trig = devm_iio_trigger_alloc(dev, "%s-trigger",
iio_dev->name);
diff --git a/drivers/iio/light/st_uvis25_spi.c b/drivers/iio/light/st_uvis25_spi.c
index c4c15093e9e5..0f78a0abfafb 100644
--- a/drivers/iio/light/st_uvis25_spi.c
+++ b/drivers/iio/light/st_uvis25_spi.c
@@ -46,7 +46,7 @@ static const struct of_device_id st_uvis25_spi_of_match[] = {
MODULE_DEVICE_TABLE(of, st_uvis25_spi_of_match);
static const struct spi_device_id st_uvis25_spi_id_table[] = {
- { ST_UVIS25_DEV_NAME },
+ { .name = ST_UVIS25_DEV_NAME },
{ }
};
MODULE_DEVICE_TABLE(spi, st_uvis25_spi_id_table);
diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c
index e7ce6f32592b..7c8a1d2b2ed0 100644
--- a/drivers/iio/light/stk3310.c
+++ b/drivers/iio/light/stk3310.c
@@ -673,11 +673,8 @@ static int stk3310_probe(struct i2c_client *client)
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
"stk3310_event", indio_dev);
- if (ret < 0) {
- dev_err(&client->dev, "request irq %d failed\n",
- client->irq);
+ if (ret)
goto err_standby;
- }
}
ret = iio_device_register(indio_dev);
diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c
index b61442c5c1be..b392943e51c8 100644
--- a/drivers/iio/light/tcs3472.c
+++ b/drivers/iio/light/tcs3472.c
@@ -9,8 +9,6 @@
* TCS34727)
*
* Datasheet: http://ams.com/eng/content/download/319364/1117183/file/TCS3472_Datasheet_EN_v2.pdf
- *
- * TODO: wait time
*/
#include <linux/cleanup.h>
@@ -19,6 +17,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pm.h>
+#include <linux/units.h>
#include <linux/iio/buffer.h>
#include <linux/iio/events.h>
@@ -53,19 +52,30 @@
#define TCS3472_STATUS_AINT BIT(4)
#define TCS3472_STATUS_AVALID BIT(0)
#define TCS3472_ENABLE_AIEN BIT(4)
+#define TCS3472_ENABLE_WEN BIT(3)
#define TCS3472_ENABLE_AEN BIT(1)
#define TCS3472_ENABLE_PON BIT(0)
+#define TCS3472_ENABLE_RUN \
+ (TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON | TCS3472_ENABLE_WEN)
#define TCS3472_CONTROL_AGAIN_MASK (BIT(0) | BIT(1))
+#define TCS3472_CONFIG_WLONG BIT(1)
+
+#define TCS3472_ATIME_TO_US(atime) (((256) - (atime)) * 2400)
struct tcs3472_data {
struct i2c_client *client;
struct mutex lock;
+ int target_freq_hz;
+ int target_freq_uhz;
u16 low_thresh;
u16 high_thresh;
u8 enable;
+ u8 enable_pre_suspend;
u8 control;
u8 atime;
u8 apers;
+ u8 wtime;
+ bool wlong;
};
static const struct iio_event_spec tcs3472_events[] = {
@@ -91,6 +101,7 @@ static const struct iio_event_spec tcs3472_events[] = {
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBSCALE) | \
BIT(IIO_CHAN_INFO_INT_TIME), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.channel2 = IIO_MOD_LIGHT_##_color, \
.address = _addr, \
.scan_index = _si, \
@@ -114,9 +125,65 @@ static const struct iio_chan_spec tcs3472_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(4),
};
+/*
+ * The chip's cycle time is the sum of three components:
+ * - ATIME: the programmable RGBC integration time.
+ * - The fixed RGBC initialization time (2400 us).
+ * - WTIME: the wait time, used only if WEN is set. If WLONG is active,
+ * the wait step is multiplied by 12 (2400 us -> 28800 us).
+ */
+static unsigned int tcs3472_cycle_time_us(struct tcs3472_data *data)
+{
+ unsigned int atime_us = TCS3472_ATIME_TO_US(data->atime);
+ unsigned int init_us = 2400;
+ unsigned int wtime_us;
+
+ if (!(data->enable & TCS3472_ENABLE_WEN))
+ wtime_us = 0;
+ else if (data->wlong)
+ wtime_us = (256 - data->wtime) * 28800;
+ else
+ wtime_us = (256 - data->wtime) * 2400;
+
+ return atime_us + init_us + wtime_us;
+}
+
+/*
+ * Convert a cycle time in microseconds to a frequency in Hz and microhertz.
+ *
+ * Given cycle_us = T (the cycle period in microseconds), the corresponding
+ * frequency is:
+ * f = 1e6 / T [Hz]
+ *
+ * The result is split into the IIO_VAL_INT_PLUS_MICRO format:
+ * val = floor(1e6 / T) [Hz]
+ * val2 = (1e6 mod T) * 1e6 / T [microhertz]
+ */
+static void tcs3472_cycle_to_freq(unsigned int cycle_us, int *val, int *val2)
+{
+ *val = USEC_PER_SEC / cycle_us;
+ *val2 = div_u64((u64)(USEC_PER_SEC % cycle_us) * USEC_PER_SEC,
+ cycle_us);
+}
+
static int tcs3472_req_data(struct tcs3472_data *data)
{
- int tries = 50;
+ /*
+ * The worst-case cycle time is reached with ATIME=0x00, WTIME=0x00
+ * and WLONG=1. So:
+ * 614 ms (Max Integration Time)
+ * + 2.4 ms (RGBC Init)
+ * + 7.37 s (Max Wait Time)
+ * = ~ 8 s (Total Max cycle time).
+ * Use that as a polling upper bound; in normal operation the loop
+ * exits as soon as AVALID is set. So the total number of tries in 8
+ * seconds considering a polling period of 20 ms is 400.
+ * Considering a 20% margin due to oscillator tolerance, the total
+ * duration becomes approximately 9.8 seconds, which corresponds to
+ * about 480 steps. Therefore, setting it to 500 appears to be a
+ * reasonable and safe trade-off.
+ */
+ int tries = 500;
int ret;
while (tries--) {
@@ -164,18 +231,165 @@ static int tcs3472_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_INT_TIME:
*val = 0;
- *val2 = (256 - data->atime) * 2400;
+ *val2 = TCS3472_ATIME_TO_US(data->atime);
return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_SAMP_FREQ: {
+ unsigned int cycle_us;
+
+ guard(mutex)(&data->lock);
+ cycle_us = tcs3472_cycle_time_us(data);
+ tcs3472_cycle_to_freq(cycle_us, val, val2);
+ return IIO_VAL_INT_PLUS_MICRO;
+ }
default:
return -EINVAL;
}
}
+/*
+ * __tcs3472_set_sampling_freq() - implementation of sampling frequency
+ * configuration. The caller must hold data->lock.
+ */
+static int __tcs3472_set_sampling_freq(struct tcs3472_data *data,
+ int val, int val2)
+{
+ unsigned int atime_us;
+ unsigned int init_us = 2400;
+ u64 cycle_us;
+ s64 wait_us;
+ int wtime;
+ bool wlong = false;
+ u8 config;
+ int ret;
+
+ if (val < 0 || val2 < 0 || (val == 0 && val2 == 0))
+ return -EINVAL;
+
+ atime_us = TCS3472_ATIME_TO_US(data->atime);
+
+ /*
+ * cycle_us = 1 / freq, expressed in microseconds.
+ * Numerator: 1 [s] = PSEC_PER_SEC [ps]
+ * Denominator: freq [Hz] * MICROHZ_PER_HZ + val2 [uHz] = freq in [uHz]
+ * Result: ps / uHz = us
+ */
+ cycle_us = div64_u64(PSEC_PER_SEC, (u64)val * MICROHZ_PER_HZ + val2);
+
+ /*
+ * wait_us can be negative when the requested frequency is too high
+ * to be reached, or very large when the requested frequency is
+ * close to zero. Use s64 to cover the full range:
+ *
+ * cycle_us = PSEC_PER_SEC / (val * MICROHZ_PER_HZ + val2)
+ *
+ * The divisor of the formula above reaches its maximum when
+ * val = val2 = INT_MAX:
+ * INT_MAX * MICROHZ_PER_HZ + INT_MAX = ~2.15e18
+ * so cycle_us_min = floor(1e12 / 2.15e18) = 0.
+ *
+ * The divisor reaches its minimum (1) when val = 0 and val2 = 1,
+ * so cycle_us_max = 1e12 / 1 = 1e12.
+ *
+ * Therefore:
+ * wait_us_min = 0 - 2400 - 612000 = -616800
+ * wait_us_max = 1e12 - 2400 - 2400 = 999999995200
+ *
+ * Both fit comfortably in s64.
+ */
+ wait_us = (s64)cycle_us - init_us - atime_us;
+ if (wait_us < 2400) {
+ if (data->enable & TCS3472_ENABLE_WEN) {
+ u8 enable = data->enable & ~TCS3472_ENABLE_WEN;
+
+ ret = i2c_smbus_write_byte_data(data->client,
+ TCS3472_ENABLE, enable);
+ if (ret)
+ return ret;
+
+ data->enable = enable;
+ }
+
+ data->target_freq_hz = val;
+ data->target_freq_uhz = val2;
+ return 0;
+ }
+
+ /*
+ * Wait state is needed: make sure WEN is active before programming
+ * WTIME (and possibly WLONG).
+ */
+ if (!(data->enable & TCS3472_ENABLE_WEN)) {
+ u8 enable = data->enable | TCS3472_ENABLE_WEN;
+
+ ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE,
+ enable);
+ if (ret)
+ return ret;
+
+ data->enable = enable;
+ }
+
+ wtime = 256 - DIV_ROUND_CLOSEST_ULL(wait_us, 2400);
+ if (wtime < 0) {
+ /*
+ * If wait_us is too high (so the requested frequency is too
+ * low), the resulting wait exceeds what WTIME can represent
+ * (max 614 ms without WLONG). Enable WLONG, whose step is 12x
+ * longer (28.8 ms instead of 2.4 ms), and recompute.
+ */
+ wlong = true;
+ wtime = 256 - DIV_ROUND_CLOSEST_ULL(wait_us, 28800);
+ }
+
+ if (wlong != data->wlong) {
+ ret = i2c_smbus_read_byte_data(data->client, TCS3472_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ config = ret;
+ if (wlong)
+ config |= TCS3472_CONFIG_WLONG;
+ else
+ config &= ~TCS3472_CONFIG_WLONG;
+
+ ret = i2c_smbus_write_byte_data(data->client, TCS3472_CONFIG,
+ config);
+ if (ret)
+ return ret;
+
+ data->wlong = wlong;
+ }
+
+ /*
+ * If the requested wait is so long that even WLONG cannot
+ * cover it, wtime may still be negative. Saturate to 0,
+ * which is the largest possible wait (256 * 28.8 ms = 7.37 s).
+ */
+ wtime = clamp(wtime, 0, 255);
+ ret = i2c_smbus_write_byte_data(data->client, TCS3472_WTIME, wtime);
+ if (ret)
+ return ret;
+
+ data->wtime = wtime;
+ data->target_freq_hz = val;
+ data->target_freq_uhz = val2;
+
+ return 0;
+}
+
+static int tcs3472_set_sampling_freq(struct tcs3472_data *data,
+ int val, int val2)
+{
+ guard(mutex)(&data->lock);
+ return __tcs3472_set_sampling_freq(data, val, val2);
+}
+
static int tcs3472_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct tcs3472_data *data = iio_priv(indio_dev);
+ int ret;
int i;
switch (mask) {
@@ -196,15 +410,31 @@ static int tcs3472_write_raw(struct iio_dev *indio_dev,
if (val != 0)
return -EINVAL;
for (i = 0; i < 256; i++) {
- if (val2 == (256 - i) * 2400) {
- data->atime = i;
- return i2c_smbus_write_byte_data(
- data->client, TCS3472_ATIME,
- data->atime);
- }
-
+ if (val2 != (256 - i) * 2400)
+ continue;
+
+ guard(mutex)(&data->lock);
+
+ ret = i2c_smbus_write_byte_data(data->client,
+ TCS3472_ATIME, i);
+ if (ret)
+ return ret;
+
+ data->atime = i;
+
+ /*
+ * ATIME just changed, so the cycle time changed too.
+ * Re-run the sampling frequency logic to recompute
+ * WTIME and preserve the user's last requested
+ * frequency. Lock is already held.
+ */
+ return __tcs3472_set_sampling_freq(data,
+ data->target_freq_hz,
+ data->target_freq_uhz);
}
return -EINVAL;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return tcs3472_set_sampling_freq(data, val, val2);
default:
return -EINVAL;
}
@@ -234,7 +464,7 @@ static int tcs3472_read_event(struct iio_dev *indio_dev,
data->high_thresh : data->low_thresh;
return IIO_VAL_INT;
case IIO_EV_INFO_PERIOD:
- period = (256 - data->atime) * 2400 *
+ period = tcs3472_cycle_time_us(data) *
tcs3472_intr_pers[data->apers];
*val = period / USEC_PER_SEC;
*val2 = period % USEC_PER_SEC;
@@ -279,11 +509,13 @@ static int tcs3472_write_event(struct iio_dev *indio_dev,
data->low_thresh = val;
return 0;
- case IIO_EV_INFO_PERIOD:
+ case IIO_EV_INFO_PERIOD:{
+ unsigned int cycle_us;
+
period = val * USEC_PER_SEC + val2;
+ cycle_us = tcs3472_cycle_time_us(data);
for (i = 1; i < ARRAY_SIZE(tcs3472_intr_pers) - 1; i++) {
- if (period <= (256 - data->atime) * 2400 *
- tcs3472_intr_pers[i])
+ if (period <= cycle_us * tcs3472_intr_pers[i])
break;
}
ret = i2c_smbus_write_byte_data(data->client, TCS3472_PERS, i);
@@ -293,6 +525,7 @@ static int tcs3472_write_event(struct iio_dev *indio_dev,
data->apers = i;
return 0;
+ }
default:
return -EINVAL;
}
@@ -434,17 +667,16 @@ static const struct iio_info tcs3472_info = {
static int tcs3472_powerdown(struct tcs3472_data *data)
{
int ret;
- u8 enable_mask = TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON;
guard(mutex)(&data->lock);
+ data->enable_pre_suspend = data->enable;
+
ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE,
- data->enable & ~enable_mask);
+ data->enable & ~TCS3472_ENABLE_RUN);
if (ret)
return ret;
- data->enable &= ~enable_mask;
-
return 0;
}
@@ -458,7 +690,9 @@ static int tcs3472_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct tcs3472_data *data;
struct iio_dev *indio_dev;
+ unsigned int cycle_us;
int ret;
+ u8 enable;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
@@ -498,6 +732,16 @@ static int tcs3472_probe(struct i2c_client *client)
return ret;
data->atime = ret;
+ ret = i2c_smbus_read_byte_data(data->client, TCS3472_WTIME);
+ if (ret < 0)
+ return ret;
+ data->wtime = ret;
+
+ ret = i2c_smbus_read_byte_data(data->client, TCS3472_CONFIG);
+ if (ret < 0)
+ return ret;
+ data->wlong = (ret & TCS3472_CONFIG_WLONG) ? 1 : 0;
+
ret = i2c_smbus_read_word_data(data->client, TCS3472_AILT);
if (ret < 0)
return ret;
@@ -518,14 +762,30 @@ static int tcs3472_probe(struct i2c_client *client)
if (ret < 0)
return ret;
- /* enable device */
- data->enable = ret | TCS3472_ENABLE_PON | TCS3472_ENABLE_AEN;
- data->enable &= ~TCS3472_ENABLE_AIEN;
- ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE,
- data->enable);
+ /*
+ * Enable the chip in its full running state, including WEN. The
+ * actual wait time is controlled by the WTIME and WLONG registers,
+ * which retain their power-on defaults until userspace writes to
+ * sampling_frequency.
+ */
+ enable = (ret | TCS3472_ENABLE_RUN) & ~TCS3472_ENABLE_AIEN;
+
+ ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, enable);
if (ret < 0)
return ret;
+ data->enable = enable;
+
+ /*
+ * Initialize target frequency from the chip's current state so that
+ * subsequent integration_time changes via IIO_CHAN_INFO_INT_TIME can
+ * preserve a meaningful sampling rate, even before userspace writes
+ * sampling_frequency for the first time.
+ */
+ cycle_us = tcs3472_cycle_time_us(data);
+ tcs3472_cycle_to_freq(cycle_us, &data->target_freq_hz,
+ &data->target_freq_uhz);
+
ret = devm_add_action_or_reset(dev, tcs3472_powerdown_action, data);
if (ret)
return ret;
@@ -561,16 +821,21 @@ static int tcs3472_resume(struct device *dev)
struct tcs3472_data *data = iio_priv(i2c_get_clientdata(
to_i2c_client(dev)));
int ret;
- u8 enable_mask = TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON;
guard(mutex)(&data->lock);
+ /*
+ * Restore the full ENABLE register from the snapshot taken in
+ * tcs3472_powerdown(). This preserves the user's last
+ * sampling_frequency configuration (in particular the WEN bit)
+ * across suspend/resume.
+ */
ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE,
- data->enable | enable_mask);
+ data->enable_pre_suspend);
if (ret)
return ret;
- data->enable |= enable_mask;
+ data->enable = data->enable_pre_suspend;
return 0;
}
diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c
index 45f3513d931e..7bef0c3118c2 100644
--- a/drivers/iio/light/tsl2563.c
+++ b/drivers/iio/light/tsl2563.c
@@ -754,7 +754,7 @@ static int tsl2563_probe(struct i2c_client *client)
"tsl2563_event",
indio_dev);
if (err)
- return dev_err_probe(dev, err, "irq request error\n");
+ return err;
}
err = tsl2563_configure(chip);
diff --git a/drivers/iio/light/tsl2583.c b/drivers/iio/light/tsl2583.c
index a0dd122af2cf..53fd423aa7ae 100644
--- a/drivers/iio/light/tsl2583.c
+++ b/drivers/iio/light/tsl2583.c
@@ -456,12 +456,8 @@ static int tsl2583_chip_init_and_power_on(struct iio_dev *indio_dev)
usleep_range(3000, 3500);
- ret = tsl2583_set_power_state(chip, TSL2583_CNTL_PWR_ON |
- TSL2583_CNTL_ADC_ENBL);
- if (ret < 0)
- return ret;
-
- return ret;
+ return tsl2583_set_power_state(chip,
+ TSL2583_CNTL_PWR_ON | TSL2583_CNTL_ADC_ENBL);
}
/* Sysfs Interface Functions */
@@ -475,7 +471,7 @@ static ssize_t in_illuminance_input_target_show(struct device *dev,
int ret;
mutex_lock(&chip->als_mutex);
- ret = sprintf(buf, "%d\n", chip->als_settings.als_cal_target);
+ ret = sysfs_emit(buf, "%d\n", chip->als_settings.als_cal_target);
mutex_unlock(&chip->als_mutex);
return ret;
@@ -533,10 +529,10 @@ static ssize_t in_illuminance_lux_table_show(struct device *dev,
int offset = 0;
for (i = 0; i < ARRAY_SIZE(chip->als_settings.als_device_lux); i++) {
- offset += sprintf(buf + offset, "%u,%u,%u,",
- chip->als_settings.als_device_lux[i].ratio,
- chip->als_settings.als_device_lux[i].ch0,
- chip->als_settings.als_device_lux[i].ch1);
+ offset += sysfs_emit_at(buf, offset, "%u,%u,%u,",
+ chip->als_settings.als_device_lux[i].ratio,
+ chip->als_settings.als_device_lux[i].ch0,
+ chip->als_settings.als_device_lux[i].ch1);
if (chip->als_settings.als_device_lux[i].ratio == 0) {
/*
* We just printed the first "0" entry.
@@ -547,7 +543,7 @@ static ssize_t in_illuminance_lux_table_show(struct device *dev,
}
}
- offset += sprintf(buf + offset, "\n");
+ offset += sysfs_emit_at(buf, offset, "\n");
return offset;
}
@@ -639,14 +635,6 @@ static const struct iio_chan_spec tsl2583_channels[] = {
},
};
-static int tsl2583_set_pm_runtime_busy(struct tsl2583_chip *chip, bool on)
-{
- if (on)
- return pm_runtime_resume_and_get(&chip->client->dev);
-
- return pm_runtime_put_autosuspend(&chip->client->dev);
-}
-
static int tsl2583_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
@@ -654,7 +642,7 @@ static int tsl2583_read_raw(struct iio_dev *indio_dev,
struct tsl2583_chip *chip = iio_priv(indio_dev);
int ret, pm_ret;
- ret = tsl2583_set_pm_runtime_busy(chip, true);
+ ret = pm_runtime_resume_and_get(&chip->client->dev);
if (ret < 0)
return ret;
@@ -722,16 +710,16 @@ read_done:
mutex_unlock(&chip->als_mutex);
if (ret < 0) {
- tsl2583_set_pm_runtime_busy(chip, false);
+ pm_runtime_put_autosuspend(&chip->client->dev);
return ret;
}
/*
* Preserve the ret variable if the call to
- * tsl2583_set_pm_runtime_busy() is successful so the reading
+ * pm_runtime_put_autosuspend() is successful so the reading
* (if applicable) is returned to user space.
*/
- pm_ret = tsl2583_set_pm_runtime_busy(chip, false);
+ pm_ret = pm_runtime_put_autosuspend(&chip->client->dev);
if (pm_ret < 0)
return pm_ret;
@@ -745,7 +733,7 @@ static int tsl2583_write_raw(struct iio_dev *indio_dev,
struct tsl2583_chip *chip = iio_priv(indio_dev);
int ret;
- ret = tsl2583_set_pm_runtime_busy(chip, true);
+ ret = pm_runtime_resume_and_get(&chip->client->dev);
if (ret < 0)
return ret;
@@ -786,15 +774,15 @@ static int tsl2583_write_raw(struct iio_dev *indio_dev,
mutex_unlock(&chip->als_mutex);
if (ret < 0) {
- tsl2583_set_pm_runtime_busy(chip, false);
+ pm_runtime_put_autosuspend(&chip->client->dev);
return ret;
}
- ret = tsl2583_set_pm_runtime_busy(chip, false);
+ ret = pm_runtime_put_autosuspend(&chip->client->dev);
if (ret < 0)
return ret;
- return ret;
+ return 0;
}
static const struct iio_info tsl2583_info = {
diff --git a/drivers/iio/light/tsl2772.c b/drivers/iio/light/tsl2772.c
index 244f44379c36..4486a1d9d84d 100644
--- a/drivers/iio/light/tsl2772.c
+++ b/drivers/iio/light/tsl2772.c
@@ -1274,7 +1274,7 @@ static int tsl2772_read_raw(struct iio_dev *indio_dev,
}
break;
case IIO_CHAN_INFO_CALIBSCALE:
- if (chan->type == IIO_LIGHT)
+ if (chan->type == IIO_INTENSITY)
*val = tsl2772_als_gain[chip->settings.als_gain];
else
*val = tsl2772_prox_gain[chip->settings.prox_gain];
@@ -1849,11 +1849,8 @@ static int tsl2772_probe(struct i2c_client *clientp)
IRQF_ONESHOT,
"TSL2772_event",
indio_dev);
- if (ret) {
- dev_err(&clientp->dev,
- "%s: irq request failed\n", __func__);
+ if (ret)
return ret;
- }
} else {
indio_dev->channels = chip->chip_info->channel_without_events;
}
diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c
index 128ae3f94074..336468d59ea7 100644
--- a/drivers/iio/light/vcnl4000.c
+++ b/drivers/iio/light/vcnl4000.c
@@ -537,16 +537,6 @@ static bool vcnl4010_is_in_periodic_mode(struct vcnl4000_data *data)
return !!(ret & VCNL4000_SELF_TIMED_EN);
}
-static int vcnl4000_set_pm_runtime_state(struct vcnl4000_data *data, bool on)
-{
- struct device *dev = &data->client->dev;
-
- if (on)
- return pm_runtime_resume_and_get(dev);
-
- return pm_runtime_put_autosuspend(dev);
-}
-
static int vcnl4040_read_als_it(struct vcnl4000_data *data, int *val, int *val2)
{
int ret;
@@ -850,7 +840,7 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = vcnl4000_set_pm_runtime_state(data, true);
+ ret = pm_runtime_resume_and_get(&data->client->dev);
if (ret < 0)
return ret;
@@ -869,7 +859,7 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev,
default:
ret = -EINVAL;
}
- vcnl4000_set_pm_runtime_state(data, false);
+ pm_runtime_put_autosuspend(&data->client->dev);
return ret;
case IIO_CHAN_INFO_SCALE:
if (chan->type != IIO_LIGHT)
@@ -1922,7 +1912,7 @@ static void vcnl4000_cleanup(void *data)
static int vcnl4000_probe(struct i2c_client *client)
{
- const char * const regulator_names[] = { "vdd", "vio", "vled" };
+ static const char * const regulator_names[] = { "vdd", "vio", "vled" };
struct device *dev = &client->dev;
struct vcnl4000_data *data;
struct iio_dev *indio_dev;
diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c
index bf3a49b4351d..ce1bd42b0c7c 100644
--- a/drivers/iio/light/vcnl4035.c
+++ b/drivers/iio/light/vcnl4035.c
@@ -145,16 +145,6 @@ static const struct iio_trigger_ops vcnl4035_trigger_ops = {
.set_trigger_state = vcnl4035_als_drdy_set_state,
};
-static int vcnl4035_set_pm_runtime_state(struct vcnl4035_data *data, bool on)
-{
- struct device *dev = &data->client->dev;
-
- if (on)
- return pm_runtime_resume_and_get(dev);
-
- return pm_runtime_put_autosuspend(dev);
-}
-
static int vcnl4035_read_info_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val)
{
@@ -202,11 +192,11 @@ static int vcnl4035_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = vcnl4035_set_pm_runtime_state(data, true);
+ ret = pm_runtime_resume_and_get(&data->client->dev);
if (ret < 0)
return ret;
ret = vcnl4035_read_info_raw(indio_dev, chan, val);
- vcnl4035_set_pm_runtime_state(data, false);
+ pm_runtime_put_autosuspend(&data->client->dev);
return ret;
case IIO_CHAN_INFO_INT_TIME:
*val = 50;
@@ -237,7 +227,7 @@ static int vcnl4035_write_raw(struct iio_dev *indio_dev,
if (val <= 0 || val > 800)
return -EINVAL;
- ret = vcnl4035_set_pm_runtime_state(data, true);
+ ret = pm_runtime_resume_and_get(&data->client->dev);
if (ret < 0)
return ret;
@@ -247,7 +237,7 @@ static int vcnl4035_write_raw(struct iio_dev *indio_dev,
if (!ret)
data->als_it_val = val / 100;
- vcnl4035_set_pm_runtime_state(data, false);
+ pm_runtime_put_autosuspend(&data->client->dev);
return ret;
default:
return -EINVAL;
@@ -647,7 +637,10 @@ static int vcnl4035_runtime_resume(struct device *dev)
struct vcnl4035_data *data = iio_priv(indio_dev);
int ret;
- regcache_sync(data->regmap);
+ ret = regcache_sync(data->regmap);
+ if (ret < 0)
+ return ret;
+
ret = vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_ENABLE);
if (ret < 0)
return ret;
diff --git a/drivers/iio/light/veml6030.c b/drivers/iio/light/veml6030.c
index 7c837d60dad8..ec9c127e7d8a 100644
--- a/drivers/iio/light/veml6030.c
+++ b/drivers/iio/light/veml6030.c
@@ -921,9 +921,7 @@ static int veml6030_set_info(struct iio_dev *indio_dev)
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
indio_dev->name, indio_dev);
if (ret < 0)
- return dev_err_probe(&client->dev, ret,
- "irq %d request failed\n",
- client->irq);
+ return ret;
indio_dev->info = &veml6030_info;
} else {
diff --git a/drivers/iio/light/vl6180.c b/drivers/iio/light/vl6180.c
index 4f270f405b21..aef8a5333442 100644
--- a/drivers/iio/light/vl6180.c
+++ b/drivers/iio/light/vl6180.c
@@ -721,7 +721,7 @@ static int vl6180_probe(struct i2c_client *client)
IRQF_ONESHOT,
indio_dev->name, indio_dev);
if (ret)
- return dev_err_probe(&client->dev, ret, "devm_request_irq error\n");
+ return ret;
init_completion(&data->completion);