// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2011 Jonathan Cameron * * A reference industrial I/O driver to illustrate the functionality available. * * There are numerous real drivers to illustrate the finer points. * The purpose of this driver is to provide a driver with far more comments * and explanatory notes than any 'real' driver would have. * Anyone starting out writing an IIO driver should first make sure they * understand all of this driver except those bits specifically marked * as being present to allow us to 'fake' the presence of hardware.
*/ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/string.h>
/** * struct iio_dummy_accel_calibscale - realworld to register mapping * @val: first value in read_raw - here integer part. * @val2: second value in read_raw etc - here micro part. * @regval: register value - magic device specific numbers.
*/ struct iio_dummy_accel_calibscale { int val; int val2; int regval; /* what would be written to hardware */
};
guard(mutex)(&st->lock); switch (chan->type) { case IIO_STEPS:
*val = st->steps; return IIO_VAL_INT; case IIO_ACTIVITY: switch (chan->channel2) { case IIO_MOD_RUNNING:
*val = st->activity_running; return IIO_VAL_INT; case IIO_MOD_WALKING:
*val = st->activity_walking; return IIO_VAL_INT; default: return -EINVAL;
} default: return -EINVAL;
}
}
/** * iio_dummy_read_raw() - data read function. * @indio_dev: the struct iio_dev associated with this device instance * @chan: the channel whose data is to be read * @val: first element of returned value (typically INT) * @val2: second element of returned value (typically MICRO) * @mask: what we actually want to read as per the info_mask_* * in iio_chan_spec.
*/ staticint iio_dummy_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{ struct iio_dummy_state *st = iio_priv(indio_dev); int ret;
switch (mask) { case IIO_CHAN_INFO_RAW: /* magic value - channel value read */ if (!iio_device_claim_direct(indio_dev)) return -EBUSY;
ret = __iio_dummy_read_raw(indio_dev, chan, val);
iio_device_release_direct(indio_dev); return ret; case IIO_CHAN_INFO_PROCESSED: if (!iio_device_claim_direct(indio_dev)) return -EBUSY;
ret = __iio_dummy_read_processed(indio_dev, chan, val);
iio_device_release_direct(indio_dev); return ret; case IIO_CHAN_INFO_OFFSET: /* only single ended adc -> 7 */
*val = 7; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_VOLTAGE: switch (chan->differential) { case 0: /* only single ended adc -> 0.001333 */
*val = 0;
*val2 = 1333; return IIO_VAL_INT_PLUS_MICRO; case 1: /* all differential adc -> 0.000001344 */
*val = 0;
*val2 = 1344; return IIO_VAL_INT_PLUS_NANO; default: return -EINVAL;
} default: return -EINVAL;
} case IIO_CHAN_INFO_CALIBBIAS: {
guard(mutex)(&st->lock); /* only the acceleration axis - read from cache */
*val = st->accel_calibbias; return IIO_VAL_INT;
} case IIO_CHAN_INFO_CALIBSCALE: {
guard(mutex)(&st->lock);
*val = st->accel_calibscale->val;
*val2 = st->accel_calibscale->val2; return IIO_VAL_INT_PLUS_MICRO;
} case IIO_CHAN_INFO_SAMP_FREQ:
*val = 3;
*val2 = 33; return IIO_VAL_INT_PLUS_NANO; case IIO_CHAN_INFO_ENABLE: {
guard(mutex)(&st->lock); switch (chan->type) { case IIO_STEPS:
*val = st->steps_enabled; return IIO_VAL_INT; default: return -EINVAL;
}
} case IIO_CHAN_INFO_CALIBHEIGHT: {
guard(mutex)(&st->lock); switch (chan->type) { case IIO_STEPS:
*val = st->height; return IIO_VAL_INT; default: return -EINVAL;
}
} default: return -EINVAL;
}
}
/** * iio_dummy_write_raw() - data write function. * @indio_dev: the struct iio_dev associated with this device instance * @chan: the channel whose data is to be written * @val: first element of value to set (typically INT) * @val2: second element of value to set (typically MICRO) * @mask: what we actually want to write as per the info_mask_* * in iio_chan_spec. * * Note that all raw writes are assumed IIO_VAL_INT and info mask elements * are assumed to be IIO_INT_PLUS_MICRO unless the callback write_raw_get_fmt * in struct iio_info is provided by the driver.
*/ staticint iio_dummy_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask)
{ int i; struct iio_dummy_state *st = iio_priv(indio_dev);
switch (mask) { case IIO_CHAN_INFO_RAW: switch (chan->type) { case IIO_VOLTAGE: if (chan->output == 0) return -EINVAL;
scoped_guard(mutex, &st->lock) { /* Locking not required as writing single value */
st->dac_val = val;
} return 0; default: return -EINVAL;
} case IIO_CHAN_INFO_PROCESSED: switch (chan->type) { case IIO_STEPS:
scoped_guard(mutex, &st->lock) {
st->steps = val;
} return 0; case IIO_ACTIVITY: if (val < 0)
val = 0; if (val > 100)
val = 100; switch (chan->channel2) { case IIO_MOD_RUNNING:
st->activity_running = val; return 0; case IIO_MOD_WALKING:
st->activity_walking = val; return 0; default: return -EINVAL;
} break; default: return -EINVAL;
} case IIO_CHAN_INFO_CALIBSCALE: {
guard(mutex)(&st->lock); /* Compare against table - hard matching here */ for (i = 0; i < ARRAY_SIZE(dummy_scales); i++) if (val == dummy_scales[i].val &&
val2 == dummy_scales[i].val2) break; if (i == ARRAY_SIZE(dummy_scales)) return -EINVAL;
st->accel_calibscale = &dummy_scales[i]; return 0;
} case IIO_CHAN_INFO_CALIBBIAS:
scoped_guard(mutex, &st->lock) {
st->accel_calibbias = val;
} return 0; case IIO_CHAN_INFO_ENABLE: switch (chan->type) { case IIO_STEPS:
scoped_guard(mutex, &st->lock) {
st->steps_enabled = val;
} return 0; default: return -EINVAL;
} case IIO_CHAN_INFO_CALIBHEIGHT: switch (chan->type) { case IIO_STEPS:
st->height = val; return 0; default: return -EINVAL;
}
/** * iio_dummy_init_device() - device instance specific init * @indio_dev: the iio device structure * * Most drivers have one of these to set up default values, * reset the device to known state etc.
*/ staticint iio_dummy_init_device(struct iio_dev *indio_dev)
{ struct iio_dummy_state *st = iio_priv(indio_dev);
/** * iio_dummy_probe() - device instance probe * @name: name of this instance. * * Arguments are bus type specific. * I2C: iio_dummy_probe(struct i2c_client *client, * const struct i2c_device_id *id) * SPI: iio_dummy_probe(struct spi_device *spi)
*/ staticstruct iio_sw_device *iio_dummy_probe(constchar *name)
{ int ret; struct iio_dev *indio_dev; struct iio_dummy_state *st; struct iio_sw_device *swd; struct device *parent = NULL;
/* * With hardware: Set the parent device. * parent = &spi->dev; * parent = &client->dev;
*/
swd = kzalloc(sizeof(*swd), GFP_KERNEL); if (!swd) return ERR_PTR(-ENOMEM);
/* * Allocate an IIO device. * * This structure contains all generic state * information about the device instance. * It also has a region (accessed by iio_priv() * for chip specific state information.
*/
indio_dev = iio_device_alloc(parent, sizeof(*st)); if (!indio_dev) {
ret = -ENOMEM; goto error_free_swd;
}
st = iio_priv(indio_dev);
mutex_init(&st->lock);
iio_dummy_init_device(indio_dev);
/* * Make the iio_dev struct available to remove function. * Bus equivalents * i2c_set_clientdata(client, indio_dev); * spi_set_drvdata(spi, indio_dev);
*/
swd->device = indio_dev;
/* * Set the device name. * * This is typically a part number and obtained from the module * id table. * e.g. for i2c and spi: * indio_dev->name = id->name; * indio_dev->name = spi_get_device_id(spi)->name;
*/
indio_dev->name = kstrdup(name, GFP_KERNEL); if (!indio_dev->name) {
ret = -ENOMEM; goto error_free_device;
}
/* Provide description of available channels */
indio_dev->channels = iio_dummy_channels;
indio_dev->num_channels = ARRAY_SIZE(iio_dummy_channels);
/* * Provide device type specific interface functions and * constant data.
*/
indio_dev->info = &iio_dummy_info;
/* Specify that device provides sysfs type interfaces */
indio_dev->modes = INDIO_DIRECT_MODE;
ret = iio_simple_dummy_events_register(indio_dev); if (ret < 0) goto error_free_name;
ret = iio_simple_dummy_configure_buffer(indio_dev); if (ret < 0) goto error_unregister_events;
ret = iio_device_register(indio_dev); if (ret < 0) goto error_unconfigure_buffer;
/** * iio_dummy_remove() - device instance removal function * @swd: pointer to software IIO device abstraction * * Parameters follow those of iio_dummy_probe for buses.
*/ staticint iio_dummy_remove(struct iio_sw_device *swd)
{ /* * Get a pointer to the device instance iio_dev structure * from the bus subsystem. E.g. * struct iio_dev *indio_dev = i2c_get_clientdata(client); * struct iio_dev *indio_dev = spi_get_drvdata(spi);
*/ struct iio_dev *indio_dev = swd->device;
/* Unregister the device */
iio_device_unregister(indio_dev);
/* Device specific code to power down etc */
/* Buffered capture related cleanup */
iio_simple_dummy_unconfigure_buffer(indio_dev);
iio_simple_dummy_events_unregister(indio_dev);
/* Free all structures */
kfree(indio_dev->name);
iio_device_free(indio_dev);
return 0;
}
/* * module_iio_sw_device_driver() - device driver registration * * Varies depending on bus type of the device. As there is no device * here, call probe directly. For information on device registration * i2c: * Documentation/i2c/writing-clients.rst * spi: * Documentation/spi/spi-summary.rst
*/ staticconststruct iio_sw_device_ops iio_dummy_device_ops = {
.probe = iio_dummy_probe,
.remove = iio_dummy_remove,
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.