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

iio: accel: Add driver support for ADXL313

ADXL313 is a small, thin, low power, 3-axis accelerometer with high
resolution measurement up to +/-4g. It includes an integrated 32-level
FIFO and has activity and inactivity sensing capabilities.

Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL313.pdf
Signed-off-by: Lucas Stankus <lucas.p.stankus@gmail.com>
Reviewed-by: Alexandru Ardelean <ardeleanalex@gmail.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Link: https://lore.kernel.org/r/d16e2d1967e46bb2b1024b6d23bc4889da77dc6b.1630523106.git.lucas.p.stankus@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Lucas Stankus and committed by
Jonathan Cameron
636d4463 af1c6b50

+582
+6
MAINTAINERS
··· 590 590 S: Maintained 591 591 F: drivers/platform/x86/adv_swbutton.c 592 592 593 + ADXL313 THREE-AXIS DIGITAL ACCELEROMETER DRIVER 594 + M: Lucas Stankus <lucas.p.stankus@gmail.com> 595 + S: Supported 596 + F: Documentation/devicetree/bindings/iio/accel/adi,adxl313.yaml 597 + F: drivers/iio/accel/adxl313* 598 + 593 599 ADXL34X THREE-AXIS DIGITAL ACCELEROMETER DRIVER (ADXL345/ADXL346) 594 600 M: Michael Hennerich <michael.hennerich@analog.com> 595 601 S: Supported
+29
drivers/iio/accel/Kconfig
··· 30 30 To compile this driver as a module, say M here: the module will be 31 31 called adis16209. 32 32 33 + config ADXL313 34 + tristate 35 + 36 + config ADXL313_I2C 37 + tristate "Analog Devices ADXL313 3-Axis Digital Accelerometer I2C Driver" 38 + depends on I2C 39 + select ADXL313 40 + select REGMAP_I2C 41 + help 42 + Say Y here if you want to build i2c support for the Analog Devices 43 + ADXL313 3-axis digital accelerometer. 44 + 45 + To compile this driver as a module, choose M here: the module 46 + will be called adxl313_i2c and you will also get adxl313_core 47 + for the core module. 48 + 49 + config ADXL313_SPI 50 + tristate "Analog Devices ADXL313 3-Axis Digital Accelerometer SPI Driver" 51 + depends on SPI 52 + select ADXL313 53 + select REGMAP_SPI 54 + help 55 + Say Y here if you want to build spi support for the Analog Devices 56 + ADXL313 3-axis digital accelerometer. 57 + 58 + To compile this driver as a module, choose M here: the module 59 + will be called adxl313_spi and you will also get adxl313_core 60 + for the core module. 61 + 33 62 config ADXL345 34 63 tristate 35 64
+3
drivers/iio/accel/Makefile
··· 6 6 # When adding new entries keep the list in alphabetical order 7 7 obj-$(CONFIG_ADIS16201) += adis16201.o 8 8 obj-$(CONFIG_ADIS16209) += adis16209.o 9 + obj-$(CONFIG_ADXL313) += adxl313_core.o 10 + obj-$(CONFIG_ADXL313_I2C) += adxl313_i2c.o 11 + obj-$(CONFIG_ADXL313_SPI) += adxl313_spi.o 9 12 obj-$(CONFIG_ADXL345) += adxl345_core.o 10 13 obj-$(CONFIG_ADXL345_I2C) += adxl345_i2c.o 11 14 obj-$(CONFIG_ADXL345_SPI) += adxl345_spi.o
+54
drivers/iio/accel/adxl313.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * ADXL313 3-Axis Digital Accelerometer 4 + * 5 + * Copyright (c) 2021 Lucas Stankus <lucas.p.stankus@gmail.com> 6 + */ 7 + 8 + #ifndef _ADXL313_H_ 9 + #define _ADXL313_H_ 10 + 11 + /* ADXL313 register definitions */ 12 + #define ADXL313_REG_DEVID0 0x00 13 + #define ADXL313_REG_DEVID1 0x01 14 + #define ADXL313_REG_PARTID 0x02 15 + #define ADXL313_REG_XID 0x04 16 + #define ADXL313_REG_SOFT_RESET 0x18 17 + #define ADXL313_REG_OFS_AXIS(index) (0x1E + (index)) 18 + #define ADXL313_REG_THRESH_ACT 0x24 19 + #define ADXL313_REG_ACT_INACT_CTL 0x27 20 + #define ADXL313_REG_BW_RATE 0x2C 21 + #define ADXL313_REG_POWER_CTL 0x2D 22 + #define ADXL313_REG_INT_MAP 0x2F 23 + #define ADXL313_REG_DATA_FORMAT 0x31 24 + #define ADXL313_REG_DATA_AXIS(index) (0x32 + ((index) * 2)) 25 + #define ADXL313_REG_FIFO_CTL 0x38 26 + #define ADXL313_REG_FIFO_STATUS 0x39 27 + 28 + #define ADXL313_DEVID0 0xAD 29 + #define ADXL313_DEVID1 0x1D 30 + #define ADXL313_PARTID 0xCB 31 + #define ADXL313_SOFT_RESET 0x52 32 + 33 + #define ADXL313_RATE_MSK GENMASK(3, 0) 34 + #define ADXL313_RATE_BASE 6 35 + 36 + #define ADXL313_POWER_CTL_MSK GENMASK(3, 2) 37 + #define ADXL313_MEASUREMENT_MODE BIT(3) 38 + 39 + #define ADXL313_RANGE_MSK GENMASK(1, 0) 40 + #define ADXL313_RANGE_4G 3 41 + 42 + #define ADXL313_FULL_RES BIT(3) 43 + #define ADXL313_SPI_3WIRE BIT(6) 44 + #define ADXL313_I2C_DISABLE BIT(6) 45 + 46 + extern const struct regmap_access_table adxl313_readable_regs_table; 47 + 48 + extern const struct regmap_access_table adxl313_writable_regs_table; 49 + 50 + int adxl313_core_probe(struct device *dev, 51 + struct regmap *regmap, 52 + const char *name, 53 + int (*setup)(struct device *, struct regmap *)); 54 + #endif /* _ADXL313_H_ */
+332
drivers/iio/accel/adxl313_core.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * ADXL313 3-Axis Digital Accelerometer 4 + * 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.pdf 8 + */ 9 + 10 + #include <linux/bitfield.h> 11 + #include <linux/iio/iio.h> 12 + #include <linux/module.h> 13 + #include <linux/regmap.h> 14 + 15 + #include "adxl313.h" 16 + 17 + static const struct regmap_range adxl313_readable_reg_range[] = { 18 + regmap_reg_range(ADXL313_REG_DEVID0, ADXL313_REG_XID), 19 + regmap_reg_range(ADXL313_REG_SOFT_RESET, ADXL313_REG_SOFT_RESET), 20 + regmap_reg_range(ADXL313_REG_OFS_AXIS(0), ADXL313_REG_OFS_AXIS(2)), 21 + regmap_reg_range(ADXL313_REG_THRESH_ACT, ADXL313_REG_ACT_INACT_CTL), 22 + regmap_reg_range(ADXL313_REG_BW_RATE, ADXL313_REG_FIFO_STATUS), 23 + }; 24 + 25 + const struct regmap_access_table adxl313_readable_regs_table = { 26 + .yes_ranges = adxl313_readable_reg_range, 27 + .n_yes_ranges = ARRAY_SIZE(adxl313_readable_reg_range), 28 + }; 29 + EXPORT_SYMBOL_GPL(adxl313_readable_regs_table); 30 + 31 + static const struct regmap_range adxl313_writable_reg_range[] = { 32 + regmap_reg_range(ADXL313_REG_SOFT_RESET, ADXL313_REG_SOFT_RESET), 33 + regmap_reg_range(ADXL313_REG_OFS_AXIS(0), ADXL313_REG_OFS_AXIS(2)), 34 + regmap_reg_range(ADXL313_REG_THRESH_ACT, ADXL313_REG_ACT_INACT_CTL), 35 + regmap_reg_range(ADXL313_REG_BW_RATE, ADXL313_REG_INT_MAP), 36 + regmap_reg_range(ADXL313_REG_DATA_FORMAT, ADXL313_REG_DATA_FORMAT), 37 + regmap_reg_range(ADXL313_REG_FIFO_CTL, ADXL313_REG_FIFO_CTL), 38 + }; 39 + 40 + const struct regmap_access_table adxl313_writable_regs_table = { 41 + .yes_ranges = adxl313_writable_reg_range, 42 + .n_yes_ranges = ARRAY_SIZE(adxl313_writable_reg_range), 43 + }; 44 + EXPORT_SYMBOL_GPL(adxl313_writable_regs_table); 45 + 46 + struct adxl313_data { 47 + struct regmap *regmap; 48 + struct mutex lock; /* lock to protect transf_buf */ 49 + __le16 transf_buf ____cacheline_aligned; 50 + }; 51 + 52 + static const int adxl313_odr_freqs[][2] = { 53 + [0] = { 6, 250000 }, 54 + [1] = { 12, 500000 }, 55 + [2] = { 25, 0 }, 56 + [3] = { 50, 0 }, 57 + [4] = { 100, 0 }, 58 + [5] = { 200, 0 }, 59 + [6] = { 400, 0 }, 60 + [7] = { 800, 0 }, 61 + [8] = { 1600, 0 }, 62 + [9] = { 3200, 0 }, 63 + }; 64 + 65 + #define ADXL313_ACCEL_CHANNEL(index, axis) { \ 66 + .type = IIO_ACCEL, \ 67 + .address = index, \ 68 + .modified = 1, \ 69 + .channel2 = IIO_MOD_##axis, \ 70 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 71 + BIT(IIO_CHAN_INFO_CALIBBIAS), \ 72 + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ 73 + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 74 + .info_mask_shared_by_type_available = \ 75 + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 76 + .scan_type = { \ 77 + .realbits = 13, \ 78 + }, \ 79 + } 80 + 81 + static const struct iio_chan_spec adxl313_channels[] = { 82 + ADXL313_ACCEL_CHANNEL(0, X), 83 + ADXL313_ACCEL_CHANNEL(1, Y), 84 + ADXL313_ACCEL_CHANNEL(2, Z), 85 + }; 86 + 87 + static int adxl313_set_odr(struct adxl313_data *data, 88 + unsigned int freq1, unsigned int freq2) 89 + { 90 + unsigned int i; 91 + 92 + for (i = 0; i < ARRAY_SIZE(adxl313_odr_freqs); i++) { 93 + if (adxl313_odr_freqs[i][0] == freq1 && 94 + adxl313_odr_freqs[i][1] == freq2) 95 + break; 96 + } 97 + 98 + if (i == ARRAY_SIZE(adxl313_odr_freqs)) 99 + return -EINVAL; 100 + 101 + return regmap_update_bits(data->regmap, ADXL313_REG_BW_RATE, 102 + ADXL313_RATE_MSK, 103 + FIELD_PREP(ADXL313_RATE_MSK, ADXL313_RATE_BASE + i)); 104 + } 105 + 106 + static int adxl313_read_axis(struct adxl313_data *data, 107 + struct iio_chan_spec const *chan) 108 + { 109 + int ret; 110 + 111 + mutex_lock(&data->lock); 112 + 113 + ret = regmap_bulk_read(data->regmap, 114 + ADXL313_REG_DATA_AXIS(chan->address), 115 + &data->transf_buf, sizeof(data->transf_buf)); 116 + if (ret) 117 + goto unlock_ret; 118 + 119 + ret = le16_to_cpu(data->transf_buf); 120 + 121 + unlock_ret: 122 + mutex_unlock(&data->lock); 123 + return ret; 124 + } 125 + 126 + static int adxl313_read_freq_avail(struct iio_dev *indio_dev, 127 + struct iio_chan_spec const *chan, 128 + const int **vals, int *type, int *length, 129 + long mask) 130 + { 131 + switch (mask) { 132 + case IIO_CHAN_INFO_SAMP_FREQ: 133 + *vals = (const int *)adxl313_odr_freqs; 134 + *length = ARRAY_SIZE(adxl313_odr_freqs) * 2; 135 + *type = IIO_VAL_INT_PLUS_MICRO; 136 + return IIO_AVAIL_LIST; 137 + default: 138 + return -EINVAL; 139 + } 140 + } 141 + 142 + static int adxl313_read_raw(struct iio_dev *indio_dev, 143 + struct iio_chan_spec const *chan, 144 + int *val, int *val2, long mask) 145 + { 146 + struct adxl313_data *data = iio_priv(indio_dev); 147 + unsigned int regval; 148 + int ret; 149 + 150 + switch (mask) { 151 + case IIO_CHAN_INFO_RAW: 152 + ret = adxl313_read_axis(data, chan); 153 + if (ret < 0) 154 + return ret; 155 + 156 + *val = sign_extend32(ret, chan->scan_type.realbits - 1); 157 + return IIO_VAL_INT; 158 + case IIO_CHAN_INFO_SCALE: 159 + /* 160 + * Scale for any g range is given in datasheet as 161 + * 1024 LSB/g = 0.0009765625 * 9.80665 = 0.009576806640625 m/s^2 162 + */ 163 + *val = 0; 164 + *val2 = 9576806; 165 + return IIO_VAL_INT_PLUS_NANO; 166 + case IIO_CHAN_INFO_CALIBBIAS: 167 + ret = regmap_read(data->regmap, 168 + ADXL313_REG_OFS_AXIS(chan->address), &regval); 169 + if (ret) 170 + return ret; 171 + 172 + /* 173 + * 8-bit resolution at +/- 0.5g, that is 4x accel data scale 174 + * factor at full resolution 175 + */ 176 + *val = sign_extend32(regval, 7) * 4; 177 + return IIO_VAL_INT; 178 + case IIO_CHAN_INFO_SAMP_FREQ: 179 + ret = regmap_read(data->regmap, ADXL313_REG_BW_RATE, &regval); 180 + if (ret) 181 + return ret; 182 + 183 + ret = FIELD_GET(ADXL313_RATE_MSK, regval) - ADXL313_RATE_BASE; 184 + *val = adxl313_odr_freqs[ret][0]; 185 + *val2 = adxl313_odr_freqs[ret][1]; 186 + return IIO_VAL_INT_PLUS_MICRO; 187 + default: 188 + return -EINVAL; 189 + } 190 + } 191 + 192 + static int adxl313_write_raw(struct iio_dev *indio_dev, 193 + struct iio_chan_spec const *chan, 194 + int val, int val2, long mask) 195 + { 196 + struct adxl313_data *data = iio_priv(indio_dev); 197 + 198 + switch (mask) { 199 + case IIO_CHAN_INFO_CALIBBIAS: 200 + /* 201 + * 8-bit resolution at +/- 0.5g, that is 4x accel data scale 202 + * factor at full resolution 203 + */ 204 + if (clamp_val(val, -128 * 4, 127 * 4) != val) 205 + return -EINVAL; 206 + 207 + return regmap_write(data->regmap, 208 + ADXL313_REG_OFS_AXIS(chan->address), 209 + val / 4); 210 + case IIO_CHAN_INFO_SAMP_FREQ: 211 + return adxl313_set_odr(data, val, val2); 212 + default: 213 + return -EINVAL; 214 + } 215 + } 216 + 217 + static const struct iio_info adxl313_info = { 218 + .read_raw = adxl313_read_raw, 219 + .write_raw = adxl313_write_raw, 220 + .read_avail = adxl313_read_freq_avail, 221 + }; 222 + 223 + static int adxl313_setup(struct device *dev, struct adxl313_data *data, 224 + int (*setup)(struct device *, struct regmap *)) 225 + { 226 + unsigned int regval; 227 + int ret; 228 + 229 + /* Ensures the device is in a consistent state after start up */ 230 + ret = regmap_write(data->regmap, ADXL313_REG_SOFT_RESET, 231 + ADXL313_SOFT_RESET); 232 + if (ret) 233 + return ret; 234 + 235 + if (setup) { 236 + ret = setup(dev, data->regmap); 237 + if (ret) 238 + return ret; 239 + } 240 + 241 + ret = regmap_read(data->regmap, ADXL313_REG_DEVID0, &regval); 242 + if (ret) 243 + return ret; 244 + 245 + if (regval != ADXL313_DEVID0) { 246 + dev_err(dev, "Invalid manufacturer ID: 0x%02x\n", regval); 247 + return -ENODEV; 248 + } 249 + 250 + ret = regmap_read(data->regmap, ADXL313_REG_DEVID1, &regval); 251 + if (ret) 252 + return ret; 253 + 254 + if (regval != ADXL313_DEVID1) { 255 + dev_err(dev, "Invalid mems ID: 0x%02x\n", regval); 256 + return -ENODEV; 257 + } 258 + 259 + ret = regmap_read(data->regmap, ADXL313_REG_PARTID, &regval); 260 + if (ret) 261 + return ret; 262 + 263 + if (regval != ADXL313_PARTID) { 264 + dev_err(dev, "Invalid device ID: 0x%02x\n", regval); 265 + return -ENODEV; 266 + } 267 + 268 + /* Sets the range to +/- 4g */ 269 + ret = regmap_update_bits(data->regmap, ADXL313_REG_DATA_FORMAT, 270 + ADXL313_RANGE_MSK, 271 + FIELD_PREP(ADXL313_RANGE_MSK, ADXL313_RANGE_4G)); 272 + if (ret) 273 + return ret; 274 + 275 + /* Enables full resolution */ 276 + ret = regmap_update_bits(data->regmap, ADXL313_REG_DATA_FORMAT, 277 + ADXL313_FULL_RES, ADXL313_FULL_RES); 278 + if (ret) 279 + return ret; 280 + 281 + /* Enables measurement mode */ 282 + return regmap_update_bits(data->regmap, ADXL313_REG_POWER_CTL, 283 + ADXL313_POWER_CTL_MSK, 284 + ADXL313_MEASUREMENT_MODE); 285 + } 286 + 287 + /** 288 + * adxl313_core_probe() - probe and setup for adxl313 accelerometer 289 + * @dev: Driver model representation of the device 290 + * @regmap: Register map of the device 291 + * @name: Device name buffer reference 292 + * @setup: Setup routine to be executed right before the standard device 293 + * setup, can also be set to NULL if not required 294 + * 295 + * Return: 0 on success, negative errno on error cases 296 + */ 297 + int adxl313_core_probe(struct device *dev, 298 + struct regmap *regmap, 299 + const char *name, 300 + int (*setup)(struct device *, struct regmap *)) 301 + { 302 + struct adxl313_data *data; 303 + struct iio_dev *indio_dev; 304 + int ret; 305 + 306 + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 307 + if (!indio_dev) 308 + return -ENOMEM; 309 + 310 + data = iio_priv(indio_dev); 311 + data->regmap = regmap; 312 + mutex_init(&data->lock); 313 + 314 + indio_dev->name = name; 315 + indio_dev->info = &adxl313_info; 316 + indio_dev->modes = INDIO_DIRECT_MODE; 317 + indio_dev->channels = adxl313_channels; 318 + indio_dev->num_channels = ARRAY_SIZE(adxl313_channels); 319 + 320 + ret = adxl313_setup(dev, data, setup); 321 + if (ret) { 322 + dev_err(dev, "ADXL313 setup failed\n"); 323 + return ret; 324 + } 325 + 326 + return devm_iio_device_register(dev, indio_dev); 327 + } 328 + EXPORT_SYMBOL_GPL(adxl313_core_probe); 329 + 330 + MODULE_AUTHOR("Lucas Stankus <lucas.p.stankus@gmail.com>"); 331 + MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer core driver"); 332 + MODULE_LICENSE("GPL v2");
+66
drivers/iio/accel/adxl313_i2c.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * ADXL313 3-Axis Digital Accelerometer 4 + * 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.pdf 8 + */ 9 + 10 + #include <linux/i2c.h> 11 + #include <linux/mod_devicetable.h> 12 + #include <linux/module.h> 13 + #include <linux/regmap.h> 14 + 15 + #include "adxl313.h" 16 + 17 + static const struct regmap_config adxl313_i2c_regmap_config = { 18 + .reg_bits = 8, 19 + .val_bits = 8, 20 + .rd_table = &adxl313_readable_regs_table, 21 + .wr_table = &adxl313_writable_regs_table, 22 + .max_register = 0x39, 23 + }; 24 + 25 + static int adxl313_i2c_probe(struct i2c_client *client) 26 + { 27 + struct regmap *regmap; 28 + 29 + regmap = devm_regmap_init_i2c(client, &adxl313_i2c_regmap_config); 30 + if (IS_ERR(regmap)) { 31 + dev_err(&client->dev, "Error initializing i2c regmap: %ld\n", 32 + PTR_ERR(regmap)); 33 + return PTR_ERR(regmap); 34 + } 35 + 36 + return adxl313_core_probe(&client->dev, regmap, client->name, NULL); 37 + } 38 + 39 + static const struct i2c_device_id adxl313_i2c_id[] = { 40 + { "adxl313" }, 41 + { } 42 + }; 43 + 44 + MODULE_DEVICE_TABLE(i2c, adxl313_i2c_id); 45 + 46 + static const struct of_device_id adxl313_of_match[] = { 47 + { .compatible = "adi,adxl313" }, 48 + { } 49 + }; 50 + 51 + MODULE_DEVICE_TABLE(of, adxl313_of_match); 52 + 53 + static struct i2c_driver adxl313_i2c_driver = { 54 + .driver = { 55 + .name = "adxl313_i2c", 56 + .of_match_table = adxl313_of_match, 57 + }, 58 + .probe_new = adxl313_i2c_probe, 59 + .id_table = adxl313_i2c_id, 60 + }; 61 + 62 + module_i2c_driver(adxl313_i2c_driver); 63 + 64 + MODULE_AUTHOR("Lucas Stankus <lucas.p.stankus@gmail.com>"); 65 + MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer I2C driver"); 66 + MODULE_LICENSE("GPL v2");
+92
drivers/iio/accel/adxl313_spi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * ADXL313 3-Axis Digital Accelerometer 4 + * 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.pdf 8 + */ 9 + 10 + #include <linux/mod_devicetable.h> 11 + #include <linux/module.h> 12 + #include <linux/regmap.h> 13 + #include <linux/spi/spi.h> 14 + 15 + #include "adxl313.h" 16 + 17 + static const struct regmap_config adxl313_spi_regmap_config = { 18 + .reg_bits = 8, 19 + .val_bits = 8, 20 + .rd_table = &adxl313_readable_regs_table, 21 + .wr_table = &adxl313_writable_regs_table, 22 + .max_register = 0x39, 23 + /* Setting bits 7 and 6 enables multiple-byte read */ 24 + .read_flag_mask = BIT(7) | BIT(6), 25 + }; 26 + 27 + static int adxl313_spi_setup(struct device *dev, struct regmap *regmap) 28 + { 29 + struct spi_device *spi = container_of(dev, struct spi_device, dev); 30 + int ret; 31 + 32 + if (spi->mode & SPI_3WIRE) { 33 + ret = regmap_write(regmap, ADXL313_REG_DATA_FORMAT, 34 + ADXL313_SPI_3WIRE); 35 + if (ret) 36 + return ret; 37 + } 38 + 39 + return regmap_update_bits(regmap, ADXL313_REG_POWER_CTL, 40 + ADXL313_I2C_DISABLE, ADXL313_I2C_DISABLE); 41 + } 42 + 43 + static int adxl313_spi_probe(struct spi_device *spi) 44 + { 45 + const struct spi_device_id *id = spi_get_device_id(spi); 46 + struct regmap *regmap; 47 + int ret; 48 + 49 + spi->mode |= SPI_MODE_3; 50 + ret = spi_setup(spi); 51 + if (ret) 52 + return ret; 53 + 54 + regmap = devm_regmap_init_spi(spi, &adxl313_spi_regmap_config); 55 + if (IS_ERR(regmap)) { 56 + dev_err(&spi->dev, "Error initializing spi regmap: %ld\n", 57 + PTR_ERR(regmap)); 58 + return PTR_ERR(regmap); 59 + } 60 + 61 + return adxl313_core_probe(&spi->dev, regmap, id->name, 62 + &adxl313_spi_setup); 63 + } 64 + 65 + static const struct spi_device_id adxl313_spi_id[] = { 66 + { "adxl313" }, 67 + { } 68 + }; 69 + 70 + MODULE_DEVICE_TABLE(spi, adxl313_spi_id); 71 + 72 + static const struct of_device_id adxl313_of_match[] = { 73 + { .compatible = "adi,adxl313" }, 74 + { } 75 + }; 76 + 77 + MODULE_DEVICE_TABLE(of, adxl313_of_match); 78 + 79 + static struct spi_driver adxl313_spi_driver = { 80 + .driver = { 81 + .name = "adxl313_spi", 82 + .of_match_table = adxl313_of_match, 83 + }, 84 + .probe = adxl313_spi_probe, 85 + .id_table = adxl313_spi_id, 86 + }; 87 + 88 + module_spi_driver(adxl313_spi_driver); 89 + 90 + MODULE_AUTHOR("Lucas Stankus <lucas.p.stankus@gmail.com>"); 91 + MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer SPI driver"); 92 + MODULE_LICENSE("GPL v2");