From e5a639421821c7cd11832fd7fbe6376bfb304880 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Thu, 8 Aug 2013 17:39:00 +0100 Subject: iio: Add tmp006 IR temperature sensor the TI TMP006 is a non-contact temperature sensor with I2C interface; it measures the surface temperature of a distance object using a thermopile to absorb IR energy emitted from the object the sensor has two channels: IR sensor voltage (16-bit) and reference temperature of the chip (14-bit); datasheet is here: http://www.ti.com/lit/ds/symlink/tmp006.pdf v2 (thanks to Grygorii Strashko, Lars-Peter Clausen, Jonathan Cameron for review comments): * power down device on driver remove * use sign_extend32() * style cleanup * add comments what channel raw LSBs mean * spelling of thermopile Signed-off-by: Peter Meerwald Cc: Grygorii Strashko Cc: Lars-Peter Clausen Cc: Jonathan Cameron Cc: LM Sensors Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index 524380c..cbea327 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -73,5 +73,6 @@ if IIO_TRIGGER source "drivers/iio/trigger/Kconfig" endif #IIO_TRIGGER source "drivers/iio/pressure/Kconfig" +source "drivers/iio/temperature/Kconfig" endif # IIO diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index 7a3866c..a0547f5 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -21,5 +21,6 @@ obj-y += frequency/ obj-y += imu/ obj-y += light/ obj-y += magnetometer/ +obj-y += temperature/ obj-y += trigger/ obj-y += pressure/ diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig new file mode 100644 index 0000000..372f8fb --- /dev/null +++ b/drivers/iio/temperature/Kconfig @@ -0,0 +1,16 @@ +# +# Temperature sensor drivers +# +menu "Temperature sensors" + +config TMP006 + tristate "TMP006 infrared thermopile sensor" + depends on I2C + help + If you say yes here you get support for the Texas Instruments + TMP006 infrared thermopile sensor. + + This driver can also be built as a module. If so, the module will + be called tmp006. + +endmenu diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile new file mode 100644 index 0000000..24d7b60 --- /dev/null +++ b/drivers/iio/temperature/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for industrial I/O temperature drivers +# + +obj-$(CONFIG_TMP006) += tmp006.o diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c new file mode 100644 index 0000000..64ccde3 --- /dev/null +++ b/drivers/iio/temperature/tmp006.c @@ -0,0 +1,291 @@ +/* + * tmp006.c - Support for TI TMP006 IR thermopile sensor + * + * Copyright (c) 2013 Peter Meerwald + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + * + * Driver for the Texas Instruments I2C 16-bit IR thermopile sensor + * + * (7-bit I2C slave address 0x40, changeable via ADR pins) + * + * TODO: data ready irq + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define TMP006_VOBJECT 0x00 +#define TMP006_TAMBIENT 0x01 +#define TMP006_CONFIG 0x02 +#define TMP006_MANUFACTURER_ID 0xfe +#define TMP006_DEVICE_ID 0xff + +#define TMP006_TAMBIENT_SHIFT 2 + +#define TMP006_CONFIG_RESET BIT(15) +#define TMP006_CONFIG_DRDY_EN BIT(8) +#define TMP006_CONFIG_DRDY BIT(7) + +#define TMP006_CONFIG_MOD_MASK 0x7000 + +#define TMP006_CONFIG_CR_MASK 0x0e00 +#define TMP006_CONFIG_CR_SHIFT 9 + +#define MANUFACTURER_MAGIC 0x5449 +#define DEVICE_MAGIC 0x0067 + +struct tmp006_data { + struct i2c_client *client; + u16 config; +}; + +static int tmp006_read_measurement(struct tmp006_data *data, u8 reg) +{ + s32 ret; + int tries = 50; + + while (tries-- > 0) { + ret = i2c_smbus_read_word_swapped(data->client, + TMP006_CONFIG); + if (ret < 0) + return ret; + if (ret & TMP006_CONFIG_DRDY) + break; + msleep(100); + } + + if (tries < 0) + return -EIO; + + return i2c_smbus_read_word_swapped(data->client, reg); +} + +static int tmp006_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, int *val, + int *val2, long mask) +{ + struct tmp006_data *data = iio_priv(indio_dev); + s32 ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (channel->type == IIO_VOLTAGE) { + /* LSB is 156.25 nV */ + ret = tmp006_read_measurement(data, TMP006_VOBJECT); + if (ret < 0) + return ret; + *val = sign_extend32(ret, 15); + } else if (channel->type == IIO_TEMP) { + /* LSB is 0.03125 degrees Celsius */ + ret = tmp006_read_measurement(data, TMP006_TAMBIENT); + if (ret < 0) + return ret; + *val = sign_extend32(ret, 15) >> TMP006_TAMBIENT_SHIFT; + } else { + break; + } + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + if (channel->type == IIO_VOLTAGE) { + *val = 0; + *val2 = 156250; + } else if (channel->type == IIO_TEMP) { + *val = 31; + *val2 = 250000; + } else { + break; + } + return IIO_VAL_INT_PLUS_MICRO; + default: + break; + } + + return -EINVAL; +} + +static const char * const tmp006_freqs[] = { "4", "2", "1", "0.5", "0.25" }; + +static ssize_t tmp006_show_freq(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tmp006_data *data = iio_priv(dev_to_iio_dev(dev)); + int cr = (data->config & TMP006_CONFIG_CR_MASK) + >> TMP006_CONFIG_CR_SHIFT; + return sprintf(buf, "%s\n", tmp006_freqs[cr]); +} + +static ssize_t tmp006_store_freq(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct tmp006_data *data = iio_priv(indio_dev); + int i; + bool found = false; + + for (i = 0; i < ARRAY_SIZE(tmp006_freqs); i++) + if (sysfs_streq(buf, tmp006_freqs[i])) { + found = true; + break; + } + if (!found) + return -EINVAL; + + data->config &= ~TMP006_CONFIG_CR_MASK; + data->config |= i << TMP006_CONFIG_CR_SHIFT; + + return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG, + data->config); +} + +static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, + tmp006_show_freq, tmp006_store_freq); + +static IIO_CONST_ATTR(sampling_frequency_available, "4 2 1 0.5 0.25"); + +static struct attribute *tmp006_attributes[] = { + &iio_dev_attr_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group tmp006_attribute_group = { + .attrs = tmp006_attributes, +}; + +static const struct iio_chan_spec tmp006_channels[] = { + { + .type = IIO_VOLTAGE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + }, + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + } +}; + +static const struct iio_info tmp006_info = { + .read_raw = tmp006_read_raw, + .attrs = &tmp006_attribute_group, + .driver_module = THIS_MODULE, +}; + +static bool tmp006_check_identification(struct i2c_client *client) +{ + int mid, did; + + mid = i2c_smbus_read_word_swapped(client, TMP006_MANUFACTURER_ID); + if (mid < 0) + return false; + + did = i2c_smbus_read_word_swapped(client, TMP006_DEVICE_ID); + if (did < 0) + return false; + + return mid == MANUFACTURER_MAGIC && did == DEVICE_MAGIC; +} + +static int tmp006_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct tmp006_data *data; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; + + if (!tmp006_check_identification(client)) { + dev_err(&client->dev, "no TMP006 sensor\n"); + return -ENODEV; + } + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + + indio_dev->dev.parent = &client->dev; + indio_dev->name = dev_name(&client->dev); + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &tmp006_info; + + indio_dev->channels = tmp006_channels; + indio_dev->num_channels = ARRAY_SIZE(tmp006_channels); + + ret = i2c_smbus_read_word_swapped(data->client, TMP006_CONFIG); + if (ret < 0) + return ret; + data->config = ret; + + return iio_device_register(indio_dev); +} + +static int tmp006_powerdown(struct tmp006_data *data) +{ + return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG, + data->config & ~TMP006_CONFIG_MOD_MASK); +} + +static int tmp006_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + tmp006_powerdown(iio_priv(indio_dev)); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int tmp006_suspend(struct device *dev) +{ + return tmp006_powerdown(iio_priv(dev_to_iio_dev(dev))); +} + +static int tmp006_resume(struct device *dev) +{ + struct tmp006_data *data = iio_priv(dev_to_iio_dev(dev)); + return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG, + data->config | TMP006_CONFIG_MOD_MASK); +} +#endif + +static SIMPLE_DEV_PM_OPS(tmp006_pm_ops, tmp006_suspend, tmp006_resume); + +static const struct i2c_device_id tmp006_id[] = { + { "tmp006", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tmp006_id); + +static struct i2c_driver tmp006_driver = { + .driver = { + .name = "tmp006", + .pm = &tmp006_pm_ops, + .owner = THIS_MODULE, + }, + .probe = tmp006_probe, + .remove = tmp006_remove, + .id_table = tmp006_id, +}; +module_i2c_driver(tmp006_driver); + +MODULE_AUTHOR("Peter Meerwald "); +MODULE_DESCRIPTION("TI TMP006 IR thermopile sensor driver"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From a5db3609989f7a496bf645783f22dfc2c285d37e Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Thu, 8 Aug 2013 17:39:00 +0100 Subject: iio: Restore alphabetic order in Makefile Signed-off-by: Peter Meerwald Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index a0547f5..bcf7e9e 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -21,6 +21,6 @@ obj-y += frequency/ obj-y += imu/ obj-y += light/ obj-y += magnetometer/ +obj-y += pressure/ obj-y += temperature/ obj-y += trigger/ -obj-y += pressure/ -- cgit v0.10.2 From da419463d8819b66c2795b0fdbf462a1766d9ace Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 13 Aug 2013 07:34:00 +0100 Subject: iio: gyro: adis16080: Use devm_iio_device_alloc Using devm_iio_device_alloc makes code simpler. Signed-off-by: Sachin Kamat Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/gyro/adis16080.c b/drivers/iio/gyro/adis16080.c index e1bb5f9..e9ec022 100644 --- a/drivers/iio/gyro/adis16080.c +++ b/drivers/iio/gyro/adis16080.c @@ -192,16 +192,13 @@ static const struct adis16080_chip_info adis16080_chip_info[] = { static int adis16080_probe(struct spi_device *spi) { const struct spi_device_id *id = spi_get_device_id(spi); - int ret; struct adis16080_state *st; struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; st = iio_priv(indio_dev); /* this is only used for removal purposes */ spi_set_drvdata(spi, indio_dev); @@ -217,22 +214,12 @@ static int adis16080_probe(struct spi_device *spi) indio_dev->info = &adis16080_info; indio_dev->modes = INDIO_DIRECT_MODE; - ret = iio_device_register(indio_dev); - if (ret) - goto error_free_dev; - return 0; - -error_free_dev: - iio_device_free(indio_dev); -error_ret: - return ret; + return iio_device_register(indio_dev); } static int adis16080_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); - return 0; } -- cgit v0.10.2 From 42aceff5a26713a50239504ff30ce78beac66b6a Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 13 Aug 2013 07:34:00 +0100 Subject: iio: gyro: adis16130: Use devm_iio_device_alloc Using devm_iio_device_alloc makes code simpler. Signed-off-by: Sachin Kamat Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/gyro/adis16130.c b/drivers/iio/gyro/adis16130.c index 129acdf..ac66fc1 100644 --- a/drivers/iio/gyro/adis16130.c +++ b/drivers/iio/gyro/adis16130.c @@ -148,16 +148,13 @@ static const struct iio_info adis16130_info = { static int adis16130_probe(struct spi_device *spi) { - int ret; struct adis16130_state *st; struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; st = iio_priv(indio_dev); /* this is only used for removal purposes */ spi_set_drvdata(spi, indio_dev); @@ -170,24 +167,12 @@ static int adis16130_probe(struct spi_device *spi) indio_dev->info = &adis16130_info; indio_dev->modes = INDIO_DIRECT_MODE; - ret = iio_device_register(indio_dev); - if (ret) - goto error_free_dev; - - return 0; - -error_free_dev: - iio_device_free(indio_dev); - -error_ret: - return ret; + return iio_device_register(indio_dev); } static int adis16130_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); - return 0; } -- cgit v0.10.2 From c0ca6d31a519682445e4c672b92f27ff7e0c5a7f Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 13 Aug 2013 07:34:00 +0100 Subject: iio: gyro: adis16136: Use devm_iio_device_alloc Using devm_iio_device_alloc makes code simpler. Signed-off-by: Sachin Kamat Cc: Lars-Peter Clausen Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c index 058e6d5..591bd55 100644 --- a/drivers/iio/gyro/adis16136.c +++ b/drivers/iio/gyro/adis16136.c @@ -497,7 +497,7 @@ static int adis16136_probe(struct spi_device *spi) struct iio_dev *indio_dev; int ret; - indio_dev = iio_device_alloc(sizeof(*adis16136)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis16136)); if (indio_dev == NULL) return -ENOMEM; @@ -515,11 +515,11 @@ static int adis16136_probe(struct spi_device *spi) ret = adis_init(&adis16136->adis, indio_dev, spi, &adis16136_data); if (ret) - goto error_free_dev; + return ret; ret = adis_setup_buffer_and_trigger(&adis16136->adis, indio_dev, NULL); if (ret) - goto error_free_dev; + return ret; ret = adis16136_initial_setup(indio_dev); if (ret) @@ -537,8 +537,6 @@ error_stop_device: adis16136_stop_device(indio_dev); error_cleanup_buffer: adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev); -error_free_dev: - iio_device_free(indio_dev); return ret; } @@ -552,8 +550,6 @@ static int adis16136_remove(struct spi_device *spi) adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev); - iio_device_free(indio_dev); - return 0; } -- cgit v0.10.2 From 827b14a8ece91f3502ae4efe454197ce3210a231 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 13 Aug 2013 07:34:00 +0100 Subject: iio: gyro: adis16260: Use devm_iio_device_alloc Using devm_iio_device_alloc makes code simpler. Signed-off-by: Sachin Kamat Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c index b4cf800..0654116 100644 --- a/drivers/iio/gyro/adis16260.c +++ b/drivers/iio/gyro/adis16260.c @@ -343,11 +343,9 @@ static int adis16260_probe(struct spi_device *spi) int ret; /* setup the industrialio driver allocated elements */ - indio_dev = iio_device_alloc(sizeof(*adis)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis)); + if (!indio_dev) + return -ENOMEM; adis = iio_priv(indio_dev); /* this is only used for removal purposes */ spi_set_drvdata(spi, indio_dev); @@ -361,11 +359,11 @@ static int adis16260_probe(struct spi_device *spi) ret = adis_init(adis, indio_dev, spi, &adis16260_data); if (ret) - goto error_free_dev; + return ret; ret = adis_setup_buffer_and_trigger(adis, indio_dev, NULL); if (ret) - goto error_free_dev; + return ret; /* Get the device into a sane initial state */ ret = adis_initial_startup(adis); @@ -379,9 +377,6 @@ static int adis16260_probe(struct spi_device *spi) error_cleanup_buffer_trigger: adis_cleanup_buffer_and_trigger(adis, indio_dev); -error_free_dev: - iio_device_free(indio_dev); -error_ret: return ret; } @@ -393,7 +388,6 @@ static int adis16260_remove(struct spi_device *spi) iio_device_unregister(indio_dev); adis16260_stop_device(indio_dev); adis_cleanup_buffer_and_trigger(adis, indio_dev); - iio_device_free(indio_dev); return 0; } -- cgit v0.10.2 From 1ba15cf249061c2f55f4a883ee142002261003a8 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 13 Aug 2013 07:34:00 +0100 Subject: iio: hid-sensor-gyro-3d: Use devm_iio_device_alloc Using devm_iio_device_alloc makes code simpler. Signed-off-by: Sachin Kamat Cc: Srinivas Pandruvada Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index 9cc8aa1..d9d7bef 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -282,11 +282,9 @@ static int hid_gyro_3d_probe(struct platform_device *pdev) struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_chan_spec *channels; - indio_dev = iio_device_alloc(sizeof(struct gyro_3d_state)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*gyro_state)); + if (!indio_dev) + return -ENOMEM; platform_set_drvdata(pdev, indio_dev); gyro_state = iio_priv(indio_dev); @@ -298,15 +296,14 @@ static int hid_gyro_3d_probe(struct platform_device *pdev) &gyro_state->common_attributes); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); - goto error_free_dev; + return ret; } channels = kmemdup(gyro_3d_channels, sizeof(gyro_3d_channels), GFP_KERNEL); if (!channels) { - ret = -ENOMEM; dev_err(&pdev->dev, "failed to duplicate channels\n"); - goto error_free_dev; + return -ENOMEM; } ret = gyro_3d_parse_report(pdev, hsdev, channels, @@ -363,9 +360,6 @@ error_unreg_buffer_funcs: iio_triggered_buffer_cleanup(indio_dev); error_free_dev_mem: kfree(indio_dev->channels); -error_free_dev: - iio_device_free(indio_dev); -error_ret: return ret; } @@ -380,7 +374,6 @@ static int hid_gyro_3d_remove(struct platform_device *pdev) hid_sensor_remove_trigger(indio_dev); iio_triggered_buffer_cleanup(indio_dev); kfree(indio_dev->channels); - iio_device_free(indio_dev); return 0; } -- cgit v0.10.2 From 6694cf9652c718b624c459867e7833c759665225 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 13 Aug 2013 07:34:00 +0100 Subject: iio: gyro: adxrs450: Use devm_iio_device_alloc Using devm_iio_device_alloc makes code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/gyro/adxrs450.c b/drivers/iio/gyro/adxrs450.c index 8bd72b4..6dab299 100644 --- a/drivers/iio/gyro/adxrs450.c +++ b/drivers/iio/gyro/adxrs450.c @@ -426,11 +426,9 @@ static int adxrs450_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; st = iio_priv(indio_dev); st->us = spi; mutex_init(&st->buf_lock); @@ -447,7 +445,7 @@ static int adxrs450_probe(struct spi_device *spi) ret = iio_device_register(indio_dev); if (ret) - goto error_free_dev; + return ret; /* Get the device into a sane initial state */ ret = adxrs450_initial_setup(indio_dev); @@ -456,17 +454,12 @@ static int adxrs450_probe(struct spi_device *spi) return 0; error_initial: iio_device_unregister(indio_dev); -error_free_dev: - iio_device_free(indio_dev); - -error_ret: return ret; } static int adxrs450_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); return 0; } -- cgit v0.10.2 From d243b3c06d4d462ccc8d29dacb894cb25d56972f Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 13 Aug 2013 07:34:00 +0100 Subject: iio: gyro: itg3200_core: Use devm_iio_device_alloc Using devm_iio_device_alloc makes code simpler. Signed-off-by: Sachin Kamat Cc: Christian Strobel Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c index d66605d2..4d3f3b9 100644 --- a/drivers/iio/gyro/itg3200_core.c +++ b/drivers/iio/gyro/itg3200_core.c @@ -309,11 +309,9 @@ static int itg3200_probe(struct i2c_client *client, dev_dbg(&client->dev, "probe I2C dev with IRQ %i", client->irq); - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; st = iio_priv(indio_dev); @@ -330,7 +328,7 @@ static int itg3200_probe(struct i2c_client *client, ret = itg3200_buffer_configure(indio_dev); if (ret) - goto error_free_dev; + return ret; if (client->irq) { ret = itg3200_probe_trigger(indio_dev); @@ -353,9 +351,6 @@ error_remove_trigger: itg3200_remove_trigger(indio_dev); error_unconfigure_buffer: itg3200_buffer_unconfigure(indio_dev); -error_free_dev: - iio_device_free(indio_dev); -error_ret: return ret; } @@ -370,8 +365,6 @@ static int itg3200_remove(struct i2c_client *client) itg3200_buffer_unconfigure(indio_dev); - iio_device_free(indio_dev); - return 0; } -- cgit v0.10.2 From 7a842ed6e38807dba811b814d9b14813f33c0b4c Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 13 Aug 2013 07:34:00 +0100 Subject: iio: gyro: st_gyro: Use devm_iio_device_alloc Using devm_iio_device_alloc makes code simpler. Signed-off-by: Sachin Kamat Cc: Denis Ciocca Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index 85fa8d3..e13c2b0 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -366,7 +366,6 @@ void st_gyro_common_remove(struct iio_dev *indio_dev) st_sensors_deallocate_trigger(indio_dev); st_gyro_deallocate_ring(indio_dev); } - iio_device_free(indio_dev); } EXPORT_SYMBOL(st_gyro_common_remove); diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c index c7a29a4..16b8b8d 100644 --- a/drivers/iio/gyro/st_gyro_i2c.c +++ b/drivers/iio/gyro/st_gyro_i2c.c @@ -25,11 +25,9 @@ static int st_gyro_i2c_probe(struct i2c_client *client, struct st_sensor_data *gdata; int err; - indio_dev = iio_device_alloc(sizeof(*gdata)); - if (indio_dev == NULL) { - err = -ENOMEM; - goto iio_device_alloc_error; - } + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*gdata)); + if (!indio_dev) + return -ENOMEM; gdata = iio_priv(indio_dev); gdata->dev = &client->dev; @@ -39,14 +37,9 @@ static int st_gyro_i2c_probe(struct i2c_client *client, err = st_gyro_common_probe(indio_dev, (struct st_sensors_platform_data *)&gyro_pdata); if (err < 0) - goto st_gyro_common_probe_error; + return err; return 0; - -st_gyro_common_probe_error: - iio_device_free(indio_dev); -iio_device_alloc_error: - return err; } static int st_gyro_i2c_remove(struct i2c_client *client) diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c index 14b0762..94763e2 100644 --- a/drivers/iio/gyro/st_gyro_spi.c +++ b/drivers/iio/gyro/st_gyro_spi.c @@ -24,11 +24,9 @@ static int st_gyro_spi_probe(struct spi_device *spi) struct st_sensor_data *gdata; int err; - indio_dev = iio_device_alloc(sizeof(*gdata)); - if (indio_dev == NULL) { - err = -ENOMEM; - goto iio_device_alloc_error; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*gdata)); + if (!indio_dev) + return -ENOMEM; gdata = iio_priv(indio_dev); gdata->dev = &spi->dev; @@ -38,14 +36,9 @@ static int st_gyro_spi_probe(struct spi_device *spi) err = st_gyro_common_probe(indio_dev, (struct st_sensors_platform_data *)&gyro_pdata); if (err < 0) - goto st_gyro_common_probe_error; + return err; return 0; - -st_gyro_common_probe_error: - iio_device_free(indio_dev); -iio_device_alloc_error: - return err; } static int st_gyro_spi_remove(struct spi_device *spi) -- cgit v0.10.2 From 1f5ac5279891140036e1000276b74adbc6c0b039 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 13 Aug 2013 07:34:00 +0100 Subject: iio: gyro: adis16060_core: Use devm_iio_device_alloc Using devm_iio_device_alloc makes code simpler. Signed-off-by: Sachin Kamat Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron diff --git a/drivers/staging/iio/gyro/adis16060_core.c b/drivers/staging/iio/gyro/adis16060_core.c index c67d3a8..6d3d771 100644 --- a/drivers/staging/iio/gyro/adis16060_core.c +++ b/drivers/staging/iio/gyro/adis16060_core.c @@ -151,11 +151,9 @@ static int adis16060_r_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; /* this is only used for removal purposes */ spi_set_drvdata(spi, indio_dev); st = iio_priv(indio_dev); @@ -171,23 +169,16 @@ static int adis16060_r_probe(struct spi_device *spi) ret = iio_device_register(indio_dev); if (ret) - goto error_free_dev; + return ret; adis16060_iio_dev = indio_dev; return 0; - -error_free_dev: - iio_device_free(indio_dev); -error_ret: - return ret; } /* fixme, confirm ordering in this function */ static int adis16060_r_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); - return 0; } -- cgit v0.10.2 From 1eb70a97452cacbe7aae752879b782e1e97a3484 Mon Sep 17 00:00:00 2001 From: Hector Palacios Date: Mon, 22 Jul 2013 15:03:00 +0100 Subject: iio: mxs-lradc: change the realbits to 12 The LRADC virtual channels have an 18 bit field to store the sum of up to 2^5 accumulated samples. The read_raw function however only operates over a single sample (12 bit resolution). In order to use this field for scaling operations, we need it to be the exact resolution value of the LRADC. Besides, the driver was using an 18 bit mask (LRADC_CH_VALUE_MASK) to report touch coordinates to userland. A 12 bit mask should be used instead or else the touch libraries will expect a coordinates range between 0 and 0x3ffff (18 bits), instead of between 0 and 0xfff (12 bits). Signed-off-by: Hector Palacios Acked-by: Marek Vasut Acked-by: Alexandre Belloni Signed-off-by: Jonathan Cameron diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index 863f086..a08c173 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -225,6 +225,9 @@ struct mxs_lradc { #define LRADC_CTRL4_LRADCSELECT_MASK(n) (0xf << ((n) * 4)) #define LRADC_CTRL4_LRADCSELECT_OFFSET(n) ((n) * 4) +#define LRADC_RESOLUTION 12 +#define LRADC_SINGLE_SAMPLE_MASK ((1 << LRADC_RESOLUTION) - 1) + /* * Raw I/O operations */ @@ -540,9 +543,10 @@ static int mxs_lradc_ts_register(struct mxs_lradc *lradc) __set_bit(EV_ABS, input->evbit); __set_bit(EV_KEY, input->evbit); __set_bit(BTN_TOUCH, input->keybit); - input_set_abs_params(input, ABS_X, 0, LRADC_CH_VALUE_MASK, 0, 0); - input_set_abs_params(input, ABS_Y, 0, LRADC_CH_VALUE_MASK, 0, 0); - input_set_abs_params(input, ABS_PRESSURE, 0, LRADC_CH_VALUE_MASK, 0, 0); + input_set_abs_params(input, ABS_X, 0, LRADC_SINGLE_SAMPLE_MASK, 0, 0); + input_set_abs_params(input, ABS_Y, 0, LRADC_SINGLE_SAMPLE_MASK, 0, 0); + input_set_abs_params(input, ABS_PRESSURE, 0, LRADC_SINGLE_SAMPLE_MASK, + 0, 0); lradc->ts_input = input; input_set_drvdata(input, lradc); @@ -817,7 +821,7 @@ static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = { .channel = (idx), \ .scan_type = { \ .sign = 'u', \ - .realbits = 18, \ + .realbits = LRADC_RESOLUTION, \ .storagebits = 32, \ }, \ } -- cgit v0.10.2 From 1696f36482e7063051a1dad86a54be83fd847f4f Mon Sep 17 00:00:00 2001 From: Oleksandr Kozaruk Date: Thu, 25 Jul 2013 14:26:00 +0100 Subject: iio: twl6030-gpadc: TWL6030, TWL6032 GPADC driver The GPADC is general purpose ADC found on TWL6030, and TWL6032 PMIC, known also as Phoenix and PhoenixLite. The TWL6030 and TWL6032 have GPADC with 17 and 19 channels respectively. Some channels have current source and are used for measuring voltage drop on resistive load for detecting battery ID resistance, or measuring voltage drop on NTC resistors for external temperature measurements. Some channels measure voltage, (i.e. battery voltage), and have voltage dividers, thus, capable to scale voltage. Some channels are dedicated for measuring die temperature. Some channels are calibrated in 2 points, having offsets from ideal values kept in trim registers. This is used to correct measurements. The differences between GPADC in TWL6030 and TWL6032: - 10 bit vs 12 bit ADC; - 17 vs 19 channels; - channels have different purpose(i.e. battery voltage channel 8 vs channel 18); - trim values are interpreted differently. Based on the driver patched from Balaji TK, Graeme Gregory, Ambresh K, Girish S Ghongdemath. Signed-off-by: Balaji T K Signed-off-by: Graeme Gregory Signed-off-by: Oleksandr Kozaruk Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index f725b45..09371cb 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -171,6 +171,20 @@ config TI_AM335X_ADC Say yes here to build support for Texas Instruments ADC driver which is also a MFD client. +config TWL6030_GPADC + tristate "TWL6030 GPADC (General Purpose A/D Converter) Support" + depends on TWL4030_CORE + default n + help + Say yes here if you want support for the TWL6030/TWL6032 General + Purpose A/D Converter. This will add support for battery type + detection, battery voltage and temperature measurement, die + temperature measurement, system supply voltage, audio accessory, + USB ID detection. + + This driver can also be built as a module. If so, the module will be + called twl6030-gpadc. + config VIPERBOARD_ADC tristate "Viperboard ADC support" depends on MFD_VIPERBOARD && USB diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 2a4324e..33656ef 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -19,4 +19,5 @@ obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_NAU7802) += nau7802.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o +obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c new file mode 100644 index 0000000..a80a049 --- /dev/null +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -0,0 +1,1029 @@ +/* + * TWL6030 GPADC module driver + * + * Copyright (C) 2009-2013 Texas Instruments Inc. + * Nishant Kamat + * Balaji T K + * Graeme Gregory + * Girish S Ghongdemath + * Ambresh K + * Oleksandr Kozaruk + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "twl6030_gpadc" + +/* + * twl6030 per TRM has 17 channels, and twl6032 has 19 channels + * 2 test network channels are not used, + * 2 die temperature channels are not used either, as it is not + * defined how to convert ADC value to temperature + */ +#define TWL6030_GPADC_USED_CHANNELS 13 +#define TWL6030_GPADC_MAX_CHANNELS 15 +#define TWL6032_GPADC_USED_CHANNELS 15 +#define TWL6032_GPADC_MAX_CHANNELS 19 +#define TWL6030_GPADC_NUM_TRIM_REGS 16 + +#define TWL6030_GPADC_CTRL_P1 0x05 + +#define TWL6032_GPADC_GPSELECT_ISB 0x07 +#define TWL6032_GPADC_CTRL_P1 0x08 + +#define TWL6032_GPADC_GPCH0_LSB 0x0d +#define TWL6032_GPADC_GPCH0_MSB 0x0e + +#define TWL6030_GPADC_CTRL_P1_SP1 BIT(3) + +#define TWL6030_GPADC_GPCH0_LSB (0x29) + +#define TWL6030_GPADC_RT_SW1_EOC_MASK BIT(5) + +#define TWL6030_GPADC_TRIM1 0xCD + +#define TWL6030_REG_TOGGLE1 0x90 +#define TWL6030_GPADCS BIT(1) +#define TWL6030_GPADCR BIT(0) + +/** + * struct twl6030_chnl_calib - channel calibration + * @gain: slope coefficient for ideal curve + * @gain_error: gain error + * @offset_error: offset of the real curve + */ +struct twl6030_chnl_calib { + s32 gain; + s32 gain_error; + s32 offset_error; +}; + +/** + * struct twl6030_ideal_code - GPADC calibration parameters + * GPADC is calibrated in two points: close to the beginning and + * to the and of the measurable input range + * + * @channel: channel number + * @code1: ideal code for the input at the beginning + * @code2: ideal code for at the end of the range + * @volt1: voltage input at the beginning(low voltage) + * @volt2: voltage input at the end(high voltage) + */ +struct twl6030_ideal_code { + int channel; + u16 code1; + u16 code2; + u16 volt1; + u16 volt2; +}; + +struct twl6030_gpadc_data; + +/** + * struct twl6030_gpadc_platform_data - platform specific data + * @nchannels: number of GPADC channels + * @iio_channels: iio channels + * @twl6030_ideal: pointer to calibration parameters + * @start_conversion: pointer to ADC start conversion function + * @channel_to_reg pointer to ADC function to convert channel to + * register address for reading conversion result + * @calibrate: pointer to calibration function + */ +struct twl6030_gpadc_platform_data { + const int nchannels; + const struct iio_chan_spec *iio_channels; + const struct twl6030_ideal_code *ideal; + int (*start_conversion)(int channel); + u8 (*channel_to_reg)(int channel); + int (*calibrate)(struct twl6030_gpadc_data *gpadc); +}; + +/** + * struct twl6030_gpadc_data - GPADC data + * @dev: device pointer + * @lock: mutual exclusion lock for the structure + * @irq_complete: completion to signal end of conversion + * @twl6030_cal_tbl: pointer to calibration data for each + * channel with gain error and offset + * @pdata: pointer to device specific data + */ +struct twl6030_gpadc_data { + struct device *dev; + struct mutex lock; + struct completion irq_complete; + struct twl6030_chnl_calib *twl6030_cal_tbl; + const struct twl6030_gpadc_platform_data *pdata; +}; + +/* + * channels 11, 12, 13, 15 and 16 have no calibration data + * calibration offset is same for channels 1, 3, 4, 5 + * + * The data is taken from GPADC_TRIM registers description. + * GPADC_TRIM registers keep difference between the code measured + * at volt1 and volt2 input voltages and corresponding code1 and code2 + */ +static const struct twl6030_ideal_code + twl6030_ideal[TWL6030_GPADC_USED_CHANNELS] = { + [0] = { /* ch 0, external, battery type, resistor value */ + .channel = 0, + .code1 = 116, + .code2 = 745, + .volt1 = 141, + .volt2 = 910, + }, + [1] = { /* ch 1, external, battery temperature, NTC resistor value */ + .channel = 1, + .code1 = 82, + .code2 = 900, + .volt1 = 100, + .volt2 = 1100, + }, + [2] = { /* ch 2, external, audio accessory/general purpose */ + .channel = 2, + .code1 = 55, + .code2 = 818, + .volt1 = 101, + .volt2 = 1499, + }, + [3] = { /* ch 3, external, general purpose */ + .channel = 3, + .code1 = 82, + .code2 = 900, + .volt1 = 100, + .volt2 = 1100, + }, + [4] = { /* ch 4, external, temperature measurement/general purpose */ + .channel = 4, + .code1 = 82, + .code2 = 900, + .volt1 = 100, + .volt2 = 1100, + }, + [5] = { /* ch 5, external, general purpose */ + .channel = 5, + .code1 = 82, + .code2 = 900, + .volt1 = 100, + .volt2 = 1100, + }, + [6] = { /* ch 6, external, general purpose */ + .channel = 6, + .code1 = 82, + .code2 = 900, + .volt1 = 100, + .volt2 = 1100, + }, + [7] = { /* ch 7, internal, main battery */ + .channel = 7, + .code1 = 614, + .code2 = 941, + .volt1 = 3001, + .volt2 = 4599, + }, + [8] = { /* ch 8, internal, backup battery */ + .channel = 8, + .code1 = 82, + .code2 = 688, + .volt1 = 501, + .volt2 = 4203, + }, + [9] = { /* ch 9, internal, external charger input */ + .channel = 9, + .code1 = 182, + .code2 = 818, + .volt1 = 2001, + .volt2 = 8996, + }, + [10] = { /* ch 10, internal, VBUS */ + .channel = 10, + .code1 = 149, + .code2 = 818, + .volt1 = 1001, + .volt2 = 5497, + }, + [11] = { /* ch 11, internal, VBUS charging current */ + .channel = 11, + }, + /* ch 12, internal, Die temperature */ + /* ch 13, internal, Die temperature */ + [12] = { /* ch 14, internal, USB ID line */ + .channel = 14, + .code1 = 48, + .code2 = 714, + .volt1 = 323, + .volt2 = 4800, + }, +}; + +static const struct twl6030_ideal_code + twl6032_ideal[TWL6032_GPADC_USED_CHANNELS] = { + [0] = { /* ch 0, external, battery type, resistor value */ + .channel = 0, + .code1 = 1441, + .code2 = 3276, + .volt1 = 440, + .volt2 = 1000, + }, + [1] = { /* ch 1, external, battery temperature, NTC resistor value */ + .channel = 1, + .code1 = 1441, + .code2 = 3276, + .volt1 = 440, + .volt2 = 1000, + }, + [2] = { /* ch 2, external, audio accessory/general purpose */ + .channel = 2, + .code1 = 1441, + .code2 = 3276, + .volt1 = 660, + .volt2 = 1500, + }, + [3] = { /* ch 3, external, temperature with external diode/general + purpose */ + .channel = 3, + .code1 = 1441, + .code2 = 3276, + .volt1 = 440, + .volt2 = 1000, + }, + [4] = { /* ch 4, external, temperature measurement/general purpose */ + .channel = 4, + .code1 = 1441, + .code2 = 3276, + .volt1 = 440, + .volt2 = 1000, + }, + [5] = { /* ch 5, external, general purpose */ + .channel = 5, + .code1 = 1441, + .code2 = 3276, + .volt1 = 440, + .volt2 = 1000, + }, + [6] = { /* ch 6, external, general purpose */ + .channel = 6, + .code1 = 1441, + .code2 = 3276, + .volt1 = 440, + .volt2 = 1000, + }, + [7] = { /* ch7, internal, system supply */ + .channel = 7, + .code1 = 1441, + .code2 = 3276, + .volt1 = 2200, + .volt2 = 5000, + }, + [8] = { /* ch8, internal, backup battery */ + .channel = 8, + .code1 = 1441, + .code2 = 3276, + .volt1 = 2200, + .volt2 = 5000, + }, + [9] = { /* ch 9, internal, external charger input */ + .channel = 9, + .code1 = 1441, + .code2 = 3276, + .volt1 = 3960, + .volt2 = 9000, + }, + [10] = { /* ch10, internal, VBUS */ + .channel = 10, + .code1 = 150, + .code2 = 751, + .volt1 = 1000, + .volt2 = 5000, + }, + [11] = { /* ch 11, internal, VBUS DC-DC output current */ + .channel = 11, + .code1 = 1441, + .code2 = 3276, + .volt1 = 660, + .volt2 = 1500, + }, + /* ch 12, internal, Die temperature */ + /* ch 13, internal, Die temperature */ + [12] = { /* ch 14, internal, USB ID line */ + .channel = 14, + .code1 = 1441, + .code2 = 3276, + .volt1 = 2420, + .volt2 = 5500, + }, + /* ch 15, internal, test network */ + /* ch 16, internal, test network */ + [13] = { /* ch 17, internal, battery charging current */ + .channel = 17, + }, + [14] = { /* ch 18, internal, battery voltage */ + .channel = 18, + .code1 = 1441, + .code2 = 3276, + .volt1 = 2200, + .volt2 = 5000, + }, +}; + +static inline int twl6030_gpadc_write(u8 reg, u8 val) +{ + return twl_i2c_write_u8(TWL6030_MODULE_GPADC, val, reg); +} + +static inline int twl6030_gpadc_read(u8 reg, u8 *val) +{ + + return twl_i2c_read(TWL6030_MODULE_GPADC, val, reg, 2); +} + +static int twl6030_gpadc_enable_irq(u8 mask) +{ + int ret; + + ret = twl6030_interrupt_unmask(mask, REG_INT_MSK_LINE_B); + if (ret < 0) + return ret; + + ret = twl6030_interrupt_unmask(mask, REG_INT_MSK_STS_B); + + return ret; +} + +static void twl6030_gpadc_disable_irq(u8 mask) +{ + twl6030_interrupt_mask(mask, REG_INT_MSK_LINE_B); + twl6030_interrupt_mask(mask, REG_INT_MSK_STS_B); +} + +static irqreturn_t twl6030_gpadc_irq_handler(int irq, void *indio_dev) +{ + struct twl6030_gpadc_data *gpadc = iio_priv(indio_dev); + + complete(&gpadc->irq_complete); + + return IRQ_HANDLED; +} + +static int twl6030_start_conversion(int channel) +{ + return twl6030_gpadc_write(TWL6030_GPADC_CTRL_P1, + TWL6030_GPADC_CTRL_P1_SP1); +} + +static int twl6032_start_conversion(int channel) +{ + int ret; + + ret = twl6030_gpadc_write(TWL6032_GPADC_GPSELECT_ISB, channel); + if (ret) + return ret; + + return twl6030_gpadc_write(TWL6032_GPADC_CTRL_P1, + TWL6030_GPADC_CTRL_P1_SP1); +} + +static u8 twl6030_channel_to_reg(int channel) +{ + return TWL6030_GPADC_GPCH0_LSB + 2 * channel; +} + +static u8 twl6032_channel_to_reg(int channel) +{ + /* + * for any prior chosen channel, when the conversion is ready + * the result is avalable in GPCH0_LSB, GPCH0_MSB. + */ + + return TWL6032_GPADC_GPCH0_LSB; +} + +static int twl6030_gpadc_lookup(const struct twl6030_ideal_code *ideal, + int channel, int size) +{ + int i; + + for (i = 0; i < size; i++) + if (ideal[i].channel == channel) + break; + + return i; +} + +static int twl6030_channel_calibrated(const struct twl6030_gpadc_platform_data + *pdata, int channel) +{ + const struct twl6030_ideal_code *ideal = pdata->ideal; + int i; + + i = twl6030_gpadc_lookup(ideal, channel, pdata->nchannels); + /* not calibrated channels have 0 in all structure members */ + return pdata->ideal[i].code2; +} + +static int twl6030_gpadc_make_correction(struct twl6030_gpadc_data *gpadc, + int channel, int raw_code) +{ + const struct twl6030_ideal_code *ideal = gpadc->pdata->ideal; + int corrected_code; + int i; + + i = twl6030_gpadc_lookup(ideal, channel, gpadc->pdata->nchannels); + corrected_code = ((raw_code * 1000) - + gpadc->twl6030_cal_tbl[i].offset_error) / + gpadc->twl6030_cal_tbl[i].gain_error; + + return corrected_code; +} + +static int twl6030_gpadc_get_raw(struct twl6030_gpadc_data *gpadc, + int channel, int *res) +{ + u8 reg = gpadc->pdata->channel_to_reg(channel); + __le16 val; + int raw_code; + int ret; + + ret = twl6030_gpadc_read(reg, (u8 *)&val); + if (ret) { + dev_dbg(gpadc->dev, "unable to read register 0x%X\n", reg); + return ret; + } + + raw_code = le16_to_cpu(val); + dev_dbg(gpadc->dev, "GPADC raw code: %d", raw_code); + + if (twl6030_channel_calibrated(gpadc->pdata, channel)) + *res = twl6030_gpadc_make_correction(gpadc, channel, raw_code); + else + *res = raw_code; + + return ret; +} + +static int twl6030_gpadc_get_processed(struct twl6030_gpadc_data *gpadc, + int channel, int *val) +{ + const struct twl6030_ideal_code *ideal = gpadc->pdata->ideal; + int corrected_code; + int channel_value; + int i; + int ret; + + ret = twl6030_gpadc_get_raw(gpadc, channel, &corrected_code); + if (ret) + return ret; + + i = twl6030_gpadc_lookup(ideal, channel, gpadc->pdata->nchannels); + channel_value = corrected_code * + gpadc->twl6030_cal_tbl[i].gain; + + /* Shift back into mV range */ + channel_value /= 1000; + + dev_dbg(gpadc->dev, "GPADC corrected code: %d", corrected_code); + dev_dbg(gpadc->dev, "GPADC value: %d", channel_value); + + *val = channel_value; + + return ret; +} + +static int twl6030_gpadc_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct twl6030_gpadc_data *gpadc = iio_priv(indio_dev); + int ret; + long timeout; + + mutex_lock(&gpadc->lock); + + ret = gpadc->pdata->start_conversion(chan->channel); + if (ret) { + dev_err(gpadc->dev, "failed to start conversion\n"); + goto err; + } + /* wait for conversion to complete */ + timeout = wait_for_completion_interruptible_timeout( + &gpadc->irq_complete, msecs_to_jiffies(5000)); + if (timeout == 0) { + ret = -ETIMEDOUT; + goto err; + } else if (timeout < 0) { + goto err; + ret = -EINTR; + } + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = twl6030_gpadc_get_raw(gpadc, chan->channel, val); + ret = ret ? -EIO : IIO_VAL_INT; + break; + + case IIO_CHAN_INFO_PROCESSED: + ret = twl6030_gpadc_get_processed(gpadc, chan->channel, val); + ret = ret ? -EIO : IIO_VAL_INT; + break; + + default: + break; + } +err: + mutex_unlock(&gpadc->lock); + + return ret; +} + +/* + * The GPADC channels are calibrated using a two point calibration method. + * The channels measured with two known values: volt1 and volt2, and + * ideal corresponding output codes are known: code1, code2. + * The difference(d1, d2) between ideal and measured codes stored in trim + * registers. + * The goal is to find offset and gain of the real curve for each calibrated + * channel. + * gain: k = 1 + ((d2 - d1) / (x2 - x1)) + * offset: b = d1 + (k - 1) * x1 + */ +static void twl6030_calibrate_channel(struct twl6030_gpadc_data *gpadc, + int channel, int d1, int d2) +{ + int b, k, gain, x1, x2, i; + const struct twl6030_ideal_code *ideal = gpadc->pdata->ideal; + + i = twl6030_gpadc_lookup(ideal, channel, gpadc->pdata->nchannels); + + /* Gain */ + gain = ((ideal[i].volt2 - ideal[i].volt1) * 1000) / + (ideal[i].code2 - ideal[i].code1); + + x1 = ideal[i].code1; + x2 = ideal[i].code2; + + /* k - real curve gain */ + k = 1000 + (((d2 - d1) * 1000) / (x2 - x1)); + + /* b - offset of the real curve gain */ + b = (d1 * 1000) - (k - 1000) * x1; + + gpadc->twl6030_cal_tbl[i].gain = gain; + gpadc->twl6030_cal_tbl[i].gain_error = k; + gpadc->twl6030_cal_tbl[i].offset_error = b; + + dev_dbg(gpadc->dev, "GPADC d1 for Chn: %d = %d\n", channel, d1); + dev_dbg(gpadc->dev, "GPADC d2 for Chn: %d = %d\n", channel, d2); + dev_dbg(gpadc->dev, "GPADC x1 for Chn: %d = %d\n", channel, x1); + dev_dbg(gpadc->dev, "GPADC x2 for Chn: %d = %d\n", channel, x2); + dev_dbg(gpadc->dev, "GPADC Gain for Chn: %d = %d\n", channel, gain); + dev_dbg(gpadc->dev, "GPADC k for Chn: %d = %d\n", channel, k); + dev_dbg(gpadc->dev, "GPADC b for Chn: %d = %d\n", channel, b); +} + +static inline int twl6030_gpadc_get_trim_offset(s8 d) +{ + /* + * XXX NOTE! + * bit 0 - sign, bit 7 - reserved, 6..1 - trim value + * though, the documentation states that trim value + * is absolute value, the correct conversion results are + * obtained if the value is interpreted as 2's complement. + */ + __u32 temp = ((d & 0x7f) >> 1) | ((d & 1) << 6); + + return sign_extend32(temp, 6); +} + +static int twl6030_calibration(struct twl6030_gpadc_data *gpadc) +{ + int ret; + int chn; + u8 trim_regs[TWL6030_GPADC_NUM_TRIM_REGS]; + s8 d1, d2; + + /* + * for calibration two measurements have been performed at + * factory, for some channels, during the production test and + * have been stored in registers. This two stored values are + * used to correct the measurements. The values represent + * offsets for the given input from the output on ideal curve. + */ + ret = twl_i2c_read(TWL6030_MODULE_ID2, trim_regs, + TWL6030_GPADC_TRIM1, TWL6030_GPADC_NUM_TRIM_REGS); + if (ret < 0) { + dev_err(gpadc->dev, "calibration failed\n"); + return ret; + } + + for (chn = 0; chn < TWL6030_GPADC_MAX_CHANNELS; chn++) { + + switch (chn) { + case 0: + d1 = trim_regs[0]; + d2 = trim_regs[1]; + break; + case 1: + case 3: + case 4: + case 5: + case 6: + d1 = trim_regs[4]; + d2 = trim_regs[5]; + break; + case 2: + d1 = trim_regs[12]; + d2 = trim_regs[13]; + break; + case 7: + d1 = trim_regs[6]; + d2 = trim_regs[7]; + break; + case 8: + d1 = trim_regs[2]; + d2 = trim_regs[3]; + break; + case 9: + d1 = trim_regs[8]; + d2 = trim_regs[9]; + break; + case 10: + d1 = trim_regs[10]; + d2 = trim_regs[11]; + break; + case 14: + d1 = trim_regs[14]; + d2 = trim_regs[15]; + break; + default: + continue; + } + + d1 = twl6030_gpadc_get_trim_offset(d1); + d2 = twl6030_gpadc_get_trim_offset(d2); + + twl6030_calibrate_channel(gpadc, chn, d1, d2); + } + + return 0; +} + +static int twl6032_get_trim_value(u8 *trim_regs, unsigned int reg0, + unsigned int reg1, unsigned int mask0, unsigned int mask1, + unsigned int shift0) +{ + int val; + + val = (trim_regs[reg0] & mask0) << shift0; + val |= (trim_regs[reg1] & mask1) >> 1; + if (trim_regs[reg1] & 0x01) + val = -val; + + return val; +} + +static int twl6032_calibration(struct twl6030_gpadc_data *gpadc) +{ + int chn, d1 = 0, d2 = 0, temp; + u8 trim_regs[TWL6030_GPADC_NUM_TRIM_REGS]; + int ret; + + ret = twl_i2c_read(TWL6030_MODULE_ID2, trim_regs, + TWL6030_GPADC_TRIM1, TWL6030_GPADC_NUM_TRIM_REGS); + if (ret < 0) { + dev_err(gpadc->dev, "calibration failed\n"); + return ret; + } + + /* + * Loop to calculate the value needed for returning voltages from + * GPADC not values. + * + * gain is calculated to 3 decimal places fixed point. + */ + for (chn = 0; chn < TWL6032_GPADC_MAX_CHANNELS; chn++) { + + switch (chn) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 11: + case 14: + d1 = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f, + 0x06, 2); + d2 = twl6032_get_trim_value(trim_regs, 3, 1, 0x3f, + 0x06, 2); + break; + case 8: + temp = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f, + 0x06, 2); + d1 = temp + twl6032_get_trim_value(trim_regs, 7, 6, + 0x18, 0x1E, 1); + + temp = twl6032_get_trim_value(trim_regs, 3, 1, 0x3F, + 0x06, 2); + d2 = temp + twl6032_get_trim_value(trim_regs, 9, 7, + 0x1F, 0x06, 2); + break; + case 9: + temp = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f, + 0x06, 2); + d1 = temp + twl6032_get_trim_value(trim_regs, 13, 11, + 0x18, 0x1E, 1); + + temp = twl6032_get_trim_value(trim_regs, 3, 1, 0x3f, + 0x06, 2); + d2 = temp + twl6032_get_trim_value(trim_regs, 15, 13, + 0x1F, 0x06, 1); + break; + case 10: + d1 = twl6032_get_trim_value(trim_regs, 10, 8, 0x0f, + 0x0E, 3); + d2 = twl6032_get_trim_value(trim_regs, 14, 12, 0x0f, + 0x0E, 3); + break; + case 7: + case 18: + temp = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f, + 0x06, 2); + + d1 = (trim_regs[4] & 0x7E) >> 1; + if (trim_regs[4] & 0x01) + d1 = -d1; + d1 += temp; + + temp = twl6032_get_trim_value(trim_regs, 3, 1, 0x3f, + 0x06, 2); + + d2 = (trim_regs[5] & 0xFE) >> 1; + if (trim_regs[5] & 0x01) + d2 = -d2; + + d2 += temp; + break; + default: + /* No data for other channels */ + continue; + } + + twl6030_calibrate_channel(gpadc, chn, d1, d2); + } + + return 0; +} + +#define TWL6030_GPADC_CHAN(chn, _type, chan_info) { \ + .type = _type, \ + .channel = chn, \ + .info_mask_separate = BIT(chan_info), \ + .indexed = 1, \ +} + +static const struct iio_chan_spec twl6030_gpadc_iio_channels[] = { + TWL6030_GPADC_CHAN(0, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), + TWL6030_GPADC_CHAN(1, IIO_TEMP, IIO_CHAN_INFO_RAW), + TWL6030_GPADC_CHAN(2, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), + TWL6030_GPADC_CHAN(3, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), + TWL6030_GPADC_CHAN(4, IIO_TEMP, IIO_CHAN_INFO_RAW), + TWL6030_GPADC_CHAN(5, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), + TWL6030_GPADC_CHAN(6, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), + TWL6030_GPADC_CHAN(7, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), + TWL6030_GPADC_CHAN(8, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), + TWL6030_GPADC_CHAN(9, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), + TWL6030_GPADC_CHAN(10, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), + TWL6030_GPADC_CHAN(11, IIO_VOLTAGE, IIO_CHAN_INFO_RAW), + TWL6030_GPADC_CHAN(14, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +}; + +static const struct iio_chan_spec twl6032_gpadc_iio_channels[] = { + TWL6030_GPADC_CHAN(0, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), + TWL6030_GPADC_CHAN(1, IIO_TEMP, IIO_CHAN_INFO_RAW), + TWL6030_GPADC_CHAN(2, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), + TWL6030_GPADC_CHAN(3, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), + TWL6030_GPADC_CHAN(4, IIO_TEMP, IIO_CHAN_INFO_RAW), + TWL6030_GPADC_CHAN(5, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), + TWL6030_GPADC_CHAN(6, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), + TWL6030_GPADC_CHAN(7, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), + TWL6030_GPADC_CHAN(8, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), + TWL6030_GPADC_CHAN(9, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), + TWL6030_GPADC_CHAN(10, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), + TWL6030_GPADC_CHAN(11, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), + TWL6030_GPADC_CHAN(14, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), + TWL6030_GPADC_CHAN(17, IIO_VOLTAGE, IIO_CHAN_INFO_RAW), + TWL6030_GPADC_CHAN(18, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +}; + +static const struct iio_info twl6030_gpadc_iio_info = { + .read_raw = &twl6030_gpadc_read_raw, + .driver_module = THIS_MODULE, +}; + +static const struct twl6030_gpadc_platform_data twl6030_pdata = { + .iio_channels = twl6030_gpadc_iio_channels, + .nchannels = TWL6030_GPADC_USED_CHANNELS, + .ideal = twl6030_ideal, + .start_conversion = twl6030_start_conversion, + .channel_to_reg = twl6030_channel_to_reg, + .calibrate = twl6030_calibration, +}; + +static const struct twl6030_gpadc_platform_data twl6032_pdata = { + .iio_channels = twl6032_gpadc_iio_channels, + .nchannels = TWL6032_GPADC_USED_CHANNELS, + .ideal = twl6032_ideal, + .start_conversion = twl6032_start_conversion, + .channel_to_reg = twl6032_channel_to_reg, + .calibrate = twl6032_calibration, +}; + +static const struct of_device_id of_twl6030_match_tbl[] = { + { + .compatible = "ti,twl6030-gpadc", + .data = &twl6030_pdata, + }, + { + .compatible = "ti,twl6032-gpadc", + .data = &twl6032_pdata, + }, + { /* end */ } +}; + +static int twl6030_gpadc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct twl6030_gpadc_data *gpadc; + const struct twl6030_gpadc_platform_data *pdata; + const struct of_device_id *match; + struct iio_dev *indio_dev; + int irq; + int ret; + + match = of_match_device(of_match_ptr(of_twl6030_match_tbl), dev); + if (!match) + return -EINVAL; + + pdata = match->data; + + indio_dev = iio_device_alloc(sizeof(*gpadc)); + if (!indio_dev) { + dev_err(dev, "failed allocating iio device\n"); + ret = -ENOMEM; + } + + gpadc = iio_priv(indio_dev); + + gpadc->twl6030_cal_tbl = devm_kzalloc(dev, + sizeof(*gpadc->twl6030_cal_tbl) * + pdata->nchannels, GFP_KERNEL); + if (!gpadc->twl6030_cal_tbl) + goto err_free_device; + + gpadc->dev = dev; + gpadc->pdata = pdata; + + platform_set_drvdata(pdev, indio_dev); + mutex_init(&gpadc->lock); + init_completion(&gpadc->irq_complete); + + ret = pdata->calibrate(gpadc); + if (ret < 0) { + dev_err(&pdev->dev, "failed to read calibration registers\n"); + goto err_free_device; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get irq\n"); + goto err_free_device; + } + + ret = request_threaded_irq(irq, NULL, twl6030_gpadc_irq_handler, + IRQF_ONESHOT, "twl6030_gpadc", indio_dev); + if (ret) { + dev_dbg(&pdev->dev, "could not request irq\n"); + goto err_free_device; + } + + ret = twl6030_gpadc_enable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK); + if (ret < 0) { + dev_err(&pdev->dev, "failed to enable GPADC interrupt\n"); + goto err_free_irq; + } + + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCS, + TWL6030_REG_TOGGLE1); + if (ret < 0) { + dev_err(&pdev->dev, "failed to enable GPADC module\n"); + goto err_free_irq; + } + + indio_dev->name = DRIVER_NAME; + indio_dev->dev.parent = dev; + indio_dev->info = &twl6030_gpadc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = pdata->iio_channels; + indio_dev->num_channels = pdata->nchannels; + + ret = iio_device_register(indio_dev); + if (ret) + goto err_free_irq; + + return ret; + +err_free_irq: + free_irq(irq, indio_dev); +err_free_device: + iio_device_free(indio_dev); + + return ret; +} + +static int twl6030_gpadc_remove(struct platform_device *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + + twl6030_gpadc_disable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK); + free_irq(platform_get_irq(pdev, 0), indio_dev); + iio_device_unregister(indio_dev); + iio_device_free(indio_dev); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int twl6030_gpadc_suspend(struct device *pdev) +{ + int ret; + + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCR, + TWL6030_REG_TOGGLE1); + if (ret) + dev_err(pdev, "error reseting GPADC (%d)!\n", ret); + + return 0; +}; + +static int twl6030_gpadc_resume(struct device *pdev) +{ + int ret; + + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCS, + TWL6030_REG_TOGGLE1); + if (ret) + dev_err(pdev, "error setting GPADC (%d)!\n", ret); + + return 0; +}; +#endif + +static SIMPLE_DEV_PM_OPS(twl6030_gpadc_pm_ops, twl6030_gpadc_suspend, + twl6030_gpadc_resume); + +static struct platform_driver twl6030_gpadc_driver = { + .probe = twl6030_gpadc_probe, + .remove = twl6030_gpadc_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .pm = &twl6030_gpadc_pm_ops, + .of_match_table = of_twl6030_match_tbl, + }, +}; + +module_platform_driver(twl6030_gpadc_driver); + +MODULE_ALIAS("platform: " DRIVER_NAME); +MODULE_AUTHOR("Balaji T K "); +MODULE_AUTHOR("Graeme Gregory "); +MODULE_AUTHOR("Oleksandr Kozaruk Date: Fri, 16 Aug 2013 14:11:00 +0100 Subject: iio: trigger: implement devm_iio_trigger_alloc/devm_iio_triger_free Add a resource managed devm_iio_trigger_alloc()/devm_iio_triger_free() to automatically clean up triggers allocated by IIO drivers, thus leading to simplified IIO drivers code. Signed-off-by: Jacek Anaszewski Signed-off-by: Kyunmin Park Signed-off-by: Jonathan Cameron diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index 1d32332..fb57d85 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -240,6 +240,8 @@ MEM IIO devm_iio_device_alloc() devm_iio_device_free() + devm_iio_trigger_alloc() + devm_iio_trigger_free() IO region devm_request_region() diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 0dd9bb8..bf5e70a 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -424,9 +424,8 @@ static void iio_trig_subirqunmask(struct irq_data *d) trig->subirqs[d->irq - trig->subirq_base].enabled = true; } -struct iio_trigger *iio_trigger_alloc(const char *fmt, ...) +static struct iio_trigger *viio_trigger_alloc(const char *fmt, va_list vargs) { - va_list vargs; struct iio_trigger *trig; trig = kzalloc(sizeof *trig, GFP_KERNEL); if (trig) { @@ -444,9 +443,8 @@ struct iio_trigger *iio_trigger_alloc(const char *fmt, ...) kfree(trig); return NULL; } - va_start(vargs, fmt); + trig->name = kvasprintf(GFP_KERNEL, fmt, vargs); - va_end(vargs); if (trig->name == NULL) { irq_free_descs(trig->subirq_base, CONFIG_IIO_CONSUMERS_PER_TRIGGER); @@ -467,6 +465,19 @@ struct iio_trigger *iio_trigger_alloc(const char *fmt, ...) } get_device(&trig->dev); } + + return trig; +} + +struct iio_trigger *iio_trigger_alloc(const char *fmt, ...) +{ + struct iio_trigger *trig; + va_list vargs; + + va_start(vargs, fmt); + trig = viio_trigger_alloc(fmt, vargs); + va_end(vargs); + return trig; } EXPORT_SYMBOL(iio_trigger_alloc); @@ -478,6 +489,59 @@ void iio_trigger_free(struct iio_trigger *trig) } EXPORT_SYMBOL(iio_trigger_free); +static void devm_iio_trigger_release(struct device *dev, void *res) +{ + iio_trigger_free(*(struct iio_trigger **)res); +} + +static int devm_iio_trigger_match(struct device *dev, void *res, void *data) +{ + struct iio_trigger **r = res; + + if (!r || !*r) { + WARN_ON(!r || !*r); + return 0; + } + + return *r == data; +} + +struct iio_trigger *devm_iio_trigger_alloc(struct device *dev, + const char *fmt, ...) +{ + struct iio_trigger **ptr, *trig; + va_list vargs; + + ptr = devres_alloc(devm_iio_trigger_release, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return NULL; + + /* use raw alloc_dr for kmalloc caller tracing */ + va_start(vargs, fmt); + trig = viio_trigger_alloc(fmt, vargs); + va_end(vargs); + if (trig) { + *ptr = trig; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return trig; +} +EXPORT_SYMBOL_GPL(devm_iio_trigger_alloc); + +void devm_iio_trigger_free(struct device *dev, struct iio_trigger *iio_trig) +{ + int rc; + + rc = devres_release(dev, devm_iio_trigger_release, + devm_iio_trigger_match, iio_trig); + WARN_ON(rc); +} +EXPORT_SYMBOL_GPL(devm_iio_trigger_free); + void iio_device_register_trigger_consumer(struct iio_dev *indio_dev) { indio_dev->groups[indio_dev->groupcounter++] = diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 09ebe0a..2103cc3 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -557,6 +557,35 @@ struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv); void devm_iio_device_free(struct device *dev, struct iio_dev *indio_dev); /** + * devm_iio_trigger_alloc - Resource-managed iio_trigger_alloc() + * @dev: Device to allocate iio_trigger for + * @fmt: trigger name format. If it includes format + * specifiers, the additional arguments following + * format are formatted and inserted in the resulting + * string replacing their respective specifiers. + * + * Managed iio_trigger_alloc. iio_trigger allocated with this function is + * automatically freed on driver detach. + * + * If an iio_trigger allocated with this function needs to be freed separately, + * devm_iio_trigger_free() must be used. + * + * RETURNS: + * Pointer to allocated iio_trigger on success, NULL on failure. + */ +struct iio_trigger *devm_iio_trigger_alloc(struct device *dev, + const char *fmt, ...); + +/** + * devm_iio_trigger_free - Resource-managed iio_trigger_free() + * @dev: Device this iio_dev belongs to + * @iio_trig: the iio_trigger associated with the device + * + * Free iio_trigger allocated with devm_iio_trigger_alloc(). + */ +void devm_iio_trigger_free(struct device *dev, struct iio_trigger *iio_trig); + +/** * iio_buffer_enabled() - helper function to test if the buffer is enabled * @indio_dev: IIO device structure for device **/ -- cgit v0.10.2 From 0c0427acd5bfd25a44c074ac0a517d667ddf0a27 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Sun, 18 Aug 2013 14:07:00 +0100 Subject: iio: Remove unnecessary _write_raw_get_fmt() in several hid-sensor drivers IIO_VAL_INT_PLUS_MICRO is the default, no need to return it explicitly Signed-off-by: Peter Meerwald Acked-by: srinivas pandruvada Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 68df341..46d22f3 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -175,18 +175,10 @@ static int accel_3d_write_raw(struct iio_dev *indio_dev, return ret; } -static int accel_3d_write_raw_get_fmt(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - long mask) -{ - return IIO_VAL_INT_PLUS_MICRO; -} - static const struct iio_info accel_3d_info = { .driver_module = THIS_MODULE, .read_raw = &accel_3d_read_raw, .write_raw = &accel_3d_write_raw, - .write_raw_get_fmt = &accel_3d_write_raw_get_fmt, }; /* Function to push data to buffer */ diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index d9d7bef..c688d97 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -175,18 +175,10 @@ static int gyro_3d_write_raw(struct iio_dev *indio_dev, return ret; } -static int gyro_3d_write_raw_get_fmt(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - long mask) -{ - return IIO_VAL_INT_PLUS_MICRO; -} - static const struct iio_info gyro_3d_info = { .driver_module = THIS_MODULE, .read_raw = &gyro_3d_read_raw, .write_raw = &gyro_3d_write_raw, - .write_raw_get_fmt = &gyro_3d_write_raw_get_fmt, }; /* Function to push data to buffer */ diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index 84cf004..e59d00c 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -154,18 +154,10 @@ static int als_write_raw(struct iio_dev *indio_dev, return ret; } -static int als_write_raw_get_fmt(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - long mask) -{ - return IIO_VAL_INT_PLUS_MICRO; -} - static const struct iio_info als_info = { .driver_module = THIS_MODULE, .read_raw = &als_read_raw, .write_raw = &als_write_raw, - .write_raw_get_fmt = &als_write_raw_get_fmt, }; /* Function to push data to buffer */ diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index 5a6162d..a98460b 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -176,18 +176,10 @@ static int magn_3d_write_raw(struct iio_dev *indio_dev, return ret; } -static int magn_3d_write_raw_get_fmt(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - long mask) -{ - return IIO_VAL_INT_PLUS_MICRO; -} - static const struct iio_info magn_3d_info = { .driver_module = THIS_MODULE, .read_raw = &magn_3d_read_raw, .write_raw = &magn_3d_write_raw, - .write_raw_get_fmt = &magn_3d_write_raw_get_fmt, }; /* Function to push data to buffer */ -- cgit v0.10.2 From 4c730292656675000a3631b12cefb6238c57d1e3 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Sun, 18 Aug 2013 13:59:00 +0100 Subject: iio: adjd_s311: Cleanup unused #defines using word reads, no need for HI/LO register #defines Signed-off-by: Peter Meerwald Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c index 55b9e18..00ab980 100644 --- a/drivers/iio/light/adjd_s311.c +++ b/drivers/iio/light/adjd_s311.c @@ -37,22 +37,14 @@ #define ADJD_S311_CAP_GREEN 0x07 #define ADJD_S311_CAP_BLUE 0x08 #define ADJD_S311_CAP_CLEAR 0x09 -#define ADJD_S311_INT_RED_LO 0x0a -#define ADJD_S311_INT_RED_HI 0x0b -#define ADJD_S311_INT_GREEN_LO 0x0c -#define ADJD_S311_INT_GREEN_HI 0x0d -#define ADJD_S311_INT_BLUE_LO 0x0e -#define ADJD_S311_INT_BLUE_HI 0x0f -#define ADJD_S311_INT_CLEAR_LO 0x10 -#define ADJD_S311_INT_CLEAR_HI 0x11 -#define ADJD_S311_DATA_RED_LO 0x40 -#define ADJD_S311_DATA_RED_HI 0x41 -#define ADJD_S311_DATA_GREEN_LO 0x42 -#define ADJD_S311_DATA_GREEN_HI 0x43 -#define ADJD_S311_DATA_BLUE_LO 0x44 -#define ADJD_S311_DATA_BLUE_HI 0x45 -#define ADJD_S311_DATA_CLEAR_LO 0x46 -#define ADJD_S311_DATA_CLEAR_HI 0x47 +#define ADJD_S311_INT_RED 0x0a +#define ADJD_S311_INT_GREEN 0x0c +#define ADJD_S311_INT_BLUE 0x0e +#define ADJD_S311_INT_CLEAR 0x10 +#define ADJD_S311_DATA_RED 0x40 +#define ADJD_S311_DATA_GREEN 0x42 +#define ADJD_S311_DATA_BLUE 0x44 +#define ADJD_S311_DATA_CLEAR 0x46 #define ADJD_S311_OFFSET_RED 0x48 #define ADJD_S311_OFFSET_GREEN 0x49 #define ADJD_S311_OFFSET_BLUE 0x4a @@ -73,8 +65,8 @@ enum adjd_s311_channel_idx { IDX_RED, IDX_GREEN, IDX_BLUE, IDX_CLEAR }; -#define ADJD_S311_DATA_REG(chan) (ADJD_S311_DATA_RED_LO + (chan) * 2) -#define ADJD_S311_INT_REG(chan) (ADJD_S311_INT_RED_LO + (chan) * 2) +#define ADJD_S311_DATA_REG(chan) (ADJD_S311_DATA_RED + (chan) * 2) +#define ADJD_S311_INT_REG(chan) (ADJD_S311_INT_RED + (chan) * 2) #define ADJD_S311_CAP_REG(chan) (ADJD_S311_CAP_RED + (chan)) static int adjd_s311_req_data(struct iio_dev *indio_dev) -- cgit v0.10.2 From fa659a40b80b06140390c364362d7ca942e2b2f6 Mon Sep 17 00:00:00 2001 From: Oleksandr Kozaruk Date: Mon, 19 Aug 2013 12:09:00 +0100 Subject: iio: adc: twl6030-gpadc: Use devm_* API family Using devm_iio_device_alloc and devm_request_threaded_irq makes code simpler. Signed-off-by: Oleksandr Kozaruk Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index a80a049..a558516 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -893,11 +893,9 @@ static int twl6030_gpadc_probe(struct platform_device *pdev) pdata = match->data; - indio_dev = iio_device_alloc(sizeof(*gpadc)); - if (!indio_dev) { - dev_err(dev, "failed allocating iio device\n"); - ret = -ENOMEM; - } + indio_dev = devm_iio_device_alloc(dev, sizeof(*gpadc)); + if (!indio_dev) + return -ENOMEM; gpadc = iio_priv(indio_dev); @@ -905,7 +903,7 @@ static int twl6030_gpadc_probe(struct platform_device *pdev) sizeof(*gpadc->twl6030_cal_tbl) * pdata->nchannels, GFP_KERNEL); if (!gpadc->twl6030_cal_tbl) - goto err_free_device; + return -ENOMEM; gpadc->dev = dev; gpadc->pdata = pdata; @@ -917,33 +915,30 @@ static int twl6030_gpadc_probe(struct platform_device *pdev) ret = pdata->calibrate(gpadc); if (ret < 0) { dev_err(&pdev->dev, "failed to read calibration registers\n"); - goto err_free_device; + return ret; } irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "failed to get irq\n"); - goto err_free_device; + return irq; } - ret = request_threaded_irq(irq, NULL, twl6030_gpadc_irq_handler, + ret = devm_request_threaded_irq(dev, irq, NULL, + twl6030_gpadc_irq_handler, IRQF_ONESHOT, "twl6030_gpadc", indio_dev); - if (ret) { - dev_dbg(&pdev->dev, "could not request irq\n"); - goto err_free_device; - } ret = twl6030_gpadc_enable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK); if (ret < 0) { dev_err(&pdev->dev, "failed to enable GPADC interrupt\n"); - goto err_free_irq; + return ret; } ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCS, TWL6030_REG_TOGGLE1); if (ret < 0) { dev_err(&pdev->dev, "failed to enable GPADC module\n"); - goto err_free_irq; + return ret; } indio_dev->name = DRIVER_NAME; @@ -954,15 +949,6 @@ static int twl6030_gpadc_probe(struct platform_device *pdev) indio_dev->num_channels = pdata->nchannels; ret = iio_device_register(indio_dev); - if (ret) - goto err_free_irq; - - return ret; - -err_free_irq: - free_irq(irq, indio_dev); -err_free_device: - iio_device_free(indio_dev); return ret; } @@ -972,9 +958,7 @@ static int twl6030_gpadc_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); twl6030_gpadc_disable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK); - free_irq(platform_get_irq(pdev, 0), indio_dev); iio_device_unregister(indio_dev); - iio_device_free(indio_dev); return 0; } -- cgit v0.10.2 From c367982ad9b927ec1b1fd66a462b72950fe5370b Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 19 Aug 2013 12:38:00 +0100 Subject: iio: dac: ad5064: Use devm_* APIs devm_* APIs are device managed and make code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c index aa26d50..a3a52be 100644 --- a/drivers/iio/dac/ad5064.c +++ b/drivers/iio/dac/ad5064.c @@ -442,7 +442,7 @@ static int ad5064_probe(struct device *dev, enum ad5064_type type, unsigned int i; int ret; - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -456,23 +456,23 @@ static int ad5064_probe(struct device *dev, enum ad5064_type type, for (i = 0; i < ad5064_num_vref(st); ++i) st->vref_reg[i].supply = ad5064_vref_name(st, i); - ret = regulator_bulk_get(dev, ad5064_num_vref(st), + ret = devm_regulator_bulk_get(dev, ad5064_num_vref(st), st->vref_reg); if (ret) { if (!st->chip_info->internal_vref) - goto error_free; + return ret; st->use_internal_vref = true; ret = ad5064_write(st, AD5064_CMD_CONFIG, 0, AD5064_CONFIG_INT_VREF_ENABLE, 0); if (ret) { dev_err(dev, "Failed to enable internal vref: %d\n", ret); - goto error_free; + return ret; } } else { ret = regulator_bulk_enable(ad5064_num_vref(st), st->vref_reg); if (ret) - goto error_free_reg; + return ret; } indio_dev->dev.parent = dev; @@ -498,11 +498,6 @@ static int ad5064_probe(struct device *dev, enum ad5064_type type, error_disable_reg: if (!st->use_internal_vref) regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg); -error_free_reg: - if (!st->use_internal_vref) - regulator_bulk_free(ad5064_num_vref(st), st->vref_reg); -error_free: - iio_device_free(indio_dev); return ret; } @@ -514,12 +509,8 @@ static int ad5064_remove(struct device *dev) iio_device_unregister(indio_dev); - if (!st->use_internal_vref) { + if (!st->use_internal_vref) regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg); - regulator_bulk_free(ad5064_num_vref(st), st->vref_reg); - } - - iio_device_free(indio_dev); return 0; } -- cgit v0.10.2 From 400d36e68de56135223ace631f4bb067d9ccb44d Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 19 Aug 2013 12:38:00 +0100 Subject: iio: dac: ad5360: Use devm_* APIs devm_* APIs are device managed and make code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/dac/ad5360.c b/drivers/iio/dac/ad5360.c index 80923af..d2da71e 100644 --- a/drivers/iio/dac/ad5360.c +++ b/drivers/iio/dac/ad5360.c @@ -459,7 +459,7 @@ static int ad5360_probe(struct spi_device *spi) unsigned int i; int ret; - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) { dev_err(&spi->dev, "Failed to allocate iio device\n"); return -ENOMEM; @@ -480,13 +480,13 @@ static int ad5360_probe(struct spi_device *spi) ret = ad5360_alloc_channels(indio_dev); if (ret) { dev_err(&spi->dev, "Failed to allocate channel spec: %d\n", ret); - goto error_free; + return ret; } for (i = 0; i < st->chip_info->num_vrefs; ++i) st->vref_reg[i].supply = ad5360_vref_name[i]; - ret = regulator_bulk_get(&st->spi->dev, st->chip_info->num_vrefs, + ret = devm_regulator_bulk_get(&st->spi->dev, st->chip_info->num_vrefs, st->vref_reg); if (ret) { dev_err(&spi->dev, "Failed to request vref regulators: %d\n", ret); @@ -496,7 +496,7 @@ static int ad5360_probe(struct spi_device *spi) ret = regulator_bulk_enable(st->chip_info->num_vrefs, st->vref_reg); if (ret) { dev_err(&spi->dev, "Failed to enable vref regulators: %d\n", ret); - goto error_free_reg; + goto error_free_channels; } ret = iio_device_register(indio_dev); @@ -509,12 +509,8 @@ static int ad5360_probe(struct spi_device *spi) error_disable_reg: regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg); -error_free_reg: - regulator_bulk_free(st->chip_info->num_vrefs, st->vref_reg); error_free_channels: kfree(indio_dev->channels); -error_free: - iio_device_free(indio_dev); return ret; } @@ -529,9 +525,6 @@ static int ad5360_remove(struct spi_device *spi) kfree(indio_dev->channels); regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg); - regulator_bulk_free(st->chip_info->num_vrefs, st->vref_reg); - - iio_device_free(indio_dev); return 0; } -- cgit v0.10.2 From c815ad372be668bd6f173439be1f67e0d7dc4e5b Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 19 Aug 2013 12:38:00 +0100 Subject: iio: dac: ad5380: Use devm_* APIs devm_* APIs are device managed and make code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index bf2db02..1c44ae3 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c @@ -369,11 +369,10 @@ static int ad5380_probe(struct device *dev, struct regmap *regmap, unsigned int ctrl = 0; int ret; - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (indio_dev == NULL) { dev_err(dev, "Failed to allocate iio device\n"); - ret = -ENOMEM; - goto error_out; + return -ENOMEM; } st = iio_priv(indio_dev); @@ -391,13 +390,13 @@ static int ad5380_probe(struct device *dev, struct regmap *regmap, ret = ad5380_alloc_channels(indio_dev); if (ret) { dev_err(dev, "Failed to allocate channel spec: %d\n", ret); - goto error_free; + return ret; } if (st->chip_info->int_vref == 2500000) ctrl |= AD5380_CTRL_INT_VREF_2V5; - st->vref_reg = regulator_get(dev, "vref"); + st->vref_reg = devm_regulator_get(dev, "vref"); if (!IS_ERR(st->vref_reg)) { ret = regulator_enable(st->vref_reg); if (ret) { @@ -434,13 +433,7 @@ error_disable_reg: if (!IS_ERR(st->vref_reg)) regulator_disable(st->vref_reg); error_free_reg: - if (!IS_ERR(st->vref_reg)) - regulator_put(st->vref_reg); - kfree(indio_dev->channels); -error_free: - iio_device_free(indio_dev); -error_out: return ret; } @@ -456,11 +449,8 @@ static int ad5380_remove(struct device *dev) if (!IS_ERR(st->vref_reg)) { regulator_disable(st->vref_reg); - regulator_put(st->vref_reg); } - iio_device_free(indio_dev); - return 0; } -- cgit v0.10.2 From 62a308a62d3d9ce3b167ce35a6643b22e66282e1 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 19 Aug 2013 12:38:00 +0100 Subject: iio: dac: ad5421: Use devm_* APIs devm_* APIs are device managed and make code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c index 98f2440..1f78b14 100644 --- a/drivers/iio/dac/ad5421.c +++ b/drivers/iio/dac/ad5421.c @@ -451,7 +451,7 @@ static int ad5421_probe(struct spi_device *spi) struct ad5421_state *st; int ret; - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) { dev_err(&spi->dev, "Failed to allocate iio device\n"); return -ENOMEM; @@ -484,31 +484,23 @@ static int ad5421_probe(struct spi_device *spi) ad5421_update_ctrl(indio_dev, 0, 0); if (spi->irq) { - ret = request_threaded_irq(spi->irq, + ret = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, ad5421_fault_handler, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "ad5421 fault", indio_dev); if (ret) - goto error_free; + return ret; } ret = iio_device_register(indio_dev); if (ret) { dev_err(&spi->dev, "Failed to register iio device: %d\n", ret); - goto error_free_irq; + return ret; } return 0; - -error_free_irq: - if (spi->irq) - free_irq(spi->irq, indio_dev); -error_free: - iio_device_free(indio_dev); - - return ret; } static int ad5421_remove(struct spi_device *spi) @@ -516,9 +508,6 @@ static int ad5421_remove(struct spi_device *spi) struct iio_dev *indio_dev = spi_get_drvdata(spi); iio_device_unregister(indio_dev); - if (spi->irq) - free_irq(spi->irq, indio_dev); - iio_device_free(indio_dev); return 0; } -- cgit v0.10.2 From ba7272954ec933eca3e459ac45003c0073a86993 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 19 Aug 2013 12:38:00 +0100 Subject: iio: dac: ad5446: Use devm_* APIs devm_* APIs are device managed and make code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c index cae8f60..96e9ed4 100644 --- a/drivers/iio/dac/ad5446.c +++ b/drivers/iio/dac/ad5446.c @@ -220,11 +220,11 @@ static int ad5446_probe(struct device *dev, const char *name, struct regulator *reg; int ret, voltage_uv = 0; - reg = regulator_get(dev, "vcc"); + reg = devm_regulator_get(dev, "vcc"); if (!IS_ERR(reg)) { ret = regulator_enable(reg); if (ret) - goto error_put_reg; + return ret; ret = regulator_get_voltage(reg); if (ret < 0) @@ -233,7 +233,7 @@ static int ad5446_probe(struct device *dev, const char *name, voltage_uv = ret; } - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_disable_reg; @@ -264,19 +264,13 @@ static int ad5446_probe(struct device *dev, const char *name, ret = iio_device_register(indio_dev); if (ret) - goto error_free_device; + goto error_disable_reg; return 0; -error_free_device: - iio_device_free(indio_dev); error_disable_reg: if (!IS_ERR(reg)) regulator_disable(reg); -error_put_reg: - if (!IS_ERR(reg)) - regulator_put(reg); - return ret; } @@ -286,11 +280,8 @@ static int ad5446_remove(struct device *dev) struct ad5446_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (!IS_ERR(st->reg)) { + if (!IS_ERR(st->reg)) regulator_disable(st->reg); - regulator_put(st->reg); - } - iio_device_free(indio_dev); return 0; } -- cgit v0.10.2 From cd5e5785417591deba06b5fe3e78137137d2a9d3 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 19 Aug 2013 12:38:00 +0100 Subject: iio: dac: ad5449: Use devm_* APIs devm_* APIs are device managed and make code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/dac/ad5449.c b/drivers/iio/dac/ad5449.c index ba1c914..fff7d07 100644 --- a/drivers/iio/dac/ad5449.c +++ b/drivers/iio/dac/ad5449.c @@ -275,7 +275,7 @@ static int ad5449_spi_probe(struct spi_device *spi) unsigned int i; int ret; - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -288,14 +288,14 @@ static int ad5449_spi_probe(struct spi_device *spi) for (i = 0; i < st->chip_info->num_channels; ++i) st->vref_reg[i].supply = ad5449_vref_name(st, i); - ret = regulator_bulk_get(&spi->dev, st->chip_info->num_channels, + ret = devm_regulator_bulk_get(&spi->dev, st->chip_info->num_channels, st->vref_reg); if (ret) - goto error_free; + return ret; ret = regulator_bulk_enable(st->chip_info->num_channels, st->vref_reg); if (ret) - goto error_free_reg; + return ret; indio_dev->dev.parent = &spi->dev; indio_dev->name = id->name; @@ -325,10 +325,6 @@ static int ad5449_spi_probe(struct spi_device *spi) error_disable_reg: regulator_bulk_disable(st->chip_info->num_channels, st->vref_reg); -error_free_reg: - regulator_bulk_free(st->chip_info->num_channels, st->vref_reg); -error_free: - iio_device_free(indio_dev); return ret; } @@ -341,9 +337,6 @@ static int ad5449_spi_remove(struct spi_device *spi) iio_device_unregister(indio_dev); regulator_bulk_disable(st->chip_info->num_channels, st->vref_reg); - regulator_bulk_free(st->chip_info->num_channels, st->vref_reg); - - iio_device_free(indio_dev); return 0; } -- cgit v0.10.2 From 8571ebf7fc1892beadd83dd7af385c599c3ec0d3 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 19 Aug 2013 12:38:00 +0100 Subject: iio: dac: ad5504: Use devm_* APIs devm_* APIs are device managed and make code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index 139206e..caffb16 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c @@ -281,16 +281,14 @@ static int ad5504_probe(struct spi_device *spi) struct regulator *reg; int ret, voltage_uv = 0; - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } - reg = regulator_get(&spi->dev, "vcc"); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + reg = devm_regulator_get(&spi->dev, "vcc"); if (!IS_ERR(reg)) { ret = regulator_enable(reg); if (ret) - goto error_put_reg; + return ret; ret = regulator_get_voltage(reg); if (ret < 0) @@ -321,7 +319,7 @@ static int ad5504_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; if (spi->irq) { - ret = request_threaded_irq(spi->irq, + ret = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, &ad5504_event_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, @@ -333,22 +331,14 @@ static int ad5504_probe(struct spi_device *spi) ret = iio_device_register(indio_dev); if (ret) - goto error_free_irq; + goto error_disable_reg; return 0; -error_free_irq: - if (spi->irq) - free_irq(spi->irq, indio_dev); error_disable_reg: if (!IS_ERR(reg)) regulator_disable(reg); -error_put_reg: - if (!IS_ERR(reg)) - regulator_put(reg); - iio_device_free(indio_dev); -error_ret: return ret; } @@ -358,14 +348,9 @@ static int ad5504_remove(struct spi_device *spi) struct ad5504_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (spi->irq) - free_irq(spi->irq, indio_dev); - if (!IS_ERR(st->reg)) { + if (!IS_ERR(st->reg)) regulator_disable(st->reg); - regulator_put(st->reg); - } - iio_device_free(indio_dev); return 0; } -- cgit v0.10.2 From 75238230cce22b99e648e96bbc043725832c6ad5 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 19 Aug 2013 12:38:00 +0100 Subject: iio: dac: ad5624r_spi: Use devm_* APIs devm_* APIs are device managed and make code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c index bb298aa..714af75 100644 --- a/drivers/iio/dac/ad5624r_spi.c +++ b/drivers/iio/dac/ad5624r_spi.c @@ -226,17 +226,15 @@ static int ad5624r_probe(struct spi_device *spi) struct iio_dev *indio_dev; int ret, voltage_uv = 0; - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; st = iio_priv(indio_dev); - st->reg = regulator_get(&spi->dev, "vcc"); + st->reg = devm_regulator_get(&spi->dev, "vcc"); if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); if (ret) - goto error_put_reg; + return ret; ret = regulator_get_voltage(st->reg); if (ret < 0) @@ -277,11 +275,6 @@ static int ad5624r_probe(struct spi_device *spi) error_disable_reg: if (!IS_ERR(st->reg)) regulator_disable(st->reg); -error_put_reg: - if (!IS_ERR(st->reg)) - regulator_put(st->reg); - iio_device_free(indio_dev); -error_ret: return ret; } @@ -292,11 +285,8 @@ static int ad5624r_remove(struct spi_device *spi) struct ad5624r_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (!IS_ERR(st->reg)) { + if (!IS_ERR(st->reg)) regulator_disable(st->reg); - regulator_put(st->reg); - } - iio_device_free(indio_dev); return 0; } -- cgit v0.10.2 From edf3fd4141f17fa81497e7417aba7a45d1a36af9 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 19 Aug 2013 12:38:00 +0100 Subject: iio: dac: ad5686: Use devm_* APIs devm_* APIs are device managed and make code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 06439b1..57825ea 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -314,18 +314,18 @@ static int ad5686_probe(struct spi_device *spi) struct iio_dev *indio_dev; int ret, regdone = 0, voltage_uv = 0; - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; st = iio_priv(indio_dev); spi_set_drvdata(spi, indio_dev); - st->reg = regulator_get(&spi->dev, "vcc"); + st->reg = devm_regulator_get(&spi->dev, "vcc"); if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); if (ret) - goto error_put_reg; + return ret; ret = regulator_get_voltage(st->reg); if (ret < 0) @@ -369,12 +369,6 @@ static int ad5686_probe(struct spi_device *spi) error_disable_reg: if (!IS_ERR(st->reg)) regulator_disable(st->reg); -error_put_reg: - if (!IS_ERR(st->reg)) - regulator_put(st->reg); - - iio_device_free(indio_dev); - return ret; } @@ -384,11 +378,8 @@ static int ad5686_remove(struct spi_device *spi) struct ad5686_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (!IS_ERR(st->reg)) { + if (!IS_ERR(st->reg)) regulator_disable(st->reg); - regulator_put(st->reg); - } - iio_device_free(indio_dev); return 0; } -- cgit v0.10.2 From fd047294e279779c36cbca589d9fef06e881e67a Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 19 Aug 2013 12:38:00 +0100 Subject: iio: dac: ad5755: Use devm_iio_device_alloc Using devm_iio_device_alloc makes code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c index 12bb315..36a4361 100644 --- a/drivers/iio/dac/ad5755.c +++ b/drivers/iio/dac/ad5755.c @@ -565,7 +565,7 @@ static int ad5755_probe(struct spi_device *spi) struct ad5755_state *st; int ret; - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) { dev_err(&spi->dev, "Failed to allocate iio device\n"); return -ENOMEM; @@ -589,24 +589,19 @@ static int ad5755_probe(struct spi_device *spi) ret = ad5755_init_channels(indio_dev, pdata); if (ret) - goto error_free; + return ret; ret = ad5755_setup_pdata(indio_dev, pdata); if (ret) - goto error_free; + return ret; ret = iio_device_register(indio_dev); if (ret) { dev_err(&spi->dev, "Failed to register iio device: %d\n", ret); - goto error_free; + return ret; } return 0; - -error_free: - iio_device_free(indio_dev); - - return ret; } static int ad5755_remove(struct spi_device *spi) @@ -614,7 +609,6 @@ static int ad5755_remove(struct spi_device *spi) struct iio_dev *indio_dev = spi_get_drvdata(spi); iio_device_unregister(indio_dev); - iio_device_free(indio_dev); return 0; } -- cgit v0.10.2 From 7ff0de3faaeb0db80c2c9f03c119167e89594879 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 19 Aug 2013 12:38:00 +0100 Subject: iio: dac: ad5764: Use devm_* APIs devm_* APIs are device managed and make code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/dac/ad5764.c b/drivers/iio/dac/ad5764.c index 7a53f7d..df7e028 100644 --- a/drivers/iio/dac/ad5764.c +++ b/drivers/iio/dac/ad5764.c @@ -275,7 +275,7 @@ static int ad5764_probe(struct spi_device *spi) struct ad5764_state *st; int ret; - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) { dev_err(&spi->dev, "Failed to allocate iio device\n"); return -ENOMEM; @@ -298,12 +298,12 @@ static int ad5764_probe(struct spi_device *spi) st->vref_reg[0].supply = "vrefAB"; st->vref_reg[1].supply = "vrefCD"; - ret = regulator_bulk_get(&st->spi->dev, + ret = devm_regulator_bulk_get(&st->spi->dev, ARRAY_SIZE(st->vref_reg), st->vref_reg); if (ret) { dev_err(&spi->dev, "Failed to request vref regulators: %d\n", ret); - goto error_free; + return ret; } ret = regulator_bulk_enable(ARRAY_SIZE(st->vref_reg), @@ -311,7 +311,7 @@ static int ad5764_probe(struct spi_device *spi) if (ret) { dev_err(&spi->dev, "Failed to enable vref regulators: %d\n", ret); - goto error_free_reg; + return ret; } } @@ -326,12 +326,6 @@ static int ad5764_probe(struct spi_device *spi) error_disable_reg: if (st->chip_info->int_vref == 0) regulator_bulk_disable(ARRAY_SIZE(st->vref_reg), st->vref_reg); -error_free_reg: - if (st->chip_info->int_vref == 0) - regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg); -error_free: - iio_device_free(indio_dev); - return ret; } @@ -342,12 +336,8 @@ static int ad5764_remove(struct spi_device *spi) iio_device_unregister(indio_dev); - if (st->chip_info->int_vref == 0) { + if (st->chip_info->int_vref == 0) regulator_bulk_disable(ARRAY_SIZE(st->vref_reg), st->vref_reg); - regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg); - } - - iio_device_free(indio_dev); return 0; } -- cgit v0.10.2 From 0d7c04d33f3e2f9e3da0a545be747731b4410e32 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 19 Aug 2013 12:38:00 +0100 Subject: iio: dac: ad5791: Use devm_* APIs devm_* APIs are device managed and make code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index 97c1e5d..ce74589 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c @@ -349,17 +349,15 @@ static int ad5791_probe(struct spi_device *spi) struct ad5791_state *st; int ret, pos_voltage_uv = 0, neg_voltage_uv = 0; - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; st = iio_priv(indio_dev); - st->reg_vdd = regulator_get(&spi->dev, "vdd"); + st->reg_vdd = devm_regulator_get(&spi->dev, "vdd"); if (!IS_ERR(st->reg_vdd)) { ret = regulator_enable(st->reg_vdd); if (ret) - goto error_put_reg_pos; + return ret; ret = regulator_get_voltage(st->reg_vdd); if (ret < 0) @@ -368,11 +366,11 @@ static int ad5791_probe(struct spi_device *spi) pos_voltage_uv = ret; } - st->reg_vss = regulator_get(&spi->dev, "vss"); + st->reg_vss = devm_regulator_get(&spi->dev, "vss"); if (!IS_ERR(st->reg_vss)) { ret = regulator_enable(st->reg_vss); if (ret) - goto error_put_reg_neg; + goto error_disable_reg_pos; ret = regulator_get_voltage(st->reg_vss); if (ret < 0) @@ -428,19 +426,9 @@ static int ad5791_probe(struct spi_device *spi) error_disable_reg_neg: if (!IS_ERR(st->reg_vss)) regulator_disable(st->reg_vss); -error_put_reg_neg: - if (!IS_ERR(st->reg_vss)) - regulator_put(st->reg_vss); - error_disable_reg_pos: if (!IS_ERR(st->reg_vdd)) regulator_disable(st->reg_vdd); -error_put_reg_pos: - if (!IS_ERR(st->reg_vdd)) - regulator_put(st->reg_vdd); - iio_device_free(indio_dev); -error_ret: - return ret; } @@ -450,16 +438,11 @@ static int ad5791_remove(struct spi_device *spi) struct ad5791_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (!IS_ERR(st->reg_vdd)) { + if (!IS_ERR(st->reg_vdd)) regulator_disable(st->reg_vdd); - regulator_put(st->reg_vdd); - } - if (!IS_ERR(st->reg_vss)) { + if (!IS_ERR(st->reg_vss)) regulator_disable(st->reg_vss); - regulator_put(st->reg_vss); - } - iio_device_free(indio_dev); return 0; } -- cgit v0.10.2 From 66e670aa0805e553e2647da37502759967f026d3 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 19 Aug 2013 12:38:00 +0100 Subject: iio: dac: ad7303: Use devm_* APIs devm_* APIs are device managed and make code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c index d546f50..ed2d276 100644 --- a/drivers/iio/dac/ad7303.c +++ b/drivers/iio/dac/ad7303.c @@ -203,7 +203,7 @@ static int ad7303_probe(struct spi_device *spi) bool ext_ref; int ret; - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -212,15 +212,13 @@ static int ad7303_probe(struct spi_device *spi) st->spi = spi; - st->vdd_reg = regulator_get(&spi->dev, "Vdd"); - if (IS_ERR(st->vdd_reg)) { - ret = PTR_ERR(st->vdd_reg); - goto err_free; - } + st->vdd_reg = devm_regulator_get(&spi->dev, "Vdd"); + if (IS_ERR(st->vdd_reg)) + return PTR_ERR(st->vdd_reg); ret = regulator_enable(st->vdd_reg); if (ret) - goto err_put_vdd_reg; + return ret; if (spi->dev.of_node) { ext_ref = of_property_read_bool(spi->dev.of_node, @@ -234,7 +232,7 @@ static int ad7303_probe(struct spi_device *spi) } if (ext_ref) { - st->vref_reg = regulator_get(&spi->dev, "REF"); + st->vref_reg = devm_regulator_get(&spi->dev, "REF"); if (IS_ERR(st->vref_reg)) { ret = PTR_ERR(st->vref_reg); goto err_disable_vdd_reg; @@ -242,7 +240,7 @@ static int ad7303_probe(struct spi_device *spi) ret = regulator_enable(st->vref_reg); if (ret) - goto err_put_vref_reg; + goto err_disable_vdd_reg; st->config |= AD7303_CFG_EXTERNAL_VREF; } @@ -263,16 +261,8 @@ static int ad7303_probe(struct spi_device *spi) err_disable_vref_reg: if (st->vref_reg) regulator_disable(st->vref_reg); -err_put_vref_reg: - if (st->vref_reg) - regulator_put(st->vref_reg); err_disable_vdd_reg: regulator_disable(st->vdd_reg); -err_put_vdd_reg: - regulator_put(st->vdd_reg); -err_free: - iio_device_free(indio_dev); - return ret; } @@ -283,14 +273,9 @@ static int ad7303_remove(struct spi_device *spi) iio_device_unregister(indio_dev); - if (st->vref_reg) { + if (st->vref_reg) regulator_disable(st->vref_reg); - regulator_put(st->vref_reg); - } regulator_disable(st->vdd_reg); - regulator_put(st->vdd_reg); - - iio_device_free(indio_dev); return 0; } -- cgit v0.10.2 From cc566fd5e52d64554d294b4d36f9d593cbe797d5 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 19 Aug 2013 12:38:00 +0100 Subject: iio: dac: max517: Use devm_iio_device_alloc Using devm_iio_device_alloc makes code simpler. Signed-off-by: Sachin Kamat Cc: Roland Stigge Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c index ebfaa41..83adcbf 100644 --- a/drivers/iio/dac/max517.c +++ b/drivers/iio/dac/max517.c @@ -164,11 +164,9 @@ static int max517_probe(struct i2c_client *client, struct max517_platform_data *platform_data = client->dev.platform_data; int err; - indio_dev = iio_device_alloc(sizeof(*data)); - if (indio_dev == NULL) { - err = -ENOMEM; - goto exit; - } + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); data->client = client; @@ -198,23 +196,16 @@ static int max517_probe(struct i2c_client *client, err = iio_device_register(indio_dev); if (err) - goto exit_free_device; + return err; dev_info(&client->dev, "DAC registered\n"); return 0; - -exit_free_device: - iio_device_free(indio_dev); -exit: - return err; } static int max517_remove(struct i2c_client *client) { iio_device_unregister(i2c_get_clientdata(client)); - iio_device_free(i2c_get_clientdata(client)); - return 0; } -- cgit v0.10.2