From 7c3e8675f37503337d901dc254cba253326b572a Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 3 Feb 2013 00:59:00 +0000 Subject: iio: max1363: Use devm_ functions whereever possible to allocate resources Signed-off-by: Guenter Roeck Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 08e4feb..c5e46c6 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -1410,8 +1410,9 @@ static int max1363_alloc_scan_masks(struct iio_dev *indio_dev) unsigned long *masks; int i; - masks = kzalloc(BITS_TO_LONGS(MAX1363_MAX_CHANNELS)*sizeof(long)* - (st->chip_info->num_modes + 1), GFP_KERNEL); + masks = devm_kzalloc(&indio_dev->dev, + BITS_TO_LONGS(MAX1363_MAX_CHANNELS) * sizeof(long) * + (st->chip_info->num_modes + 1), GFP_KERNEL); if (!masks) return -ENOMEM; @@ -1504,7 +1505,7 @@ static int max1363_probe(struct i2c_client *client, st = iio_priv(indio_dev); - st->reg = regulator_get(&client->dev, "vcc"); + st->reg = devm_regulator_get(&client->dev, "vcc"); if (IS_ERR(st->reg)) { ret = PTR_ERR(st->reg); goto error_unregister_map; @@ -1512,7 +1513,7 @@ static int max1363_probe(struct i2c_client *client, ret = regulator_enable(st->reg); if (ret) - goto error_put_reg; + goto error_unregister_map; /* this is only used for device removal purposes */ i2c_set_clientdata(client, indio_dev); @@ -1533,15 +1534,15 @@ static int max1363_probe(struct i2c_client *client, indio_dev->modes = INDIO_DIRECT_MODE; ret = max1363_initial_setup(st); if (ret < 0) - goto error_free_available_scan_masks; + goto error_disable_reg; ret = iio_triggered_buffer_setup(indio_dev, NULL, &max1363_trigger_handler, &max1363_buffered_setup_ops); if (ret) - goto error_free_available_scan_masks; + goto error_disable_reg; if (client->irq) { - ret = request_threaded_irq(st->client->irq, + ret = devm_request_threaded_irq(&client->dev, st->client->irq, NULL, &max1363_event_handler, IRQF_TRIGGER_RISING | IRQF_ONESHOT, @@ -1554,20 +1555,14 @@ static int max1363_probe(struct i2c_client *client, ret = iio_device_register(indio_dev); if (ret < 0) - goto error_free_irq; + goto error_uninit_buffer; return 0; -error_free_irq: - if (client->irq) - free_irq(st->client->irq, indio_dev); + error_uninit_buffer: iio_triggered_buffer_cleanup(indio_dev); -error_free_available_scan_masks: - kfree(indio_dev->available_scan_masks); error_disable_reg: regulator_disable(st->reg); -error_put_reg: - regulator_put(st->reg); error_unregister_map: iio_map_array_unregister(indio_dev); error_free_device: @@ -1582,12 +1577,8 @@ static int max1363_remove(struct i2c_client *client) struct max1363_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (client->irq) - free_irq(st->client->irq, indio_dev); iio_triggered_buffer_cleanup(indio_dev); - kfree(indio_dev->available_scan_masks); regulator_disable(st->reg); - regulator_put(st->reg); iio_map_array_unregister(indio_dev); iio_device_free(indio_dev); -- cgit v0.10.2 From a405b00e4470b15ed062de97c4ce552d41a0a60b Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 3 Feb 2013 00:59:00 +0000 Subject: iio/adc: (max1363) Add support for external reference voltage Implement external reference voltage as regulator named "vref". Signed-off-by: Guenter Roeck Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index c5e46c6..6c1cfb7 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -163,6 +163,8 @@ struct max1363_chip_info { * @mask_low: bitmask for enabled low thresholds * @thresh_high: high threshold values * @thresh_low: low threshold values + * @vref: Reference voltage regulator + * @vref_uv: Actual (external or internal) reference voltage */ struct max1363_state { struct i2c_client *client; @@ -182,6 +184,8 @@ struct max1363_state { /* 4x unipolar first then the fours bipolar ones */ s16 thresh_high[8]; s16 thresh_low[8]; + struct regulator *vref; + u32 vref_uv; }; #define MAX1363_MODE_SINGLE(_num, _mask) { \ @@ -393,6 +397,8 @@ static int max1363_read_raw(struct iio_dev *indio_dev, { struct max1363_state *st = iio_priv(indio_dev); int ret; + unsigned long scale_uv; + switch (m) { case IIO_CHAN_INFO_RAW: ret = max1363_read_single_chan(indio_dev, chan, val, m); @@ -400,16 +406,10 @@ static int max1363_read_raw(struct iio_dev *indio_dev, return ret; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - if ((1 << (st->chip_info->bits + 1)) > - st->chip_info->int_vref_mv) { - *val = 0; - *val2 = 500000; - return IIO_VAL_INT_PLUS_MICRO; - } else { - *val = (st->chip_info->int_vref_mv) - >> st->chip_info->bits; - return IIO_VAL_INT; - } + scale_uv = st->vref_uv >> st->chip_info->bits; + *val = scale_uv / 1000; + *val2 = (scale_uv % 1000) * 1000; + return IIO_VAL_INT_PLUS_MICRO; default: return -EINVAL; } @@ -1390,12 +1390,16 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { static int max1363_initial_setup(struct max1363_state *st) { - st->setupbyte = MAX1363_SETUP_AIN3_IS_AIN3_REF_IS_VDD - | MAX1363_SETUP_POWER_UP_INT_REF - | MAX1363_SETUP_INT_CLOCK + st->setupbyte = MAX1363_SETUP_INT_CLOCK | MAX1363_SETUP_UNIPOLAR | MAX1363_SETUP_NORESET; + if (st->vref) + st->setupbyte |= MAX1363_SETUP_AIN3_IS_REF_EXT_TO_REF; + else + st->setupbyte |= MAX1363_SETUP_POWER_UP_INT_REF + | MAX1363_SETUP_AIN3_IS_AIN3_REF_IS_INT; + /* Set scan mode writes the config anyway so wait until then */ st->setupbyte = MAX1363_SETUP_BYTE(st->setupbyte); st->current_mode = &max1363_mode_table[st->chip_info->default_mode]; @@ -1491,6 +1495,7 @@ static int max1363_probe(struct i2c_client *client, int ret; struct max1363_state *st; struct iio_dev *indio_dev; + struct regulator *vref; indio_dev = iio_device_alloc(sizeof(struct max1363_state)); if (indio_dev == NULL) { @@ -1521,6 +1526,23 @@ static int max1363_probe(struct i2c_client *client, st->chip_info = &max1363_chip_info_tbl[id->driver_data]; st->client = client; + st->vref_uv = st->chip_info->int_vref_mv * 1000; + vref = devm_regulator_get(&client->dev, "vref"); + if (!IS_ERR(vref)) { + int vref_uv; + + ret = regulator_enable(vref); + if (ret) + goto error_disable_reg; + st->vref = vref; + vref_uv = regulator_get_voltage(vref); + if (vref_uv <= 0) { + ret = -EINVAL; + goto error_disable_reg; + } + st->vref_uv = vref_uv; + } + ret = max1363_alloc_scan_masks(indio_dev); if (ret) goto error_disable_reg; @@ -1562,6 +1584,8 @@ static int max1363_probe(struct i2c_client *client, error_uninit_buffer: iio_triggered_buffer_cleanup(indio_dev); error_disable_reg: + if (st->vref) + regulator_disable(st->vref); regulator_disable(st->reg); error_unregister_map: iio_map_array_unregister(indio_dev); @@ -1578,6 +1602,8 @@ static int max1363_remove(struct i2c_client *client) iio_device_unregister(indio_dev); iio_triggered_buffer_cleanup(indio_dev); + if (st->vref) + regulator_disable(st->vref); regulator_disable(st->reg); iio_map_array_unregister(indio_dev); iio_device_free(indio_dev); -- cgit v0.10.2 From 860c9c54272deaab43b40dbe416becb34abd344f Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Mon, 4 Feb 2013 11:36:00 +0000 Subject: iio: tweak language in industrialio-trigger comments Signed-off-by: Peter Meerwald Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 4fe0ead..4d6c7d8 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -160,7 +160,7 @@ void iio_trigger_notify_done(struct iio_trigger *trig) trig->use_count--; if (trig->use_count == 0 && trig->ops && trig->ops->try_reenable) if (trig->ops->try_reenable(trig)) - /* Missed and interrupt so launch new poll now */ + /* Missed an interrupt so launch new poll now */ iio_trigger_poll(trig, 0); } EXPORT_SYMBOL(iio_trigger_notify_done); @@ -193,7 +193,7 @@ static void iio_trigger_put_irq(struct iio_trigger *trig, int irq) * This is not currently handled. Alternative of not enabling trigger unless * the relevant function is in there may be the best option. */ -/* Worth protecting against double additions?*/ +/* Worth protecting against double additions? */ static int iio_trigger_attach_poll_func(struct iio_trigger *trig, struct iio_poll_func *pf) { @@ -201,7 +201,7 @@ static int iio_trigger_attach_poll_func(struct iio_trigger *trig, bool notinuse = bitmap_empty(trig->pool, CONFIG_IIO_CONSUMERS_PER_TRIGGER); - /* Prevent the module being removed whilst attached to a trigger */ + /* Prevent the module from being removed whilst attached to a trigger */ __module_get(pf->indio_dev->info->driver_module); pf->irq = iio_trigger_get_irq(trig); ret = request_threaded_irq(pf->irq, pf->h, pf->thread, @@ -288,7 +288,7 @@ void iio_dealloc_pollfunc(struct iio_poll_func *pf) EXPORT_SYMBOL_GPL(iio_dealloc_pollfunc); /** - * iio_trigger_read_current() - trigger consumer sysfs query which trigger + * iio_trigger_read_current() - trigger consumer sysfs query current trigger * * For trigger consumers the current_trigger interface allows the trigger * used by the device to be queried. @@ -305,7 +305,7 @@ static ssize_t iio_trigger_read_current(struct device *dev, } /** - * iio_trigger_write_current() trigger consumer sysfs set current trigger + * iio_trigger_write_current() - trigger consumer sysfs set current trigger * * For trigger consumers the current_trigger interface allows the trigger * used for this device to be specified at run time based on the triggers @@ -476,7 +476,7 @@ void iio_device_register_trigger_consumer(struct iio_dev *indio_dev) void iio_device_unregister_trigger_consumer(struct iio_dev *indio_dev) { - /* Clean up and associated but not attached triggers references */ + /* Clean up an associated but not attached trigger reference */ if (indio_dev->trig) iio_trigger_put(indio_dev->trig); } -- cgit v0.10.2 From 5aa57f0a655276f62683c0cc714cd6328d98e08a Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 4 Feb 2013 20:26:00 +0000 Subject: iio: Update iio_channel_get API to use consumer device pointer as argument For iio_channel_get to work with OF based configurations, it needs the consumer device pointer instead of the consumer device name as argument. Signed-off-by: Guenter Roeck Acked-by: Anton Vorontsov Acked-by: Chanwoo Choi Signed-off-by: Jonathan Cameron diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index eda2a1aa..d0233cd 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -135,8 +135,7 @@ static int adc_jack_probe(struct platform_device *pdev) ; data->num_conditions = i; - data->chan = iio_channel_get(dev_name(&pdev->dev), - pdata->consumer_channel); + data->chan = iio_channel_get(&pdev->dev, pdata->consumer_channel); if (IS_ERR(data->chan)) { err = PTR_ERR(data->chan); goto out; diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index c42aba6..b289915b 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -93,7 +93,8 @@ static const struct iio_chan_spec } -struct iio_channel *iio_channel_get(const char *name, const char *channel_name) +static struct iio_channel *iio_channel_get_sys(const char *name, + const char *channel_name) { struct iio_map_internal *c_i = NULL, *c = NULL; struct iio_channel *channel; @@ -144,6 +145,14 @@ error_no_mem: iio_device_put(c->indio_dev); return ERR_PTR(err); } + +struct iio_channel *iio_channel_get(struct device *dev, + const char *channel_name) +{ + const char *name = dev ? dev_name(dev) : NULL; + + return iio_channel_get_sys(name, channel_name); +} EXPORT_SYMBOL_GPL(iio_channel_get); void iio_channel_release(struct iio_channel *channel) diff --git a/drivers/power/generic-adc-battery.c b/drivers/power/generic-adc-battery.c index 32ce17e..42733c4 100644 --- a/drivers/power/generic-adc-battery.c +++ b/drivers/power/generic-adc-battery.c @@ -287,8 +287,8 @@ static int gab_probe(struct platform_device *pdev) * 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]); + adc_bat->channel[chan] = iio_channel_get(&pdev->dev, + gab_chan_name[chan]); if (IS_ERR(adc_bat->channel[chan])) { ret = PTR_ERR(adc_bat->channel[chan]); } else { diff --git a/drivers/power/lp8788-charger.c b/drivers/power/lp8788-charger.c index 22b6407c..2788908 100644 --- a/drivers/power/lp8788-charger.c +++ b/drivers/power/lp8788-charger.c @@ -580,7 +580,7 @@ static void lp8788_irq_unregister(struct platform_device *pdev, } } -static void lp8788_setup_adc_channel(const char *consumer_name, +static void lp8788_setup_adc_channel(struct device *dev, struct lp8788_charger *pchg) { struct lp8788_charger_platform_data *pdata = pchg->pdata; @@ -590,11 +590,11 @@ static void lp8788_setup_adc_channel(const char *consumer_name, return; /* ADC channel for battery voltage */ - chan = iio_channel_get(consumer_name, pdata->adc_vbatt); + chan = iio_channel_get(dev, pdata->adc_vbatt); pchg->chan[LP8788_VBATT] = IS_ERR(chan) ? NULL : chan; /* ADC channel for battery temperature */ - chan = iio_channel_get(consumer_name, pdata->adc_batt_temp); + chan = iio_channel_get(dev, pdata->adc_batt_temp); pchg->chan[LP8788_BATT_TEMP] = IS_ERR(chan) ? NULL : chan; } @@ -704,7 +704,7 @@ static int lp8788_charger_probe(struct platform_device *pdev) if (ret) return ret; - lp8788_setup_adc_channel(pdev->name, pchg); + lp8788_setup_adc_channel(&pdev->dev, pchg); ret = lp8788_psy_register(pdev, pchg); if (ret) diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index a85787a..833926c 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -31,14 +31,15 @@ struct iio_channel { /** * iio_channel_get() - get description of all that is needed to access channel. - * @name: Unique name of the device as provided in the iio_map + * @dev: Pointer to consumer device. Device name must match + * the name of the device as provided in the iio_map * with which the desired provider to consumer mapping * was registered. * @consumer_channel: Unique name to identify the channel on the consumer * side. This typically describes the channels use within * the consumer. E.g. 'battery_voltage' */ -struct iio_channel *iio_channel_get(const char *name, +struct iio_channel *iio_channel_get(struct device *dev, const char *consumer_channel); /** -- cgit v0.10.2 From 91ffbabfd9ae6b9bfef02bb1e0fbba451c7289a7 Mon Sep 17 00:00:00 2001 From: Denis CIOCCA Date: Thu, 7 Feb 2013 09:46:00 +0000 Subject: iio:common: added allocate and deallocate trigger functions when trigger is disabled. This patch resolve a bugfix when driver is compiled without trigger. Signed-off-by: Denis Ciocca Reported-by: Randy Dunlap Signed-off-by: Jonathan Cameron diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h index c40fdf5..1f86a97 100644 --- a/include/linux/iio/common/st_sensors.h +++ b/include/linux/iio/common/st_sensors.h @@ -235,6 +235,16 @@ void st_sensors_deallocate_trigger(struct iio_dev *indio_dev); irqreturn_t st_sensors_trigger_handler(int irq, void *p); int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf); +#else +static inline int st_sensors_allocate_trigger(struct iio_dev *indio_dev, + const struct iio_trigger_ops *trigger_ops) +{ + return 0; +} +static inline void st_sensors_deallocate_trigger(struct iio_dev *indio_dev) +{ + return; +} #endif int st_sensors_init_sensor(struct iio_dev *indio_dev); -- cgit v0.10.2 From ad76fda78318821fe8823b4b7c587a46a268eecf Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 6 Feb 2013 02:54:00 +0000 Subject: iio: mxs-lradc: Fix 'duplicate const' warning The following warning is generated by sparse: drivers/staging/iio/adc/mxs-lradc.c:118:47: warning: duplicate const Remove the duplicate const. Signed-off-by: Fabio Estevam Signed-off-by: Jonathan Cameron diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index b1b8c42..f5fb0df 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -114,7 +114,7 @@ struct mxs_lradc_of_config { const char * const *irq_name; }; -static const struct mxs_lradc_of_config const mxs_lradc_of_config[] = { +static const struct mxs_lradc_of_config mxs_lradc_of_config[] = { [IMX23_LRADC] = { .irq_count = ARRAY_SIZE(mx23_lradc_irq_names), .irq_name = mx23_lradc_irq_names, -- cgit v0.10.2 From 6d9eecd418afb2c12e5db5be3d72f0f1df43bdd9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 9 Jan 2013 17:31:00 +0000 Subject: spi: Add helper functions for setting up transfers Quite often the pattern used for setting up and transferring a synchronous SPI transaction looks very much like the following: struct spi_message msg; struct spi_transfer xfers[] = { ... }; spi_message_init(&msg); spi_message_add_tail(&xfers[0], &msg); ... spi_message_add_tail(&xfers[ARRAY_SIZE(xfers) - 1], &msg); ret = spi_sync(&msg); This patch adds two new helper functions for handling this case. The first helper function spi_message_init_with_transfers() takes a spi_message and an array of spi_transfers. It will initialize the message and then call spi_message_add_tail() for each transfer in the array. E.g. the following spi_message_init(&msg); spi_message_add_tail(&xfers[0], &msg); ... spi_message_add_tail(&xfers[ARRAY_SIZE(xfers) - 1], &msg); can be rewritten as spi_message_init_with_transfers(&msg, xfers, ARRAY_SIZE(xfers)); The second function spi_sync_transfer() takes a SPI device and an array of spi_transfers. It will allocate a new spi_message (on the stack) and add all transfers in the array to the message. Finally it will call spi_sync() on the message. E.g. the follwing struct spi_message msg; struct spi_transfer xfers[] = { ... }; spi_message_init(&msg); spi_message_add_tail(&xfers[0], &msg); ... spi_message_add_tail(&xfers[ARRAY_SIZE(xfers) - 1], &msg); ret = spi_sync(spi, &msg); can be rewritten as struct spi_transfer xfers[] = { ... }; ret = spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers)); A coccinelle script to find such instances will follow. Signed-off-by: Lars-Peter Clausen Reviewed-by: Mark Brown Signed-off-by: Jonathan Cameron diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index f629189..7dbe586 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -591,6 +591,26 @@ spi_transfer_del(struct spi_transfer *t) list_del(&t->transfer_list); } +/** + * spi_message_init_with_transfers - Initialize spi_message and append transfers + * @m: spi_message to be initialized + * @xfers: An array of spi transfers + * @num_xfers: Number of items in the xfer array + * + * This function initializes the given spi_message and adds each spi_transfer in + * the given array to the message. + */ +static inline void +spi_message_init_with_transfers(struct spi_message *m, +struct spi_transfer *xfers, unsigned int num_xfers) +{ + unsigned int i; + + spi_message_init(m); + for (i = 0; i < num_xfers; ++i) + spi_message_add_tail(&xfers[i], m); +} + /* It's fine to embed message and transaction structures in other data * structures so long as you don't free them while they're in use. */ @@ -683,6 +703,30 @@ spi_read(struct spi_device *spi, void *buf, size_t len) return spi_sync(spi, &m); } +/** + * spi_sync_transfer - synchronous SPI data transfer + * @spi: device with which data will be exchanged + * @xfers: An array of spi_transfers + * @num_xfers: Number of items in the xfer array + * Context: can sleep + * + * Does a synchronous SPI data transfer of the given spi_transfer array. + * + * For more specific semantics see spi_sync(). + * + * It returns zero on success, else a negative error code. + */ +static inline int +spi_sync_transfer(struct spi_device *spi, struct spi_transfer *xfers, + unsigned int num_xfers) +{ + struct spi_message msg; + + spi_message_init_with_transfers(&msg, xfers, num_xfers); + + return spi_sync(spi, &msg); +} + /* this copies txbuf and rxbuf data; for small transfers only! */ extern int spi_write_then_read(struct spi_device *spi, const void *txbuf, unsigned n_tx, -- cgit v0.10.2 From 14543a00fc3ce6dac9f297535c502a0085a50467 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 9 Jan 2013 17:31:00 +0000 Subject: iio: Use spi_sync_transfer() Use the new spi_sync_transfer() helper function instead of open-coding it. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c index 4a24c2e..c2229a5 100644 --- a/drivers/iio/accel/kxsd9.c +++ b/drivers/iio/accel/kxsd9.c @@ -94,7 +94,6 @@ error_ret: static int kxsd9_read(struct iio_dev *indio_dev, u8 address) { - struct spi_message msg; int ret; struct kxsd9_state *st = iio_priv(indio_dev); struct spi_transfer xfers[] = { @@ -112,10 +111,7 @@ static int kxsd9_read(struct iio_dev *indio_dev, u8 address) mutex_lock(&st->buf_lock); st->tx[0] = KXSD9_READ(address); - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); if (ret) return ret; return (((u16)(st->rx[0])) << 8) | (st->rx[1] & 0xF0); diff --git a/drivers/iio/dac/ad5360.c b/drivers/iio/dac/ad5360.c index 54b46fd..9277121 100644 --- a/drivers/iio/dac/ad5360.c +++ b/drivers/iio/dac/ad5360.c @@ -213,7 +213,6 @@ static int ad5360_read(struct iio_dev *indio_dev, unsigned int type, unsigned int addr) { struct ad5360_state *st = iio_priv(indio_dev); - struct spi_message m; int ret; struct spi_transfer t[] = { { @@ -226,10 +225,6 @@ static int ad5360_read(struct iio_dev *indio_dev, unsigned int type, }, }; - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - mutex_lock(&indio_dev->mlock); st->data[0].d32 = cpu_to_be32(AD5360_CMD(AD5360_CMD_SPECIAL_FUNCTION) | @@ -237,7 +232,7 @@ static int ad5360_read(struct iio_dev *indio_dev, unsigned int type, AD5360_READBACK_TYPE(type) | AD5360_READBACK_ADDR(addr)); - ret = spi_sync(st->spi, &m); + ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); if (ret >= 0) ret = be32_to_cpu(st->data[1].d32) & 0xffff; diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c index 43be948..6b86a63 100644 --- a/drivers/iio/dac/ad5421.c +++ b/drivers/iio/dac/ad5421.c @@ -127,7 +127,6 @@ static int ad5421_write(struct iio_dev *indio_dev, unsigned int reg, static int ad5421_read(struct iio_dev *indio_dev, unsigned int reg) { struct ad5421_state *st = iio_priv(indio_dev); - struct spi_message m; int ret; struct spi_transfer t[] = { { @@ -140,15 +139,11 @@ static int ad5421_read(struct iio_dev *indio_dev, unsigned int reg) }, }; - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - mutex_lock(&indio_dev->mlock); st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16)); - ret = spi_sync(st->spi, &m); + ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); if (ret >= 0) ret = be32_to_cpu(st->data[1].d32) & 0xffff; diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index 0661829..e5e5974 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c @@ -85,11 +85,7 @@ static int ad5504_spi_read(struct spi_device *spi, u8 addr) .rx_buf = &val, .len = 2, }; - struct spi_message m; - - spi_message_init(&m); - spi_message_add_tail(&t, &m); - ret = spi_sync(spi, &m); + ret = spi_sync_transfer(spi, &t, 1); if (ret < 0) return ret; diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index ca9609d..5e554af 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -117,18 +117,13 @@ static int ad5686_spi_read(struct ad5686_state *st, u8 addr) .len = 3, }, }; - struct spi_message m; int ret; - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_READBACK_ENABLE) | AD5686_ADDR(addr)); st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP)); - ret = spi_sync(st->spi, &m); + ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); if (ret < 0) return ret; diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c index 0869bbd..71faabc 100644 --- a/drivers/iio/dac/ad5755.c +++ b/drivers/iio/dac/ad5755.c @@ -153,7 +153,6 @@ static int ad5755_write_ctrl(struct iio_dev *indio_dev, unsigned int channel, static int ad5755_read(struct iio_dev *indio_dev, unsigned int addr) { struct ad5755_state *st = iio_priv(indio_dev); - struct spi_message m; int ret; struct spi_transfer t[] = { { @@ -167,16 +166,12 @@ static int ad5755_read(struct iio_dev *indio_dev, unsigned int addr) }, }; - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - mutex_lock(&indio_dev->mlock); st->data[0].d32 = cpu_to_be32(AD5755_READ_FLAG | (addr << 16)); st->data[1].d32 = cpu_to_be32(AD5755_NOOP); - ret = spi_sync(st->spi, &m); + ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); if (ret >= 0) ret = be32_to_cpu(st->data[1].d32) & 0xffff; diff --git a/drivers/iio/dac/ad5764.c b/drivers/iio/dac/ad5764.c index 7f9045e..5b7acd3 100644 --- a/drivers/iio/dac/ad5764.c +++ b/drivers/iio/dac/ad5764.c @@ -135,7 +135,6 @@ static int ad5764_read(struct iio_dev *indio_dev, unsigned int reg, unsigned int *val) { struct ad5764_state *st = iio_priv(indio_dev); - struct spi_message m; int ret; struct spi_transfer t[] = { { @@ -148,15 +147,11 @@ static int ad5764_read(struct iio_dev *indio_dev, unsigned int reg, }, }; - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - mutex_lock(&indio_dev->mlock); st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16)); - ret = spi_sync(st->spi, &m); + ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); if (ret >= 0) *val = be32_to_cpu(st->data[1].d32) & 0xffff; diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index 6407b54..8dfd3da 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c @@ -125,7 +125,6 @@ static int ad5791_spi_read(struct spi_device *spi, u8 addr, u32 *val) u8 d8[4]; } data[3]; int ret; - struct spi_message msg; struct spi_transfer xfers[] = { { .tx_buf = &data[0].d8[1], @@ -144,10 +143,7 @@ static int ad5791_spi_read(struct spi_device *spi, u8 addr, u32 *val) AD5791_ADDR(addr)); data[1].d32 = cpu_to_be32(AD5791_ADDR(AD5791_ADDR_NOOP)); - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(spi, &msg); + ret = spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers)); *val = be32_to_cpu(data[2].d32); diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c index 8030747..1ea132e 100644 --- a/drivers/iio/frequency/ad9523.c +++ b/drivers/iio/frequency/ad9523.c @@ -287,7 +287,6 @@ struct ad9523_state { static int ad9523_read(struct iio_dev *indio_dev, unsigned addr) { struct ad9523_state *st = iio_priv(indio_dev); - struct spi_message m; int ret; /* We encode the register size 1..3 bytes into the register address. @@ -305,15 +304,11 @@ static int ad9523_read(struct iio_dev *indio_dev, unsigned addr) }, }; - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - st->data[0].d32 = cpu_to_be32(AD9523_READ | AD9523_CNT(AD9523_TRANSF_LEN(addr)) | AD9523_ADDR(addr)); - ret = spi_sync(st->spi, &m); + ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); if (ret < 0) dev_err(&indio_dev->dev, "read failed (%d)", ret); else @@ -326,7 +321,6 @@ static int ad9523_read(struct iio_dev *indio_dev, unsigned addr) static int ad9523_write(struct iio_dev *indio_dev, unsigned addr, unsigned val) { struct ad9523_state *st = iio_priv(indio_dev); - struct spi_message m; int ret; struct spi_transfer t[] = { { @@ -338,16 +332,12 @@ static int ad9523_write(struct iio_dev *indio_dev, unsigned addr, unsigned val) }, }; - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - st->data[0].d32 = cpu_to_be32(AD9523_WRITE | AD9523_CNT(AD9523_TRANSF_LEN(addr)) | AD9523_ADDR(addr)); st->data[1].d32 = cpu_to_be32(val); - ret = spi_sync(st->spi, &m); + ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); if (ret < 0) dev_err(&indio_dev->dev, "write failed (%d)", ret); diff --git a/drivers/iio/gyro/adxrs450.c b/drivers/iio/gyro/adxrs450.c index d9d4383..5b79953 100644 --- a/drivers/iio/gyro/adxrs450.c +++ b/drivers/iio/gyro/adxrs450.c @@ -213,7 +213,6 @@ error_ret: static int adxrs450_spi_initial(struct adxrs450_state *st, u32 *val, char chk) { - struct spi_message msg; int ret; u32 tx; struct spi_transfer xfers = { @@ -228,9 +227,7 @@ static int adxrs450_spi_initial(struct adxrs450_state *st, if (chk) tx |= (ADXRS450_CHK | ADXRS450_P); st->tx = cpu_to_be32(tx); - spi_message_init(&msg); - spi_message_add_tail(&xfers, &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, &xfers, 1); if (ret) { dev_err(&st->us->dev, "Problem while reading initializing data\n"); goto error_ret; -- cgit v0.10.2 From ad6c46b0c712e0d8fd8a80ee372b30f14a781888 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 9 Jan 2013 17:31:00 +0000 Subject: staging:iio: Use spi_sync_transfer() Use the new spi_sync_transfer() helper function instead of open-coding it. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c index 37ed1b8..0e01930 100644 --- a/drivers/staging/iio/accel/lis3l02dq_core.c +++ b/drivers/staging/iio/accel/lis3l02dq_core.c @@ -53,7 +53,6 @@ int lis3l02dq_spi_read_reg_8(struct iio_dev *indio_dev, u8 reg_address, u8 *val) { struct lis3l02dq_state *st = iio_priv(indio_dev); - struct spi_message msg; int ret; struct spi_transfer xfer = { .tx_buf = st->tx, @@ -66,9 +65,7 @@ int lis3l02dq_spi_read_reg_8(struct iio_dev *indio_dev, st->tx[0] = LIS3L02DQ_READ_REG(reg_address); st->tx[1] = 0; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, &xfer, 1); *val = st->rx[1]; mutex_unlock(&st->buf_lock); @@ -109,7 +106,6 @@ static int lis3l02dq_spi_write_reg_s16(struct iio_dev *indio_dev, s16 value) { int ret; - struct spi_message msg; struct lis3l02dq_state *st = iio_priv(indio_dev); struct spi_transfer xfers[] = { { .tx_buf = st->tx, @@ -129,10 +125,7 @@ static int lis3l02dq_spi_write_reg_s16(struct iio_dev *indio_dev, st->tx[2] = LIS3L02DQ_WRITE_REG(lower_reg_address + 1); st->tx[3] = (value >> 8) & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); mutex_unlock(&st->buf_lock); return ret; @@ -143,8 +136,6 @@ static int lis3l02dq_read_reg_s16(struct iio_dev *indio_dev, int *val) { struct lis3l02dq_state *st = iio_priv(indio_dev); - - struct spi_message msg; int ret; s16 tempval; struct spi_transfer xfers[] = { { @@ -167,10 +158,7 @@ static int lis3l02dq_read_reg_s16(struct iio_dev *indio_dev, st->tx[2] = LIS3L02DQ_READ_REG(lower_reg_address + 1); st->tx[3] = 0; - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->us->dev, "problem when reading 16 bit register"); goto error_ret; diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c index 414d3ca..14683f5 100644 --- a/drivers/staging/iio/accel/sca3000_core.c +++ b/drivers/staging/iio/accel/sca3000_core.c @@ -90,7 +90,6 @@ int sca3000_read_data_short(struct sca3000_state *st, uint8_t reg_address_high, int len) { - struct spi_message msg; struct spi_transfer xfer[2] = { { .len = 1, @@ -101,11 +100,8 @@ int sca3000_read_data_short(struct sca3000_state *st, } }; st->tx[0] = SCA3000_READ_REG(reg_address_high); - spi_message_init(&msg); - spi_message_add_tail(&xfer[0], &msg); - spi_message_add_tail(&xfer[1], &msg); - return spi_sync(st->us, &msg); + return spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); } /** @@ -133,7 +129,6 @@ static int sca3000_reg_lock_on(struct sca3000_state *st) **/ static int __sca3000_unlock_reg_lock(struct sca3000_state *st) { - struct spi_message msg; struct spi_transfer xfer[3] = { { .len = 2, @@ -154,12 +149,8 @@ static int __sca3000_unlock_reg_lock(struct sca3000_state *st) st->tx[3] = 0x50; st->tx[4] = SCA3000_WRITE_REG(SCA3000_REG_ADDR_UNLOCK); st->tx[5] = 0xA0; - spi_message_init(&msg); - spi_message_add_tail(&xfer[0], &msg); - spi_message_add_tail(&xfer[1], &msg); - spi_message_add_tail(&xfer[2], &msg); - return spi_sync(st->us, &msg); + return spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); } /** diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c index cbec2f1..3e5e860 100644 --- a/drivers/staging/iio/accel/sca3000_ring.c +++ b/drivers/staging/iio/accel/sca3000_ring.c @@ -39,7 +39,6 @@ static int sca3000_read_data(struct sca3000_state *st, int len) { int ret; - struct spi_message msg; struct spi_transfer xfer[2] = { { .len = 1, @@ -55,10 +54,7 @@ static int sca3000_read_data(struct sca3000_state *st, } xfer[1].rx_buf = *rx_p; st->tx[0] = SCA3000_READ_REG(reg_address_high); - spi_message_init(&msg); - spi_message_add_tail(&xfer[0], &msg); - spi_message_add_tail(&xfer[1], &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); if (ret) { dev_err(get_device(&st->us->dev), "problem reading register"); goto error_free_rx; diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index fa81a49..1f190c1 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -199,12 +199,8 @@ static int __ad7280_read32(struct spi_device *spi, unsigned *val) .rx_buf = &rx_buf, .len = 4, }; - struct spi_message m; - spi_message_init(&m); - spi_message_add_tail(&t, &m); - - ret = spi_sync(spi, &m); + ret = spi_sync_transfer(spi, &t, 1); if (ret) return ret; diff --git a/drivers/staging/iio/frequency/ad5930.c b/drivers/staging/iio/frequency/ad5930.c index 23777be..69e90e9 100644 --- a/drivers/staging/iio/frequency/ad5930.c +++ b/drivers/staging/iio/frequency/ad5930.c @@ -44,7 +44,6 @@ static ssize_t ad5930_set_parameter(struct device *dev, const char *buf, size_t len) { - struct spi_message msg; struct spi_transfer xfer; int ret; struct ad5903_config *config = (struct ad5903_config *)buf; @@ -64,9 +63,7 @@ static ssize_t ad5930_set_parameter(struct device *dev, xfer.tx_buf = config; mutex_lock(&st->lock); - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; error_ret: diff --git a/drivers/staging/iio/frequency/ad9850.c b/drivers/staging/iio/frequency/ad9850.c index 104f7a4..01a8a93 100644 --- a/drivers/staging/iio/frequency/ad9850.c +++ b/drivers/staging/iio/frequency/ad9850.c @@ -39,7 +39,6 @@ static ssize_t ad9850_set_parameter(struct device *dev, const char *buf, size_t len) { - struct spi_message msg; struct spi_transfer xfer; int ret; struct ad9850_config *config = (struct ad9850_config *)buf; @@ -50,9 +49,7 @@ static ssize_t ad9850_set_parameter(struct device *dev, xfer.tx_buf = config; mutex_lock(&st->lock); - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; error_ret: diff --git a/drivers/staging/iio/frequency/ad9852.c b/drivers/staging/iio/frequency/ad9852.c index 17ac825..1344031 100644 --- a/drivers/staging/iio/frequency/ad9852.c +++ b/drivers/staging/iio/frequency/ad9852.c @@ -183,7 +183,6 @@ static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9852_set_parameter, 0); static void ad9852_init(struct ad9852_state *st) { - struct spi_message msg; struct spi_transfer xfer; int ret; u8 config[5]; @@ -199,9 +198,7 @@ static void ad9852_init(struct ad9852_state *st) xfer.len = 5; xfer.tx_buf = &config; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c index 51c3bde..e5943e2 100644 --- a/drivers/staging/iio/meter/ade7753.c +++ b/drivers/staging/iio/meter/ade7753.c @@ -103,7 +103,6 @@ static int ade7753_spi_read_reg_24(struct device *dev, u8 reg_address, u32 *val) { - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7753_state *st = iio_priv(indio_dev); int ret; @@ -122,10 +121,7 @@ static int ade7753_spi_read_reg_24(struct device *dev, mutex_lock(&st->buf_lock); st->tx[0] = ADE7753_READ_REG(reg_address); - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X", reg_address); diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c index b50c89e..7b6503b 100644 --- a/drivers/staging/iio/meter/ade7754.c +++ b/drivers/staging/iio/meter/ade7754.c @@ -103,7 +103,6 @@ static int ade7754_spi_read_reg_24(struct device *dev, u8 reg_address, u32 *val) { - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7754_state *st = iio_priv(indio_dev); int ret; @@ -122,9 +121,7 @@ static int ade7754_spi_read_reg_24(struct device *dev, st->tx[2] = 0; st->tx[3] = 0; - spi_message_init(&msg); - spi_message_add_tail(xfers, &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X", reg_address); diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c index 3454e51..53c68dc 100644 --- a/drivers/staging/iio/meter/ade7758_core.c +++ b/drivers/staging/iio/meter/ade7758_core.c @@ -47,7 +47,6 @@ static int ade7758_spi_write_reg_16(struct device *dev, u16 value) { int ret; - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7758_state *st = iio_priv(indio_dev); struct spi_transfer xfers[] = { @@ -63,9 +62,7 @@ static int ade7758_spi_write_reg_16(struct device *dev, st->tx[1] = (value >> 8) & 0xFF; st->tx[2] = value & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(xfers, &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); mutex_unlock(&st->buf_lock); return ret; @@ -76,7 +73,6 @@ static int ade7758_spi_write_reg_24(struct device *dev, u32 value) { int ret; - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7758_state *st = iio_priv(indio_dev); struct spi_transfer xfers[] = { @@ -93,9 +89,7 @@ static int ade7758_spi_write_reg_24(struct device *dev, st->tx[2] = (value >> 8) & 0xFF; st->tx[3] = value & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(xfers, &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); mutex_unlock(&st->buf_lock); return ret; @@ -105,7 +99,6 @@ int ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val) { - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7758_state *st = iio_priv(indio_dev); int ret; @@ -128,10 +121,7 @@ int ade7758_spi_read_reg_8(struct device *dev, st->tx[0] = ADE7758_READ_REG(reg_address); st->tx[1] = 0; - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X", reg_address); @@ -148,7 +138,6 @@ static int ade7758_spi_read_reg_16(struct device *dev, u8 reg_address, u16 *val) { - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7758_state *st = iio_priv(indio_dev); int ret; @@ -173,10 +162,7 @@ static int ade7758_spi_read_reg_16(struct device *dev, st->tx[1] = 0; st->tx[2] = 0; - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X", reg_address); @@ -194,7 +180,6 @@ static int ade7758_spi_read_reg_24(struct device *dev, u8 reg_address, u32 *val) { - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7758_state *st = iio_priv(indio_dev); int ret; @@ -219,10 +204,7 @@ static int ade7758_spi_read_reg_24(struct device *dev, st->tx[2] = 0; st->tx[3] = 0; - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X", reg_address); diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c index 10b911b..17dc373 100644 --- a/drivers/staging/iio/meter/ade7759.c +++ b/drivers/staging/iio/meter/ade7759.c @@ -103,7 +103,6 @@ static int ade7759_spi_read_reg_40(struct device *dev, u8 reg_address, u64 *val) { - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7759_state *st = iio_priv(indio_dev); int ret; @@ -120,9 +119,7 @@ static int ade7759_spi_read_reg_40(struct device *dev, st->tx[0] = ADE7759_READ_REG(reg_address); memset(&st->tx[1], 0 , 5); - spi_message_init(&msg); - spi_message_add_tail(xfers, &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->us->dev, "problem when reading 40 bit register 0x%02X", reg_address); diff --git a/drivers/staging/iio/meter/ade7854-spi.c b/drivers/staging/iio/meter/ade7854-spi.c index f0984fa..a802cf2 100644 --- a/drivers/staging/iio/meter/ade7854-spi.c +++ b/drivers/staging/iio/meter/ade7854-spi.c @@ -20,7 +20,6 @@ static int ade7854_spi_write_reg_8(struct device *dev, u8 value) { int ret; - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); struct spi_transfer xfer = { @@ -35,9 +34,7 @@ static int ade7854_spi_write_reg_8(struct device *dev, st->tx[2] = reg_address & 0xFF; st->tx[3] = value & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->spi, &msg); + ret = spi_sync_transfer(st->spi, &xfer, 1); mutex_unlock(&st->buf_lock); return ret; @@ -48,7 +45,6 @@ static int ade7854_spi_write_reg_16(struct device *dev, u16 value) { int ret; - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); struct spi_transfer xfer = { @@ -64,9 +60,7 @@ static int ade7854_spi_write_reg_16(struct device *dev, st->tx[3] = (value >> 8) & 0xFF; st->tx[4] = value & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->spi, &msg); + ret = spi_sync_transfer(st->spi, &xfer, 1); mutex_unlock(&st->buf_lock); return ret; @@ -77,7 +71,6 @@ static int ade7854_spi_write_reg_24(struct device *dev, u32 value) { int ret; - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); struct spi_transfer xfer = { @@ -94,9 +87,7 @@ static int ade7854_spi_write_reg_24(struct device *dev, st->tx[4] = (value >> 8) & 0xFF; st->tx[5] = value & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->spi, &msg); + ret = spi_sync_transfer(st->spi, &xfer, 1); mutex_unlock(&st->buf_lock); return ret; @@ -107,7 +98,6 @@ static int ade7854_spi_write_reg_32(struct device *dev, u32 value) { int ret; - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); struct spi_transfer xfer = { @@ -125,9 +115,7 @@ static int ade7854_spi_write_reg_32(struct device *dev, st->tx[5] = (value >> 8) & 0xFF; st->tx[6] = value & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->spi, &msg); + ret = spi_sync_transfer(st->spi, &xfer, 1); mutex_unlock(&st->buf_lock); return ret; @@ -137,7 +125,6 @@ static int ade7854_spi_read_reg_8(struct device *dev, u16 reg_address, u8 *val) { - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; @@ -159,10 +146,7 @@ static int ade7854_spi_read_reg_8(struct device *dev, st->tx[1] = (reg_address >> 8) & 0xFF; st->tx[2] = reg_address & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->spi, &msg); + ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->spi->dev, "problem when reading 8 bit register 0x%02X", reg_address); @@ -179,7 +163,6 @@ static int ade7854_spi_read_reg_16(struct device *dev, u16 reg_address, u16 *val) { - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; @@ -200,10 +183,7 @@ static int ade7854_spi_read_reg_16(struct device *dev, st->tx[1] = (reg_address >> 8) & 0xFF; st->tx[2] = reg_address & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->spi, &msg); + ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->spi->dev, "problem when reading 16 bit register 0x%02X", reg_address); @@ -220,7 +200,6 @@ static int ade7854_spi_read_reg_24(struct device *dev, u16 reg_address, u32 *val) { - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; @@ -242,10 +221,7 @@ static int ade7854_spi_read_reg_24(struct device *dev, st->tx[1] = (reg_address >> 8) & 0xFF; st->tx[2] = reg_address & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->spi, &msg); + ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->spi->dev, "problem when reading 24 bit register 0x%02X", reg_address); @@ -262,7 +238,6 @@ static int ade7854_spi_read_reg_32(struct device *dev, u16 reg_address, u32 *val) { - struct spi_message msg; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; @@ -284,10 +259,7 @@ static int ade7854_spi_read_reg_32(struct device *dev, st->tx[1] = (reg_address >> 8) & 0xFF; st->tx[2] = reg_address & 0xFF; - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->spi, &msg); + ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->spi->dev, "problem when reading 32 bit register 0x%02X", reg_address); diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index ed07a34..53110b6 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -130,15 +130,12 @@ static int ad2s1210_config_read(struct ad2s1210_state *st, .rx_buf = st->rx, .tx_buf = st->tx, }; - struct spi_message msg; int ret = 0; ad2s1210_set_mode(MOD_CONFIG, st); - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); st->tx[0] = address | AD2S1210_MSB_IS_HIGH; st->tx[1] = AD2S1210_REG_FAULT; - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret < 0) return ret; st->old_data = true; -- cgit v0.10.2 From aaa300262c5912bda34c9cf871719209eae01b06 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 9 Feb 2013 10:49:00 +0000 Subject: iio:triggers Protect functions in triggers.h from use when not compiled Also include a couple of forward defs of struct iio_trigger and struct iio_trigger_ops to avoid doing this in each driver. Signed-off-by: Jonathan Cameron Reported-by: Randy Dunlap Acked-by: Denis Ciocca diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h index 20239da..c66e0a9 100644 --- a/include/linux/iio/trigger.h +++ b/include/linux/iio/trigger.h @@ -12,6 +12,7 @@ #ifndef _IIO_TRIGGER_H_ #define _IIO_TRIGGER_H_ +#ifdef CONFIG_IIO_TRIGGER struct iio_subirq { bool enabled; }; @@ -117,4 +118,8 @@ irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private); __printf(1, 2) struct iio_trigger *iio_trigger_alloc(const char *fmt, ...); void iio_trigger_free(struct iio_trigger *trig); +#else +struct iio_trigger; +struct iio_trigger_ops; +#endif #endif /* _IIO_TRIGGER_H_ */ -- cgit v0.10.2 From 8ce4a56a52bf566659768a9e46e759e7cd5f33d9 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 9 Feb 2013 10:49:00 +0000 Subject: iio:st_sensors fix build when !CONFIG_IIO_TRIGGER Partly a case of removing unused headers and partly a case of ifdefing out the iio_trigger_ops structures. This has come about because of an 'unusual' separation of code in this driver. Signed-off-by: Jonathan Cameron Reported-by: Randy Dunlap Acked-by: Denis Ciocca diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index a235de2..e0f5a3c 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include @@ -419,10 +419,15 @@ static const struct iio_info accel_info = { .write_raw = &st_accel_write_raw, }; +#ifdef CONFIG_IIO_TRIGGER static const struct iio_trigger_ops st_accel_trigger_ops = { .owner = THIS_MODULE, .set_trigger_state = ST_ACCEL_TRIGGER_SET_STATE, }; +#define ST_ACCEL_TRIGGER_OPS (&st_accel_trigger_ops) +#else +#define ST_ACCEL_TRIGGER_OPS NULL +#endif int st_accel_common_probe(struct iio_dev *indio_dev) { @@ -455,7 +460,7 @@ int st_accel_common_probe(struct iio_dev *indio_dev) goto st_accel_common_probe_error; err = st_sensors_allocate_trigger(indio_dev, - &st_accel_trigger_ops); + ST_ACCEL_TRIGGER_OPS); if (err < 0) goto st_accel_probe_trigger_error; } diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index 90b8ddf..ffc9d09 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index dbd45c0..22b35bf 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index 0a09998..fa9b242 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include @@ -287,10 +287,15 @@ static const struct iio_info gyro_info = { .write_raw = &st_gyro_write_raw, }; +#ifdef CONFIG_IIO_TRIGGER static const struct iio_trigger_ops st_gyro_trigger_ops = { .owner = THIS_MODULE, .set_trigger_state = ST_GYRO_TRIGGER_SET_STATE, }; +#define ST_GYRO_TRIGGER_OPS (&st_gyro_trigger_ops) +#else +#define ST_GYRO_TRIGGER_OPS NULL +#endif int st_gyro_common_probe(struct iio_dev *indio_dev) { @@ -323,7 +328,7 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) goto st_gyro_common_probe_error; err = st_sensors_allocate_trigger(indio_dev, - &st_gyro_trigger_ops); + ST_GYRO_TRIGGER_OPS); if (err < 0) goto st_gyro_probe_trigger_error; } diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c index a44b5b4..8a31050 100644 --- a/drivers/iio/gyro/st_gyro_i2c.c +++ b/drivers/iio/gyro/st_gyro_i2c.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c index 8b4dcc5..f354039 100644 --- a/drivers/iio/gyro/st_gyro_spi.c +++ b/drivers/iio/gyro/st_gyro_spi.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index a69fbe1..16f0d6d 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index 710b256a5..e6adc4a 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c index 94547e7..51adb79 100644 --- a/drivers/iio/magnetometer/st_magn_spi.c +++ b/drivers/iio/magnetometer/st_magn_spi.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include -- cgit v0.10.2 From 09a642b78523e9f4c5970c806ad218aa3de31551 Mon Sep 17 00:00:00 2001 From: Ge Gao Date: Sat, 2 Feb 2013 00:26:00 +0000 Subject: Invensense MPU6050 Device Driver. This the basic functional Invensense MPU6050 Device driver. Signed-off-by: Ge Gao Reviewed-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron diff --git a/Documentation/ABI/testing/sysfs-bus-iio-mpu6050 b/Documentation/ABI/testing/sysfs-bus-iio-mpu6050 new file mode 100644 index 0000000..cb53737 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-mpu6050 @@ -0,0 +1,13 @@ +What: /sys/bus/iio/devices/iio:deviceX/in_gyro_matrix +What: /sys/bus/iio/devices/iio:deviceX/in_accel_matrix +What: /sys/bus/iio/devices/iio:deviceX/in_magn_matrix +KernelVersion: 3.4.0 +Contact: linux-iio@vger.kernel.org +Description: + This is mounting matrix for motion sensors. Mounting matrix + is a 3x3 unitary matrix. A typical mounting matrix would look like + [0, 1, 0; 1, 0, 0; 0, 0, -1]. Using this information, it would be + easy to tell the relative positions among sensors as well as their + positions relative to the board that holds these sensors. Identity matrix + [1, 0, 0; 0, 1, 0; 0, 0, 1] means sensor chip and device are perfectly + aligned with each other. All axes are exactly the same. diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 47f66ed..4f40a10 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -36,3 +36,5 @@ config IIO_ADIS_LIB_BUFFER help A set of buffer helper functions for the Analog Devices ADIS* device family. + +source "drivers/iio/imu/inv_mpu6050/Kconfig" diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index 019b717..f2f56ce 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -11,3 +11,5 @@ adis_lib-y += adis.o adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_trigger.o adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o + +obj-y += inv_mpu6050/ diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig new file mode 100644 index 0000000..b5cfa3a --- /dev/null +++ b/drivers/iio/imu/inv_mpu6050/Kconfig @@ -0,0 +1,13 @@ +# +# inv-mpu6050 drivers for Invensense MPU devices and combos +# + +config INV_MPU6050_IIO + tristate "Invensense MPU6050 devices" + depends on I2C && SYSFS + select IIO_TRIGGERED_BUFFER + help + This driver supports the Invensense MPU6050 devices. + It is a gyroscope/accelerometer combo device. + This driver can be built as a module. The module will be called + inv-mpu6050. diff --git a/drivers/iio/imu/inv_mpu6050/Makefile b/drivers/iio/imu/inv_mpu6050/Makefile new file mode 100644 index 0000000..3a677c7 --- /dev/null +++ b/drivers/iio/imu/inv_mpu6050/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for Invensense MPU6050 device. +# + +obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o +inv-mpu6050-objs := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c new file mode 100644 index 0000000..37ca05b --- /dev/null +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -0,0 +1,795 @@ +/* +* Copyright (C) 2012 Invensense, Inc. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "inv_mpu_iio.h" + +/* + * this is the gyro scale translated from dynamic range plus/minus + * {250, 500, 1000, 2000} to rad/s + */ +static const int gyro_scale_6050[] = {133090, 266181, 532362, 1064724}; + +/* + * this is the accel scale translated from dynamic range plus/minus + * {2, 4, 8, 16} to m/s^2 + */ +static const int accel_scale[] = {598, 1196, 2392, 4785}; + +static const struct inv_mpu6050_reg_map reg_set_6050 = { + .sample_rate_div = INV_MPU6050_REG_SAMPLE_RATE_DIV, + .lpf = INV_MPU6050_REG_CONFIG, + .user_ctrl = INV_MPU6050_REG_USER_CTRL, + .fifo_en = INV_MPU6050_REG_FIFO_EN, + .gyro_config = INV_MPU6050_REG_GYRO_CONFIG, + .accl_config = INV_MPU6050_REG_ACCEL_CONFIG, + .fifo_count_h = INV_MPU6050_REG_FIFO_COUNT_H, + .fifo_r_w = INV_MPU6050_REG_FIFO_R_W, + .raw_gyro = INV_MPU6050_REG_RAW_GYRO, + .raw_accl = INV_MPU6050_REG_RAW_ACCEL, + .temperature = INV_MPU6050_REG_TEMPERATURE, + .int_enable = INV_MPU6050_REG_INT_ENABLE, + .pwr_mgmt_1 = INV_MPU6050_REG_PWR_MGMT_1, + .pwr_mgmt_2 = INV_MPU6050_REG_PWR_MGMT_2, +}; + +static const struct inv_mpu6050_chip_config chip_config_6050 = { + .fsr = INV_MPU6050_FSR_2000DPS, + .lpf = INV_MPU6050_FILTER_20HZ, + .fifo_rate = INV_MPU6050_INIT_FIFO_RATE, + .gyro_fifo_enable = false, + .accl_fifo_enable = false, + .accl_fs = INV_MPU6050_FS_02G, +}; + +static const struct inv_mpu6050_hw hw_info[INV_NUM_PARTS] = { + { + .num_reg = 117, + .name = "MPU6050", + .reg = ®_set_6050, + .config = &chip_config_6050, + }, +}; + +int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 d) +{ + return i2c_smbus_write_i2c_block_data(st->client, reg, 1, &d); +} + +int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask) +{ + u8 d, mgmt_1; + int result; + + /* switch clock needs to be careful. Only when gyro is on, can + clock source be switched to gyro. Otherwise, it must be set to + internal clock */ + if (INV_MPU6050_BIT_PWR_GYRO_STBY == mask) { + result = i2c_smbus_read_i2c_block_data(st->client, + st->reg->pwr_mgmt_1, 1, &mgmt_1); + if (result != 1) + return result; + + mgmt_1 &= ~INV_MPU6050_BIT_CLK_MASK; + } + + if ((INV_MPU6050_BIT_PWR_GYRO_STBY == mask) && (!en)) { + /* turning off gyro requires switch to internal clock first. + Then turn off gyro engine */ + mgmt_1 |= INV_CLK_INTERNAL; + result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, mgmt_1); + if (result) + return result; + } + + result = i2c_smbus_read_i2c_block_data(st->client, + st->reg->pwr_mgmt_2, 1, &d); + if (result != 1) + return result; + if (en) + d &= ~mask; + else + d |= mask; + result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_2, d); + if (result) + return result; + + if (en) { + /* Wait for output stablize */ + msleep(INV_MPU6050_TEMP_UP_TIME); + if (INV_MPU6050_BIT_PWR_GYRO_STBY == mask) { + /* switch internal clock to PLL */ + mgmt_1 |= INV_CLK_PLL; + result = inv_mpu6050_write_reg(st, + st->reg->pwr_mgmt_1, mgmt_1); + if (result) + return result; + } + } + + return 0; +} + +int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on) +{ + int result; + + if (power_on) + result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, 0); + else + result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, + INV_MPU6050_BIT_SLEEP); + if (result) + return result; + + if (power_on) + msleep(INV_MPU6050_REG_UP_TIME); + + return 0; +} + +/** + * inv_mpu6050_init_config() - Initialize hardware, disable FIFO. + * + * Initial configuration: + * FSR: ± 2000DPS + * DLPF: 20Hz + * FIFO rate: 50Hz + * Clock source: Gyro PLL + */ +static int inv_mpu6050_init_config(struct iio_dev *indio_dev) +{ + int result; + u8 d; + struct inv_mpu6050_state *st = iio_priv(indio_dev); + + result = inv_mpu6050_set_power_itg(st, true); + if (result) + return result; + d = (INV_MPU6050_FSR_2000DPS << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT); + result = inv_mpu6050_write_reg(st, st->reg->gyro_config, d); + if (result) + return result; + + d = INV_MPU6050_FILTER_20HZ; + result = inv_mpu6050_write_reg(st, st->reg->lpf, d); + if (result) + return result; + + d = INV_MPU6050_ONE_K_HZ / INV_MPU6050_INIT_FIFO_RATE - 1; + result = inv_mpu6050_write_reg(st, st->reg->sample_rate_div, d); + if (result) + return result; + + d = (INV_MPU6050_FS_02G << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT); + result = inv_mpu6050_write_reg(st, st->reg->accl_config, d); + if (result) + return result; + + memcpy(&st->chip_config, hw_info[st->chip_type].config, + sizeof(struct inv_mpu6050_chip_config)); + result = inv_mpu6050_set_power_itg(st, false); + + return result; +} + +static int inv_mpu6050_sensor_show(struct inv_mpu6050_state *st, int reg, + int axis, int *val) +{ + int ind, result; + __be16 d; + + ind = (axis - IIO_MOD_X) * 2; + result = i2c_smbus_read_i2c_block_data(st->client, reg + ind, 2, + (u8 *)&d); + if (result != 2) + return -EINVAL; + *val = (short)be16_to_cpup(&d); + + return IIO_VAL_INT; +} + +static int inv_mpu6050_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) { + struct inv_mpu6050_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + { + int ret, result; + + ret = IIO_VAL_INT; + result = 0; + mutex_lock(&indio_dev->mlock); + if (!st->chip_config.enable) { + result = inv_mpu6050_set_power_itg(st, true); + if (result) + goto error_read_raw; + } + /* when enable is on, power is already on */ + switch (chan->type) { + case IIO_ANGL_VEL: + if (!st->chip_config.gyro_fifo_enable || + !st->chip_config.enable) { + result = inv_mpu6050_switch_engine(st, true, + INV_MPU6050_BIT_PWR_GYRO_STBY); + if (result) + goto error_read_raw; + } + ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro, + chan->channel2, val); + if (!st->chip_config.gyro_fifo_enable || + !st->chip_config.enable) { + result = inv_mpu6050_switch_engine(st, false, + INV_MPU6050_BIT_PWR_GYRO_STBY); + if (result) + goto error_read_raw; + } + break; + case IIO_ACCEL: + if (!st->chip_config.accl_fifo_enable || + !st->chip_config.enable) { + result = inv_mpu6050_switch_engine(st, true, + INV_MPU6050_BIT_PWR_ACCL_STBY); + if (result) + goto error_read_raw; + } + ret = inv_mpu6050_sensor_show(st, st->reg->raw_accl, + chan->channel2, val); + if (!st->chip_config.accl_fifo_enable || + !st->chip_config.enable) { + result = inv_mpu6050_switch_engine(st, false, + INV_MPU6050_BIT_PWR_ACCL_STBY); + if (result) + goto error_read_raw; + } + break; + case IIO_TEMP: + /* wait for stablization */ + msleep(INV_MPU6050_SENSOR_UP_TIME); + inv_mpu6050_sensor_show(st, st->reg->temperature, + IIO_MOD_X, val); + break; + default: + ret = -EINVAL; + break; + } +error_read_raw: + if (!st->chip_config.enable) + result |= inv_mpu6050_set_power_itg(st, false); + mutex_unlock(&indio_dev->mlock); + if (result) + return result; + + return ret; + } + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_ANGL_VEL: + *val = 0; + *val2 = gyro_scale_6050[st->chip_config.fsr]; + + return IIO_VAL_INT_PLUS_NANO; + case IIO_ACCEL: + *val = 0; + *val2 = accel_scale[st->chip_config.accl_fs]; + + return IIO_VAL_INT_PLUS_MICRO; + case IIO_TEMP: + *val = 0; + *val2 = INV_MPU6050_TEMP_SCALE; + + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + switch (chan->type) { + case IIO_TEMP: + *val = INV_MPU6050_TEMP_OFFSET; + + return IIO_VAL_INT; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int inv_mpu6050_write_fsr(struct inv_mpu6050_state *st, int fsr) +{ + int result; + u8 d; + + if (fsr < 0 || fsr > INV_MPU6050_MAX_GYRO_FS_PARAM) + return -EINVAL; + if (fsr == st->chip_config.fsr) + return 0; + + d = (fsr << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT); + result = inv_mpu6050_write_reg(st, st->reg->gyro_config, d); + if (result) + return result; + st->chip_config.fsr = fsr; + + return 0; +} + +static int inv_mpu6050_write_accel_fs(struct inv_mpu6050_state *st, int fs) +{ + int result; + u8 d; + + if (fs < 0 || fs > INV_MPU6050_MAX_ACCL_FS_PARAM) + return -EINVAL; + if (fs == st->chip_config.accl_fs) + return 0; + + d = (fs << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT); + result = inv_mpu6050_write_reg(st, st->reg->accl_config, d); + if (result) + return result; + st->chip_config.accl_fs = fs; + + return 0; +} + +static int inv_mpu6050_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) { + struct inv_mpu6050_state *st = iio_priv(indio_dev); + int result; + + mutex_lock(&indio_dev->mlock); + /* we should only update scale when the chip is disabled, i.e., + not running */ + if (st->chip_config.enable) { + result = -EBUSY; + goto error_write_raw; + } + result = inv_mpu6050_set_power_itg(st, true); + if (result) + goto error_write_raw; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_ANGL_VEL: + result = inv_mpu6050_write_fsr(st, val); + break; + case IIO_ACCEL: + result = inv_mpu6050_write_accel_fs(st, val); + break; + default: + result = -EINVAL; + break; + } + break; + default: + result = -EINVAL; + break; + } + +error_write_raw: + result |= inv_mpu6050_set_power_itg(st, false); + mutex_unlock(&indio_dev->mlock); + + return result; +} + +/** + * inv_mpu6050_set_lpf() - set low pass filer based on fifo rate. + * + * Based on the Nyquist principle, the sampling rate must + * exceed twice of the bandwidth of the signal, or there + * would be alising. This function basically search for the + * correct low pass parameters based on the fifo rate, e.g, + * sampling frequency. + */ +static int inv_mpu6050_set_lpf(struct inv_mpu6050_state *st, int rate) +{ + const int hz[] = {188, 98, 42, 20, 10, 5}; + const int d[] = {INV_MPU6050_FILTER_188HZ, INV_MPU6050_FILTER_98HZ, + INV_MPU6050_FILTER_42HZ, INV_MPU6050_FILTER_20HZ, + INV_MPU6050_FILTER_10HZ, INV_MPU6050_FILTER_5HZ}; + int i, h, result; + u8 data; + + h = (rate >> 1); + i = 0; + while ((h < hz[i]) && (i < ARRAY_SIZE(d) - 1)) + i++; + data = d[i]; + result = inv_mpu6050_write_reg(st, st->reg->lpf, data); + if (result) + return result; + st->chip_config.lpf = data; + + return 0; +} + +/** + * inv_mpu6050_fifo_rate_store() - Set fifo rate. + */ +static ssize_t inv_mpu6050_fifo_rate_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + s32 fifo_rate; + u8 d; + int result; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_mpu6050_state *st = iio_priv(indio_dev); + + if (kstrtoint(buf, 10, &fifo_rate)) + return -EINVAL; + if (fifo_rate < INV_MPU6050_MIN_FIFO_RATE || + fifo_rate > INV_MPU6050_MAX_FIFO_RATE) + return -EINVAL; + if (fifo_rate == st->chip_config.fifo_rate) + return count; + + mutex_lock(&indio_dev->mlock); + if (st->chip_config.enable) { + result = -EBUSY; + goto fifo_rate_fail; + } + result = inv_mpu6050_set_power_itg(st, true); + if (result) + goto fifo_rate_fail; + + d = INV_MPU6050_ONE_K_HZ / fifo_rate - 1; + result = inv_mpu6050_write_reg(st, st->reg->sample_rate_div, d); + if (result) + goto fifo_rate_fail; + st->chip_config.fifo_rate = fifo_rate; + + result = inv_mpu6050_set_lpf(st, fifo_rate); + if (result) + goto fifo_rate_fail; + +fifo_rate_fail: + result |= inv_mpu6050_set_power_itg(st, false); + mutex_unlock(&indio_dev->mlock); + if (result) + return result; + + return count; +} + +/** + * inv_fifo_rate_show() - Get the current sampling rate. + */ +static ssize_t inv_fifo_rate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct inv_mpu6050_state *st = iio_priv(dev_to_iio_dev(dev)); + + return sprintf(buf, "%d\n", st->chip_config.fifo_rate); +} + +/** + * inv_attr_show() - calling this function will show current + * parameters. + */ +static ssize_t inv_attr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct inv_mpu6050_state *st = iio_priv(dev_to_iio_dev(dev)); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + s8 *m; + + switch (this_attr->address) { + /* In MPU6050, the two matrix are the same because gyro and accel + are integrated in one chip */ + case ATTR_GYRO_MATRIX: + case ATTR_ACCL_MATRIX: + m = st->plat_data.orientation; + + return sprintf(buf, "%d, %d, %d; %d, %d, %d; %d, %d, %d\n", + m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]); + default: + return -EINVAL; + } +} + +/** + * inv_mpu6050_validate_trigger() - validate_trigger callback for invensense + * MPU6050 device. + * @indio_dev: The IIO device + * @trig: The new trigger + * + * Returns: 0 if the 'trig' matches the trigger registered by the MPU6050 + * device, -EINVAL otherwise. + */ +static int inv_mpu6050_validate_trigger(struct iio_dev *indio_dev, + struct iio_trigger *trig) +{ + struct inv_mpu6050_state *st = iio_priv(indio_dev); + + if (st->trig != trig) + return -EINVAL; + + return 0; +} + +#define INV_MPU6050_CHAN(_type, _channel2, _index) \ + { \ + .type = _type, \ + .modified = 1, \ + .channel2 = _channel2, \ + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT \ + | IIO_CHAN_INFO_RAW_SEPARATE_BIT, \ + .scan_index = _index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .shift = 0 , \ + .endianness = IIO_BE, \ + }, \ + } + +static const struct iio_chan_spec inv_mpu_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(INV_MPU6050_SCAN_TIMESTAMP), + /* + * Note that temperature should only be via polled reading only, + * not the final scan elements output. + */ + { + .type = IIO_TEMP, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT + | IIO_CHAN_INFO_OFFSET_SEPARATE_BIT + | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .scan_index = -1, + }, + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X), + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU6050_SCAN_GYRO_Y), + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU6050_SCAN_GYRO_Z), + + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_X, INV_MPU6050_SCAN_ACCL_X), + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_MPU6050_SCAN_ACCL_Y), + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z), +}; + +/* constant IIO attribute */ +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("10 20 50 100 200 500"); +static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, inv_fifo_rate_show, + inv_mpu6050_fifo_rate_store); +static IIO_DEVICE_ATTR(in_gyro_matrix, S_IRUGO, inv_attr_show, NULL, + ATTR_GYRO_MATRIX); +static IIO_DEVICE_ATTR(in_accel_matrix, S_IRUGO, inv_attr_show, NULL, + ATTR_ACCL_MATRIX); + +static struct attribute *inv_attributes[] = { + &iio_dev_attr_in_gyro_matrix.dev_attr.attr, + &iio_dev_attr_in_accel_matrix.dev_attr.attr, + &iio_dev_attr_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group inv_attribute_group = { + .attrs = inv_attributes +}; + +static const struct iio_info mpu_info = { + .driver_module = THIS_MODULE, + .read_raw = &inv_mpu6050_read_raw, + .write_raw = &inv_mpu6050_write_raw, + .attrs = &inv_attribute_group, + .validate_trigger = inv_mpu6050_validate_trigger, +}; + +/** + * inv_check_and_setup_chip() - check and setup chip. + */ +static int inv_check_and_setup_chip(struct inv_mpu6050_state *st, + const struct i2c_device_id *id) +{ + int result; + + st->chip_type = INV_MPU6050; + st->hw = &hw_info[st->chip_type]; + st->reg = hw_info[st->chip_type].reg; + + /* reset to make sure previous state are not there */ + result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, + INV_MPU6050_BIT_H_RESET); + if (result) + return result; + msleep(INV_MPU6050_POWER_UP_TIME); + /* toggle power state. After reset, the sleep bit could be on + or off depending on the OTP settings. Toggling power would + make it in a definite state as well as making the hardware + state align with the software state */ + result = inv_mpu6050_set_power_itg(st, false); + if (result) + return result; + result = inv_mpu6050_set_power_itg(st, true); + if (result) + return result; + + result = inv_mpu6050_switch_engine(st, false, + INV_MPU6050_BIT_PWR_ACCL_STBY); + if (result) + return result; + result = inv_mpu6050_switch_engine(st, false, + INV_MPU6050_BIT_PWR_GYRO_STBY); + if (result) + return result; + + return 0; +} + +/** + * inv_mpu_probe() - probe function. + * @client: i2c client. + * @id: i2c device id. + * + * Returns 0 on success, a negative error code otherwise. + */ +static int inv_mpu_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct inv_mpu6050_state *st; + struct iio_dev *indio_dev; + int result; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_I2C_BLOCK | + I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) { + result = -ENOSYS; + goto out_no_free; + } + indio_dev = iio_device_alloc(sizeof(*st)); + if (indio_dev == NULL) { + result = -ENOMEM; + goto out_no_free; + } + st = iio_priv(indio_dev); + st->client = client; + st->plat_data = *(struct inv_mpu6050_platform_data + *)dev_get_platdata(&client->dev); + /* power is turned on inside check chip type*/ + result = inv_check_and_setup_chip(st, id); + if (result) + goto out_free; + + result = inv_mpu6050_init_config(indio_dev); + if (result) { + dev_err(&client->dev, + "Could not initialize device.\n"); + goto out_free; + } + + i2c_set_clientdata(client, indio_dev); + indio_dev->dev.parent = &client->dev; + indio_dev->name = id->name; + indio_dev->channels = inv_mpu_channels; + indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels); + + indio_dev->info = &mpu_info; + indio_dev->modes = INDIO_BUFFER_TRIGGERED; + + result = iio_triggered_buffer_setup(indio_dev, + inv_mpu6050_irq_handler, + inv_mpu6050_read_fifo, + NULL); + if (result) { + dev_err(&st->client->dev, "configure buffer fail %d\n", + result); + goto out_free; + } + result = inv_mpu6050_probe_trigger(indio_dev); + if (result) { + dev_err(&st->client->dev, "trigger probe fail %d\n", result); + goto out_unreg_ring; + } + + INIT_KFIFO(st->timestamps); + spin_lock_init(&st->time_stamp_lock); + result = iio_device_register(indio_dev); + if (result) { + dev_err(&st->client->dev, "IIO register fail %d\n", result); + goto out_remove_trigger; + } + + return 0; + +out_remove_trigger: + inv_mpu6050_remove_trigger(st); +out_unreg_ring: + iio_triggered_buffer_cleanup(indio_dev); +out_free: + iio_device_free(indio_dev); +out_no_free: + + return result; +} + +static int inv_mpu_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct inv_mpu6050_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + inv_mpu6050_remove_trigger(st); + iio_triggered_buffer_cleanup(indio_dev); + iio_device_free(indio_dev); + + return 0; +} +#ifdef CONFIG_PM_SLEEP + +static int inv_mpu_resume(struct device *dev) +{ + return inv_mpu6050_set_power_itg( + iio_priv(i2c_get_clientdata(to_i2c_client(dev))), true); +} + +static int inv_mpu_suspend(struct device *dev) +{ + return inv_mpu6050_set_power_itg( + iio_priv(i2c_get_clientdata(to_i2c_client(dev))), false); +} +static SIMPLE_DEV_PM_OPS(inv_mpu_pmops, inv_mpu_suspend, inv_mpu_resume); + +#define INV_MPU6050_PMOPS (&inv_mpu_pmops) +#else +#define INV_MPU6050_PMOPS NULL +#endif /* CONFIG_PM_SLEEP */ + +/* + * device id table is used to identify what device can be + * supported by this driver + */ +static const struct i2c_device_id inv_mpu_id[] = { + {"mpu6050", INV_MPU6050}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, inv_mpu_id); + +static struct i2c_driver inv_mpu_driver = { + .probe = inv_mpu_probe, + .remove = inv_mpu_remove, + .id_table = inv_mpu_id, + .driver = { + .owner = THIS_MODULE, + .name = "inv-mpu6050", + .pm = INV_MPU6050_PMOPS, + }, +}; + +module_i2c_driver(inv_mpu_driver); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Invensense device MPU6050 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h new file mode 100644 index 0000000..f383955 --- /dev/null +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -0,0 +1,246 @@ +/* +* Copyright (C) 2012 Invensense, Inc. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * struct inv_mpu6050_reg_map - Notable registers. + * @sample_rate_div: Divider applied to gyro output rate. + * @lpf: Configures internal low pass filter. + * @user_ctrl: Enables/resets the FIFO. + * @fifo_en: Determines which data will appear in FIFO. + * @gyro_config: gyro config register. + * @accl_config: accel config register + * @fifo_count_h: Upper byte of FIFO count. + * @fifo_r_w: FIFO register. + * @raw_gyro: Address of first gyro register. + * @raw_accl: Address of first accel register. + * @temperature: temperature register + * @int_enable: Interrupt enable register. + * @pwr_mgmt_1: Controls chip's power state and clock source. + * @pwr_mgmt_2: Controls power state of individual sensors. + */ +struct inv_mpu6050_reg_map { + u8 sample_rate_div; + u8 lpf; + u8 user_ctrl; + u8 fifo_en; + u8 gyro_config; + u8 accl_config; + u8 fifo_count_h; + u8 fifo_r_w; + u8 raw_gyro; + u8 raw_accl; + u8 temperature; + u8 int_enable; + u8 pwr_mgmt_1; + u8 pwr_mgmt_2; +}; + +/*device enum */ +enum inv_devices { + INV_MPU6050, + INV_NUM_PARTS +}; + +/** + * struct inv_mpu6050_chip_config - Cached chip configuration data. + * @fsr: Full scale range. + * @lpf: Digital low pass filter frequency. + * @accl_fs: accel full scale range. + * @enable: master enable state. + * @accl_fifo_enable: enable accel data output + * @gyro_fifo_enable: enable gyro data output + * @fifo_rate: FIFO update rate. + */ +struct inv_mpu6050_chip_config { + unsigned int fsr:2; + unsigned int lpf:3; + unsigned int accl_fs:2; + unsigned int enable:1; + unsigned int accl_fifo_enable:1; + unsigned int gyro_fifo_enable:1; + u16 fifo_rate; +}; + +/** + * struct inv_mpu6050_hw - Other important hardware information. + * @num_reg: Number of registers on device. + * @name: name of the chip. + * @reg: register map of the chip. + * @config: configuration of the chip. + */ +struct inv_mpu6050_hw { + u8 num_reg; + u8 *name; + const struct inv_mpu6050_reg_map *reg; + const struct inv_mpu6050_chip_config *config; +}; + +/* + * struct inv_mpu6050_state - Driver state variables. + * @TIMESTAMP_FIFO_SIZE: fifo size for timestamp. + * @trig: IIO trigger. + * @chip_config: Cached attribute information. + * @reg: Map of important registers. + * @hw: Other hardware-specific information. + * @chip_type: chip type. + * @time_stamp_lock: spin lock to time stamp. + * @client: i2c client handle. + * @plat_data: platform data. + * @timestamps: kfifo queue to store time stamp. + */ +struct inv_mpu6050_state { +#define TIMESTAMP_FIFO_SIZE 16 + struct iio_trigger *trig; + struct inv_mpu6050_chip_config chip_config; + const struct inv_mpu6050_reg_map *reg; + const struct inv_mpu6050_hw *hw; + enum inv_devices chip_type; + spinlock_t time_stamp_lock; + struct i2c_client *client; + struct inv_mpu6050_platform_data plat_data; + DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE); +}; + +/*register and associated bit definition*/ +#define INV_MPU6050_REG_SAMPLE_RATE_DIV 0x19 +#define INV_MPU6050_REG_CONFIG 0x1A +#define INV_MPU6050_REG_GYRO_CONFIG 0x1B +#define INV_MPU6050_REG_ACCEL_CONFIG 0x1C + +#define INV_MPU6050_REG_FIFO_EN 0x23 +#define INV_MPU6050_BIT_ACCEL_OUT 0x08 +#define INV_MPU6050_BITS_GYRO_OUT 0x70 + +#define INV_MPU6050_REG_INT_ENABLE 0x38 +#define INV_MPU6050_BIT_DATA_RDY_EN 0x01 +#define INV_MPU6050_BIT_DMP_INT_EN 0x02 + +#define INV_MPU6050_REG_RAW_ACCEL 0x3B +#define INV_MPU6050_REG_TEMPERATURE 0x41 +#define INV_MPU6050_REG_RAW_GYRO 0x43 + +#define INV_MPU6050_REG_USER_CTRL 0x6A +#define INV_MPU6050_BIT_FIFO_RST 0x04 +#define INV_MPU6050_BIT_DMP_RST 0x08 +#define INV_MPU6050_BIT_I2C_MST_EN 0x20 +#define INV_MPU6050_BIT_FIFO_EN 0x40 +#define INV_MPU6050_BIT_DMP_EN 0x80 + +#define INV_MPU6050_REG_PWR_MGMT_1 0x6B +#define INV_MPU6050_BIT_H_RESET 0x80 +#define INV_MPU6050_BIT_SLEEP 0x40 +#define INV_MPU6050_BIT_CLK_MASK 0x7 + +#define INV_MPU6050_REG_PWR_MGMT_2 0x6C +#define INV_MPU6050_BIT_PWR_ACCL_STBY 0x38 +#define INV_MPU6050_BIT_PWR_GYRO_STBY 0x07 + +#define INV_MPU6050_REG_FIFO_COUNT_H 0x72 +#define INV_MPU6050_REG_FIFO_R_W 0x74 + +#define INV_MPU6050_BYTES_PER_3AXIS_SENSOR 6 +#define INV_MPU6050_FIFO_COUNT_BYTE 2 +#define INV_MPU6050_FIFO_THRESHOLD 500 +#define INV_MPU6050_POWER_UP_TIME 100 +#define INV_MPU6050_TEMP_UP_TIME 100 +#define INV_MPU6050_SENSOR_UP_TIME 30 +#define INV_MPU6050_REG_UP_TIME 5 + +#define INV_MPU6050_TEMP_OFFSET 12421 +#define INV_MPU6050_TEMP_SCALE 2941 +#define INV_MPU6050_MAX_GYRO_FS_PARAM 3 +#define INV_MPU6050_MAX_ACCL_FS_PARAM 3 +#define INV_MPU6050_THREE_AXIS 3 +#define INV_MPU6050_GYRO_CONFIG_FSR_SHIFT 3 +#define INV_MPU6050_ACCL_CONFIG_FSR_SHIFT 3 + +/* 6 + 6 round up and plus 8 */ +#define INV_MPU6050_OUTPUT_DATA_SIZE 24 + +/* init parameters */ +#define INV_MPU6050_INIT_FIFO_RATE 50 +#define INV_MPU6050_TIME_STAMP_TOR 5 +#define INV_MPU6050_MAX_FIFO_RATE 1000 +#define INV_MPU6050_MIN_FIFO_RATE 4 +#define INV_MPU6050_ONE_K_HZ 1000 + +/* scan element definition */ +enum inv_mpu6050_scan { + INV_MPU6050_SCAN_ACCL_X, + INV_MPU6050_SCAN_ACCL_Y, + INV_MPU6050_SCAN_ACCL_Z, + INV_MPU6050_SCAN_GYRO_X, + INV_MPU6050_SCAN_GYRO_Y, + INV_MPU6050_SCAN_GYRO_Z, + INV_MPU6050_SCAN_TIMESTAMP, +}; + +enum inv_mpu6050_filter_e { + INV_MPU6050_FILTER_256HZ_NOLPF2 = 0, + INV_MPU6050_FILTER_188HZ, + INV_MPU6050_FILTER_98HZ, + INV_MPU6050_FILTER_42HZ, + INV_MPU6050_FILTER_20HZ, + INV_MPU6050_FILTER_10HZ, + INV_MPU6050_FILTER_5HZ, + INV_MPU6050_FILTER_2100HZ_NOLPF, + NUM_MPU6050_FILTER +}; + +/* IIO attribute address */ +enum INV_MPU6050_IIO_ATTR_ADDR { + ATTR_GYRO_MATRIX, + ATTR_ACCL_MATRIX, +}; + +enum inv_mpu6050_accl_fs_e { + INV_MPU6050_FS_02G = 0, + INV_MPU6050_FS_04G, + INV_MPU6050_FS_08G, + INV_MPU6050_FS_16G, + NUM_ACCL_FSR +}; + +enum inv_mpu6050_fsr_e { + INV_MPU6050_FSR_250DPS = 0, + INV_MPU6050_FSR_500DPS, + INV_MPU6050_FSR_1000DPS, + INV_MPU6050_FSR_2000DPS, + NUM_MPU6050_FSR +}; + +enum inv_mpu6050_clock_sel_e { + INV_CLK_INTERNAL = 0, + INV_CLK_PLL, + NUM_CLK +}; + +irqreturn_t inv_mpu6050_irq_handler(int irq, void *p); +irqreturn_t inv_mpu6050_read_fifo(int irq, void *p); +int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev); +void inv_mpu6050_remove_trigger(struct inv_mpu6050_state *st); +int inv_reset_fifo(struct iio_dev *indio_dev); +int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask); +int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 val); +int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c new file mode 100644 index 0000000..331781f --- /dev/null +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c @@ -0,0 +1,196 @@ +/* +* Copyright (C) 2012 Invensense, Inc. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "inv_mpu_iio.h" + +int inv_reset_fifo(struct iio_dev *indio_dev) +{ + int result; + u8 d; + struct inv_mpu6050_state *st = iio_priv(indio_dev); + + /* disable interrupt */ + result = inv_mpu6050_write_reg(st, st->reg->int_enable, 0); + if (result) { + dev_err(&st->client->dev, "int_enable failed %d\n", result); + return result; + } + /* disable the sensor output to FIFO */ + result = inv_mpu6050_write_reg(st, st->reg->fifo_en, 0); + if (result) + goto reset_fifo_fail; + /* disable fifo reading */ + result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, 0); + if (result) + goto reset_fifo_fail; + + /* reset FIFO*/ + result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, + INV_MPU6050_BIT_FIFO_RST); + if (result) + goto reset_fifo_fail; + /* enable interrupt */ + if (st->chip_config.accl_fifo_enable || + st->chip_config.gyro_fifo_enable) { + result = inv_mpu6050_write_reg(st, st->reg->int_enable, + INV_MPU6050_BIT_DATA_RDY_EN); + if (result) + return result; + } + /* enable FIFO reading and I2C master interface*/ + result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, + INV_MPU6050_BIT_FIFO_EN); + if (result) + goto reset_fifo_fail; + /* enable sensor output to FIFO */ + d = 0; + if (st->chip_config.gyro_fifo_enable) + d |= INV_MPU6050_BITS_GYRO_OUT; + if (st->chip_config.accl_fifo_enable) + d |= INV_MPU6050_BIT_ACCEL_OUT; + result = inv_mpu6050_write_reg(st, st->reg->fifo_en, d); + if (result) + goto reset_fifo_fail; + + return 0; + +reset_fifo_fail: + dev_err(&st->client->dev, "reset fifo failed %d\n", result); + result = inv_mpu6050_write_reg(st, st->reg->int_enable, + INV_MPU6050_BIT_DATA_RDY_EN); + + return result; +} + +static void inv_clear_kfifo(struct inv_mpu6050_state *st) +{ + unsigned long flags; + + /* take the spin lock sem to avoid interrupt kick in */ + spin_lock_irqsave(&st->time_stamp_lock, flags); + kfifo_reset(&st->timestamps); + spin_unlock_irqrestore(&st->time_stamp_lock, flags); +} + +/** + * inv_mpu6050_irq_handler() - Cache a timestamp at each data ready interrupt. + */ +irqreturn_t inv_mpu6050_irq_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct inv_mpu6050_state *st = iio_priv(indio_dev); + s64 timestamp; + + timestamp = iio_get_time_ns(); + spin_lock(&st->time_stamp_lock); + kfifo_in(&st->timestamps, ×tamp, 1); + spin_unlock(&st->time_stamp_lock); + + return IRQ_WAKE_THREAD; +} + +/** + * inv_mpu6050_read_fifo() - Transfer data from hardware FIFO to KFIFO. + */ +irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct inv_mpu6050_state *st = iio_priv(indio_dev); + size_t bytes_per_datum; + int result; + u8 data[INV_MPU6050_OUTPUT_DATA_SIZE]; + u16 fifo_count; + s64 timestamp; + u64 *tmp; + + mutex_lock(&indio_dev->mlock); + if (!(st->chip_config.accl_fifo_enable | + st->chip_config.gyro_fifo_enable)) + goto end_session; + bytes_per_datum = 0; + if (st->chip_config.accl_fifo_enable) + bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR; + + if (st->chip_config.gyro_fifo_enable) + bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR; + + /* + * read fifo_count register to know how many bytes inside FIFO + * right now + */ + result = i2c_smbus_read_i2c_block_data(st->client, + st->reg->fifo_count_h, + INV_MPU6050_FIFO_COUNT_BYTE, data); + if (result != INV_MPU6050_FIFO_COUNT_BYTE) + goto end_session; + fifo_count = be16_to_cpup((__be16 *)(&data[0])); + if (fifo_count < bytes_per_datum) + goto end_session; + /* fifo count can't be odd number, if it is odd, reset fifo*/ + if (fifo_count & 1) + goto flush_fifo; + if (fifo_count > INV_MPU6050_FIFO_THRESHOLD) + goto flush_fifo; + /* Timestamp mismatch. */ + if (kfifo_len(&st->timestamps) > + fifo_count / bytes_per_datum + INV_MPU6050_TIME_STAMP_TOR) + goto flush_fifo; + while (fifo_count >= bytes_per_datum) { + result = i2c_smbus_read_i2c_block_data(st->client, + st->reg->fifo_r_w, + bytes_per_datum, data); + if (result != bytes_per_datum) + goto flush_fifo; + + result = kfifo_out(&st->timestamps, ×tamp, 1); + /* when there is no timestamp, put timestamp as 0 */ + if (0 == result) + timestamp = 0; + + tmp = (u64 *)data; + tmp[DIV_ROUND_UP(bytes_per_datum, 8)] = timestamp; + result = iio_push_to_buffers(indio_dev, data); + if (result) + goto flush_fifo; + fifo_count -= bytes_per_datum; + } + +end_session: + mutex_unlock(&indio_dev->mlock); + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; + +flush_fifo: + /* Flush HW and SW FIFOs. */ + inv_reset_fifo(indio_dev); + inv_clear_kfifo(st); + mutex_unlock(&indio_dev->mlock); + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c new file mode 100644 index 0000000..e1d0869 --- /dev/null +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c @@ -0,0 +1,155 @@ +/* +* Copyright (C) 2012 Invensense, Inc. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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. +*/ + +#include "inv_mpu_iio.h" + +static void inv_scan_query(struct iio_dev *indio_dev) +{ + struct inv_mpu6050_state *st = iio_priv(indio_dev); + + st->chip_config.gyro_fifo_enable = + test_bit(INV_MPU6050_SCAN_GYRO_X, + indio_dev->active_scan_mask) || + test_bit(INV_MPU6050_SCAN_GYRO_Y, + indio_dev->active_scan_mask) || + test_bit(INV_MPU6050_SCAN_GYRO_Z, + indio_dev->active_scan_mask); + + st->chip_config.accl_fifo_enable = + test_bit(INV_MPU6050_SCAN_ACCL_X, + indio_dev->active_scan_mask) || + test_bit(INV_MPU6050_SCAN_ACCL_Y, + indio_dev->active_scan_mask) || + test_bit(INV_MPU6050_SCAN_ACCL_Z, + indio_dev->active_scan_mask); +} + +/** + * inv_mpu6050_set_enable() - enable chip functions. + * @indio_dev: Device driver instance. + * @enable: enable/disable + */ +static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable) +{ + struct inv_mpu6050_state *st = iio_priv(indio_dev); + int result; + + if (enable) { + result = inv_mpu6050_set_power_itg(st, true); + if (result) + return result; + inv_scan_query(indio_dev); + if (st->chip_config.gyro_fifo_enable) { + result = inv_mpu6050_switch_engine(st, true, + INV_MPU6050_BIT_PWR_GYRO_STBY); + if (result) + return result; + } + if (st->chip_config.accl_fifo_enable) { + result = inv_mpu6050_switch_engine(st, true, + INV_MPU6050_BIT_PWR_ACCL_STBY); + if (result) + return result; + } + result = inv_reset_fifo(indio_dev); + if (result) + return result; + } else { + result = inv_mpu6050_write_reg(st, st->reg->fifo_en, 0); + if (result) + return result; + + result = inv_mpu6050_write_reg(st, st->reg->int_enable, 0); + if (result) + return result; + + result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, 0); + if (result) + return result; + + result = inv_mpu6050_switch_engine(st, false, + INV_MPU6050_BIT_PWR_GYRO_STBY); + if (result) + return result; + + result = inv_mpu6050_switch_engine(st, false, + INV_MPU6050_BIT_PWR_ACCL_STBY); + if (result) + return result; + result = inv_mpu6050_set_power_itg(st, false); + if (result) + return result; + } + st->chip_config.enable = enable; + + return 0; +} + +/** + * inv_mpu_data_rdy_trigger_set_state() - set data ready interrupt state + * @trig: Trigger instance + * @state: Desired trigger state + */ +static int inv_mpu_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + return inv_mpu6050_set_enable(trig->private_data, state); +} + +static const struct iio_trigger_ops inv_mpu_trigger_ops = { + .owner = THIS_MODULE, + .set_trigger_state = &inv_mpu_data_rdy_trigger_set_state, +}; + +int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev) +{ + int ret; + struct inv_mpu6050_state *st = iio_priv(indio_dev); + + st->trig = iio_trigger_alloc("%s-dev%d", + indio_dev->name, + indio_dev->id); + if (st->trig == NULL) { + ret = -ENOMEM; + goto error_ret; + } + ret = request_irq(st->client->irq, &iio_trigger_generic_data_rdy_poll, + IRQF_TRIGGER_RISING, + "inv_mpu", + st->trig); + if (ret) + goto error_free_trig; + st->trig->dev.parent = &st->client->dev; + st->trig->private_data = indio_dev; + st->trig->ops = &inv_mpu_trigger_ops; + ret = iio_trigger_register(st->trig); + if (ret) + goto error_free_irq; + indio_dev->trig = st->trig; + + return 0; + +error_free_irq: + free_irq(st->client->irq, st->trig); +error_free_trig: + iio_trigger_free(st->trig); +error_ret: + return ret; +} + +void inv_mpu6050_remove_trigger(struct inv_mpu6050_state *st) +{ + iio_trigger_unregister(st->trig); + free_irq(st->client->irq, st->trig); + iio_trigger_free(st->trig); +} diff --git a/include/linux/platform_data/invensense_mpu6050.h b/include/linux/platform_data/invensense_mpu6050.h new file mode 100644 index 0000000..ad3aa7b --- /dev/null +++ b/include/linux/platform_data/invensense_mpu6050.h @@ -0,0 +1,31 @@ +/* +* Copyright (C) 2012 Invensense, Inc. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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. +*/ + +#ifndef __INV_MPU6050_PLATFORM_H_ +#define __INV_MPU6050_PLATFORM_H_ + +/** + * struct inv_mpu6050_platform_data - Platform data for the mpu driver + * @orientation: Orientation matrix of the chip + * + * Contains platform specific information on how to configure the MPU6050 to + * work on this platform. The orientation matricies are 3x3 rotation matricies + * that are applied to the data to rotate from the mounting orientation to the + * platform orientation. The values must be one of 0, 1, or -1 and each row and + * column should have exactly 1 non-zero value. + */ +struct inv_mpu6050_platform_data { + __s8 orientation[9]; +}; + +#endif -- cgit v0.10.2