520 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * STMicroelectronics gyroscopes driver4 *5 * Copyright 2012-2013 STMicroelectronics Inc.6 *7 * Denis Ciocca <denis.ciocca@st.com>8 */9 10#include <linux/kernel.h>11#include <linux/module.h>12#include <linux/mutex.h>13#include <linux/interrupt.h>14#include <linux/sysfs.h>15#include <linux/iio/iio.h>16#include <linux/iio/sysfs.h>17#include <linux/iio/trigger.h>18 19#include <linux/iio/common/st_sensors.h>20#include "st_gyro.h"21 22#define ST_GYRO_NUMBER_DATA_CHANNELS 323 24/* DEFAULT VALUE FOR SENSORS */25#define ST_GYRO_DEFAULT_OUT_X_L_ADDR 0x2826#define ST_GYRO_DEFAULT_OUT_Y_L_ADDR 0x2a27#define ST_GYRO_DEFAULT_OUT_Z_L_ADDR 0x2c28 29/* FULLSCALE */30#define ST_GYRO_FS_AVL_245DPS 24531#define ST_GYRO_FS_AVL_250DPS 25032#define ST_GYRO_FS_AVL_500DPS 50033#define ST_GYRO_FS_AVL_2000DPS 200034 35static const struct iio_mount_matrix *36st_gyro_get_mount_matrix(const struct iio_dev *indio_dev,37 const struct iio_chan_spec *chan)38{39 struct st_sensor_data *gdata = iio_priv(indio_dev);40 41 return &gdata->mount_matrix;42}43 44static const struct iio_chan_spec_ext_info st_gyro_mount_matrix_ext_info[] = {45 IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, st_gyro_get_mount_matrix),46 { }47};48 49static const struct iio_chan_spec st_gyro_16bit_channels[] = {50 ST_SENSORS_LSM_CHANNELS_EXT(IIO_ANGL_VEL,51 BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),52 ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16,53 ST_GYRO_DEFAULT_OUT_X_L_ADDR,54 st_gyro_mount_matrix_ext_info),55 ST_SENSORS_LSM_CHANNELS_EXT(IIO_ANGL_VEL,56 BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),57 ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16,58 ST_GYRO_DEFAULT_OUT_Y_L_ADDR,59 st_gyro_mount_matrix_ext_info),60 ST_SENSORS_LSM_CHANNELS_EXT(IIO_ANGL_VEL,61 BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),62 ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16,63 ST_GYRO_DEFAULT_OUT_Z_L_ADDR,64 st_gyro_mount_matrix_ext_info),65 IIO_CHAN_SOFT_TIMESTAMP(3)66};67 68static const struct st_sensor_settings st_gyro_sensors_settings[] = {69 {70 .wai = 0xd3,71 .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,72 .sensors_supported = {73 [0] = L3G4200D_GYRO_DEV_NAME,74 [1] = LSM330DL_GYRO_DEV_NAME,75 },76 .ch = (struct iio_chan_spec *)st_gyro_16bit_channels,77 .odr = {78 .addr = 0x20,79 .mask = 0xc0,80 .odr_avl = {81 { .hz = 100, .value = 0x00, },82 { .hz = 200, .value = 0x01, },83 { .hz = 400, .value = 0x02, },84 { .hz = 800, .value = 0x03, },85 },86 },87 .pw = {88 .addr = 0x20,89 .mask = 0x08,90 .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,91 .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,92 },93 .enable_axis = {94 .addr = ST_SENSORS_DEFAULT_AXIS_ADDR,95 .mask = ST_SENSORS_DEFAULT_AXIS_MASK,96 },97 .fs = {98 .addr = 0x23,99 .mask = 0x30,100 .fs_avl = {101 [0] = {102 .num = ST_GYRO_FS_AVL_250DPS,103 .value = 0x00,104 .gain = IIO_DEGREE_TO_RAD(8750),105 },106 [1] = {107 .num = ST_GYRO_FS_AVL_500DPS,108 .value = 0x01,109 .gain = IIO_DEGREE_TO_RAD(17500),110 },111 [2] = {112 .num = ST_GYRO_FS_AVL_2000DPS,113 .value = 0x02,114 .gain = IIO_DEGREE_TO_RAD(70000),115 },116 },117 },118 .bdu = {119 .addr = 0x23,120 .mask = 0x80,121 },122 .drdy_irq = {123 .int2 = {124 .addr = 0x22,125 .mask = 0x08,126 },127 /*128 * The sensor has IHL (active low) and open129 * drain settings, but only for INT1 and not130 * for the DRDY line on INT2.131 */132 .stat_drdy = {133 .addr = ST_SENSORS_DEFAULT_STAT_ADDR,134 .mask = 0x07,135 },136 },137 .sim = {138 .addr = 0x23,139 .value = BIT(0),140 },141 .multi_read_bit = true,142 .bootime = 2,143 },144 {145 .wai = 0xd4,146 .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,147 .sensors_supported = {148 [0] = L3GD20_GYRO_DEV_NAME,149 [1] = LSM330D_GYRO_DEV_NAME,150 [2] = LSM330DLC_GYRO_DEV_NAME,151 [3] = L3G4IS_GYRO_DEV_NAME,152 [4] = LSM330_GYRO_DEV_NAME,153 },154 .ch = (struct iio_chan_spec *)st_gyro_16bit_channels,155 .odr = {156 .addr = 0x20,157 .mask = 0xc0,158 .odr_avl = {159 { .hz = 95, .value = 0x00, },160 { .hz = 190, .value = 0x01, },161 { .hz = 380, .value = 0x02, },162 { .hz = 760, .value = 0x03, },163 },164 },165 .pw = {166 .addr = 0x20,167 .mask = 0x08,168 .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,169 .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,170 },171 .enable_axis = {172 .addr = ST_SENSORS_DEFAULT_AXIS_ADDR,173 .mask = ST_SENSORS_DEFAULT_AXIS_MASK,174 },175 .fs = {176 .addr = 0x23,177 .mask = 0x30,178 .fs_avl = {179 [0] = {180 .num = ST_GYRO_FS_AVL_250DPS,181 .value = 0x00,182 .gain = IIO_DEGREE_TO_RAD(8750),183 },184 [1] = {185 .num = ST_GYRO_FS_AVL_500DPS,186 .value = 0x01,187 .gain = IIO_DEGREE_TO_RAD(17500),188 },189 [2] = {190 .num = ST_GYRO_FS_AVL_2000DPS,191 .value = 0x02,192 .gain = IIO_DEGREE_TO_RAD(70000),193 },194 },195 },196 .bdu = {197 .addr = 0x23,198 .mask = 0x80,199 },200 .drdy_irq = {201 .int2 = {202 .addr = 0x22,203 .mask = 0x08,204 },205 /*206 * The sensor has IHL (active low) and open207 * drain settings, but only for INT1 and not208 * for the DRDY line on INT2.209 */210 .stat_drdy = {211 .addr = ST_SENSORS_DEFAULT_STAT_ADDR,212 .mask = 0x07,213 },214 },215 .sim = {216 .addr = 0x23,217 .value = BIT(0),218 },219 .multi_read_bit = true,220 .bootime = 2,221 },222 {223 .wai = 0xd4,224 .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,225 .sensors_supported = {226 [0] = LSM9DS0_GYRO_DEV_NAME,227 },228 .ch = (struct iio_chan_spec *)st_gyro_16bit_channels,229 .odr = {230 .addr = 0x20,231 .mask = GENMASK(7, 6),232 .odr_avl = {233 { .hz = 95, .value = 0x00, },234 { .hz = 190, .value = 0x01, },235 { .hz = 380, .value = 0x02, },236 { .hz = 760, .value = 0x03, },237 },238 },239 .pw = {240 .addr = 0x20,241 .mask = BIT(3),242 .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,243 .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,244 },245 .enable_axis = {246 .addr = ST_SENSORS_DEFAULT_AXIS_ADDR,247 .mask = ST_SENSORS_DEFAULT_AXIS_MASK,248 },249 .fs = {250 .addr = 0x23,251 .mask = GENMASK(5, 4),252 .fs_avl = {253 [0] = {254 .num = ST_GYRO_FS_AVL_245DPS,255 .value = 0x00,256 .gain = IIO_DEGREE_TO_RAD(8750),257 },258 [1] = {259 .num = ST_GYRO_FS_AVL_500DPS,260 .value = 0x01,261 .gain = IIO_DEGREE_TO_RAD(17500),262 },263 [2] = {264 .num = ST_GYRO_FS_AVL_2000DPS,265 .value = 0x02,266 .gain = IIO_DEGREE_TO_RAD(70000),267 },268 },269 },270 .bdu = {271 .addr = 0x23,272 .mask = BIT(7),273 },274 .drdy_irq = {275 .int2 = {276 .addr = 0x22,277 .mask = BIT(3),278 },279 /*280 * The sensor has IHL (active low) and open281 * drain settings, but only for INT1 and not282 * for the DRDY line on INT2.283 */284 .stat_drdy = {285 .addr = ST_SENSORS_DEFAULT_STAT_ADDR,286 .mask = GENMASK(2, 0),287 },288 },289 .sim = {290 .addr = 0x23,291 .value = BIT(0),292 },293 .multi_read_bit = true,294 .bootime = 2,295 },296 {297 .wai = 0xd7,298 .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,299 .sensors_supported = {300 [0] = L3GD20H_GYRO_DEV_NAME,301 },302 .ch = (struct iio_chan_spec *)st_gyro_16bit_channels,303 .odr = {304 .addr = 0x20,305 .mask = 0xc0,306 .odr_avl = {307 { .hz = 100, .value = 0x00, },308 { .hz = 200, .value = 0x01, },309 { .hz = 400, .value = 0x02, },310 { .hz = 800, .value = 0x03, },311 },312 },313 .pw = {314 .addr = 0x20,315 .mask = 0x08,316 .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,317 .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,318 },319 .enable_axis = {320 .addr = ST_SENSORS_DEFAULT_AXIS_ADDR,321 .mask = ST_SENSORS_DEFAULT_AXIS_MASK,322 },323 .fs = {324 .addr = 0x23,325 .mask = 0x30,326 .fs_avl = {327 [0] = {328 .num = ST_GYRO_FS_AVL_245DPS,329 .value = 0x00,330 .gain = IIO_DEGREE_TO_RAD(8750),331 },332 [1] = {333 .num = ST_GYRO_FS_AVL_500DPS,334 .value = 0x01,335 .gain = IIO_DEGREE_TO_RAD(17500),336 },337 [2] = {338 .num = ST_GYRO_FS_AVL_2000DPS,339 .value = 0x02,340 .gain = IIO_DEGREE_TO_RAD(70000),341 },342 },343 },344 .bdu = {345 .addr = 0x23,346 .mask = 0x80,347 },348 .drdy_irq = {349 .int2 = {350 .addr = 0x22,351 .mask = 0x08,352 },353 /*354 * The sensor has IHL (active low) and open355 * drain settings, but only for INT1 and not356 * for the DRDY line on INT2.357 */358 .stat_drdy = {359 .addr = ST_SENSORS_DEFAULT_STAT_ADDR,360 .mask = 0x07,361 },362 },363 .sim = {364 .addr = 0x23,365 .value = BIT(0),366 },367 .multi_read_bit = true,368 .bootime = 2,369 },370};371 372/* DRDY on gyros is available only on INT2 pin */373static const struct st_sensors_platform_data gyro_pdata = {374 .drdy_int_pin = 2,375};376 377static int st_gyro_read_raw(struct iio_dev *indio_dev,378 struct iio_chan_spec const *ch, int *val,379 int *val2, long mask)380{381 int err;382 struct st_sensor_data *gdata = iio_priv(indio_dev);383 384 switch (mask) {385 case IIO_CHAN_INFO_RAW:386 err = st_sensors_read_info_raw(indio_dev, ch, val);387 if (err < 0)388 goto read_error;389 390 return IIO_VAL_INT;391 case IIO_CHAN_INFO_SCALE:392 *val = 0;393 *val2 = gdata->current_fullscale->gain;394 return IIO_VAL_INT_PLUS_MICRO;395 case IIO_CHAN_INFO_SAMP_FREQ:396 *val = gdata->odr;397 return IIO_VAL_INT;398 default:399 return -EINVAL;400 }401 402read_error:403 return err;404}405 406static int st_gyro_write_raw(struct iio_dev *indio_dev,407 struct iio_chan_spec const *chan, int val, int val2, long mask)408{409 switch (mask) {410 case IIO_CHAN_INFO_SCALE:411 return st_sensors_set_fullscale_by_gain(indio_dev, val2);412 case IIO_CHAN_INFO_SAMP_FREQ:413 if (val2)414 return -EINVAL;415 416 return st_sensors_set_odr(indio_dev, val);417 default:418 return -EINVAL;419 }420}421 422static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL();423static ST_SENSORS_DEV_ATTR_SCALE_AVAIL(in_anglvel_scale_available);424 425static struct attribute *st_gyro_attributes[] = {426 &iio_dev_attr_sampling_frequency_available.dev_attr.attr,427 &iio_dev_attr_in_anglvel_scale_available.dev_attr.attr,428 NULL,429};430 431static const struct attribute_group st_gyro_attribute_group = {432 .attrs = st_gyro_attributes,433};434 435static const struct iio_info gyro_info = {436 .attrs = &st_gyro_attribute_group,437 .read_raw = &st_gyro_read_raw,438 .write_raw = &st_gyro_write_raw,439 .debugfs_reg_access = &st_sensors_debugfs_reg_access,440};441 442#ifdef CONFIG_IIO_TRIGGER443static const struct iio_trigger_ops st_gyro_trigger_ops = {444 .set_trigger_state = ST_GYRO_TRIGGER_SET_STATE,445 .validate_device = st_sensors_validate_device,446};447#define ST_GYRO_TRIGGER_OPS (&st_gyro_trigger_ops)448#else449#define ST_GYRO_TRIGGER_OPS NULL450#endif451 452/*453 * st_gyro_get_settings() - get sensor settings from device name454 * @name: device name buffer reference.455 *456 * Return: valid reference on success, NULL otherwise.457 */458const struct st_sensor_settings *st_gyro_get_settings(const char *name)459{460 int index = st_sensors_get_settings_index(name,461 st_gyro_sensors_settings,462 ARRAY_SIZE(st_gyro_sensors_settings));463 if (index < 0)464 return NULL;465 466 return &st_gyro_sensors_settings[index];467}468EXPORT_SYMBOL_NS(st_gyro_get_settings, IIO_ST_SENSORS);469 470int st_gyro_common_probe(struct iio_dev *indio_dev)471{472 struct st_sensor_data *gdata = iio_priv(indio_dev);473 struct st_sensors_platform_data *pdata;474 struct device *parent = indio_dev->dev.parent;475 int err;476 477 indio_dev->modes = INDIO_DIRECT_MODE;478 indio_dev->info = &gyro_info;479 480 err = st_sensors_verify_id(indio_dev);481 if (err < 0)482 return err;483 484 gdata->num_data_channels = ST_GYRO_NUMBER_DATA_CHANNELS;485 indio_dev->channels = gdata->sensor_settings->ch;486 indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;487 488 err = iio_read_mount_matrix(parent, &gdata->mount_matrix);489 if (err)490 return err;491 492 gdata->current_fullscale = &gdata->sensor_settings->fs.fs_avl[0];493 gdata->odr = gdata->sensor_settings->odr.odr_avl[0].hz;494 495 pdata = (struct st_sensors_platform_data *)&gyro_pdata;496 497 err = st_sensors_init_sensor(indio_dev, pdata);498 if (err < 0)499 return err;500 501 err = st_gyro_allocate_ring(indio_dev);502 if (err < 0)503 return err;504 505 if (gdata->irq > 0) {506 err = st_sensors_allocate_trigger(indio_dev,507 ST_GYRO_TRIGGER_OPS);508 if (err < 0)509 return err;510 }511 512 return devm_iio_device_register(parent, indio_dev);513}514EXPORT_SYMBOL_NS(st_gyro_common_probe, IIO_ST_SENSORS);515 516MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");517MODULE_DESCRIPTION("STMicroelectronics gyroscopes driver");518MODULE_LICENSE("GPL v2");519MODULE_IMPORT_NS(IIO_ST_SENSORS);520