Lines Matching +full:startup +full:- +full:time +full:- +full:ms
1 // SPDX-License-Identifier: GPL-2.0-only
3 * mlx90614.c - Support for Melexis MLX90614 contactless IR temperature sensor
9 * Driver for the Melexis MLX90614 I2C 16-bit IR thermopile sensor
11 * (7-bit I2C slave address 0x5a, 100KHz bus speed only!)
14 * for at least 33ms. This is achieved with an extra GPIO that can be connected
18 * always has a pull-up so we do not need an extra GPIO to drive it high. If
37 /* RAM offsets with 16-bit data, MSB first */
44 /* EEPROM offsets with 16-bit data, MSB first */
58 /* Timings (in ms) */
59 #define MLX90614_TIMING_EEPROM 20 /* time for EEPROM write/erase to complete */
60 #define MLX90614_TIMING_WAKEUP 34 /* time to hold SDA low for wake-up */
61 #define MLX90614_TIMING_STARTUP 250 /* time before first data after wake-up */
66 #define MLX90614_CONST_OFFSET_DEC -13657 /* decimal part of the Kelvin offset */
76 struct gpio_desc *wakeup_gpio; /* NULL to disable sleep/wake-up */
109 dev_dbg(&client->dev, "Writing 0x%x to address 0x%x", value, command); in mlx90614_write_word()
112 ret = i2c_smbus_xfer(client->adapter, client->addr, in mlx90614_write_word()
113 client->flags | I2C_CLIENT_PEC, in mlx90614_write_word()
122 ret = i2c_smbus_xfer(client->adapter, client->addr, in mlx90614_write_word()
123 client->flags | I2C_CLIENT_PEC, in mlx90614_write_word()
148 return -EINVAL; in mlx90614_iir_search()
171 * If @startup is true, make sure MLX90614_TIMING_STARTUP ms have elapsed since
172 * the last wake-up. This is normally only needed to get a valid temperature
176 static int mlx90614_power_get(struct mlx90614_data *data, bool startup) in mlx90614_power_get() argument
180 if (!data->wakeup_gpio) in mlx90614_power_get()
183 pm_runtime_get_sync(&data->client->dev); in mlx90614_power_get()
185 if (startup) { in mlx90614_power_get()
187 if (time_before(now, data->ready_timestamp) && in mlx90614_power_get()
189 data->ready_timestamp - now)) != 0) { in mlx90614_power_get()
190 pm_runtime_put_autosuspend(&data->client->dev); in mlx90614_power_get()
191 return -EINTR; in mlx90614_power_get()
200 if (!data->wakeup_gpio) in mlx90614_power_put()
203 pm_runtime_mark_last_busy(&data->client->dev); in mlx90614_power_put()
204 pm_runtime_put_autosuspend(&data->client->dev); in mlx90614_power_put()
207 static inline int mlx90614_power_get(struct mlx90614_data *data, bool startup) in mlx90614_power_get() argument
227 switch (channel->channel2) { in mlx90614_read_raw()
232 switch (channel->channel) { in mlx90614_read_raw()
240 return -EINVAL; in mlx90614_read_raw()
244 return -EINVAL; in mlx90614_read_raw()
250 ret = i2c_smbus_read_word_data(data->client, cmd); in mlx90614_read_raw()
258 return -EIO; in mlx90614_read_raw()
271 mutex_lock(&data->lock); in mlx90614_read_raw()
272 ret = i2c_smbus_read_word_data(data->client, in mlx90614_read_raw()
274 mutex_unlock(&data->lock); in mlx90614_read_raw()
291 mutex_lock(&data->lock); in mlx90614_read_raw()
292 ret = i2c_smbus_read_word_data(data->client, MLX90614_CONFIG); in mlx90614_read_raw()
293 mutex_unlock(&data->lock); in mlx90614_read_raw()
304 return -EINVAL; in mlx90614_read_raw()
318 return -EINVAL; in mlx90614_write_raw()
323 mutex_lock(&data->lock); in mlx90614_write_raw()
324 ret = mlx90614_write_word(data->client, MLX90614_EMISSIVITY, in mlx90614_write_raw()
326 mutex_unlock(&data->lock); in mlx90614_write_raw()
332 return -EINVAL; in mlx90614_write_raw()
335 mutex_lock(&data->lock); in mlx90614_write_raw()
336 ret = mlx90614_iir_search(data->client, in mlx90614_write_raw()
338 mutex_unlock(&data->lock); in mlx90614_write_raw()
343 return -EINVAL; in mlx90614_write_raw()
357 return -EINVAL; in mlx90614_write_raw_get_fmt()
406 if (!data->wakeup_gpio) { in mlx90614_sleep()
407 dev_dbg(&data->client->dev, "Sleep disabled"); in mlx90614_sleep()
408 return -ENOSYS; in mlx90614_sleep()
411 dev_dbg(&data->client->dev, "Requesting sleep"); in mlx90614_sleep()
413 mutex_lock(&data->lock); in mlx90614_sleep()
414 ret = i2c_smbus_xfer(data->client->adapter, data->client->addr, in mlx90614_sleep()
415 data->client->flags | I2C_CLIENT_PEC, in mlx90614_sleep()
418 mutex_unlock(&data->lock); in mlx90614_sleep()
425 if (!data->wakeup_gpio) { in mlx90614_wakeup()
426 dev_dbg(&data->client->dev, "Wake-up disabled"); in mlx90614_wakeup()
427 return -ENOSYS; in mlx90614_wakeup()
430 dev_dbg(&data->client->dev, "Requesting wake-up"); in mlx90614_wakeup()
432 i2c_lock_bus(data->client->adapter, I2C_LOCK_ROOT_ADAPTER); in mlx90614_wakeup()
433 gpiod_direction_output(data->wakeup_gpio, 0); in mlx90614_wakeup()
435 gpiod_direction_input(data->wakeup_gpio); in mlx90614_wakeup()
436 i2c_unlock_bus(data->client->adapter, I2C_LOCK_ROOT_ADAPTER); in mlx90614_wakeup()
438 data->ready_timestamp = jiffies + in mlx90614_wakeup()
443 * wake-up signal has been sent. As a workaround, do a dummy read. in mlx90614_wakeup()
447 i2c_smbus_read_word_data(data->client, MLX90614_CONFIG); in mlx90614_wakeup()
452 /* Return wake-up GPIO or NULL if sleep functionality should be disabled. */
457 if (!i2c_check_functionality(client->adapter, in mlx90614_probe_wakeup()
459 dev_info(&client->dev, in mlx90614_probe_wakeup()
464 gpio = devm_gpiod_get_optional(&client->dev, "wakeup", GPIOD_IN); in mlx90614_probe_wakeup()
467 dev_warn(&client->dev, in mlx90614_probe_wakeup()
472 dev_info(&client->dev, in mlx90614_probe_wakeup()
473 "wakeup-gpio not found, sleep disabled"); in mlx90614_probe_wakeup()
481 return -ENOSYS; in mlx90614_sleep()
485 return -ENOSYS; in mlx90614_wakeup()
513 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) in mlx90614_probe()
514 return -EOPNOTSUPP; in mlx90614_probe()
516 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); in mlx90614_probe()
518 return -ENOMEM; in mlx90614_probe()
522 data->client = client; in mlx90614_probe()
523 mutex_init(&data->lock); in mlx90614_probe()
524 data->wakeup_gpio = mlx90614_probe_wakeup(client); in mlx90614_probe()
528 indio_dev->name = id->name; in mlx90614_probe()
529 indio_dev->modes = INDIO_DIRECT_MODE; in mlx90614_probe()
530 indio_dev->info = &mlx90614_info; in mlx90614_probe()
535 dev_dbg(&client->dev, "Found single sensor"); in mlx90614_probe()
536 indio_dev->channels = mlx90614_channels; in mlx90614_probe()
537 indio_dev->num_channels = 2; in mlx90614_probe()
540 dev_dbg(&client->dev, "Found dual sensor"); in mlx90614_probe()
541 indio_dev->channels = mlx90614_channels; in mlx90614_probe()
542 indio_dev->num_channels = 3; in mlx90614_probe()
548 if (data->wakeup_gpio) { in mlx90614_probe()
549 pm_runtime_set_autosuspend_delay(&client->dev, in mlx90614_probe()
551 pm_runtime_use_autosuspend(&client->dev); in mlx90614_probe()
552 pm_runtime_set_active(&client->dev); in mlx90614_probe()
553 pm_runtime_enable(&client->dev); in mlx90614_probe()
566 if (data->wakeup_gpio) { in mlx90614_remove()
567 pm_runtime_disable(&client->dev); in mlx90614_remove()
568 if (!pm_runtime_status_suspended(&client->dev)) in mlx90614_remove()
570 pm_runtime_set_suspended(&client->dev); in mlx90614_remove()
594 if (data->wakeup_gpio && pm_runtime_active(dev)) in mlx90614_pm_suspend()
606 if (data->wakeup_gpio) { in mlx90614_pm_resume()
657 MODULE_AUTHOR("Vianney le Clément de Saint-Marcq <vianney.leclement@essensium.com>");