Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iio: magnetometer: add ti tmag5273 driver

Add support for TI TMAG5273 Low-Power Linear 3D Hall-Effect Sensor.
Additionally to temperature and magnetic X, Y and Z-axes the angle and
magnitude are reported.
The sensor is operating in continuous measurement mode and changes to sleep
mode if not used for 5 seconds.

Datasheet: https://www.ti.com/lit/gpn/tmag5273
Signed-off-by: Gerald Loacker <gerald.loacker@wolfvision.net>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://lore.kernel.org/r/20221201072220.402585-4-gerald.loacker@wolfvision.net
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Gerald Loacker and committed by
Jonathan Cameron
866a1389 fbb6d04e

+758
+1
MAINTAINERS
··· 20912 20912 L: linux-iio@vger.kernel.org 20913 20913 S: Maintained 20914 20914 F: Documentation/devicetree/bindings/iio/magnetometer/ti,tmag5273.yaml 20915 + F: drivers/iio/magnetometer/tmag5273.c 20915 20916 20916 20917 TI TRF7970A NFC DRIVER 20917 20918 M: Mark Greer <mgreer@animalcreek.com>
+12
drivers/iio/magnetometer/Kconfig
··· 208 208 To compile this driver as a module, choose M here: the module 209 209 will be called rm3100-spi. 210 210 211 + config TI_TMAG5273 212 + tristate "TI TMAG5273 Low-Power Linear 3D Hall-Effect Sensor" 213 + depends on I2C 214 + select REGMAP_I2C 215 + help 216 + Say Y here to add support for the TI TMAG5273 Low-Power 217 + Linear 3D Hall-Effect Sensor. 218 + 219 + This driver can also be compiled as a module. 220 + To compile this driver as a module, choose M here: the module 221 + will be called tmag5273. 222 + 211 223 config YAMAHA_YAS530 212 224 tristate "Yamaha YAS530 family of 3-Axis Magnetometers (I2C)" 213 225 depends on I2C
+2
drivers/iio/magnetometer/Makefile
··· 29 29 obj-$(CONFIG_SENSORS_RM3100_I2C) += rm3100-i2c.o 30 30 obj-$(CONFIG_SENSORS_RM3100_SPI) += rm3100-spi.o 31 31 32 + obj-$(CONFIG_TI_TMAG5273) += tmag5273.o 33 + 32 34 obj-$(CONFIG_YAMAHA_YAS530) += yamaha-yas530.o
+743
drivers/iio/magnetometer/tmag5273.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Driver for the TI TMAG5273 Low-Power Linear 3D Hall-Effect Sensor 4 + * 5 + * Copyright (C) 2022 WolfVision GmbH 6 + * 7 + * Author: Gerald Loacker <gerald.loacker@wolfvision.net> 8 + */ 9 + 10 + #include <linux/bitfield.h> 11 + #include <linux/bits.h> 12 + #include <linux/delay.h> 13 + #include <linux/module.h> 14 + #include <linux/i2c.h> 15 + #include <linux/regmap.h> 16 + #include <linux/pm_runtime.h> 17 + 18 + #include <linux/iio/iio.h> 19 + #include <linux/iio/sysfs.h> 20 + 21 + #define TMAG5273_DEVICE_CONFIG_1 0x00 22 + #define TMAG5273_DEVICE_CONFIG_2 0x01 23 + #define TMAG5273_SENSOR_CONFIG_1 0x02 24 + #define TMAG5273_SENSOR_CONFIG_2 0x03 25 + #define TMAG5273_X_THR_CONFIG 0x04 26 + #define TMAG5273_Y_THR_CONFIG 0x05 27 + #define TMAG5273_Z_THR_CONFIG 0x06 28 + #define TMAG5273_T_CONFIG 0x07 29 + #define TMAG5273_INT_CONFIG_1 0x08 30 + #define TMAG5273_MAG_GAIN_CONFIG 0x09 31 + #define TMAG5273_MAG_OFFSET_CONFIG_1 0x0A 32 + #define TMAG5273_MAG_OFFSET_CONFIG_2 0x0B 33 + #define TMAG5273_I2C_ADDRESS 0x0C 34 + #define TMAG5273_DEVICE_ID 0x0D 35 + #define TMAG5273_MANUFACTURER_ID_LSB 0x0E 36 + #define TMAG5273_MANUFACTURER_ID_MSB 0x0F 37 + #define TMAG5273_T_MSB_RESULT 0x10 38 + #define TMAG5273_T_LSB_RESULT 0x11 39 + #define TMAG5273_X_MSB_RESULT 0x12 40 + #define TMAG5273_X_LSB_RESULT 0x13 41 + #define TMAG5273_Y_MSB_RESULT 0x14 42 + #define TMAG5273_Y_LSB_RESULT 0x15 43 + #define TMAG5273_Z_MSB_RESULT 0x16 44 + #define TMAG5273_Z_LSB_RESULT 0x17 45 + #define TMAG5273_CONV_STATUS 0x18 46 + #define TMAG5273_ANGLE_RESULT_MSB 0x19 47 + #define TMAG5273_ANGLE_RESULT_LSB 0x1A 48 + #define TMAG5273_MAGNITUDE_RESULT 0x1B 49 + #define TMAG5273_DEVICE_STATUS 0x1C 50 + #define TMAG5273_MAX_REG TMAG5273_DEVICE_STATUS 51 + 52 + #define TMAG5273_AUTOSLEEP_DELAY_MS 5000 53 + #define TMAG5273_MAX_AVERAGE 32 54 + 55 + /* 56 + * bits in the TMAG5273_MANUFACTURER_ID_LSB / MSB register 57 + * 16-bit unique manufacturer ID 0x49 / 0x54 = "TI" 58 + */ 59 + #define TMAG5273_MANUFACTURER_ID 0x5449 60 + 61 + /* bits in the TMAG5273_DEVICE_CONFIG_1 register */ 62 + #define TMAG5273_AVG_MODE_MASK GENMASK(4, 2) 63 + #define TMAG5273_AVG_1_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 0) 64 + #define TMAG5273_AVG_2_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 1) 65 + #define TMAG5273_AVG_4_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 2) 66 + #define TMAG5273_AVG_8_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 3) 67 + #define TMAG5273_AVG_16_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 4) 68 + #define TMAG5273_AVG_32_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 5) 69 + 70 + /* bits in the TMAG5273_DEVICE_CONFIG_2 register */ 71 + #define TMAG5273_OP_MODE_MASK GENMASK(1, 0) 72 + #define TMAG5273_OP_MODE_STANDBY FIELD_PREP(TMAG5273_OP_MODE_MASK, 0) 73 + #define TMAG5273_OP_MODE_SLEEP FIELD_PREP(TMAG5273_OP_MODE_MASK, 1) 74 + #define TMAG5273_OP_MODE_CONT FIELD_PREP(TMAG5273_OP_MODE_MASK, 2) 75 + #define TMAG5273_OP_MODE_WAKEUP FIELD_PREP(TMAG5273_OP_MODE_MASK, 3) 76 + 77 + /* bits in the TMAG5273_SENSOR_CONFIG_1 register */ 78 + #define TMAG5273_MAG_CH_EN_MASK GENMASK(7, 4) 79 + #define TMAG5273_MAG_CH_EN_X_Y_Z 7 80 + 81 + /* bits in the TMAG5273_SENSOR_CONFIG_2 register */ 82 + #define TMAG5273_Z_RANGE_MASK BIT(0) 83 + #define TMAG5273_X_Y_RANGE_MASK BIT(1) 84 + #define TMAG5273_ANGLE_EN_MASK GENMASK(3, 2) 85 + #define TMAG5273_ANGLE_EN_OFF 0 86 + #define TMAG5273_ANGLE_EN_X_Y 1 87 + #define TMAG5273_ANGLE_EN_Y_Z 2 88 + #define TMAG5273_ANGLE_EN_X_Z 3 89 + 90 + /* bits in the TMAG5273_T_CONFIG register */ 91 + #define TMAG5273_T_CH_EN BIT(0) 92 + 93 + /* bits in the TMAG5273_DEVICE_ID register */ 94 + #define TMAG5273_VERSION_MASK GENMASK(1, 0) 95 + 96 + /* bits in the TMAG5273_CONV_STATUS register */ 97 + #define TMAG5273_CONV_STATUS_COMPLETE BIT(0) 98 + 99 + enum tmag5273_channels { 100 + TEMPERATURE = 0, 101 + AXIS_X, 102 + AXIS_Y, 103 + AXIS_Z, 104 + ANGLE, 105 + MAGNITUDE, 106 + }; 107 + 108 + enum tmag5273_scale_index { 109 + MAGN_RANGE_LOW = 0, 110 + MAGN_RANGE_HIGH, 111 + MAGN_RANGE_NUM 112 + }; 113 + 114 + /* state container for the TMAG5273 driver */ 115 + struct tmag5273_data { 116 + struct device *dev; 117 + unsigned int devid; 118 + unsigned int version; 119 + char name[16]; 120 + unsigned int conv_avg; 121 + unsigned int scale; 122 + enum tmag5273_scale_index scale_index; 123 + unsigned int angle_measurement; 124 + struct regmap *map; 125 + struct regulator *vcc; 126 + 127 + /* 128 + * Locks the sensor for exclusive use during a measurement (which 129 + * involves several register transactions so the regmap lock is not 130 + * enough) so that measurements get serialized in a 131 + * first-come-first-serve manner. 132 + */ 133 + struct mutex lock; 134 + }; 135 + 136 + static const char *const tmag5273_angle_names[] = { "off", "x-y", "y-z", "x-z" }; 137 + 138 + /* 139 + * Averaging enables additional sampling of the sensor data to reduce the noise 140 + * effect, but also increases conversion time. 141 + */ 142 + static const unsigned int tmag5273_avg_table[] = { 143 + 1, 2, 4, 8, 16, 32, 144 + }; 145 + 146 + /* 147 + * Magnetic resolution in Gauss for different TMAG5273 versions. 148 + * Scale[Gauss] = Range[mT] * 1000 / 2^15 * 10, (1 mT = 10 Gauss) 149 + * Only version 1 and 2 are valid, version 0 and 3 are reserved. 150 + */ 151 + static const struct iio_val_int_plus_micro tmag5273_scale[][MAGN_RANGE_NUM] = { 152 + { { 0, 0 }, { 0, 0 } }, 153 + { { 0, 12200 }, { 0, 24400 } }, 154 + { { 0, 40600 }, { 0, 81200 } }, 155 + { { 0, 0 }, { 0, 0 } }, 156 + }; 157 + 158 + static int tmag5273_get_measure(struct tmag5273_data *data, s16 *t, s16 *x, 159 + s16 *y, s16 *z, u16 *angle, u16 *magnitude) 160 + { 161 + unsigned int status, val; 162 + __be16 reg_data[4]; 163 + int ret; 164 + 165 + mutex_lock(&data->lock); 166 + 167 + /* 168 + * Max. conversion time is 2425 us in 32x averaging mode for all three 169 + * channels. Since we are in continuous measurement mode, a measurement 170 + * may already be there, so poll for completed measurement with 171 + * timeout. 172 + */ 173 + ret = regmap_read_poll_timeout(data->map, TMAG5273_CONV_STATUS, status, 174 + status & TMAG5273_CONV_STATUS_COMPLETE, 175 + 100, 10000); 176 + if (ret) { 177 + dev_err(data->dev, "timeout waiting for measurement\n"); 178 + goto out_unlock; 179 + } 180 + 181 + ret = regmap_bulk_read(data->map, TMAG5273_T_MSB_RESULT, reg_data, 182 + sizeof(reg_data)); 183 + if (ret) 184 + goto out_unlock; 185 + *t = be16_to_cpu(reg_data[0]); 186 + *x = be16_to_cpu(reg_data[1]); 187 + *y = be16_to_cpu(reg_data[2]); 188 + *z = be16_to_cpu(reg_data[3]); 189 + 190 + ret = regmap_bulk_read(data->map, TMAG5273_ANGLE_RESULT_MSB, 191 + &reg_data[0], sizeof(reg_data[0])); 192 + if (ret) 193 + goto out_unlock; 194 + /* 195 + * angle has 9 bits integer value and 4 bits fractional part 196 + * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 197 + * 0 0 0 a a a a a a a a a f f f f 198 + */ 199 + *angle = be16_to_cpu(reg_data[0]); 200 + 201 + ret = regmap_read(data->map, TMAG5273_MAGNITUDE_RESULT, &val); 202 + if (ret < 0) 203 + goto out_unlock; 204 + *magnitude = val; 205 + 206 + out_unlock: 207 + mutex_unlock(&data->lock); 208 + return ret; 209 + } 210 + 211 + static int tmag5273_write_osr(struct tmag5273_data *data, int val) 212 + { 213 + int i; 214 + 215 + if (val == data->conv_avg) 216 + return 0; 217 + 218 + for (i = 0; i < ARRAY_SIZE(tmag5273_avg_table); i++) { 219 + if (tmag5273_avg_table[i] == val) 220 + break; 221 + } 222 + if (i == ARRAY_SIZE(tmag5273_avg_table)) 223 + return -EINVAL; 224 + data->conv_avg = val; 225 + 226 + return regmap_update_bits(data->map, TMAG5273_DEVICE_CONFIG_1, 227 + TMAG5273_AVG_MODE_MASK, 228 + FIELD_PREP(TMAG5273_AVG_MODE_MASK, i)); 229 + } 230 + 231 + static int tmag5273_write_scale(struct tmag5273_data *data, int scale_micro) 232 + { 233 + u32 value; 234 + int i; 235 + 236 + for (i = 0; i < ARRAY_SIZE(tmag5273_scale[0]); i++) { 237 + if (tmag5273_scale[data->version][i].micro == scale_micro) 238 + break; 239 + } 240 + if (i == ARRAY_SIZE(tmag5273_scale[0])) 241 + return -EINVAL; 242 + data->scale_index = i; 243 + 244 + if (data->scale_index == MAGN_RANGE_LOW) 245 + value = 0; 246 + else 247 + value = TMAG5273_Z_RANGE_MASK | TMAG5273_X_Y_RANGE_MASK; 248 + 249 + return regmap_update_bits(data->map, TMAG5273_SENSOR_CONFIG_2, 250 + TMAG5273_Z_RANGE_MASK | TMAG5273_X_Y_RANGE_MASK, value); 251 + } 252 + 253 + static int tmag5273_read_avail(struct iio_dev *indio_dev, 254 + struct iio_chan_spec const *chan, 255 + const int **vals, int *type, int *length, 256 + long mask) 257 + { 258 + struct tmag5273_data *data = iio_priv(indio_dev); 259 + 260 + switch (mask) { 261 + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 262 + *vals = tmag5273_avg_table; 263 + *type = IIO_VAL_INT; 264 + *length = ARRAY_SIZE(tmag5273_avg_table); 265 + return IIO_AVAIL_LIST; 266 + case IIO_CHAN_INFO_SCALE: 267 + switch (chan->type) { 268 + case IIO_MAGN: 269 + *type = IIO_VAL_INT_PLUS_MICRO; 270 + *vals = (int *)tmag5273_scale[data->version]; 271 + *length = ARRAY_SIZE(tmag5273_scale[data->version]) * 272 + MAGN_RANGE_NUM; 273 + return IIO_AVAIL_LIST; 274 + default: 275 + return -EINVAL; 276 + } 277 + default: 278 + return -EINVAL; 279 + } 280 + } 281 + 282 + static int tmag5273_read_raw(struct iio_dev *indio_dev, 283 + const struct iio_chan_spec *chan, int *val, 284 + int *val2, long mask) 285 + { 286 + struct tmag5273_data *data = iio_priv(indio_dev); 287 + s16 t, x, y, z; 288 + u16 angle, magnitude; 289 + int ret; 290 + 291 + switch (mask) { 292 + case IIO_CHAN_INFO_PROCESSED: 293 + case IIO_CHAN_INFO_RAW: 294 + ret = pm_runtime_resume_and_get(data->dev); 295 + if (ret < 0) 296 + return ret; 297 + 298 + ret = tmag5273_get_measure(data, &t, &x, &y, &z, &angle, &magnitude); 299 + if (ret) 300 + return ret; 301 + 302 + pm_runtime_mark_last_busy(data->dev); 303 + pm_runtime_put_autosuspend(data->dev); 304 + 305 + switch (chan->address) { 306 + case TEMPERATURE: 307 + *val = t; 308 + return IIO_VAL_INT; 309 + case AXIS_X: 310 + *val = x; 311 + return IIO_VAL_INT; 312 + case AXIS_Y: 313 + *val = y; 314 + return IIO_VAL_INT; 315 + case AXIS_Z: 316 + *val = z; 317 + return IIO_VAL_INT; 318 + case ANGLE: 319 + *val = angle; 320 + return IIO_VAL_INT; 321 + case MAGNITUDE: 322 + *val = magnitude; 323 + return IIO_VAL_INT; 324 + default: 325 + return -EINVAL; 326 + } 327 + case IIO_CHAN_INFO_SCALE: 328 + switch (chan->type) { 329 + case IIO_TEMP: 330 + /* 331 + * Convert device specific value to millicelsius. 332 + * Resolution from the sensor is 60.1 LSB/celsius and 333 + * the reference value at 25 celsius is 17508 LSBs. 334 + */ 335 + *val = 10000; 336 + *val2 = 601; 337 + return IIO_VAL_FRACTIONAL; 338 + case IIO_MAGN: 339 + /* Magnetic resolution in uT */ 340 + *val = 0; 341 + *val2 = tmag5273_scale[data->version] 342 + [data->scale_index].micro; 343 + return IIO_VAL_INT_PLUS_MICRO; 344 + case IIO_ANGL: 345 + /* 346 + * Angle is in degrees and has four fractional bits, 347 + * therefore use 1/16 * pi/180 to convert to radians. 348 + */ 349 + *val = 1000; 350 + *val2 = 916732; 351 + return IIO_VAL_FRACTIONAL; 352 + default: 353 + return -EINVAL; 354 + } 355 + case IIO_CHAN_INFO_OFFSET: 356 + switch (chan->type) { 357 + case IIO_TEMP: 358 + *val = -266314; 359 + return IIO_VAL_INT; 360 + default: 361 + return -EINVAL; 362 + } 363 + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 364 + *val = data->conv_avg; 365 + return IIO_VAL_INT; 366 + 367 + default: 368 + return -EINVAL; 369 + } 370 + } 371 + 372 + static int tmag5273_write_raw(struct iio_dev *indio_dev, 373 + struct iio_chan_spec const *chan, int val, 374 + int val2, long mask) 375 + { 376 + struct tmag5273_data *data = iio_priv(indio_dev); 377 + 378 + switch (mask) { 379 + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 380 + return tmag5273_write_osr(data, val); 381 + case IIO_CHAN_INFO_SCALE: 382 + switch (chan->type) { 383 + case IIO_MAGN: 384 + if (val) 385 + return -EINVAL; 386 + return tmag5273_write_scale(data, val2); 387 + default: 388 + return -EINVAL; 389 + } 390 + default: 391 + return -EINVAL; 392 + } 393 + } 394 + 395 + #define TMAG5273_AXIS_CHANNEL(axis, index) \ 396 + { \ 397 + .type = IIO_MAGN, \ 398 + .modified = 1, \ 399 + .channel2 = IIO_MOD_##axis, \ 400 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 401 + BIT(IIO_CHAN_INFO_SCALE), \ 402 + .info_mask_shared_by_type_available = \ 403 + BIT(IIO_CHAN_INFO_SCALE), \ 404 + .info_mask_shared_by_all = \ 405 + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ 406 + .info_mask_shared_by_all_available = \ 407 + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ 408 + .address = index, \ 409 + .scan_index = index, \ 410 + .scan_type = { \ 411 + .sign = 's', \ 412 + .realbits = 16, \ 413 + .storagebits = 16, \ 414 + .endianness = IIO_CPU, \ 415 + }, \ 416 + } 417 + 418 + static const struct iio_chan_spec tmag5273_channels[] = { 419 + { 420 + .type = IIO_TEMP, 421 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 422 + BIT(IIO_CHAN_INFO_SCALE) | 423 + BIT(IIO_CHAN_INFO_OFFSET), 424 + .address = TEMPERATURE, 425 + .scan_index = TEMPERATURE, 426 + .scan_type = { 427 + .sign = 'u', 428 + .realbits = 16, 429 + .storagebits = 16, 430 + .endianness = IIO_CPU, 431 + }, 432 + }, 433 + TMAG5273_AXIS_CHANNEL(X, AXIS_X), 434 + TMAG5273_AXIS_CHANNEL(Y, AXIS_Y), 435 + TMAG5273_AXIS_CHANNEL(Z, AXIS_Z), 436 + { 437 + .type = IIO_ANGL, 438 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 439 + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), 440 + .info_mask_shared_by_all = 441 + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), 442 + .info_mask_shared_by_all_available = 443 + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), 444 + .address = ANGLE, 445 + .scan_index = ANGLE, 446 + .scan_type = { 447 + .sign = 'u', 448 + .realbits = 16, 449 + .storagebits = 16, 450 + .endianness = IIO_CPU, 451 + }, 452 + }, 453 + { 454 + .type = IIO_DISTANCE, 455 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 456 + .info_mask_shared_by_all = 457 + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), 458 + .info_mask_shared_by_all_available = 459 + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), 460 + .address = MAGNITUDE, 461 + .scan_index = MAGNITUDE, 462 + .scan_type = { 463 + .sign = 'u', 464 + .realbits = 16, 465 + .storagebits = 16, 466 + .endianness = IIO_CPU, 467 + }, 468 + }, 469 + IIO_CHAN_SOFT_TIMESTAMP(6), 470 + }; 471 + 472 + static const struct iio_info tmag5273_info = { 473 + .read_avail = tmag5273_read_avail, 474 + .read_raw = tmag5273_read_raw, 475 + .write_raw = tmag5273_write_raw, 476 + }; 477 + 478 + static bool tmag5273_volatile_reg(struct device *dev, unsigned int reg) 479 + { 480 + return reg >= TMAG5273_T_MSB_RESULT && reg <= TMAG5273_MAGNITUDE_RESULT; 481 + } 482 + 483 + static const struct regmap_config tmag5273_regmap_config = { 484 + .reg_bits = 8, 485 + .val_bits = 8, 486 + .max_register = TMAG5273_MAX_REG, 487 + .volatile_reg = tmag5273_volatile_reg, 488 + }; 489 + 490 + static int tmag5273_set_operating_mode(struct tmag5273_data *data, 491 + unsigned int val) 492 + { 493 + return regmap_write(data->map, TMAG5273_DEVICE_CONFIG_2, val); 494 + } 495 + 496 + static void tmag5273_read_device_property(struct tmag5273_data *data) 497 + { 498 + struct device *dev = data->dev; 499 + const char *str; 500 + int ret; 501 + 502 + data->angle_measurement = TMAG5273_ANGLE_EN_X_Y; 503 + 504 + ret = device_property_read_string(dev, "ti,angle-measurement", &str); 505 + if (ret) 506 + return; 507 + 508 + ret = match_string(tmag5273_angle_names, 509 + ARRAY_SIZE(tmag5273_angle_names), str); 510 + if (ret >= 0) 511 + data->angle_measurement = ret; 512 + } 513 + 514 + static void tmag5273_wake_up(struct tmag5273_data *data) 515 + { 516 + int val; 517 + 518 + /* Wake up the chip by sending a dummy I2C command */ 519 + regmap_read(data->map, TMAG5273_DEVICE_ID, &val); 520 + /* 521 + * Time to go to stand-by mode from sleep mode is 50us 522 + * typically, during this time no I2C access is possible. 523 + */ 524 + usleep_range(80, 200); 525 + } 526 + 527 + static int tmag5273_chip_init(struct tmag5273_data *data) 528 + { 529 + int ret; 530 + 531 + ret = regmap_write(data->map, TMAG5273_DEVICE_CONFIG_1, 532 + TMAG5273_AVG_32_MODE); 533 + if (ret) 534 + return ret; 535 + data->conv_avg = 32; 536 + 537 + ret = regmap_write(data->map, TMAG5273_DEVICE_CONFIG_2, 538 + TMAG5273_OP_MODE_CONT); 539 + if (ret) 540 + return ret; 541 + 542 + ret = regmap_write(data->map, TMAG5273_SENSOR_CONFIG_1, 543 + FIELD_PREP(TMAG5273_MAG_CH_EN_MASK, 544 + TMAG5273_MAG_CH_EN_X_Y_Z)); 545 + if (ret) 546 + return ret; 547 + 548 + ret = regmap_write(data->map, TMAG5273_SENSOR_CONFIG_2, 549 + FIELD_PREP(TMAG5273_ANGLE_EN_MASK, 550 + data->angle_measurement)); 551 + if (ret) 552 + return ret; 553 + data->scale_index = MAGN_RANGE_LOW; 554 + 555 + return regmap_write(data->map, TMAG5273_T_CONFIG, TMAG5273_T_CH_EN); 556 + } 557 + 558 + static int tmag5273_check_device_id(struct tmag5273_data *data) 559 + { 560 + __le16 devid; 561 + int val, ret; 562 + 563 + ret = regmap_read(data->map, TMAG5273_DEVICE_ID, &val); 564 + if (ret) 565 + return dev_err_probe(data->dev, ret, "failed to power on device\n"); 566 + data->version = FIELD_PREP(TMAG5273_VERSION_MASK, val); 567 + 568 + ret = regmap_bulk_read(data->map, TMAG5273_MANUFACTURER_ID_LSB, &devid, 569 + sizeof(devid)); 570 + if (ret) 571 + return dev_err_probe(data->dev, ret, "failed to read device ID\n"); 572 + data->devid = le16_to_cpu(devid); 573 + 574 + switch (data->devid) { 575 + case TMAG5273_MANUFACTURER_ID: 576 + /* 577 + * The device name matches the orderable part number. 'x' stands 578 + * for A, B, C or D devices, which have different I2C addresses. 579 + * Versions 1 or 2 (0 and 3 is reserved) stands for different 580 + * magnetic strengths. 581 + */ 582 + snprintf(data->name, sizeof(data->name), "tmag5273x%1u", data->version); 583 + if (data->version < 1 || data->version > 2) 584 + dev_warn(data->dev, "Unsupported device %s\n", data->name); 585 + return 0; 586 + default: 587 + /* 588 + * Only print warning in case of unknown device ID to allow 589 + * fallback compatible in device tree. 590 + */ 591 + dev_warn(data->dev, "Unknown device ID 0x%x\n", data->devid); 592 + return 0; 593 + } 594 + } 595 + 596 + static void tmag5273_power_down(void *data) 597 + { 598 + tmag5273_set_operating_mode(data, TMAG5273_OP_MODE_SLEEP); 599 + } 600 + 601 + static int tmag5273_probe(struct i2c_client *i2c) 602 + { 603 + struct device *dev = &i2c->dev; 604 + struct tmag5273_data *data; 605 + struct iio_dev *indio_dev; 606 + int ret; 607 + 608 + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 609 + if (!indio_dev) 610 + return -ENOMEM; 611 + 612 + data = iio_priv(indio_dev); 613 + data->dev = dev; 614 + i2c_set_clientdata(i2c, indio_dev); 615 + 616 + data->map = devm_regmap_init_i2c(i2c, &tmag5273_regmap_config); 617 + if (IS_ERR(data->map)) 618 + return dev_err_probe(dev, PTR_ERR(data->map), 619 + "failed to allocate register map\n"); 620 + 621 + mutex_init(&data->lock); 622 + 623 + ret = devm_regulator_get_enable(dev, "vcc"); 624 + if (ret) 625 + return dev_err_probe(dev, ret, "failed to enable regulator\n"); 626 + 627 + tmag5273_wake_up(data); 628 + 629 + ret = tmag5273_check_device_id(data); 630 + if (ret) 631 + return ret; 632 + 633 + ret = tmag5273_set_operating_mode(data, TMAG5273_OP_MODE_CONT); 634 + if (ret) 635 + return dev_err_probe(dev, ret, "failed to power on device\n"); 636 + 637 + /* 638 + * Register powerdown deferred callback which suspends the chip 639 + * after module unloaded. 640 + * 641 + * TMAG5273 should be in SUSPEND mode in the two cases: 642 + * 1) When driver is loaded, but we do not have any data or 643 + * configuration requests to it (we are solving it using 644 + * autosuspend feature). 645 + * 2) When driver is unloaded and device is not used (devm action is 646 + * used in this case). 647 + */ 648 + ret = devm_add_action_or_reset(dev, tmag5273_power_down, data); 649 + if (ret) 650 + return dev_err_probe(dev, ret, "failed to add powerdown action\n"); 651 + 652 + ret = pm_runtime_set_active(dev); 653 + if (ret < 0) 654 + return ret; 655 + 656 + ret = devm_pm_runtime_enable(dev); 657 + if (ret) 658 + return ret; 659 + 660 + pm_runtime_get_noresume(dev); 661 + pm_runtime_set_autosuspend_delay(dev, TMAG5273_AUTOSLEEP_DELAY_MS); 662 + pm_runtime_use_autosuspend(dev); 663 + 664 + tmag5273_read_device_property(data); 665 + 666 + ret = tmag5273_chip_init(data); 667 + if (ret) 668 + return dev_err_probe(dev, ret, "failed to init device\n"); 669 + 670 + indio_dev->info = &tmag5273_info; 671 + indio_dev->modes = INDIO_DIRECT_MODE; 672 + indio_dev->name = data->name; 673 + indio_dev->channels = tmag5273_channels; 674 + indio_dev->num_channels = ARRAY_SIZE(tmag5273_channels); 675 + 676 + pm_runtime_mark_last_busy(dev); 677 + pm_runtime_put_autosuspend(dev); 678 + 679 + ret = devm_iio_device_register(dev, indio_dev); 680 + if (ret) 681 + return dev_err_probe(dev, ret, "device register failed\n"); 682 + 683 + return 0; 684 + } 685 + 686 + static int tmag5273_runtime_suspend(struct device *dev) 687 + { 688 + struct iio_dev *indio_dev = dev_get_drvdata(dev); 689 + struct tmag5273_data *data = iio_priv(indio_dev); 690 + int ret; 691 + 692 + ret = tmag5273_set_operating_mode(data, TMAG5273_OP_MODE_SLEEP); 693 + if (ret) 694 + dev_err(dev, "failed to power off device (%pe)\n", ERR_PTR(ret)); 695 + 696 + return ret; 697 + } 698 + 699 + static int tmag5273_runtime_resume(struct device *dev) 700 + { 701 + struct iio_dev *indio_dev = dev_get_drvdata(dev); 702 + struct tmag5273_data *data = iio_priv(indio_dev); 703 + int ret; 704 + 705 + tmag5273_wake_up(data); 706 + 707 + ret = tmag5273_set_operating_mode(data, TMAG5273_OP_MODE_CONT); 708 + if (ret) 709 + dev_err(dev, "failed to power on device (%pe)\n", ERR_PTR(ret)); 710 + 711 + return ret; 712 + } 713 + 714 + static DEFINE_RUNTIME_DEV_PM_OPS(tmag5273_pm_ops, 715 + tmag5273_runtime_suspend, tmag5273_runtime_resume, 716 + NULL); 717 + 718 + static const struct i2c_device_id tmag5273_id[] = { 719 + { "tmag5273" }, 720 + { /* sentinel */ } 721 + }; 722 + MODULE_DEVICE_TABLE(i2c, tmag5273_id); 723 + 724 + static const struct of_device_id tmag5273_of_match[] = { 725 + { .compatible = "ti,tmag5273" }, 726 + { /* sentinel */ } 727 + }; 728 + MODULE_DEVICE_TABLE(of, tmag5273_of_match); 729 + 730 + static struct i2c_driver tmag5273_driver = { 731 + .driver = { 732 + .name = "tmag5273", 733 + .of_match_table = tmag5273_of_match, 734 + .pm = pm_ptr(&tmag5273_pm_ops), 735 + }, 736 + .probe_new = tmag5273_probe, 737 + .id_table = tmag5273_id, 738 + }; 739 + module_i2c_driver(tmag5273_driver); 740 + 741 + MODULE_DESCRIPTION("TI TMAG5273 Low-Power Linear 3D Hall-Effect Sensor driver"); 742 + MODULE_AUTHOR("Gerald Loacker <gerald.loacker@wolfvision.net>"); 743 + MODULE_LICENSE("GPL");