bma220_spi.c (7942B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * BMA220 Digital triaxial acceleration sensor driver 4 * 5 * Copyright (c) 2016,2020 Intel Corporation. 6 */ 7 8#include <linux/bits.h> 9#include <linux/kernel.h> 10#include <linux/mod_devicetable.h> 11#include <linux/module.h> 12#include <linux/spi/spi.h> 13 14#include <linux/iio/buffer.h> 15#include <linux/iio/iio.h> 16#include <linux/iio/sysfs.h> 17#include <linux/iio/trigger_consumer.h> 18#include <linux/iio/triggered_buffer.h> 19 20#define BMA220_REG_ID 0x00 21#define BMA220_REG_ACCEL_X 0x02 22#define BMA220_REG_ACCEL_Y 0x03 23#define BMA220_REG_ACCEL_Z 0x04 24#define BMA220_REG_RANGE 0x11 25#define BMA220_REG_SUSPEND 0x18 26 27#define BMA220_CHIP_ID 0xDD 28#define BMA220_READ_MASK BIT(7) 29#define BMA220_RANGE_MASK GENMASK(1, 0) 30#define BMA220_SUSPEND_SLEEP 0xFF 31#define BMA220_SUSPEND_WAKE 0x00 32 33#define BMA220_DEVICE_NAME "bma220" 34 35#define BMA220_ACCEL_CHANNEL(index, reg, axis) { \ 36 .type = IIO_ACCEL, \ 37 .address = reg, \ 38 .modified = 1, \ 39 .channel2 = IIO_MOD_##axis, \ 40 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 41 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 42 .scan_index = index, \ 43 .scan_type = { \ 44 .sign = 's', \ 45 .realbits = 6, \ 46 .storagebits = 8, \ 47 .shift = 2, \ 48 .endianness = IIO_CPU, \ 49 }, \ 50} 51 52enum bma220_axis { 53 AXIS_X, 54 AXIS_Y, 55 AXIS_Z, 56}; 57 58static const int bma220_scale_table[][2] = { 59 {0, 623000}, {1, 248000}, {2, 491000}, {4, 983000}, 60}; 61 62struct bma220_data { 63 struct spi_device *spi_device; 64 struct mutex lock; 65 struct { 66 s8 chans[3]; 67 /* Ensure timestamp is naturally aligned. */ 68 s64 timestamp __aligned(8); 69 } scan; 70 u8 tx_buf[2] ____cacheline_aligned; 71}; 72 73static const struct iio_chan_spec bma220_channels[] = { 74 BMA220_ACCEL_CHANNEL(0, BMA220_REG_ACCEL_X, X), 75 BMA220_ACCEL_CHANNEL(1, BMA220_REG_ACCEL_Y, Y), 76 BMA220_ACCEL_CHANNEL(2, BMA220_REG_ACCEL_Z, Z), 77 IIO_CHAN_SOFT_TIMESTAMP(3), 78}; 79 80static inline int bma220_read_reg(struct spi_device *spi, u8 reg) 81{ 82 return spi_w8r8(spi, reg | BMA220_READ_MASK); 83} 84 85static const unsigned long bma220_accel_scan_masks[] = { 86 BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), 87 0 88}; 89 90static irqreturn_t bma220_trigger_handler(int irq, void *p) 91{ 92 int ret; 93 struct iio_poll_func *pf = p; 94 struct iio_dev *indio_dev = pf->indio_dev; 95 struct bma220_data *data = iio_priv(indio_dev); 96 struct spi_device *spi = data->spi_device; 97 98 mutex_lock(&data->lock); 99 data->tx_buf[0] = BMA220_REG_ACCEL_X | BMA220_READ_MASK; 100 ret = spi_write_then_read(spi, data->tx_buf, 1, &data->scan.chans, 101 ARRAY_SIZE(bma220_channels) - 1); 102 if (ret < 0) 103 goto err; 104 105 iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, 106 pf->timestamp); 107err: 108 mutex_unlock(&data->lock); 109 iio_trigger_notify_done(indio_dev->trig); 110 111 return IRQ_HANDLED; 112} 113 114static int bma220_read_raw(struct iio_dev *indio_dev, 115 struct iio_chan_spec const *chan, 116 int *val, int *val2, long mask) 117{ 118 int ret; 119 u8 range_idx; 120 struct bma220_data *data = iio_priv(indio_dev); 121 122 switch (mask) { 123 case IIO_CHAN_INFO_RAW: 124 ret = bma220_read_reg(data->spi_device, chan->address); 125 if (ret < 0) 126 return -EINVAL; 127 *val = sign_extend32(ret >> chan->scan_type.shift, 128 chan->scan_type.realbits - 1); 129 return IIO_VAL_INT; 130 case IIO_CHAN_INFO_SCALE: 131 ret = bma220_read_reg(data->spi_device, BMA220_REG_RANGE); 132 if (ret < 0) 133 return ret; 134 range_idx = ret & BMA220_RANGE_MASK; 135 *val = bma220_scale_table[range_idx][0]; 136 *val2 = bma220_scale_table[range_idx][1]; 137 return IIO_VAL_INT_PLUS_MICRO; 138 } 139 140 return -EINVAL; 141} 142 143static int bma220_write_raw(struct iio_dev *indio_dev, 144 struct iio_chan_spec const *chan, 145 int val, int val2, long mask) 146{ 147 int i; 148 int ret; 149 int index = -1; 150 struct bma220_data *data = iio_priv(indio_dev); 151 152 switch (mask) { 153 case IIO_CHAN_INFO_SCALE: 154 for (i = 0; i < ARRAY_SIZE(bma220_scale_table); i++) 155 if (val == bma220_scale_table[i][0] && 156 val2 == bma220_scale_table[i][1]) { 157 index = i; 158 break; 159 } 160 if (index < 0) 161 return -EINVAL; 162 163 mutex_lock(&data->lock); 164 data->tx_buf[0] = BMA220_REG_RANGE; 165 data->tx_buf[1] = index; 166 ret = spi_write(data->spi_device, data->tx_buf, 167 sizeof(data->tx_buf)); 168 if (ret < 0) 169 dev_err(&data->spi_device->dev, 170 "failed to set measurement range\n"); 171 mutex_unlock(&data->lock); 172 173 return 0; 174 } 175 176 return -EINVAL; 177} 178 179static int bma220_read_avail(struct iio_dev *indio_dev, 180 struct iio_chan_spec const *chan, 181 const int **vals, int *type, int *length, 182 long mask) 183{ 184 switch (mask) { 185 case IIO_CHAN_INFO_SCALE: 186 *vals = (int *)bma220_scale_table; 187 *type = IIO_VAL_INT_PLUS_MICRO; 188 *length = ARRAY_SIZE(bma220_scale_table) * 2; 189 return IIO_AVAIL_LIST; 190 default: 191 return -EINVAL; 192 } 193} 194 195static const struct iio_info bma220_info = { 196 .read_raw = bma220_read_raw, 197 .write_raw = bma220_write_raw, 198 .read_avail = bma220_read_avail, 199}; 200 201static int bma220_init(struct spi_device *spi) 202{ 203 int ret; 204 205 ret = bma220_read_reg(spi, BMA220_REG_ID); 206 if (ret != BMA220_CHIP_ID) 207 return -ENODEV; 208 209 /* Make sure the chip is powered on */ 210 ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); 211 if (ret == BMA220_SUSPEND_WAKE) 212 ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); 213 if (ret < 0) 214 return ret; 215 if (ret == BMA220_SUSPEND_WAKE) 216 return -EBUSY; 217 218 return 0; 219} 220 221static int bma220_power(struct spi_device *spi, bool up) 222{ 223 int i, ret; 224 225 /** 226 * The chip can be suspended/woken up by a simple register read. 227 * So, we need up to 2 register reads of the suspend register 228 * to make sure that the device is in the desired state. 229 */ 230 for (i = 0; i < 2; i++) { 231 ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); 232 if (ret < 0) 233 return ret; 234 235 if (up && ret == BMA220_SUSPEND_SLEEP) 236 return 0; 237 238 if (!up && ret == BMA220_SUSPEND_WAKE) 239 return 0; 240 } 241 242 return -EBUSY; 243} 244 245static void bma220_deinit(void *spi) 246{ 247 bma220_power(spi, false); 248} 249 250static int bma220_probe(struct spi_device *spi) 251{ 252 int ret; 253 struct iio_dev *indio_dev; 254 struct bma220_data *data; 255 256 indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data)); 257 if (!indio_dev) { 258 dev_err(&spi->dev, "iio allocation failed!\n"); 259 return -ENOMEM; 260 } 261 262 data = iio_priv(indio_dev); 263 data->spi_device = spi; 264 mutex_init(&data->lock); 265 266 indio_dev->info = &bma220_info; 267 indio_dev->name = BMA220_DEVICE_NAME; 268 indio_dev->modes = INDIO_DIRECT_MODE; 269 indio_dev->channels = bma220_channels; 270 indio_dev->num_channels = ARRAY_SIZE(bma220_channels); 271 indio_dev->available_scan_masks = bma220_accel_scan_masks; 272 273 ret = bma220_init(data->spi_device); 274 if (ret) 275 return ret; 276 277 ret = devm_add_action_or_reset(&spi->dev, bma220_deinit, spi); 278 if (ret) 279 return ret; 280 281 ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, 282 iio_pollfunc_store_time, 283 bma220_trigger_handler, NULL); 284 if (ret < 0) { 285 dev_err(&spi->dev, "iio triggered buffer setup failed\n"); 286 return ret; 287 } 288 289 return devm_iio_device_register(&spi->dev, indio_dev); 290} 291 292static __maybe_unused int bma220_suspend(struct device *dev) 293{ 294 struct spi_device *spi = to_spi_device(dev); 295 296 return bma220_power(spi, false); 297} 298 299static __maybe_unused int bma220_resume(struct device *dev) 300{ 301 struct spi_device *spi = to_spi_device(dev); 302 303 return bma220_power(spi, true); 304} 305static SIMPLE_DEV_PM_OPS(bma220_pm_ops, bma220_suspend, bma220_resume); 306 307static const struct spi_device_id bma220_spi_id[] = { 308 {"bma220", 0}, 309 {} 310}; 311 312static const struct acpi_device_id bma220_acpi_id[] = { 313 {"BMA0220", 0}, 314 {} 315}; 316MODULE_DEVICE_TABLE(spi, bma220_spi_id); 317 318static struct spi_driver bma220_driver = { 319 .driver = { 320 .name = "bma220_spi", 321 .pm = &bma220_pm_ops, 322 .acpi_match_table = bma220_acpi_id, 323 }, 324 .probe = bma220_probe, 325 .id_table = bma220_spi_id, 326}; 327module_spi_driver(bma220_driver); 328 329MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>"); 330MODULE_DESCRIPTION("BMA220 acceleration sensor driver"); 331MODULE_LICENSE("GPL v2");