diff options
Diffstat (limited to 'drivers/iio/health/max30100.c')
| -rw-r--r-- | drivers/iio/health/max30100.c | 95 |
1 files changed, 60 insertions, 35 deletions
diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c index 84010501762d..3d441013893c 100644 --- a/drivers/iio/health/max30100.c +++ b/drivers/iio/health/max30100.c @@ -5,7 +5,6 @@ * Copyright (C) 2015, 2018 * Author: Matt Ranostay <matt.ranostay@konsulko.com> * - * TODO: enable pulse length controls via device tree properties */ #include <linux/module.h> @@ -16,13 +15,13 @@ #include <linux/irq.h> #include <linux/i2c.h> #include <linux/mutex.h> -#include <linux/of.h> +#include <linux/property.h> #include <linux/regmap.h> +#include <linux/bitfield.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> #include <linux/iio/kfifo_buf.h> -#define MAX30100_REGMAP_NAME "max30100_regmap" #define MAX30100_DRV_NAME "max30100" #define MAX30100_REG_INT_STATUS 0x00 @@ -53,9 +52,13 @@ #define MAX30100_REG_MODE_CONFIG_PWR BIT(7) #define MAX30100_REG_SPO2_CONFIG 0x07 +#define MAX30100_REG_SPO2_CONFIG_PW_MASK GENMASK(1, 0) +#define MAX30100_REG_SPO2_CONFIG_200US 0x0 +#define MAX30100_REG_SPO2_CONFIG_400US 0x1 +#define MAX30100_REG_SPO2_CONFIG_800US 0x2 +#define MAX30100_REG_SPO2_CONFIG_1600US 0x3 #define MAX30100_REG_SPO2_CONFIG_100HZ BIT(2) #define MAX30100_REG_SPO2_CONFIG_HI_RES_EN BIT(6) -#define MAX30100_REG_SPO2_CONFIG_1600US 0x3 #define MAX30100_REG_LED_CONFIG 0x09 #define MAX30100_REG_LED_CONFIG_LED_MASK 0x0f @@ -94,7 +97,7 @@ static bool max30100_is_volatile_reg(struct device *dev, unsigned int reg) } static const struct regmap_config max30100_regmap_config = { - .name = MAX30100_REGMAP_NAME, + .name = "max30100_regmap", .reg_bits = 8, .val_bits = 8, @@ -267,11 +270,10 @@ static int max30100_get_current_idx(unsigned int val, int *reg) static int max30100_led_init(struct max30100_data *data) { struct device *dev = &data->client->dev; - struct device_node *np = dev->of_node; unsigned int val[2]; int reg, ret; - ret = of_property_read_u32_array(np, "maxim,led-current-microamp", + ret = device_property_read_u32_array(dev, "maxim,led-current-microamp", (unsigned int *) &val, 2); if (ret) { /* Default to 24 mA RED LED, 50 mA IR LED */ @@ -308,19 +310,47 @@ static int max30100_led_init(struct max30100_data *data) MAX30100_REG_LED_CONFIG_LED_MASK, reg); } +static int max30100_get_pulse_width(unsigned int pwidth_us) +{ + switch (pwidth_us) { + case 200: + return MAX30100_REG_SPO2_CONFIG_200US; + case 400: + return MAX30100_REG_SPO2_CONFIG_400US; + case 800: + return MAX30100_REG_SPO2_CONFIG_800US; + case 1600: + return MAX30100_REG_SPO2_CONFIG_1600US; + default: + return -EINVAL; + } +} + static int max30100_chip_init(struct max30100_data *data) { int ret; + int pulse_width; + /* set default LED pulse-width to 1600 us */ + unsigned int pulse_us = 1600; + struct device *dev = &data->client->dev; /* setup LED current settings */ ret = max30100_led_init(data); if (ret) return ret; + /* Read LED pulse-width-us from DT */ + device_property_read_u32(dev, "maxim,pulse-width-us", &pulse_us); + + pulse_width = max30100_get_pulse_width(pulse_us); + if (pulse_width < 0) + return dev_err_probe(dev, pulse_width, "invalid LED pulse-width %uus\n", pulse_us); + /* enable hi-res SPO2 readings at 100Hz */ ret = regmap_write(data->regmap, MAX30100_REG_SPO2_CONFIG, MAX30100_REG_SPO2_CONFIG_HI_RES_EN | - MAX30100_REG_SPO2_CONFIG_100HZ); + MAX30100_REG_SPO2_CONFIG_100HZ | + FIELD_PREP(MAX30100_REG_SPO2_CONFIG_PW_MASK, pulse_width)); if (ret) return ret; @@ -364,9 +394,8 @@ static int max30100_get_temp(struct max30100_data *data, int *val) int ret; /* start acquisition */ - ret = regmap_update_bits(data->regmap, MAX30100_REG_MODE_CONFIG, - MAX30100_REG_MODE_CONFIG_TEMP_EN, - MAX30100_REG_MODE_CONFIG_TEMP_EN); + ret = regmap_set_bits(data->regmap, MAX30100_REG_MODE_CONFIG, + MAX30100_REG_MODE_CONFIG_TEMP_EN); if (ret) return ret; @@ -388,18 +417,21 @@ static int max30100_read_raw(struct iio_dev *indio_dev, * Temperature reading can only be acquired while engine * is running */ - mutex_lock(&indio_dev->mlock); - - if (!iio_buffer_enabled(indio_dev)) + if (iio_device_claim_buffer_mode(indio_dev)) { + /* + * Replacing -EBUSY or other error code + * returned by iio_device_claim_buffer_mode() + * because user space may rely on the current + * one. + */ ret = -EAGAIN; - else { + } else { ret = max30100_get_temp(data, val); if (!ret) ret = IIO_VAL_INT; + iio_device_release_buffer_mode(indio_dev); } - - mutex_unlock(&indio_dev->mlock); break; case IIO_CHAN_INFO_SCALE: *val = 1; /* 0.0625 */ @@ -415,11 +447,9 @@ static const struct iio_info max30100_info = { .read_raw = max30100_read_raw, }; -static int max30100_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max30100_probe(struct i2c_client *client) { struct max30100_data *data; - struct iio_buffer *buffer; struct iio_dev *indio_dev; int ret; @@ -427,20 +457,17 @@ static int max30100_probe(struct i2c_client *client, if (!indio_dev) return -ENOMEM; - buffer = devm_iio_kfifo_allocate(&client->dev); - if (!buffer) - return -ENOMEM; - - iio_device_attach_buffer(indio_dev, buffer); - indio_dev->name = MAX30100_DRV_NAME; indio_dev->channels = max30100_channels; indio_dev->info = &max30100_info; indio_dev->num_channels = ARRAY_SIZE(max30100_channels); indio_dev->available_scan_masks = max30100_scan_masks; - indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE); - indio_dev->setup_ops = &max30100_buffer_setup_ops; - indio_dev->dev.parent = &client->dev; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = devm_iio_kfifo_buffer_setup(&client->dev, indio_dev, + &max30100_buffer_setup_ops); + if (ret) + return ret; data = iio_priv(indio_dev); data->indio_dev = indio_dev; @@ -476,20 +503,18 @@ static int max30100_probe(struct i2c_client *client, return iio_device_register(indio_dev); } -static int max30100_remove(struct i2c_client *client) +static void max30100_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct max30100_data *data = iio_priv(indio_dev); iio_device_unregister(indio_dev); max30100_set_powermode(data, false); - - return 0; } static const struct i2c_device_id max30100_id[] = { - { "max30100", 0 }, - {} + { "max30100" }, + { } }; MODULE_DEVICE_TABLE(i2c, max30100_id); @@ -502,7 +527,7 @@ MODULE_DEVICE_TABLE(of, max30100_dt_ids); static struct i2c_driver max30100_driver = { .driver = { .name = MAX30100_DRV_NAME, - .of_match_table = of_match_ptr(max30100_dt_ids), + .of_match_table = max30100_dt_ids, }, .probe = max30100_probe, .remove = max30100_remove, |
