summaryrefslogtreecommitdiff
path: root/drivers/misc/m4sensorhub_heartrate.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/m4sensorhub_heartrate.c')
-rw-r--r--drivers/misc/m4sensorhub_heartrate.c160
1 files changed, 83 insertions, 77 deletions
diff --git a/drivers/misc/m4sensorhub_heartrate.c b/drivers/misc/m4sensorhub_heartrate.c
index 312ed396244..8f6ea2f1648 100644
--- a/drivers/misc/m4sensorhub_heartrate.c
+++ b/drivers/misc/m4sensorhub_heartrate.c
@@ -43,11 +43,9 @@ struct m4hrt_driver_data {
struct platform_device *pdev;
struct m4sensorhub_data *m4;
struct mutex mutex; /* controls driver entry points */
- struct iio_dev *iio;
- uint16_t heartrate;
+ struct m4sensorhub_heartrate_iio_data iiodat;
int16_t samplerate;
-
uint16_t status;
};
@@ -55,34 +53,27 @@ struct m4hrt_driver_data {
static void m4hrt_isr(enum m4sensorhub_irqs int_event, void *handle)
{
int err = 0;
- struct m4hrt_driver_data *dd = handle;
+ struct iio_dev *iio = handle;
+ struct m4hrt_driver_data *dd = iio_priv(iio);
int size = 0;
- struct m4sensorhub_heartrate_iio_data databuf;
mutex_lock(&(dd->mutex));
size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_HEARTRATE_HEARTRATE);
- if (size < 0) {
- m4hrt_err("%s: Reading from invalid register %d.\n",
- __func__, size);
- err = size;
- goto m4hrt_isr_fail;
- }
-
err = m4sensorhub_reg_read(dd->m4, M4SH_REG_HEARTRATE_HEARTRATE,
- (char *)&(databuf.heartrate));
+ (char *)&(dd->iiodat.heartrate));
if (err < 0) {
m4hrt_err("%s: Failed to read heartrate data.\n", __func__);
goto m4hrt_isr_fail;
} else if (err != size) {
- m4hrt_err("%s: Read %d bytes instead of %d.\n",
- __func__, err, size);
+ m4hrt_err("%s: Read %d bytes instead of %d for %s.\n",
+ __func__, err, size, "heartrate");
+ err = -EBADE;
goto m4hrt_isr_fail;
}
- dd->heartrate = databuf.heartrate;
- databuf.timestamp = iio_get_time_ns();
- iio_push_to_buffers(dd->iio, (unsigned char *)&databuf);
+ dd->iiodat.timestamp = iio_get_time_ns();
+ iio_push_to_buffers(iio, (unsigned char *)&(dd->iiodat));
m4hrt_isr_fail:
if (err < 0)
@@ -93,17 +84,17 @@ m4hrt_isr_fail:
return;
}
-static int m4hrt_set_samplerate(struct m4hrt_driver_data *dd, int16_t rate)
+static int m4hrt_set_samplerate(struct iio_dev *iio, int16_t rate)
{
int err = 0;
+ struct m4hrt_driver_data *dd = iio_priv(iio);
int size = 0;
if (rate == dd->samplerate)
- goto m4hrt_change_interrupt_bit;
+ goto m4hrt_set_samplerate_irq_check;
size = m4sensorhub_reg_getsize(dd->m4,
M4SH_REG_HEARTRATESENSOR_SAMPLERATE);
-
err = m4sensorhub_reg_write(dd->m4, M4SH_REG_HEARTRATESENSOR_SAMPLERATE,
(char *)&rate, m4sh_no_mask);
if (err < 0) {
@@ -117,28 +108,30 @@ static int m4hrt_set_samplerate(struct m4hrt_driver_data *dd, int16_t rate)
}
dd->samplerate = rate;
-m4hrt_change_interrupt_bit:
- if (rate == -1) {
- if (dd->status & (1 << M4HRT_IRQ_ENABLED_BIT)) {
- err = m4sensorhub_irq_disable(dd->m4,
+m4hrt_set_samplerate_irq_check:
+ if (rate >= 0) {
+ /* Enable the IRQ if necessary */
+ if (!(dd->status & (1 << M4HRT_IRQ_ENABLED_BIT))) {
+ err = m4sensorhub_irq_enable(dd->m4,
M4SH_IRQ_HEARTRATESENSOR_DATA_READY);
if (err < 0) {
- m4hrt_err("%s: Failed to disable interrupt.\n",
- __func__);
+ m4hrt_err("%s: Failed to enable irq.\n",
+ __func__);
goto m4hrt_set_samplerate_fail;
}
- dd->status = dd->status & ~(1 << M4HRT_IRQ_ENABLED_BIT);
+ dd->status = dd->status | (1 << M4HRT_IRQ_ENABLED_BIT);
}
} else {
- if (!(dd->status & (1 << M4HRT_IRQ_ENABLED_BIT))) {
- err = m4sensorhub_irq_enable(dd->m4,
+ /* Disable the IRQ if necessary */
+ if (dd->status & (1 << M4HRT_IRQ_ENABLED_BIT)) {
+ err = m4sensorhub_irq_disable(dd->m4,
M4SH_IRQ_HEARTRATESENSOR_DATA_READY);
if (err < 0) {
- m4hrt_err("%s: Failed to enable interrupt.\n",
- __func__);
+ m4hrt_err("%s: Failed to disable irq.\n",
+ __func__);
goto m4hrt_set_samplerate_fail;
}
- dd->status = dd->status | (1 << M4HRT_IRQ_ENABLED_BIT);
+ dd->status = dd->status & ~(1 << M4HRT_IRQ_ENABLED_BIT);
}
}
@@ -146,7 +139,6 @@ m4hrt_set_samplerate_fail:
return err;
}
-
static ssize_t m4hrt_setrate_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -178,13 +170,13 @@ static ssize_t m4hrt_setrate_store(struct device *dev,
}
if ((value < -1) || (value > 32767)) {
- m4hrt_err("%s: Invalid samplerate %d\n",
+ m4hrt_err("%s: Invalid samplerate %d passed.\n",
__func__, value);
- err = -EOVERFLOW;
+ err = -EINVAL;
goto m4hrt_enable_store_exit;
}
- err = m4hrt_set_samplerate(dd, value);
+ err = m4hrt_set_samplerate(iio, value);
if (err < 0) {
m4hrt_err("%s: Failed to set sample rate.\n", __func__);
goto m4hrt_enable_store_exit;
@@ -203,7 +195,7 @@ m4hrt_enable_store_exit:
static IIO_DEVICE_ATTR(setrate, S_IRUSR | S_IWUSR,
m4hrt_setrate_show, m4hrt_setrate_store, 0);
-static ssize_t m4hrt_heartrate_show(struct device *dev,
+static ssize_t m4hrt_iiodata_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -212,16 +204,16 @@ static ssize_t m4hrt_heartrate_show(struct device *dev,
ssize_t size = 0;
mutex_lock(&(dd->mutex));
- size = snprintf(buf, PAGE_SIZE, "Current heartrate: %d\n",
- dd->heartrate);
+ size = snprintf(buf, PAGE_SIZE, "%s%hu\n",
+ "heartrate: ", dd->iiodat.heartrate);
mutex_unlock(&(dd->mutex));
return size;
}
-static IIO_DEVICE_ATTR(heartrate, S_IRUGO, m4hrt_heartrate_show, NULL, 0);
+static IIO_DEVICE_ATTR(iiodata, S_IRUGO, m4hrt_iiodata_show, NULL, 0);
static struct attribute *m4hrt_iio_attributes[] = {
&iio_dev_attr_setrate.dev_attr.attr,
- &iio_dev_attr_heartrate.dev_attr.attr,
+ &iio_dev_attr_iiodata.dev_attr.attr,
NULL,
};
@@ -250,44 +242,47 @@ static const struct iio_chan_spec m4hrt_iio_channels[] = {
},
};
-static void m4hrt_remove_iiodev(struct m4hrt_driver_data *dd)
+static void m4hrt_remove_iiodev(struct iio_dev *iio)
{
- iio_kfifo_free(dd->iio->buffer);
- iio_buffer_unregister(dd->iio);
- iio_device_unregister(dd->iio);
+ struct m4hrt_driver_data *dd = iio_priv(iio);
+
+ /* Remember, only call when dd->mutex is locked */
+ iio_kfifo_free(iio->buffer);
+ iio_buffer_unregister(iio);
+ iio_device_unregister(iio);
mutex_destroy(&(dd->mutex));
- iio_device_free(dd->iio); /* dd is freed here */
+ iio_device_free(iio); /* dd is freed here */
return;
}
-static int m4hrt_create_iiodev(struct m4hrt_driver_data *dd)
+static int m4hrt_create_iiodev(struct iio_dev *iio)
{
int err = 0;
+ struct m4hrt_driver_data *dd = iio_priv(iio);
- dd->iio->name = M4HRT_DRIVER_NAME;
- dd->iio->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_HARDWARE;
- dd->iio->num_channels = 1;
- dd->iio->info = &m4hrt_iio_info;
- dd->iio->channels = m4hrt_iio_channels;
+ iio->name = M4HRT_DRIVER_NAME;
+ iio->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_HARDWARE;
+ iio->num_channels = 1;
+ iio->info = &m4hrt_iio_info;
+ iio->channels = m4hrt_iio_channels;
- dd->iio->buffer = iio_kfifo_allocate(dd->iio);
- if (dd->iio->buffer == NULL) {
+ iio->buffer = iio_kfifo_allocate(iio);
+ if (iio->buffer == NULL) {
m4hrt_err("%s: Failed to allocate IIO buffer.\n", __func__);
err = -ENOMEM;
goto m4hrt_create_iiodev_kfifo_fail;
}
- dd->iio->buffer->scan_timestamp = true;
- dd->iio->buffer->access->set_bytes_per_datum(dd->iio->buffer,
- sizeof(struct m4sensorhub_heartrate_iio_data));
- err = iio_buffer_register(dd->iio, dd->iio->channels,
- dd->iio->num_channels);
+ iio->buffer->scan_timestamp = true;
+ iio->buffer->access->set_bytes_per_datum(iio->buffer,
+ sizeof(dd->iiodat));
+ err = iio_buffer_register(iio, iio->channels, iio->num_channels);
if (err < 0) {
m4hrt_err("%s: Failed to register IIO buffer.\n", __func__);
goto m4hrt_create_iiodev_buffer_fail;
}
- err = iio_device_register(dd->iio);
+ err = iio_device_register(iio);
if (err < 0) {
m4hrt_err("%s: Failed to register IIO device.\n", __func__);
goto m4hrt_create_iiodev_iioreg_fail;
@@ -296,19 +291,19 @@ static int m4hrt_create_iiodev(struct m4hrt_driver_data *dd)
goto m4hrt_create_iiodev_exit;
m4hrt_create_iiodev_iioreg_fail:
- iio_buffer_unregister(dd->iio);
+ iio_buffer_unregister(iio);
m4hrt_create_iiodev_buffer_fail:
- iio_kfifo_free(dd->iio->buffer);
+ iio_kfifo_free(iio->buffer);
m4hrt_create_iiodev_kfifo_fail:
- iio_device_free(dd->iio);
- dd->iio = NULL;
+ iio_device_free(iio); /* dd is freed here */
m4hrt_create_iiodev_exit:
return err;
}
static int m4hrt_driver_init(struct init_calldata *p_arg)
{
- struct m4hrt_driver_data *dd = p_arg->p_data;
+ struct iio_dev *iio = p_arg->p_data;
+ struct m4hrt_driver_data *dd = iio_priv(iio);
int err = 0;
mutex_lock(&(dd->mutex));
@@ -320,25 +315,32 @@ static int m4hrt_driver_init(struct init_calldata *p_arg)
goto m4hrt_driver_init_fail;
}
- err = m4hrt_create_iiodev(dd);
+ err = m4hrt_create_iiodev(iio);
if (err < 0) {
- m4hrt_err("%s: Failed to create M4 event device.\n", __func__);
+ m4hrt_err("%s: Failed to create IIO device.\n", __func__);
goto m4hrt_driver_init_fail;
}
err = m4sensorhub_irq_register(dd->m4,
- M4SH_IRQ_HEARTRATESENSOR_DATA_READY, m4hrt_isr, dd);
+ M4SH_IRQ_HEARTRATESENSOR_DATA_READY, m4hrt_isr, iio);
if (err < 0) {
m4hrt_err("%s: Failed to register M4 IRQ.\n", __func__);
goto m4hrt_driver_init_irq_fail;
}
+ /*
+ * NOTE: We're intentionally unlocking here instead of
+ * at function end (after error cases). The reason
+ * is that the mutex ceases to exist because IIO is
+ * freed, so we would cause a panic putting the unlock
+ * after m4hrt_driver_init_exit.
+ */
mutex_unlock(&(dd->mutex));
goto m4hrt_driver_init_exit;
m4hrt_driver_init_irq_fail:
- m4hrt_remove_iiodev(dd); /* dd is freed here */
+ m4hrt_remove_iiodev(iio); /* dd is freed here */
m4hrt_driver_init_fail:
m4hrt_err("%s: Init failed with error code %d.\n", __func__, err);
m4hrt_driver_init_exit:
@@ -359,12 +361,12 @@ static int m4hrt_probe(struct platform_device *pdev)
}
dd = iio_priv(iio);
- dd->iio = iio;
dd->pdev = pdev;
mutex_init(&(dd->mutex));
- platform_set_drvdata(pdev, dd);
+ platform_set_drvdata(pdev, iio);
+ dd->samplerate = -1; /* We always start disabled */
- err = m4sensorhub_register_initcall(m4hrt_driver_init, dd);
+ err = m4sensorhub_register_initcall(m4hrt_driver_init, iio);
if (err < 0) {
m4hrt_err("%s: Failed to register initcall.\n", __func__);
goto m4hrt_probe_fail;
@@ -374,7 +376,7 @@ static int m4hrt_probe(struct platform_device *pdev)
m4hrt_probe_fail:
mutex_destroy(&(dd->mutex));
- iio_device_free(dd->iio); /* dd is freed here */
+ iio_device_free(iio); /* dd is freed here */
m4hrt_probe_fail_noiio:
m4hrt_err("%s: Probe failed with error code %d.\n", __func__, err);
return err;
@@ -382,8 +384,13 @@ m4hrt_probe_fail_noiio:
static int __exit m4hrt_remove(struct platform_device *pdev)
{
- struct m4hrt_driver_data *dd = platform_get_drvdata(pdev);
+ struct iio_dev *iio = platform_get_drvdata(pdev);
+ struct m4hrt_driver_data *dd = NULL;
+ if (iio == NULL)
+ goto m4hrt_remove_exit;
+
+ dd = iio_priv(iio);
if (dd == NULL)
goto m4hrt_remove_exit;
@@ -397,8 +404,7 @@ static int __exit m4hrt_remove(struct platform_device *pdev)
M4SH_IRQ_HEARTRATESENSOR_DATA_READY);
m4sensorhub_unregister_initcall(m4hrt_driver_init);
mutex_destroy(&(dd->mutex));
- if (dd->iio != NULL)
- m4hrt_remove_iiodev(dd); /* dd is freed here */
+ m4hrt_remove_iiodev(iio); /* dd is freed here */
m4hrt_remove_exit:
return 0;