Lines Matching +full:startup +full:- +full:sensor
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!)
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 */
51 #define MLX90614_CONFIG_DUAL_SHIFT 6 /* single (0) or dual (1) IR sensor */
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()
134 * which is equivalent to the bit value in sensor register
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
181 if (!data->wakeup_gpio) in mlx90614_power_get()
184 ret = pm_runtime_resume_and_get(&data->client->dev); in mlx90614_power_get()
188 if (startup) { in mlx90614_power_get()
190 if (time_before(now, data->ready_timestamp) && in mlx90614_power_get()
192 data->ready_timestamp - now)) != 0) { in mlx90614_power_get()
193 pm_runtime_put_autosuspend(&data->client->dev); in mlx90614_power_get()
194 return -EINTR; in mlx90614_power_get()
203 if (!data->wakeup_gpio) in mlx90614_power_put()
206 pm_runtime_mark_last_busy(&data->client->dev); in mlx90614_power_put()
207 pm_runtime_put_autosuspend(&data->client->dev); in mlx90614_power_put()
210 static inline int mlx90614_power_get(struct mlx90614_data *data, bool startup) in mlx90614_power_get() argument
230 switch (channel->channel2) { in mlx90614_read_raw()
235 switch (channel->channel) { in mlx90614_read_raw()
243 return -EINVAL; in mlx90614_read_raw()
247 return -EINVAL; in mlx90614_read_raw()
253 ret = i2c_smbus_read_word_data(data->client, cmd); in mlx90614_read_raw()
261 return -EIO; in mlx90614_read_raw()
277 mutex_lock(&data->lock); in mlx90614_read_raw()
278 ret = i2c_smbus_read_word_data(data->client, in mlx90614_read_raw()
280 mutex_unlock(&data->lock); in mlx90614_read_raw()
300 mutex_lock(&data->lock); in mlx90614_read_raw()
301 ret = i2c_smbus_read_word_data(data->client, MLX90614_CONFIG); in mlx90614_read_raw()
302 mutex_unlock(&data->lock); in mlx90614_read_raw()
313 return -EINVAL; in mlx90614_read_raw()
327 return -EINVAL; in mlx90614_write_raw()
335 mutex_lock(&data->lock); in mlx90614_write_raw()
336 ret = mlx90614_write_word(data->client, MLX90614_EMISSIVITY, in mlx90614_write_raw()
338 mutex_unlock(&data->lock); in mlx90614_write_raw()
344 return -EINVAL; in mlx90614_write_raw()
350 mutex_lock(&data->lock); in mlx90614_write_raw()
351 ret = mlx90614_iir_search(data->client, in mlx90614_write_raw()
353 mutex_unlock(&data->lock); in mlx90614_write_raw()
358 return -EINVAL; in mlx90614_write_raw()
372 return -EINVAL; in mlx90614_write_raw_get_fmt()
421 if (!data->wakeup_gpio) { in mlx90614_sleep()
422 dev_dbg(&data->client->dev, "Sleep disabled"); in mlx90614_sleep()
423 return -ENOSYS; in mlx90614_sleep()
426 dev_dbg(&data->client->dev, "Requesting sleep"); in mlx90614_sleep()
428 mutex_lock(&data->lock); in mlx90614_sleep()
429 ret = i2c_smbus_xfer(data->client->adapter, data->client->addr, in mlx90614_sleep()
430 data->client->flags | I2C_CLIENT_PEC, in mlx90614_sleep()
433 mutex_unlock(&data->lock); in mlx90614_sleep()
440 if (!data->wakeup_gpio) { in mlx90614_wakeup()
441 dev_dbg(&data->client->dev, "Wake-up disabled"); in mlx90614_wakeup()
442 return -ENOSYS; in mlx90614_wakeup()
445 dev_dbg(&data->client->dev, "Requesting wake-up"); in mlx90614_wakeup()
447 i2c_lock_bus(data->client->adapter, I2C_LOCK_ROOT_ADAPTER); in mlx90614_wakeup()
448 gpiod_direction_output(data->wakeup_gpio, 0); in mlx90614_wakeup()
450 gpiod_direction_input(data->wakeup_gpio); in mlx90614_wakeup()
451 i2c_unlock_bus(data->client->adapter, I2C_LOCK_ROOT_ADAPTER); in mlx90614_wakeup()
453 data->ready_timestamp = jiffies + in mlx90614_wakeup()
458 * wake-up signal has been sent. As a workaround, do a dummy read. in mlx90614_wakeup()
462 i2c_smbus_read_word_data(data->client, MLX90614_CONFIG); in mlx90614_wakeup()
467 /* Return wake-up GPIO or NULL if sleep functionality should be disabled. */
472 if (!i2c_check_functionality(client->adapter, in mlx90614_probe_wakeup()
474 dev_info(&client->dev, in mlx90614_probe_wakeup()
479 gpio = devm_gpiod_get_optional(&client->dev, "wakeup", GPIOD_IN); in mlx90614_probe_wakeup()
482 dev_warn(&client->dev, in mlx90614_probe_wakeup()
487 dev_info(&client->dev, in mlx90614_probe_wakeup()
488 "wakeup-gpio not found, sleep disabled"); in mlx90614_probe_wakeup()
496 return -ENOSYS; in mlx90614_sleep()
500 return -ENOSYS; in mlx90614_wakeup()
508 /* Return 0 for single sensor, 1 for dual sensor, <0 on error. */
528 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) in mlx90614_probe()
529 return -EOPNOTSUPP; in mlx90614_probe()
531 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); in mlx90614_probe()
533 return -ENOMEM; in mlx90614_probe()
537 data->client = client; in mlx90614_probe()
538 mutex_init(&data->lock); in mlx90614_probe()
539 data->wakeup_gpio = mlx90614_probe_wakeup(client); in mlx90614_probe()
543 indio_dev->name = id->name; in mlx90614_probe()
544 indio_dev->modes = INDIO_DIRECT_MODE; in mlx90614_probe()
545 indio_dev->info = &mlx90614_info; in mlx90614_probe()
550 dev_dbg(&client->dev, "Found single sensor"); in mlx90614_probe()
551 indio_dev->channels = mlx90614_channels; in mlx90614_probe()
552 indio_dev->num_channels = 2; in mlx90614_probe()
555 dev_dbg(&client->dev, "Found dual sensor"); in mlx90614_probe()
556 indio_dev->channels = mlx90614_channels; in mlx90614_probe()
557 indio_dev->num_channels = 3; in mlx90614_probe()
563 if (data->wakeup_gpio) { in mlx90614_probe()
564 pm_runtime_set_autosuspend_delay(&client->dev, in mlx90614_probe()
566 pm_runtime_use_autosuspend(&client->dev); in mlx90614_probe()
567 pm_runtime_set_active(&client->dev); in mlx90614_probe()
568 pm_runtime_enable(&client->dev); in mlx90614_probe()
581 if (data->wakeup_gpio) { in mlx90614_remove()
582 pm_runtime_disable(&client->dev); in mlx90614_remove()
583 if (!pm_runtime_status_suspended(&client->dev)) in mlx90614_remove()
585 pm_runtime_set_suspended(&client->dev); in mlx90614_remove()
609 if (data->wakeup_gpio && pm_runtime_active(dev)) in mlx90614_pm_suspend()
621 if (data->wakeup_gpio) { in mlx90614_pm_resume()
672 MODULE_AUTHOR("Vianney le Clément de Saint-Marcq <vianney.leclement@essensium.com>");
674 MODULE_DESCRIPTION("Melexis MLX90614 contactless IR temperature sensor driver");