From f45c69b1136078bb35ee0f1cb89ae92fd9bc5cd0 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 12 Sep 2012 07:07:00 +0100 Subject: [PATCH 01/22] HID: sensors: fix up for mfd_add_devices() API change Signed-off-by: Stephen Rothwell Signed-off-by: Jonathan Cameron --- drivers/hid/hid-sensor-hub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 34a35ba95fc1..4ac759c1fe22 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -596,7 +596,7 @@ static int sensor_hub_probe(struct hid_device *hdev, } } ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs, - sd->hid_sensor_client_cnt, NULL, 0); + sd->hid_sensor_client_cnt, NULL, 0, NULL); if (ret < 0) goto err_free_names; From 2b7c4b8e3edfd109a8423ff593a12a5fe09615b2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 14 Sep 2012 06:53:23 +0000 Subject: [PATCH 02/22] HID: sensors: use GFP_ATOMIC under spinlock We're holding a spinlock here so we can't call kmalloc() with GFP_KERNEL. Signed-off-by: Dan Carpenter Signed-off-by: Jiri Kosina Signed-off-by: Jonathan Cameron --- drivers/hid/hid-sensor-hub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 4ac759c1fe22..0c93b10b0813 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -173,7 +173,7 @@ int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev, spin_unlock(&pdata->dyn_callback_lock); return -EINVAL; } - callback = kzalloc(sizeof(*callback), GFP_KERNEL); + callback = kzalloc(sizeof(*callback), GFP_ATOMIC); if (!callback) { spin_unlock(&pdata->dyn_callback_lock); return -ENOMEM; @@ -462,7 +462,7 @@ static int sensor_hub_raw_event(struct hid_device *hdev, if (pdata->pending.status && pdata->pending.attr_usage_id == report->field[i]->usage->hid) { hid_dbg(hdev, "data was pending ...\n"); - pdata->pending.raw_data = kmalloc(sz, GFP_KERNEL); + pdata->pending.raw_data = kmalloc(sz, GFP_ATOMIC); if (pdata->pending.raw_data) { memcpy(pdata->pending.raw_data, ptr, sz); pdata->pending.raw_size = sz; From 24db0d75d3666b2aa5950a8bec0c1898929f2945 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 14 Sep 2012 06:53:46 +0000 Subject: [PATCH 03/22] HID: sensors: remove some unneeded checks "report_id" is unsigned so it's never less than zero. These checks can be removed without any problem. Signed-off-by: Dan Carpenter Signed-off-by: Jiri Kosina Signed-off-by: Jonathan Cameron --- drivers/hid/hid-sensor-hub.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 0c93b10b0813..22ec3c69a799 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -214,9 +214,6 @@ int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); int ret = 0; - if (report_id < 0) - return -EINVAL; - mutex_lock(&data->mutex); report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT); if (!report || (field_index >= report->maxfield)) { @@ -241,9 +238,6 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); int ret = 0; - if (report_id < 0) - return -EINVAL; - mutex_lock(&data->mutex); report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT); if (!report || (field_index >= report->maxfield)) { @@ -271,9 +265,6 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, struct hid_report *report; int ret_val = 0; - if (report_id < 0) - return -EINVAL; - mutex_lock(&data->mutex); memset(&data->pending, 0, sizeof(data->pending)); init_completion(&data->pending.ready); From f07b60b7c34b771431f1d00e783f29a3667ff5ee Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 20 Sep 2012 01:15:00 +0100 Subject: [PATCH 04/22] iio: hid-sensors: Prevent crash during hot-unplug When hid sensor hub is unplugged, there is a crash in iio_device_unregister_trigger_consumer. In a typical IIO driver when remove is called, it will unregister and free trigger and then it will call iio_device_free. The function iio_trigger_free() will free the allocated memory for trigger. If this trigger was assigned to iio_dev->trig, then it should be set to NULL. Othewise when iio_device_free() is called later, it finally calls iio_device_unregsister_trigger(), which checks for if (indio_dev->trig) iio_trigger_put(indio_dev->trig); If indio_dev->trig is not set to NULL, it calls iio_trigger_put on a bad pointer causing crash. This scenerio can happen in any driver, which is storing trigger pointer in iio_dev structure and following current procedure during remove. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/common/hid-sensors/hid-sensor-trigger.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index 12277e8bbd80..d4b790d18efb 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -56,6 +56,7 @@ void hid_sensor_remove_trigger(struct iio_dev *indio_dev) { iio_trigger_unregister(indio_dev->trig); iio_trigger_free(indio_dev->trig); + indio_dev->trig = NULL; } EXPORT_SYMBOL(hid_sensor_remove_trigger); From 369d0e20138c774e4c0c07ca1572e412207bc3fc Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 19 Sep 2012 07:27:00 +0100 Subject: [PATCH 05/22] iio: dac/ad5755: signedness bug in ad5755_setup_pdata() We need "ret" to be signed for the error handling to work correctly. Signed-off-by: Dan Carpenter Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5755.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c index e6dbe5ff7e5a..5db3506034c5 100644 --- a/drivers/iio/dac/ad5755.c +++ b/drivers/iio/dac/ad5755.c @@ -451,9 +451,9 @@ static int __devinit ad5755_setup_pdata(struct iio_dev *indio_dev, const struct ad5755_platform_data *pdata) { struct ad5755_state *st = iio_priv(indio_dev); - unsigned int ret; unsigned int val; unsigned int i; + int ret; if (pdata->dc_dc_phase > AD5755_DC_DC_PHASE_90_DEGREE || pdata->dc_dc_freq > AD5755_DC_DC_FREQ_650kHZ || From 801c4b5ca373c4cfe78912616d68e1f7fd84110c Mon Sep 17 00:00:00 2001 From: "Kim, Milo" Date: Tue, 18 Sep 2012 05:55:00 +0100 Subject: [PATCH 06/22] iio: inkern: put the IIO device when it fails to allocate memory The reference count of the IIO device is increased if the IIO map has matched consumer name. After then, it tries to allocate the iio_channel which is used by the consumer. If it fails to allocate memory, the reference count should be decreased. This patch enables restoring the reference count of the IIO device. Signed-off-by: Milo(Woogyom) Kim Signed-off-by: Jonathan Cameron --- drivers/iio/inkern.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 25b00761005a..e38f41464fe4 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -132,7 +132,7 @@ struct iio_channel *iio_channel_get(const char *name, const char *channel_name) channel = kzalloc(sizeof(*channel), GFP_KERNEL); if (channel == NULL) - return ERR_PTR(-ENOMEM); + goto error_no_mem; channel->indio_dev = c->indio_dev; @@ -151,6 +151,9 @@ struct iio_channel *iio_channel_get(const char *name, const char *channel_name) iio_device_put(c->indio_dev); kfree(channel); return ERR_PTR(-EINVAL); +error_no_mem: + iio_device_put(c->indio_dev); + return ERR_PTR(-ENOMEM); } EXPORT_SYMBOL_GPL(iio_channel_get); From 3183bac16f537503eb3177773781d6d3059ad7b1 Mon Sep 17 00:00:00 2001 From: "Kim, Milo" Date: Tue, 18 Sep 2012 05:56:00 +0100 Subject: [PATCH 07/22] iio: inkern: clean up error return code When the IIO consumer tries to get specific IIO channel, few error cases can be happened. (a) Memory allocation failure (b) No matched ADC channel error (c) Invalid input arguments This patch enables cleaning up error handling in case of (a) and (b). In error handling code, (a): the reference count of the IIO device should be decreased. (b): the allocated memory should be freed with restoring the reference count. Therefore iio_deivce_put() is called in both cases. This can be handled in the last error statement. Additionally, integer variable is used for stating each error case explicitly. Then, the error returns as ERR_PTR() with this value. Signed-off-by: Milo(Woogyom) Kim Signed-off-by: Jonathan Cameron --- drivers/iio/inkern.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index e38f41464fe4..f2b78d4fe457 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -111,6 +111,7 @@ struct iio_channel *iio_channel_get(const char *name, const char *channel_name) { struct iio_map_internal *c_i = NULL, *c = NULL; struct iio_channel *channel; + int err; if (name == NULL && channel_name == NULL) return ERR_PTR(-ENODEV); @@ -131,8 +132,10 @@ struct iio_channel *iio_channel_get(const char *name, const char *channel_name) return ERR_PTR(-ENODEV); channel = kzalloc(sizeof(*channel), GFP_KERNEL); - if (channel == NULL) + if (channel == NULL) { + err = -ENOMEM; goto error_no_mem; + } channel->indio_dev = c->indio_dev; @@ -141,19 +144,19 @@ struct iio_channel *iio_channel_get(const char *name, const char *channel_name) iio_chan_spec_from_name(channel->indio_dev, c->map->adc_channel_label); - if (channel->channel == NULL) + if (channel->channel == NULL) { + err = -EINVAL; goto error_no_chan; + } } return channel; error_no_chan: - iio_device_put(c->indio_dev); kfree(channel); - return ERR_PTR(-EINVAL); error_no_mem: iio_device_put(c->indio_dev); - return ERR_PTR(-ENOMEM); + return ERR_PTR(err); } EXPORT_SYMBOL_GPL(iio_channel_get); From bea3e8a31f42269318378461ee2663b17957b165 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 22 Sep 2012 09:56:00 +0100 Subject: [PATCH 08/22] staging:iio:adis16200: Do not return a error in remove function In the Linux device driver model the remove callback is not allowed to fail and the device will be removed regardless of the return value of the remove callback. So if we abort in the remove function and do not free all resources we will create a resource leak. Also all kinds of undefined behaviour are expected to happen since the IIO device is still there while its parent is already gone. The error which the driver tries to handle in the remove function is non-critical, so we can just ignore it and continue to free all resources and remove the IIO device. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/gyro/adis16260_core.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c index 1d58d0e2b397..9571c03aa4cc 100644 --- a/drivers/staging/iio/gyro/adis16260_core.c +++ b/drivers/staging/iio/gyro/adis16260_core.c @@ -702,22 +702,16 @@ static int __devinit adis16260_probe(struct spi_device *spi) static int __devexit adis16260_remove(struct spi_device *spi) { - int ret; struct iio_dev *indio_dev = spi_get_drvdata(spi); iio_device_unregister(indio_dev); - - ret = adis16260_stop_device(indio_dev); - if (ret) - goto err_ret; - + adis16260_stop_device(indio_dev); adis16260_remove_trigger(indio_dev); iio_buffer_unregister(indio_dev); adis16260_unconfigure_ring(indio_dev); iio_device_free(indio_dev); -err_ret: - return ret; + return 0; } /* From 0b4ac3dce4093f426322be0eec0e38127a62bb7f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 22 Sep 2012 09:56:00 +0100 Subject: [PATCH 09/22] staging:iio:adis16400: Do not return a error in remove function In the Linux device driver model the remove callback is not allowed to fail and the device will be removed regardless of the return value of the remove callback. So if we abort in the remove function and do not free all resources we will create a resource leak. Also all kinds of undefined behaviour are expected to happen since the IIO device is still there while its parent is already gone. The error which the driver tries to handle in the remove function is non-critical, so we can just ignore it and continue to free all resources and remove the IIO device. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/imu/adis16400_core.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index b8c280cb8865..b302c9ba2712 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -1208,13 +1208,10 @@ static int __devinit adis16400_probe(struct spi_device *spi) /* fixme, confirm ordering in this function */ static int __devexit adis16400_remove(struct spi_device *spi) { - int ret; struct iio_dev *indio_dev = spi_get_drvdata(spi); iio_device_unregister(indio_dev); - ret = adis16400_stop_device(indio_dev); - if (ret) - goto err_ret; + adis16400_stop_device(indio_dev); adis16400_remove_trigger(indio_dev); iio_buffer_unregister(indio_dev); @@ -1222,9 +1219,6 @@ static int __devexit adis16400_remove(struct spi_device *spi) iio_device_free(indio_dev); return 0; - -err_ret: - return ret; } static const struct spi_device_id adis16400_id[] = { From d576c7558616e3c096fca1f21531e1e50d2f27ca Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 22 Sep 2012 09:56:00 +0100 Subject: [PATCH 10/22] staging:iio:ade7753: Do not return a error in remove function In the Linux device driver model the remove callback is not allowed to fail and the device will be removed regardless of the return value of the remove callback. So if we abort in the remove function and do not free all resources we will create a resource leak. Also all kinds of undefined behaviour are expected to happen since the IIO device is still there while its parent is already gone. The error which the driver tries to handle in the remove function is non-critical, so we can just ignore it and continue to free all resources and remove the IIO device. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/meter/ade7753.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c index 380c05e7f7ff..8b9eceb66b37 100644 --- a/drivers/staging/iio/meter/ade7753.c +++ b/drivers/staging/iio/meter/ade7753.c @@ -557,18 +557,13 @@ static int __devinit ade7753_probe(struct spi_device *spi) /* fixme, confirm ordering in this function */ static int __devexit ade7753_remove(struct spi_device *spi) { - int ret; struct iio_dev *indio_dev = spi_get_drvdata(spi); iio_device_unregister(indio_dev); - - ret = ade7753_stop_device(&(indio_dev->dev)); - if (ret) - goto err_ret; - + ade7753_stop_device(&indio_dev->dev); iio_device_free(indio_dev); -err_ret: - return ret; + + return 0; } static struct spi_driver ade7753_driver = { From db314a1aaa2c0aa262f24e14c81b91b09e72e470 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 22 Sep 2012 09:56:00 +0100 Subject: [PATCH 11/22] staging:iio:ade7754: Do not return a error in remove function In the Linux device driver model the remove callback is not allowed to fail and the device will be removed regardless of the return value of the remove callback. So if we abort in the remove function and do not free all resources we will create a resource leak. Also all kinds of undefined behaviour are expected to happen since the IIO device is still there while its parent is already gone. The error which the driver tries to handle in the remove function is non-critical, so we can just ignore it and continue to free all resources and remove the IIO device. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/meter/ade7754.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c index 7dea7fdb9a61..76e0adee96ea 100644 --- a/drivers/staging/iio/meter/ade7754.c +++ b/drivers/staging/iio/meter/ade7754.c @@ -579,19 +579,13 @@ static int __devinit ade7754_probe(struct spi_device *spi) /* fixme, confirm ordering in this function */ static int __devexit ade7754_remove(struct spi_device *spi) { - int ret; struct iio_dev *indio_dev = spi_get_drvdata(spi); iio_device_unregister(indio_dev); - ret = ade7754_stop_device(&(indio_dev->dev)); - if (ret) - goto err_ret; - + ade7754_stop_device(&indio_dev->dev); iio_device_free(indio_dev); -err_ret: - return ret; - + return 0; } static struct spi_driver ade7754_driver = { From 4922fd697a573cfc519668b3013a7f8de97c4ae7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 22 Sep 2012 09:56:00 +0100 Subject: [PATCH 12/22] staging:iio:ade7758: Do not return a error in remove function In the Linux device driver model the remove callback is not allowed to fail and the device will be removed regardless of the return value of the remove callback. So if we abort in the remove function and do not free all resources we will create a resource leak. Also all kinds of undefined behaviour are expected to happen since the IIO device is still there while its parent is already gone. The error which the driver tries to handle in the remove function is non-critical, so we can just ignore it and continue to free all resources and remove the IIO device. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/meter/ade7758_core.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c index 958f8f235b42..a0fef77d8e5e 100644 --- a/drivers/staging/iio/meter/ade7758_core.c +++ b/drivers/staging/iio/meter/ade7758_core.c @@ -966,13 +966,9 @@ static int __devexit ade7758_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ade7758_state *st = iio_priv(indio_dev); - int ret; iio_device_unregister(indio_dev); - ret = ade7758_stop_device(&indio_dev->dev); - if (ret) - goto err_ret; - + ade7758_stop_device(&indio_dev->dev); ade7758_remove_trigger(indio_dev); ade7758_uninitialize_ring(indio_dev); ade7758_unconfigure_ring(indio_dev); @@ -981,8 +977,7 @@ static int __devexit ade7758_remove(struct spi_device *spi) iio_device_free(indio_dev); -err_ret: - return ret; + return 0; } static const struct spi_device_id ade7758_id[] = { From e854bcc938e734e2f556bc7ada9552669b8f58b0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 22 Sep 2012 09:56:00 +0100 Subject: [PATCH 13/22] staging:iio:ade7759: Do not return a error in remove function In the Linux device driver model the remove callback is not allowed to fail and the device will be removed regardless of the return value of the remove callback. So if we abort in the remove function and do not free all resources we will create a resource leak. Also all kinds of undefined behaviour are expected to happen since the IIO device is still there while its parent is already gone. The error which the driver tries to handle in the remove function is non-critical, so we can just ignore it and continue to free all resources and remove the IIO device. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/meter/ade7759.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c index 435e35bd9c82..cb0707cbc347 100644 --- a/drivers/staging/iio/meter/ade7759.c +++ b/drivers/staging/iio/meter/ade7759.c @@ -501,18 +501,13 @@ static int __devinit ade7759_probe(struct spi_device *spi) /* fixme, confirm ordering in this function */ static int __devexit ade7759_remove(struct spi_device *spi) { - int ret; struct iio_dev *indio_dev = spi_get_drvdata(spi); iio_device_unregister(indio_dev); - ret = ade7759_stop_device(&(indio_dev->dev)); - if (ret) - goto err_ret; - + ade7759_stop_device(&indio_dev->dev); iio_device_free(indio_dev); -err_ret: - return ret; + return 0; } static struct spi_driver ade7759_driver = { From e71a837c810587e12620c957f1464c0674220d51 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 22 Sep 2012 09:56:00 +0100 Subject: [PATCH 14/22] staging:iio:lis3l02dq: Do not return a error in remove function In the Linux device driver model the remove callback is not allowed to fail and the device will be removed regardless of the return value of the remove callback. So if we abort in the remove function and do not free all resources we will create a resource leak. Also all kinds of undefined behaviour are expected to happen since the IIO device is still there while its parent is already gone. The errors which the driver tries to handle in the remove function are non-critical, so we can just ignore them and continue to free all resources and remove the IIO device. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/accel/lis3l02dq_core.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c index d900d63d5a5b..21b0469f8bc2 100644 --- a/drivers/staging/iio/accel/lis3l02dq_core.c +++ b/drivers/staging/iio/accel/lis3l02dq_core.c @@ -782,19 +782,13 @@ static int lis3l02dq_stop_device(struct iio_dev *indio_dev) /* fixme, confirm ordering in this function */ static int __devexit lis3l02dq_remove(struct spi_device *spi) { - int ret; struct iio_dev *indio_dev = spi_get_drvdata(spi); struct lis3l02dq_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); - ret = lis3l02dq_disable_all_events(indio_dev); - if (ret) - goto err_ret; - - ret = lis3l02dq_stop_device(indio_dev); - if (ret) - goto err_ret; + lis3l02dq_disable_all_events(indio_dev); + lis3l02dq_stop_device(indio_dev); if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) free_irq(st->us->irq, indio_dev); @@ -804,8 +798,8 @@ static int __devexit lis3l02dq_remove(struct spi_device *spi) lis3l02dq_unconfigure_buffer(indio_dev); iio_device_free(indio_dev); -err_ret: - return ret; + + return 0; } static struct spi_driver lis3l02dq_driver = { From 67ad4e08dcc772153fda90cc747cfc9e03ab44f6 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 22 Sep 2012 09:56:00 +0100 Subject: [PATCH 15/22] staging:iio:sca3000: Do not return a error in remove function In the Linux device driver model the remove callback is not allowed to fail and the device will be removed regardless of the return value of the remove callback. So if we abort in the remove function and do not free all resources we will create a resource leak. Also all kinds of undefined behaviour are expected to happen since the IIO device is still there while its parent is already gone. The errors which the driver tries to handle in the remove function are non-critical, so we can just ignore them and continue to free all resources and remove the IIO device. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/accel/sca3000_core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c index 6d72d97fb9e5..ffd1697a9db0 100644 --- a/drivers/staging/iio/accel/sca3000_core.c +++ b/drivers/staging/iio/accel/sca3000_core.c @@ -1237,11 +1237,9 @@ static int __devexit sca3000_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct sca3000_state *st = iio_priv(indio_dev); - int ret; + /* Must ensure no interrupts can be generated after this!*/ - ret = sca3000_stop_all_interrupts(st); - if (ret) - return ret; + sca3000_stop_all_interrupts(st); if (spi->irq) free_irq(spi->irq, indio_dev); iio_device_unregister(indio_dev); From 332ed63ee9ec0b899cf6d03eecd85bebe1b8e943 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 21 Sep 2012 14:29:00 +0100 Subject: [PATCH 16/22] staging:iio:ad7780: Make powerdown GPIO optional Some designs hardwire the PDRST pin to always on. In this case there is no GPIO to control the mode of the device, so make the GPIO optional. Since now all of the the platform data fields are optional now, make the platform data as a whole optional as well. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7780.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/staging/iio/adc/ad7780.c b/drivers/staging/iio/adc/ad7780.c index 5f807ce3bf11..1dd7cdb1dbc8 100644 --- a/drivers/staging/iio/adc/ad7780.c +++ b/drivers/staging/iio/adc/ad7780.c @@ -73,7 +73,8 @@ static int ad7780_set_mode(struct ad_sigma_delta *sigma_delta, break; } - gpio_set_value(st->powerdown_gpio, val); + if (gpio_is_valid(st->powerdown_gpio)) + gpio_set_value(st->powerdown_gpio, val); return 0; } @@ -148,11 +149,6 @@ static int __devinit ad7780_probe(struct spi_device *spi) struct iio_dev *indio_dev; int ret, voltage_uv = 0; - if (!pdata) { - dev_dbg(&spi->dev, "no platform data?\n"); - return -ENODEV; - } - indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -174,8 +170,6 @@ static int __devinit ad7780_probe(struct spi_device *spi) st->chip_info = &ad7780_chip_info_tbl[spi_get_device_id(spi)->driver_data]; - st->powerdown_gpio = pdata->gpio_pdrst; - if (pdata && pdata->vref_mv) st->int_vref_mv = pdata->vref_mv; else if (voltage_uv) @@ -192,11 +186,17 @@ static int __devinit ad7780_probe(struct spi_device *spi) indio_dev->num_channels = 1; indio_dev->info = &ad7780_info; - ret = gpio_request_one(pdata->gpio_pdrst, GPIOF_OUT_INIT_LOW, + if (pdata && gpio_is_valid(pdata->gpio_pdrst)) { + + ret = gpio_request_one(pdata->gpio_pdrst, GPIOF_OUT_INIT_LOW, "AD7780 /PDRST"); - if (ret) { - dev_err(&spi->dev, "failed to request GPIO PDRST\n"); - goto error_disable_reg; + if (ret) { + dev_err(&spi->dev, "failed to request GPIO PDRST\n"); + goto error_disable_reg; + } + st->powerdown_gpio = pdata->gpio_pdrst; + } else { + st->powerdown_gpio = -1; } ret = ad_sd_setup_buffer_and_trigger(indio_dev); @@ -212,7 +212,8 @@ static int __devinit ad7780_probe(struct spi_device *spi) error_cleanup_buffer_and_trigger: ad_sd_cleanup_buffer_and_trigger(indio_dev); error_free_gpio: - gpio_free(pdata->gpio_pdrst); + if (pdata && gpio_is_valid(pdata->gpio_pdrst)) + gpio_free(pdata->gpio_pdrst); error_disable_reg: if (!IS_ERR(st->reg)) regulator_disable(st->reg); @@ -233,7 +234,9 @@ static int __devexit ad7780_remove(struct spi_device *spi) iio_device_unregister(indio_dev); ad_sd_cleanup_buffer_and_trigger(indio_dev); - gpio_free(st->powerdown_gpio); + if (gpio_is_valid(st->powerdown_gpio)) + gpio_free(st->powerdown_gpio); + if (!IS_ERR(st->reg)) { regulator_disable(st->reg); regulator_put(st->reg); From 7aecec986e043f02738705328d85f97375ca6f41 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 21 Sep 2012 14:29:00 +0100 Subject: [PATCH 17/22] staging:iio:ad7780: Add support for the ad7170/ad7171 The ad7170/ad7171 have a software interface similar to the ad7780. They do not have an external pin which allows to change the internal gain and the what is used for the gain bit in the ad7780/ad7781 becomes part of the check pattern. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/Kconfig | 4 ++-- drivers/staging/iio/adc/ad7780.c | 36 ++++++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index 1b4a356639a5..a525143ecbea 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -82,12 +82,12 @@ config AD7887 module will be called ad7887. config AD7780 - tristate "Analog Devices AD7780 AD7781 ADC driver" + tristate "Analog Devices AD7780 and similar ADCs driver" depends on SPI depends on GPIOLIB select AD_SIGMA_DELTA help - Say yes here to build support for Analog Devices + Say yes here to build support for Analog Devices AD7170, AD7171, AD7780 and AD7781 SPI analog to digital converters (ADC). If unsure, say N (but it's safe to say "Y"). diff --git a/drivers/staging/iio/adc/ad7780.c b/drivers/staging/iio/adc/ad7780.c index 1dd7cdb1dbc8..0a1328b8657f 100644 --- a/drivers/staging/iio/adc/ad7780.c +++ b/drivers/staging/iio/adc/ad7780.c @@ -1,5 +1,5 @@ /* - * AD7780/AD7781 SPI ADC driver + * AD7170/AD7171 and AD7780/AD7781 SPI ADC driver * * Copyright 2011 Analog Devices Inc. * @@ -34,7 +34,9 @@ #define AD7780_PAT0 (1 << 0) struct ad7780_chip_info { - struct iio_chan_spec channel; + struct iio_chan_spec channel; + unsigned int pattern_mask; + unsigned int pattern; }; struct ad7780_state { @@ -48,6 +50,8 @@ struct ad7780_state { }; enum ad7780_supported_device_ids { + ID_AD7170, + ID_AD7171, ID_AD7780, ID_AD7781, }; @@ -109,9 +113,10 @@ static int ad7780_postprocess_sample(struct ad_sigma_delta *sigma_delta, unsigned int raw_sample) { struct ad7780_state *st = ad_sigma_delta_to_ad7780(sigma_delta); + const struct ad7780_chip_info *chip_info = st->chip_info; if ((raw_sample & AD7780_ERR) || - !((raw_sample & AD7780_PAT0) && !(raw_sample & AD7780_PAT1))) + ((raw_sample & chip_info->pattern_mask) != chip_info->pattern)) return -EIO; if (raw_sample & AD7780_GAIN) @@ -128,12 +133,29 @@ static const struct ad_sigma_delta_info ad7780_sigma_delta_info = { .has_registers = false, }; +#define AD7780_CHANNEL(bits, wordsize) \ + AD_SD_CHANNEL(1, 0, 0, bits, 32, wordsize - bits) + static const struct ad7780_chip_info ad7780_chip_info_tbl[] = { + [ID_AD7170] = { + .channel = AD7780_CHANNEL(12, 24), + .pattern = 0x5, + .pattern_mask = 0x7, + }, + [ID_AD7171] = { + .channel = AD7780_CHANNEL(16, 24), + .pattern = 0x5, + .pattern_mask = 0x7, + }, [ID_AD7780] = { - .channel = AD_SD_CHANNEL(1, 0, 0, 24, 32, 8), + .channel = AD7780_CHANNEL(24, 32), + .pattern = 0x1, + .pattern_mask = 0x3, }, [ID_AD7781] = { - .channel = AD_SD_CHANNEL(1, 0, 0, 20, 32, 12), + .channel = AD7780_CHANNEL(20, 32), + .pattern = 0x1, + .pattern_mask = 0x3, }, }; @@ -247,6 +269,8 @@ static int __devexit ad7780_remove(struct spi_device *spi) } static const struct spi_device_id ad7780_id[] = { + {"ad7170", ID_AD7170}, + {"ad7171", ID_AD7171}, {"ad7780", ID_AD7780}, {"ad7781", ID_AD7781}, {} @@ -265,5 +289,5 @@ static struct spi_driver ad7780_driver = { module_spi_driver(ad7780_driver); MODULE_AUTHOR("Michael Hennerich "); -MODULE_DESCRIPTION("Analog Devices AD7780/1 ADC"); +MODULE_DESCRIPTION("Analog Devices AD7780 and similar ADCs"); MODULE_LICENSE("GPL v2"); From f0347c36ccd7cfd31c8af10509d4110f0a769a85 Mon Sep 17 00:00:00 2001 From: "Kim, Milo" Date: Mon, 17 Sep 2012 10:35:00 +0100 Subject: [PATCH 18/22] iio: adc: add new lp8788 adc driver TI LP8788 PMU provides regulators, battery charger, ADC, RTC, backlight driver and current sinks. This patch enables the LP8788 ADC functions. The LP8788 ADC has several ADC input selection and supports 12bit resolution. Internal operation of getting ADC is access to registers of LP8788. The LP8788 ADC uses exported functions for accessing these registers. (exported by LP8788 MFD device driver) This driver supports IIO_CHAN_INFO_RAW and SCALE. So the IIO consumer can calculate the value with raw and scale. The unit of scale is micro. (ADC Input Selection) Voltage: battery voltage (MAX 5.0, 5.5 and 6.0V) charger input voltage four general ADC inputs coin cell voltage Current: battery charging current Temperature: IC temperature (The IIO map for the IIO consumer) The ADC input is configurable in the platform side. Even though this platform data is not defined, the default IIO map is created for supporting the power supply driver. The battery voltage and temperature are used inside this driver. (History) Patch v6. (a) Fix scale value for each ADC input selection Voltage and current type are mili unit and temperature is degree. To calculate the IC temperature, temp = raw * scaleint + (raw * scalepart)/ 1000000, scaleint is always 0. = raw * 0.061050, raw: 0 ~ 4095 Then range of IC temperature(ADC result) is 0 ~ 250'C (b) Reorganization of the IIO channel Spec Remove address, scan_type and scan_index and rollback the datasheet name. The reason why 'address' field is unnecessary is no relation with each channel. Moreover, to get the raw ADC value, the address info is not only one register but also several registers. Therefore specific function(lp8788_get_adc_result) is called rather than using one 'address' field. (c) Fix coding style Remove duplicated checking routine while unregistering the IIO map. Fix code for space and parenthesis. Patch v5. Fix default consumer name as 'lp8788-charger'. Add mutex for ADC read operation. Reorganization on lp8788_adc_read_raw(). Patch v4. Fix adc_raw function: support RAW and SCALE channel info. Change LP8788 ADC platform data - iio map. Enables the default IIO map. Patch v3. Fix wrong size of allocating iio private data. Fix coding styles. Patch v2. Support RAW and SCALE interface for IIO consumer. Clean up the iio channel spec macro. Signed-off-by: Milo(Woogyom) Kim Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 6 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/lp8788_adc.c | 264 +++++++++++++++++++++++++++++++++++ 3 files changed, 271 insertions(+) create mode 100644 drivers/iio/adc/lp8788_adc.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 03791a6de349..492758120338 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -54,4 +54,10 @@ config AT91_ADC help Say yes here to build support for Atmel AT91 ADC. +config LP8788_ADC + bool "LP8788 ADC driver" + depends on MFD_LP8788 + help + Say yes here to build support for TI LP8788 ADC. + endmenu diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 9824a70f4fd8..900995d5e179 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_AD7266) += ad7266.o obj-$(CONFIG_AD7476) += ad7476.o obj-$(CONFIG_AD7791) += ad7791.o obj-$(CONFIG_AT91_ADC) += at91_adc.o +obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o diff --git a/drivers/iio/adc/lp8788_adc.c b/drivers/iio/adc/lp8788_adc.c new file mode 100644 index 000000000000..a93aaf0bb841 --- /dev/null +++ b/drivers/iio/adc/lp8788_adc.c @@ -0,0 +1,264 @@ +/* + * TI LP8788 MFD - ADC driver + * + * Copyright 2012 Texas Instruments + * + * Author: Milo(Woogyom) Kim + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* register address */ +#define LP8788_ADC_CONF 0x60 +#define LP8788_ADC_RAW 0x61 +#define LP8788_ADC_DONE 0x63 + +#define ADC_CONV_START 1 + +struct lp8788_adc { + struct lp8788 *lp; + struct iio_map *map; + struct mutex lock; +}; + +static const int lp8788_scale[LPADC_MAX] = { + [LPADC_VBATT_5P5] = 1343101, + [LPADC_VIN_CHG] = 3052503, + [LPADC_IBATT] = 610500, + [LPADC_IC_TEMP] = 61050, + [LPADC_VBATT_6P0] = 1465201, + [LPADC_VBATT_5P0] = 1221001, + [LPADC_ADC1] = 610500, + [LPADC_ADC2] = 610500, + [LPADC_VDD] = 1025641, + [LPADC_VCOIN] = 757020, + [LPADC_ADC3] = 610500, + [LPADC_ADC4] = 610500, +}; + +static int lp8788_get_adc_result(struct lp8788_adc *adc, enum lp8788_adc_id id, + int *val) +{ + unsigned int msb; + unsigned int lsb; + unsigned int result; + u8 data; + u8 rawdata[2]; + int size = ARRAY_SIZE(rawdata); + int retry = 5; + int ret; + + data = (id << 1) | ADC_CONV_START; + ret = lp8788_write_byte(adc->lp, LP8788_ADC_CONF, data); + if (ret) + goto err_io; + + /* retry until adc conversion is done */ + data = 0; + while (retry--) { + usleep_range(100, 200); + + ret = lp8788_read_byte(adc->lp, LP8788_ADC_DONE, &data); + if (ret) + goto err_io; + + /* conversion done */ + if (data) + break; + } + + ret = lp8788_read_multi_bytes(adc->lp, LP8788_ADC_RAW, rawdata, size); + if (ret) + goto err_io; + + msb = (rawdata[0] << 4) & 0x00000ff0; + lsb = (rawdata[1] >> 4) & 0x0000000f; + result = msb | lsb; + *val = result; + + return 0; + +err_io: + return ret; +} + +static int lp8788_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct lp8788_adc *adc = iio_priv(indio_dev); + enum lp8788_adc_id id = chan->channel; + int ret; + + mutex_lock(&adc->lock); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = lp8788_get_adc_result(adc, id, val) ? -EIO : IIO_VAL_INT; + break; + case IIO_CHAN_INFO_SCALE: + *val = lp8788_scale[id] / 1000000; + *val2 = lp8788_scale[id] % 1000000; + ret = IIO_VAL_INT_PLUS_MICRO; + break; + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&adc->lock); + + return ret; +} + +static const struct iio_info lp8788_adc_info = { + .read_raw = &lp8788_adc_read_raw, + .driver_module = THIS_MODULE, +}; + +#define LP8788_CHAN(_id, _type) { \ + .type = _type, \ + .indexed = 1, \ + .channel = LPADC_##_id, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ + .datasheet_name = #_id, \ +} + +static const struct iio_chan_spec lp8788_adc_channels[] = { + [LPADC_VBATT_5P5] = LP8788_CHAN(VBATT_5P5, IIO_VOLTAGE), + [LPADC_VIN_CHG] = LP8788_CHAN(VIN_CHG, IIO_VOLTAGE), + [LPADC_IBATT] = LP8788_CHAN(IBATT, IIO_CURRENT), + [LPADC_IC_TEMP] = LP8788_CHAN(IC_TEMP, IIO_TEMP), + [LPADC_VBATT_6P0] = LP8788_CHAN(VBATT_6P0, IIO_VOLTAGE), + [LPADC_VBATT_5P0] = LP8788_CHAN(VBATT_5P0, IIO_VOLTAGE), + [LPADC_ADC1] = LP8788_CHAN(ADC1, IIO_VOLTAGE), + [LPADC_ADC2] = LP8788_CHAN(ADC2, IIO_VOLTAGE), + [LPADC_VDD] = LP8788_CHAN(VDD, IIO_VOLTAGE), + [LPADC_VCOIN] = LP8788_CHAN(VCOIN, IIO_VOLTAGE), + [LPADC_ADC3] = LP8788_CHAN(ADC3, IIO_VOLTAGE), + [LPADC_ADC4] = LP8788_CHAN(ADC4, IIO_VOLTAGE), +}; + +/* default maps used by iio consumer (lp8788-charger driver) */ +static struct iio_map lp8788_default_iio_maps[] = { + { + .consumer_dev_name = "lp8788-charger", + .consumer_channel = "lp8788_vbatt_5p0", + .adc_channel_label = "VBATT_5P0", + }, + { + .consumer_dev_name = "lp8788-charger", + .consumer_channel = "lp8788_adc1", + .adc_channel_label = "ADC1", + }, + { } +}; + +static int lp8788_iio_map_register(struct iio_dev *indio_dev, + struct lp8788_platform_data *pdata, + struct lp8788_adc *adc) +{ + struct iio_map *map; + int ret; + + map = (!pdata || !pdata->adc_pdata) ? + lp8788_default_iio_maps : pdata->adc_pdata; + + ret = iio_map_array_register(indio_dev, map); + if (ret) { + dev_err(adc->lp->dev, "iio map err: %d\n", ret); + return ret; + } + + adc->map = map; + return 0; +} + +static inline void lp8788_iio_map_unregister(struct iio_dev *indio_dev, + struct lp8788_adc *adc) +{ + iio_map_array_unregister(indio_dev, adc->map); +} + +static int __devinit lp8788_adc_probe(struct platform_device *pdev) +{ + struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); + struct iio_dev *indio_dev; + struct lp8788_adc *adc; + int ret; + + indio_dev = iio_device_alloc(sizeof(*adc)); + if (!indio_dev) + return -ENOMEM; + + adc = iio_priv(indio_dev); + adc->lp = lp; + platform_set_drvdata(pdev, indio_dev); + + ret = lp8788_iio_map_register(indio_dev, lp->pdata, adc); + if (ret) + goto err_iio_map; + + mutex_init(&adc->lock); + + indio_dev->dev.parent = lp->dev; + indio_dev->name = pdev->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &lp8788_adc_info; + indio_dev->channels = lp8788_adc_channels; + indio_dev->num_channels = ARRAY_SIZE(lp8788_adc_channels); + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(lp->dev, "iio dev register err: %d\n", ret); + goto err_iio_device; + } + + return 0; + +err_iio_device: + lp8788_iio_map_unregister(indio_dev, adc); +err_iio_map: + iio_device_free(indio_dev); + return ret; +} + +static int __devexit lp8788_adc_remove(struct platform_device *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct lp8788_adc *adc = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + lp8788_iio_map_unregister(indio_dev, adc); + iio_device_free(indio_dev); + + return 0; +} + +static struct platform_driver lp8788_adc_driver = { + .probe = lp8788_adc_probe, + .remove = __devexit_p(lp8788_adc_remove), + .driver = { + .name = LP8788_DEV_ADC, + .owner = THIS_MODULE, + }, +}; +module_platform_driver(lp8788_adc_driver); + +MODULE_DESCRIPTION("Texas Instruments LP8788 ADC Driver"); +MODULE_AUTHOR("Milo Kim"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:lp8788-adc"); From 3f257caf2d18fb45ab8d0fbaf71812d2b403cd0d Mon Sep 17 00:00:00 2001 From: Axel Lin <[mailto:axel.lin@gmail.com]> Date: Wed, 19 Sep 2012 16:30:00 +0100 Subject: [PATCH 19/22] HID: hid-sensor-hub: Remove hdev->claimed setting Current implementation of hid_hw_start() allows connect_mask to be 0. Setting hdev->claimed = HID_CLAIMED_INPUT before calling hid_hw_start() is not necessary. Remove it. Signed-off-by: Axel Lin Acked-by: Jiri Kosina Acked-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/hid/hid-sensor-hub.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 22ec3c69a799..0e0fad0285ab 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -530,7 +530,6 @@ static int sensor_hub_probe(struct hid_device *hdev, } INIT_LIST_HEAD(&hdev->inputs); - hdev->claimed = HID_CLAIMED_INPUT; ret = hid_hw_start(hdev, 0); if (ret) { hid_err(hdev, "hw start failed\n"); @@ -618,7 +617,6 @@ static void sensor_hub_remove(struct hid_device *hdev) int i; hid_dbg(hdev, " hardware removed\n"); - hdev->claimed &= ~HID_CLAIMED_INPUT; hid_hw_stop(hdev); hid_hw_close(hdev); spin_lock_irqsave(&data->lock, flags); From f2f13a68c37c13a7147b279b77b8fb2a36846059 Mon Sep 17 00:00:00 2001 From: Axel Lin <[mailto:axel.lin@gmail.com]> Date: Wed, 19 Sep 2012 16:30:00 +0100 Subject: [PATCH 20/22] HID: hid-sensor-hub: Fix sensor_hub_probe error handling Fix below issues: 1. In the case of goto err_close, hid_hw_stop(hdev) is called twice. Fix it. 2. If fails to allocate MFD device name, we also need to free all successfully allocated names in previous iterations. 3. In sensor_hub_remove(), Call hid_hw_close() before hid_hw_stop(). 4. Adjust unnecessary change lines for hid_err. Signed-off-by: Axel Lin Acked-by: Jiri Kosina Acked-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/hid/hid-sensor-hub.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 0e0fad0285ab..d9d73e9163eb 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -555,8 +555,7 @@ static int sensor_hub_probe(struct hid_device *hdev, sizeof(struct mfd_cell), GFP_KERNEL); if (sd->hid_sensor_hub_client_devs == NULL) { - hid_err(hdev, - "Failed to allocate memory for mfd cells\n"); + hid_err(hdev, "Failed to allocate memory for mfd cells\n"); ret = -ENOMEM; goto err_close; } @@ -568,10 +567,9 @@ static int sensor_hub_probe(struct hid_device *hdev, name = kasprintf(GFP_KERNEL, "HID-SENSOR-%x", field->physical); if (name == NULL) { - hid_err(hdev, - "Failed MFD device name\n"); + hid_err(hdev, "Failed MFD device name\n"); ret = -ENOMEM; - goto err_free_cells; + goto err_free_names; } sd->hid_sensor_hub_client_devs[ sd->hid_sensor_client_cnt].name = name; @@ -595,10 +593,8 @@ static int sensor_hub_probe(struct hid_device *hdev, err_free_names: for (i = 0; i < sd->hid_sensor_client_cnt ; ++i) kfree(sd->hid_sensor_hub_client_devs[i].name); -err_free_cells: kfree(sd->hid_sensor_hub_client_devs); err_close: - hid_hw_stop(hdev); hid_hw_close(hdev); err_stop_hw: hid_hw_stop(hdev); @@ -617,8 +613,8 @@ static void sensor_hub_remove(struct hid_device *hdev) int i; hid_dbg(hdev, " hardware removed\n"); - hid_hw_stop(hdev); hid_hw_close(hdev); + hid_hw_stop(hdev); spin_lock_irqsave(&data->lock, flags); if (data->pending.status) complete(&data->pending.ready); From e60fea794e6ecb9ea4df2623c9498412afe31d4d Mon Sep 17 00:00:00 2001 From: anish kumar Date: Fri, 21 Sep 2012 17:10:00 +0100 Subject: [PATCH 21/22] power: battery: Generic battery driver using IIO Driver to allow use of the ADC drivers supported by the IIO subsystem for battery status monitoring. Connecting this driver to the relevant IIO device requires registration of the appropriate iio_map structure array by the IIO device driver (usually from platform data). If specified the driver will also make use of a gpio to provide interrupt driven notification that the battery is fully charged. In last version: Addressed concerns raised by lars: a. made the adc_bat per device. b. get the IIO channel using hardcoded channel names. c. Minor issues related to gpio_is_valid and some code refactoring. In V1: Addressed concerns raised by Anton: a. changed the struct name to gab(generic adc battery). b. Added some functions to neaten the code. c. Some minor coding guidelines changes. d. Used the latest function introduce by lars: iio_read_channel_processed to streamline the code. In V2: Addressed concerns by lars: a. No need of allocating memory for channels.Make it array. b. Code restructring, coding style and following kernel guidelines changes suggested by him. In V3: Addressed conerns by Anton: a. Added the copyright. b. Coding guidelines changes suggested by him. c. Added Makefile and Kconfig Signed-off-by: anish kumar Acked-by: Anton Vorontsov Signed-off-by: Jonathan Cameron --- drivers/power/Kconfig | 7 + drivers/power/Makefile | 1 + drivers/power/generic-adc-battery.c | 422 ++++++++++++++++++++++ include/linux/power/generic-adc-battery.h | 29 ++ 4 files changed, 459 insertions(+) create mode 100644 drivers/power/generic-adc-battery.c create mode 100644 include/linux/power/generic-adc-battery.h diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index c1892f321c46..80978196aae8 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -29,6 +29,13 @@ config APM_POWER Say Y here to enable support APM status emulation using battery class devices. +config GENERIC_ADC_BATTERY + tristate "Generic battery support using IIO" + depends on IIO + help + Say Y here to enable support for the generic battery driver + which uses IIO framework to read adc. + config MAX8925_POWER tristate "MAX8925 battery charger support" depends on MFD_MAX8925 diff --git a/drivers/power/Makefile b/drivers/power/Makefile index ee58afb1e71f..e0b4d4284e1d 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -5,6 +5,7 @@ power_supply-$(CONFIG_SYSFS) += power_supply_sysfs.o power_supply-$(CONFIG_LEDS_TRIGGERS) += power_supply_leds.o obj-$(CONFIG_POWER_SUPPLY) += power_supply.o +obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o obj-$(CONFIG_PDA_POWER) += pda_power.o obj-$(CONFIG_APM_POWER) += apm_power.o diff --git a/drivers/power/generic-adc-battery.c b/drivers/power/generic-adc-battery.c new file mode 100644 index 000000000000..9bdf44470396 --- /dev/null +++ b/drivers/power/generic-adc-battery.c @@ -0,0 +1,422 @@ +/* + * Generic battery driver code using IIO + * Copyright (C) 2012, Anish Kumar + * based on jz4740-battery.c + * based on s3c_adc_battery.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define JITTER_DEFAULT 10 /* hope 10ms is enough */ + +enum gab_chan_type { + GAB_VOLTAGE = 0, + GAB_CURRENT, + GAB_POWER, + GAB_MAX_CHAN_TYPE +}; + +/* + * gab_chan_name suggests the standard channel names for commonly used + * channel types. + */ +static const char *const gab_chan_name[] = { + [GAB_VOLTAGE] = "voltage", + [GAB_CURRENT] = "current", + [GAB_POWER] = "power", +}; + +struct gab { + struct power_supply psy; + struct iio_channel *channel[GAB_MAX_CHAN_TYPE]; + struct gab_platform_data *pdata; + struct delayed_work bat_work; + int level; + int status; + bool cable_plugged; +}; + +static struct gab *to_generic_bat(struct power_supply *psy) +{ + return container_of(psy, struct gab, psy); +} + +static void gab_ext_power_changed(struct power_supply *psy) +{ + struct gab *adc_bat = to_generic_bat(psy); + + schedule_delayed_work(&adc_bat->bat_work, msecs_to_jiffies(0)); +} + +static const enum power_supply_property gab_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, + POWER_SUPPLY_PROP_MODEL_NAME, +}; + +/* + * This properties are set based on the received platform data and this + * should correspond one-to-one with enum chan_type. + */ +static const enum power_supply_property gab_dyn_props[] = { + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_POWER_NOW, +}; + +static bool gab_charge_finished(struct gab *adc_bat) +{ + struct gab_platform_data *pdata = adc_bat->pdata; + bool ret = gpio_get_value(pdata->gpio_charge_finished); + bool inv = pdata->gpio_inverted; + + if (!gpio_is_valid(pdata->gpio_charge_finished)) + return false; + return ret ^ inv; +} + +static int gab_get_status(struct gab *adc_bat) +{ + struct gab_platform_data *pdata = adc_bat->pdata; + struct power_supply_info *bat_info; + + bat_info = &pdata->battery_info; + if (adc_bat->level == bat_info->charge_full_design) + return POWER_SUPPLY_STATUS_FULL; + return adc_bat->status; +} + +static enum gab_chan_type gab_prop_to_chan(enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_POWER_NOW: + return GAB_POWER; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + return GAB_VOLTAGE; + case POWER_SUPPLY_PROP_CURRENT_NOW: + return GAB_CURRENT; + default: + WARN_ON(1); + break; + } + return GAB_POWER; +} + +static int read_channel(struct gab *adc_bat, enum power_supply_property psp, + int *result) +{ + int ret; + int chan_index; + + chan_index = gab_prop_to_chan(psp); + ret = iio_read_channel_processed(adc_bat->channel[chan_index], + result); + if (ret < 0) + pr_err("read channel error\n"); + return ret; +} + +static int gab_get_property(struct power_supply *psy, + enum power_supply_property psp, union power_supply_propval *val) +{ + struct gab *adc_bat; + struct gab_platform_data *pdata; + struct power_supply_info *bat_info; + int result = 0; + int ret = 0; + + adc_bat = to_generic_bat(psy); + if (!adc_bat) { + dev_err(psy->dev, "no battery infos ?!\n"); + return -EINVAL; + } + pdata = adc_bat->pdata; + bat_info = &pdata->battery_info; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + gab_get_status(adc_bat); + break; + case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN: + val->intval = 0; + break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + val->intval = pdata->cal_charge(result); + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + case POWER_SUPPLY_PROP_CURRENT_NOW: + case POWER_SUPPLY_PROP_POWER_NOW: + ret = read_channel(adc_bat, psp, &result); + if (ret < 0) + goto err; + val->intval = result; + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = bat_info->technology; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + val->intval = bat_info->voltage_min_design; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + val->intval = bat_info->voltage_max_design; + break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + val->intval = bat_info->charge_full_design; + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = bat_info->name; + break; + default: + return -EINVAL; + } +err: + return ret; +} + +static void gab_work(struct work_struct *work) +{ + struct gab *adc_bat; + struct gab_platform_data *pdata; + struct delayed_work *delayed_work; + bool is_plugged; + int status; + + delayed_work = container_of(work, struct delayed_work, work); + adc_bat = container_of(delayed_work, struct gab, bat_work); + pdata = adc_bat->pdata; + status = adc_bat->status; + + is_plugged = power_supply_am_i_supplied(&adc_bat->psy); + adc_bat->cable_plugged = is_plugged; + + if (!is_plugged) + adc_bat->status = POWER_SUPPLY_STATUS_DISCHARGING; + else if (gab_charge_finished(adc_bat)) + adc_bat->status = POWER_SUPPLY_STATUS_NOT_CHARGING; + else + adc_bat->status = POWER_SUPPLY_STATUS_CHARGING; + + if (status != adc_bat->status) + power_supply_changed(&adc_bat->psy); +} + +static irqreturn_t gab_charged(int irq, void *dev_id) +{ + struct gab *adc_bat = dev_id; + struct gab_platform_data *pdata = adc_bat->pdata; + int delay; + + delay = pdata->jitter_delay ? pdata->jitter_delay : JITTER_DEFAULT; + schedule_delayed_work(&adc_bat->bat_work, + msecs_to_jiffies(delay)); + return IRQ_HANDLED; +} + +static int __devinit gab_probe(struct platform_device *pdev) +{ + struct gab *adc_bat; + struct power_supply *psy; + struct gab_platform_data *pdata = pdev->dev.platform_data; + enum power_supply_property *properties; + int ret = 0; + int chan; + int index = 0; + + adc_bat = devm_kzalloc(&pdev->dev, sizeof(*adc_bat), GFP_KERNEL); + if (!adc_bat) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + + psy = &adc_bat->psy; + psy->name = pdata->battery_info.name; + + /* bootup default values for the battery */ + adc_bat->cable_plugged = false; + adc_bat->status = POWER_SUPPLY_STATUS_DISCHARGING; + psy->type = POWER_SUPPLY_TYPE_BATTERY; + psy->get_property = gab_get_property; + psy->external_power_changed = gab_ext_power_changed; + adc_bat->pdata = pdata; + + /* calculate the total number of channels */ + chan = ARRAY_SIZE(gab_chan_name); + + /* + * copying the static properties and allocating extra memory for holding + * the extra configurable properties received from platform data. + */ + psy->properties = kcalloc(ARRAY_SIZE(gab_props) + + ARRAY_SIZE(gab_chan_name), + sizeof(*psy->properties), GFP_KERNEL); + if (!psy->properties) { + ret = -ENOMEM; + goto first_mem_fail; + } + + memcpy(psy->properties, gab_props, sizeof(gab_props)); + properties = psy->properties + sizeof(gab_props); + + /* + * getting channel from iio and copying the battery properties + * based on the channel supported by consumer device. + */ + for (chan = 0; chan < ARRAY_SIZE(gab_chan_name); chan++) { + adc_bat->channel[chan] = iio_channel_get(dev_name(&pdev->dev), + gab_chan_name[chan]); + if (IS_ERR(adc_bat->channel[chan])) { + ret = PTR_ERR(adc_bat->channel[chan]); + } else { + /* copying properties for supported channels only */ + memcpy(properties + sizeof(*(psy->properties)) * index, + &gab_dyn_props[chan], + sizeof(gab_dyn_props[chan])); + index++; + } + } + + /* none of the channels are supported so let's bail out */ + if (index == ARRAY_SIZE(gab_chan_name)) + goto second_mem_fail; + + /* + * Total number of properties is equal to static properties + * plus the dynamic properties.Some properties may not be set + * as come channels may be not be supported by the device.So + * we need to take care of that. + */ + psy->num_properties = ARRAY_SIZE(gab_props) + index; + + ret = power_supply_register(&pdev->dev, psy); + if (ret) + goto err_reg_fail; + + INIT_DELAYED_WORK(&adc_bat->bat_work, gab_work); + + if (gpio_is_valid(pdata->gpio_charge_finished)) { + int irq; + ret = gpio_request(pdata->gpio_charge_finished, "charged"); + if (ret) + goto gpio_req_fail; + + irq = gpio_to_irq(pdata->gpio_charge_finished); + ret = request_any_context_irq(irq, gab_charged, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "battery charged", adc_bat); + if (ret) + goto err_gpio; + } + + platform_set_drvdata(pdev, adc_bat); + + /* Schedule timer to check current status */ + schedule_delayed_work(&adc_bat->bat_work, + msecs_to_jiffies(0)); + return 0; + +err_gpio: + gpio_free(pdata->gpio_charge_finished); +gpio_req_fail: + power_supply_unregister(psy); +err_reg_fail: + for (chan = 0; ARRAY_SIZE(gab_chan_name); chan++) + iio_channel_release(adc_bat->channel[chan]); +second_mem_fail: + kfree(psy->properties); +first_mem_fail: + return ret; +} + +static int __devexit gab_remove(struct platform_device *pdev) +{ + int chan; + struct gab *adc_bat = platform_get_drvdata(pdev); + struct gab_platform_data *pdata = adc_bat->pdata; + + power_supply_unregister(&adc_bat->psy); + + if (gpio_is_valid(pdata->gpio_charge_finished)) { + free_irq(gpio_to_irq(pdata->gpio_charge_finished), adc_bat); + gpio_free(pdata->gpio_charge_finished); + } + + for (chan = 0; ARRAY_SIZE(gab_chan_name); chan++) + iio_channel_release(adc_bat->channel[chan]); + + kfree(adc_bat->psy.properties); + cancel_delayed_work(&adc_bat->bat_work); + return 0; +} + +#ifdef CONFIG_PM +static int gab_suspend(struct device *dev) +{ + struct gab *adc_bat = dev_get_drvdata(dev); + + cancel_delayed_work_sync(&adc_bat->bat_work); + adc_bat->status = POWER_SUPPLY_STATUS_UNKNOWN; + return 0; +} + +static int gab_resume(struct device *dev) +{ + struct gab *adc_bat = dev_get_drvdata(dev); + struct gab_platform_data *pdata = adc_bat->pdata; + int delay; + + delay = pdata->jitter_delay ? pdata->jitter_delay : JITTER_DEFAULT; + + /* Schedule timer to check current status */ + schedule_delayed_work(&adc_bat->bat_work, + msecs_to_jiffies(delay)); + return 0; +} + +static const struct dev_pm_ops gab_pm_ops = { + .suspend = gab_suspend, + .resume = gab_resume, +}; + +#define GAB_PM_OPS (&gab_pm_ops) +#else +#define GAB_PM_OPS (NULL) +#endif + +static struct platform_driver gab_driver = { + .driver = { + .name = "generic-adc-battery", + .owner = THIS_MODULE, + .pm = GAB_PM_OPS + }, + .probe = gab_probe, + .remove = __devexit_p(gab_remove), +}; +module_platform_driver(gab_driver); + +MODULE_AUTHOR("anish kumar "); +MODULE_DESCRIPTION("generic battery driver using IIO"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/power/generic-adc-battery.h b/include/linux/power/generic-adc-battery.h new file mode 100644 index 000000000000..b1ebe08533b6 --- /dev/null +++ b/include/linux/power/generic-adc-battery.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2012, Anish Kumar + * 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. + */ + +#ifndef GENERIC_ADC_BATTERY_H +#define GENERIC_ADC_BATTERY_H + +/** + * struct gab_platform_data - platform_data for generic adc iio battery driver. + * @battery_info: recommended structure to specify static power supply + * parameters + * @cal_charge: calculate charge level. + * @gpio_charge_finished: gpio for the charger. + * @gpio_inverted: Should be 1 if the GPIO is active low otherwise 0 + * @jitter_delay: delay required after the interrupt to check battery + * status.Default set is 10ms. + */ +struct gab_platform_data { + struct power_supply_info battery_info; + int (*cal_charge)(long value); + int gpio_charge_finished; + bool gpio_inverted; + int jitter_delay; +}; + +#endif /* GENERIC_ADC_BATTERY_H */ From 3fff22743640637c2b61473d3cc8d7dc2215984f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 12 Sep 2012 12:06:00 +0100 Subject: [PATCH 22/22] staging:iio:dummy: Fix potential NULL pointer dereference If the config contains CONFIG_IIO_BUFFER=y and CONFIG_IIO_SIMPLE_DUMMY_BUFFER=n iio_simple_dummy_configure_buffer() is stubbed out and iio_buffer_register() is not. As a result we try to register a buffer which has not been configured. This will causes a NULL pointer deref in iio_buffer_register. To solve this issue move the iio_buffer_register() call to iio_simple_dummy_configure_buffer(), so it will only be called if iio_simple_dummy_configure_buffer() has been called. Reported-by: Fengguang Wu Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/iio_simple_dummy.c | 20 +++++++------------ drivers/staging/iio/iio_simple_dummy.h | 6 ++++-- drivers/staging/iio/iio_simple_dummy_buffer.c | 11 +++++++++- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/drivers/staging/iio/iio_simple_dummy.c b/drivers/staging/iio/iio_simple_dummy.c index 029bcc67f164..dc6c728ea47a 100644 --- a/drivers/staging/iio/iio_simple_dummy.c +++ b/drivers/staging/iio/iio_simple_dummy.c @@ -445,26 +445,20 @@ static int __devinit iio_dummy_probe(int index) if (ret < 0) goto error_free_device; - /* Configure buffered capture support. */ - ret = iio_simple_dummy_configure_buffer(indio_dev); - if (ret < 0) - goto error_unregister_events; - /* - * Register the channels with the buffer, but avoid the output - * channel being registered by reducing the number of channels by 1. + * Configure buffered capture support and register the channels with the + * buffer, but avoid the output channel being registered by reducing the + * number of channels by 1. */ - ret = iio_buffer_register(indio_dev, iio_dummy_channels, 5); + ret = iio_simple_dummy_configure_buffer(indio_dev, iio_dummy_channels, 5); if (ret < 0) - goto error_unconfigure_buffer; + goto error_unregister_events; ret = iio_device_register(indio_dev); if (ret < 0) - goto error_unregister_buffer; + goto error_unconfigure_buffer; return 0; -error_unregister_buffer: - iio_buffer_unregister(indio_dev); error_unconfigure_buffer: iio_simple_dummy_unconfigure_buffer(indio_dev); error_unregister_events: @@ -499,7 +493,6 @@ static int iio_dummy_remove(int index) /* Device specific code to power down etc */ /* Buffered capture related cleanup */ - iio_buffer_unregister(indio_dev); iio_simple_dummy_unconfigure_buffer(indio_dev); ret = iio_simple_dummy_events_unregister(indio_dev); @@ -530,6 +523,7 @@ static __init int iio_dummy_init(void) instances = 1; return -EINVAL; } + /* Fake a bus */ iio_dummy_devs = kcalloc(instances, sizeof(*iio_dummy_devs), GFP_KERNEL); diff --git a/drivers/staging/iio/iio_simple_dummy.h b/drivers/staging/iio/iio_simple_dummy.h index 53975d916fc9..c9e8702caca4 100644 --- a/drivers/staging/iio/iio_simple_dummy.h +++ b/drivers/staging/iio/iio_simple_dummy.h @@ -95,10 +95,12 @@ enum iio_simple_dummy_scan_elements { }; #ifdef CONFIG_IIO_SIMPLE_DUMMY_BUFFER -int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev); +int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev, + const struct iio_chan_spec *channels, unsigned int num_channels); void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev); #else -static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev) +static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev, + const struct iio_chan_spec *channels, unsigned int num_channels) { return 0; }; diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c index 1fd38095b2ca..697d9700db2f 100644 --- a/drivers/staging/iio/iio_simple_dummy_buffer.c +++ b/drivers/staging/iio/iio_simple_dummy_buffer.c @@ -126,7 +126,8 @@ static const struct iio_buffer_setup_ops iio_simple_dummy_buffer_setup_ops = { .predisable = &iio_triggered_buffer_predisable, }; -int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev) +int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev, + const struct iio_chan_spec *channels, unsigned int num_channels) { int ret; struct iio_buffer *buffer; @@ -182,8 +183,15 @@ int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev) * driven by a trigger. */ indio_dev->modes |= INDIO_BUFFER_TRIGGERED; + + ret = iio_buffer_register(indio_dev, channels, num_channels); + if (ret) + goto error_dealloc_pollfunc; + return 0; +error_dealloc_pollfunc: + iio_dealloc_pollfunc(indio_dev->pollfunc); error_free_buffer: iio_kfifo_free(indio_dev->buffer); error_ret: @@ -197,6 +205,7 @@ int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev) */ void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev) { + iio_buffer_unregister(indio_dev); iio_dealloc_pollfunc(indio_dev->pollfunc); iio_kfifo_free(indio_dev->buffer); }