256 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * ADXL345 3-Axis Digital Accelerometer IIO core driver4 *5 * Copyright (c) 2017 Eva Rachel Retuya <eraretuya@gmail.com>6 *7 * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf8 */9 10#include <linux/module.h>11#include <linux/property.h>12#include <linux/regmap.h>13#include <linux/units.h>14 15#include <linux/iio/iio.h>16#include <linux/iio/sysfs.h>17 18#include "adxl345.h"19 20struct adxl345_data {21 const struct adxl345_chip_info *info;22 struct regmap *regmap;23};24 25#define ADXL345_CHANNEL(index, axis) { \26 .type = IIO_ACCEL, \27 .modified = 1, \28 .channel2 = IIO_MOD_##axis, \29 .address = index, \30 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \31 BIT(IIO_CHAN_INFO_CALIBBIAS), \32 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \33 BIT(IIO_CHAN_INFO_SAMP_FREQ), \34}35 36static const struct iio_chan_spec adxl345_channels[] = {37 ADXL345_CHANNEL(0, X),38 ADXL345_CHANNEL(1, Y),39 ADXL345_CHANNEL(2, Z),40};41 42static int adxl345_read_raw(struct iio_dev *indio_dev,43 struct iio_chan_spec const *chan,44 int *val, int *val2, long mask)45{46 struct adxl345_data *data = iio_priv(indio_dev);47 __le16 accel;48 long long samp_freq_nhz;49 unsigned int regval;50 int ret;51 52 switch (mask) {53 case IIO_CHAN_INFO_RAW:54 /*55 * Data is stored in adjacent registers:56 * ADXL345_REG_DATA(X0/Y0/Z0) contain the least significant byte57 * and ADXL345_REG_DATA(X0/Y0/Z0) + 1 the most significant byte58 */59 ret = regmap_bulk_read(data->regmap,60 ADXL345_REG_DATA_AXIS(chan->address),61 &accel, sizeof(accel));62 if (ret < 0)63 return ret;64 65 *val = sign_extend32(le16_to_cpu(accel), 12);66 return IIO_VAL_INT;67 case IIO_CHAN_INFO_SCALE:68 *val = 0;69 *val2 = data->info->uscale;70 return IIO_VAL_INT_PLUS_MICRO;71 case IIO_CHAN_INFO_CALIBBIAS:72 ret = regmap_read(data->regmap,73 ADXL345_REG_OFS_AXIS(chan->address), ®val);74 if (ret < 0)75 return ret;76 /*77 * 8-bit resolution at +/- 2g, that is 4x accel data scale78 * factor79 */80 *val = sign_extend32(regval, 7) * 4;81 82 return IIO_VAL_INT;83 case IIO_CHAN_INFO_SAMP_FREQ:84 ret = regmap_read(data->regmap, ADXL345_REG_BW_RATE, ®val);85 if (ret < 0)86 return ret;87 88 samp_freq_nhz = ADXL345_BASE_RATE_NANO_HZ <<89 (regval & ADXL345_BW_RATE);90 *val = div_s64_rem(samp_freq_nhz, NANOHZ_PER_HZ, val2);91 92 return IIO_VAL_INT_PLUS_NANO;93 }94 95 return -EINVAL;96}97 98static int adxl345_write_raw(struct iio_dev *indio_dev,99 struct iio_chan_spec const *chan,100 int val, int val2, long mask)101{102 struct adxl345_data *data = iio_priv(indio_dev);103 s64 n;104 105 switch (mask) {106 case IIO_CHAN_INFO_CALIBBIAS:107 /*108 * 8-bit resolution at +/- 2g, that is 4x accel data scale109 * factor110 */111 return regmap_write(data->regmap,112 ADXL345_REG_OFS_AXIS(chan->address),113 val / 4);114 case IIO_CHAN_INFO_SAMP_FREQ:115 n = div_s64(val * NANOHZ_PER_HZ + val2,116 ADXL345_BASE_RATE_NANO_HZ);117 118 return regmap_update_bits(data->regmap, ADXL345_REG_BW_RATE,119 ADXL345_BW_RATE,120 clamp_val(ilog2(n), 0,121 ADXL345_BW_RATE));122 }123 124 return -EINVAL;125}126 127static int adxl345_write_raw_get_fmt(struct iio_dev *indio_dev,128 struct iio_chan_spec const *chan,129 long mask)130{131 switch (mask) {132 case IIO_CHAN_INFO_CALIBBIAS:133 return IIO_VAL_INT;134 case IIO_CHAN_INFO_SAMP_FREQ:135 return IIO_VAL_INT_PLUS_NANO;136 default:137 return -EINVAL;138 }139}140 141static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(142"0.09765625 0.1953125 0.390625 0.78125 1.5625 3.125 6.25 12.5 25 50 100 200 400 800 1600 3200"143);144 145static struct attribute *adxl345_attrs[] = {146 &iio_const_attr_sampling_frequency_available.dev_attr.attr,147 NULL148};149 150static const struct attribute_group adxl345_attrs_group = {151 .attrs = adxl345_attrs,152};153 154static const struct iio_info adxl345_info = {155 .attrs = &adxl345_attrs_group,156 .read_raw = adxl345_read_raw,157 .write_raw = adxl345_write_raw,158 .write_raw_get_fmt = adxl345_write_raw_get_fmt,159};160 161static int adxl345_powerup(void *regmap)162{163 return regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_MEASURE);164}165 166static void adxl345_powerdown(void *regmap)167{168 regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_STANDBY);169}170 171/**172 * adxl345_core_probe() - probe and setup for the adxl345 accelerometer,173 * also covers the adlx375 accelerometer174 * @dev: Driver model representation of the device175 * @regmap: Regmap instance for the device176 * @setup: Setup routine to be executed right before the standard device177 * setup178 *179 * Return: 0 on success, negative errno on error180 */181int adxl345_core_probe(struct device *dev, struct regmap *regmap,182 int (*setup)(struct device*, struct regmap*))183{184 struct adxl345_data *data;185 struct iio_dev *indio_dev;186 u32 regval;187 unsigned int data_format_mask = (ADXL345_DATA_FORMAT_RANGE |188 ADXL345_DATA_FORMAT_JUSTIFY |189 ADXL345_DATA_FORMAT_FULL_RES |190 ADXL345_DATA_FORMAT_SELF_TEST);191 int ret;192 193 indio_dev = devm_iio_device_alloc(dev, sizeof(*data));194 if (!indio_dev)195 return -ENOMEM;196 197 data = iio_priv(indio_dev);198 data->regmap = regmap;199 data->info = device_get_match_data(dev);200 if (!data->info)201 return -ENODEV;202 203 indio_dev->name = data->info->name;204 indio_dev->info = &adxl345_info;205 indio_dev->modes = INDIO_DIRECT_MODE;206 indio_dev->channels = adxl345_channels;207 indio_dev->num_channels = ARRAY_SIZE(adxl345_channels);208 209 if (setup) {210 /* Perform optional initial bus specific configuration */211 ret = setup(dev, data->regmap);212 if (ret)213 return ret;214 215 /* Enable full-resolution mode */216 ret = regmap_update_bits(data->regmap, ADXL345_REG_DATA_FORMAT,217 data_format_mask,218 ADXL345_DATA_FORMAT_FULL_RES);219 if (ret)220 return dev_err_probe(dev, ret,221 "Failed to set data range\n");222 223 } else {224 /* Enable full-resolution mode (init all data_format bits) */225 ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT,226 ADXL345_DATA_FORMAT_FULL_RES);227 if (ret)228 return dev_err_probe(dev, ret,229 "Failed to set data range\n");230 }231 232 ret = regmap_read(data->regmap, ADXL345_REG_DEVID, ®val);233 if (ret < 0)234 return dev_err_probe(dev, ret, "Error reading device ID\n");235 236 if (regval != ADXL345_DEVID)237 return dev_err_probe(dev, -ENODEV, "Invalid device ID: %x, expected %x\n",238 regval, ADXL345_DEVID);239 240 /* Enable measurement mode */241 ret = adxl345_powerup(data->regmap);242 if (ret < 0)243 return dev_err_probe(dev, ret, "Failed to enable measurement mode\n");244 245 ret = devm_add_action_or_reset(dev, adxl345_powerdown, data->regmap);246 if (ret < 0)247 return ret;248 249 return devm_iio_device_register(dev, indio_dev);250}251EXPORT_SYMBOL_NS_GPL(adxl345_core_probe, IIO_ADXL345);252 253MODULE_AUTHOR("Eva Rachel Retuya <eraretuya@gmail.com>");254MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer core driver");255MODULE_LICENSE("GPL v2");256