425 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * ADXL313 3-Axis Digital Accelerometer4 *5 * Copyright (c) 2021 Lucas Stankus <lucas.p.stankus@gmail.com>6 *7 * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL313.pdf8 */9 10#include <linux/bitfield.h>11#include <linux/module.h>12#include <linux/regmap.h>13 14#include "adxl313.h"15 16static const struct regmap_range adxl312_readable_reg_range[] = {17 regmap_reg_range(ADXL313_REG_DEVID0, ADXL313_REG_DEVID0),18 regmap_reg_range(ADXL313_REG_OFS_AXIS(0), ADXL313_REG_OFS_AXIS(2)),19 regmap_reg_range(ADXL313_REG_THRESH_ACT, ADXL313_REG_ACT_INACT_CTL),20 regmap_reg_range(ADXL313_REG_BW_RATE, ADXL313_REG_FIFO_STATUS),21};22 23static const struct regmap_range adxl313_readable_reg_range[] = {24 regmap_reg_range(ADXL313_REG_DEVID0, ADXL313_REG_XID),25 regmap_reg_range(ADXL313_REG_SOFT_RESET, ADXL313_REG_SOFT_RESET),26 regmap_reg_range(ADXL313_REG_OFS_AXIS(0), ADXL313_REG_OFS_AXIS(2)),27 regmap_reg_range(ADXL313_REG_THRESH_ACT, ADXL313_REG_ACT_INACT_CTL),28 regmap_reg_range(ADXL313_REG_BW_RATE, ADXL313_REG_FIFO_STATUS),29};30 31const struct regmap_access_table adxl312_readable_regs_table = {32 .yes_ranges = adxl312_readable_reg_range,33 .n_yes_ranges = ARRAY_SIZE(adxl312_readable_reg_range),34};35EXPORT_SYMBOL_NS_GPL(adxl312_readable_regs_table, IIO_ADXL313);36 37const struct regmap_access_table adxl313_readable_regs_table = {38 .yes_ranges = adxl313_readable_reg_range,39 .n_yes_ranges = ARRAY_SIZE(adxl313_readable_reg_range),40};41EXPORT_SYMBOL_NS_GPL(adxl313_readable_regs_table, IIO_ADXL313);42 43const struct regmap_access_table adxl314_readable_regs_table = {44 .yes_ranges = adxl312_readable_reg_range,45 .n_yes_ranges = ARRAY_SIZE(adxl312_readable_reg_range),46};47EXPORT_SYMBOL_NS_GPL(adxl314_readable_regs_table, IIO_ADXL313);48 49static int adxl312_check_id(struct device *dev,50 struct adxl313_data *data)51{52 unsigned int regval;53 int ret;54 55 ret = regmap_read(data->regmap, ADXL313_REG_DEVID0, ®val);56 if (ret)57 return ret;58 59 if (regval != ADXL313_DEVID0_ADXL312_314)60 dev_warn(dev, "Invalid manufacturer ID: %#02x\n", regval);61 62 return 0;63}64 65static int adxl313_check_id(struct device *dev,66 struct adxl313_data *data)67{68 unsigned int regval;69 int ret;70 71 ret = regmap_read(data->regmap, ADXL313_REG_DEVID0, ®val);72 if (ret)73 return ret;74 75 if (regval != ADXL313_DEVID0)76 dev_warn(dev, "Invalid manufacturer ID: 0x%02x\n", regval);77 78 /* Check DEVID1 and PARTID */79 if (regval == ADXL313_DEVID0) {80 ret = regmap_read(data->regmap, ADXL313_REG_DEVID1, ®val);81 if (ret)82 return ret;83 84 if (regval != ADXL313_DEVID1)85 dev_warn(dev, "Invalid mems ID: 0x%02x\n", regval);86 87 ret = regmap_read(data->regmap, ADXL313_REG_PARTID, ®val);88 if (ret)89 return ret;90 91 if (regval != ADXL313_PARTID)92 dev_warn(dev, "Invalid device ID: 0x%02x\n", regval);93 }94 95 return 0;96}97 98const struct adxl313_chip_info adxl31x_chip_info[] = {99 [ADXL312] = {100 .name = "adxl312",101 .type = ADXL312,102 .scale_factor = 28425072,103 .variable_range = true,104 .soft_reset = false,105 .check_id = &adxl312_check_id,106 },107 [ADXL313] = {108 .name = "adxl313",109 .type = ADXL313,110 .scale_factor = 9576806,111 .variable_range = true,112 .soft_reset = true,113 .check_id = &adxl313_check_id,114 },115 [ADXL314] = {116 .name = "adxl314",117 .type = ADXL314,118 .scale_factor = 478858719,119 .variable_range = false,120 .soft_reset = false,121 .check_id = &adxl312_check_id,122 },123};124EXPORT_SYMBOL_NS_GPL(adxl31x_chip_info, IIO_ADXL313);125 126static const struct regmap_range adxl312_writable_reg_range[] = {127 regmap_reg_range(ADXL313_REG_OFS_AXIS(0), ADXL313_REG_OFS_AXIS(2)),128 regmap_reg_range(ADXL313_REG_THRESH_ACT, ADXL313_REG_ACT_INACT_CTL),129 regmap_reg_range(ADXL313_REG_BW_RATE, ADXL313_REG_INT_MAP),130 regmap_reg_range(ADXL313_REG_DATA_FORMAT, ADXL313_REG_DATA_FORMAT),131 regmap_reg_range(ADXL313_REG_FIFO_CTL, ADXL313_REG_FIFO_CTL),132};133 134static const struct regmap_range adxl313_writable_reg_range[] = {135 regmap_reg_range(ADXL313_REG_SOFT_RESET, ADXL313_REG_SOFT_RESET),136 regmap_reg_range(ADXL313_REG_OFS_AXIS(0), ADXL313_REG_OFS_AXIS(2)),137 regmap_reg_range(ADXL313_REG_THRESH_ACT, ADXL313_REG_ACT_INACT_CTL),138 regmap_reg_range(ADXL313_REG_BW_RATE, ADXL313_REG_INT_MAP),139 regmap_reg_range(ADXL313_REG_DATA_FORMAT, ADXL313_REG_DATA_FORMAT),140 regmap_reg_range(ADXL313_REG_FIFO_CTL, ADXL313_REG_FIFO_CTL),141};142 143const struct regmap_access_table adxl312_writable_regs_table = {144 .yes_ranges = adxl312_writable_reg_range,145 .n_yes_ranges = ARRAY_SIZE(adxl312_writable_reg_range),146};147EXPORT_SYMBOL_NS_GPL(adxl312_writable_regs_table, IIO_ADXL313);148 149const struct regmap_access_table adxl313_writable_regs_table = {150 .yes_ranges = adxl313_writable_reg_range,151 .n_yes_ranges = ARRAY_SIZE(adxl313_writable_reg_range),152};153EXPORT_SYMBOL_NS_GPL(adxl313_writable_regs_table, IIO_ADXL313);154 155const struct regmap_access_table adxl314_writable_regs_table = {156 .yes_ranges = adxl312_writable_reg_range,157 .n_yes_ranges = ARRAY_SIZE(adxl312_writable_reg_range),158};159EXPORT_SYMBOL_NS_GPL(adxl314_writable_regs_table, IIO_ADXL313);160 161static const int adxl313_odr_freqs[][2] = {162 [0] = { 6, 250000 },163 [1] = { 12, 500000 },164 [2] = { 25, 0 },165 [3] = { 50, 0 },166 [4] = { 100, 0 },167 [5] = { 200, 0 },168 [6] = { 400, 0 },169 [7] = { 800, 0 },170 [8] = { 1600, 0 },171 [9] = { 3200, 0 },172};173 174#define ADXL313_ACCEL_CHANNEL(index, axis) { \175 .type = IIO_ACCEL, \176 .address = index, \177 .modified = 1, \178 .channel2 = IIO_MOD_##axis, \179 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \180 BIT(IIO_CHAN_INFO_CALIBBIAS), \181 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \182 BIT(IIO_CHAN_INFO_SAMP_FREQ), \183 .info_mask_shared_by_type_available = \184 BIT(IIO_CHAN_INFO_SAMP_FREQ), \185 .scan_type = { \186 .realbits = 13, \187 }, \188}189 190static const struct iio_chan_spec adxl313_channels[] = {191 ADXL313_ACCEL_CHANNEL(0, X),192 ADXL313_ACCEL_CHANNEL(1, Y),193 ADXL313_ACCEL_CHANNEL(2, Z),194};195 196static int adxl313_set_odr(struct adxl313_data *data,197 unsigned int freq1, unsigned int freq2)198{199 unsigned int i;200 201 for (i = 0; i < ARRAY_SIZE(adxl313_odr_freqs); i++) {202 if (adxl313_odr_freqs[i][0] == freq1 &&203 adxl313_odr_freqs[i][1] == freq2)204 break;205 }206 207 if (i == ARRAY_SIZE(adxl313_odr_freqs))208 return -EINVAL;209 210 return regmap_update_bits(data->regmap, ADXL313_REG_BW_RATE,211 ADXL313_RATE_MSK,212 FIELD_PREP(ADXL313_RATE_MSK, ADXL313_RATE_BASE + i));213}214 215static int adxl313_read_axis(struct adxl313_data *data,216 struct iio_chan_spec const *chan)217{218 int ret;219 220 mutex_lock(&data->lock);221 222 ret = regmap_bulk_read(data->regmap,223 ADXL313_REG_DATA_AXIS(chan->address),224 &data->transf_buf, sizeof(data->transf_buf));225 if (ret)226 goto unlock_ret;227 228 ret = le16_to_cpu(data->transf_buf);229 230unlock_ret:231 mutex_unlock(&data->lock);232 return ret;233}234 235static int adxl313_read_freq_avail(struct iio_dev *indio_dev,236 struct iio_chan_spec const *chan,237 const int **vals, int *type, int *length,238 long mask)239{240 switch (mask) {241 case IIO_CHAN_INFO_SAMP_FREQ:242 *vals = (const int *)adxl313_odr_freqs;243 *length = ARRAY_SIZE(adxl313_odr_freqs) * 2;244 *type = IIO_VAL_INT_PLUS_MICRO;245 return IIO_AVAIL_LIST;246 default:247 return -EINVAL;248 }249}250 251static int adxl313_read_raw(struct iio_dev *indio_dev,252 struct iio_chan_spec const *chan,253 int *val, int *val2, long mask)254{255 struct adxl313_data *data = iio_priv(indio_dev);256 unsigned int regval;257 int ret;258 259 switch (mask) {260 case IIO_CHAN_INFO_RAW:261 ret = adxl313_read_axis(data, chan);262 if (ret < 0)263 return ret;264 265 *val = sign_extend32(ret, chan->scan_type.realbits - 1);266 return IIO_VAL_INT;267 case IIO_CHAN_INFO_SCALE:268 *val = 0;269 270 *val2 = data->chip_info->scale_factor;271 272 return IIO_VAL_INT_PLUS_NANO;273 case IIO_CHAN_INFO_CALIBBIAS:274 ret = regmap_read(data->regmap,275 ADXL313_REG_OFS_AXIS(chan->address), ®val);276 if (ret)277 return ret;278 279 /*280 * 8-bit resolution at minimum range, that is 4x accel data scale281 * factor at full resolution282 */283 *val = sign_extend32(regval, 7) * 4;284 return IIO_VAL_INT;285 case IIO_CHAN_INFO_SAMP_FREQ:286 ret = regmap_read(data->regmap, ADXL313_REG_BW_RATE, ®val);287 if (ret)288 return ret;289 290 ret = FIELD_GET(ADXL313_RATE_MSK, regval) - ADXL313_RATE_BASE;291 *val = adxl313_odr_freqs[ret][0];292 *val2 = adxl313_odr_freqs[ret][1];293 return IIO_VAL_INT_PLUS_MICRO;294 default:295 return -EINVAL;296 }297}298 299static int adxl313_write_raw(struct iio_dev *indio_dev,300 struct iio_chan_spec const *chan,301 int val, int val2, long mask)302{303 struct adxl313_data *data = iio_priv(indio_dev);304 305 switch (mask) {306 case IIO_CHAN_INFO_CALIBBIAS:307 /*308 * 8-bit resolution at minimum range, that is 4x accel data scale309 * factor at full resolution310 */311 if (clamp_val(val, -128 * 4, 127 * 4) != val)312 return -EINVAL;313 314 return regmap_write(data->regmap,315 ADXL313_REG_OFS_AXIS(chan->address),316 val / 4);317 case IIO_CHAN_INFO_SAMP_FREQ:318 return adxl313_set_odr(data, val, val2);319 default:320 return -EINVAL;321 }322}323 324static const struct iio_info adxl313_info = {325 .read_raw = adxl313_read_raw,326 .write_raw = adxl313_write_raw,327 .read_avail = adxl313_read_freq_avail,328};329 330static int adxl313_setup(struct device *dev, struct adxl313_data *data,331 int (*setup)(struct device *, struct regmap *))332{333 int ret;334 335 /*336 * If sw reset available, ensures the device is in a consistent337 * state after start up338 */339 if (data->chip_info->soft_reset) {340 ret = regmap_write(data->regmap, ADXL313_REG_SOFT_RESET,341 ADXL313_SOFT_RESET);342 if (ret)343 return ret;344 }345 346 if (setup) {347 ret = setup(dev, data->regmap);348 if (ret)349 return ret;350 }351 352 ret = data->chip_info->check_id(dev, data);353 if (ret)354 return ret;355 356 /* Sets the range to maximum, full resolution, if applicable */357 if (data->chip_info->variable_range) {358 ret = regmap_update_bits(data->regmap, ADXL313_REG_DATA_FORMAT,359 ADXL313_RANGE_MSK,360 FIELD_PREP(ADXL313_RANGE_MSK, ADXL313_RANGE_MAX));361 if (ret)362 return ret;363 364 /* Enables full resolution */365 ret = regmap_update_bits(data->regmap, ADXL313_REG_DATA_FORMAT,366 ADXL313_FULL_RES, ADXL313_FULL_RES);367 if (ret)368 return ret;369 }370 371 /* Enables measurement mode */372 return regmap_update_bits(data->regmap, ADXL313_REG_POWER_CTL,373 ADXL313_POWER_CTL_MSK,374 ADXL313_MEASUREMENT_MODE);375}376 377/**378 * adxl313_core_probe() - probe and setup for adxl313 accelerometer379 * @dev: Driver model representation of the device380 * @regmap: Register map of the device381 * @chip_info: Structure containing device specific data382 * @setup: Setup routine to be executed right before the standard device383 * setup, can also be set to NULL if not required384 *385 * Return: 0 on success, negative errno on error cases386 */387int adxl313_core_probe(struct device *dev,388 struct regmap *regmap,389 const struct adxl313_chip_info *chip_info,390 int (*setup)(struct device *, struct regmap *))391{392 struct adxl313_data *data;393 struct iio_dev *indio_dev;394 int ret;395 396 indio_dev = devm_iio_device_alloc(dev, sizeof(*data));397 if (!indio_dev)398 return -ENOMEM;399 400 data = iio_priv(indio_dev);401 data->regmap = regmap;402 data->chip_info = chip_info;403 404 mutex_init(&data->lock);405 406 indio_dev->name = chip_info->name;407 indio_dev->info = &adxl313_info;408 indio_dev->modes = INDIO_DIRECT_MODE;409 indio_dev->channels = adxl313_channels;410 indio_dev->num_channels = ARRAY_SIZE(adxl313_channels);411 412 ret = adxl313_setup(dev, data, setup);413 if (ret) {414 dev_err(dev, "ADXL313 setup failed\n");415 return ret;416 }417 418 return devm_iio_device_register(dev, indio_dev);419}420EXPORT_SYMBOL_NS_GPL(adxl313_core_probe, IIO_ADXL313);421 422MODULE_AUTHOR("Lucas Stankus <lucas.p.stankus@gmail.com>");423MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer core driver");424MODULE_LICENSE("GPL v2");425