| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /** |
|---|
| 2 | 3 | * BMA220 Digital triaxial acceleration sensor driver |
|---|
| 3 | 4 | * |
|---|
| 4 | | - * Copyright (c) 2016, Intel Corporation. |
|---|
| 5 | | - * |
|---|
| 6 | | - * This file is subject to the terms and conditions of version 2 of |
|---|
| 7 | | - * the GNU General Public License. See the file COPYING in the main |
|---|
| 8 | | - * directory of this archive for more details. |
|---|
| 5 | + * Copyright (c) 2016,2020 Intel Corporation. |
|---|
| 9 | 6 | */ |
|---|
| 10 | 7 | |
|---|
| 11 | | -#include <linux/acpi.h> |
|---|
| 8 | +#include <linux/bits.h> |
|---|
| 12 | 9 | #include <linux/kernel.h> |
|---|
| 10 | +#include <linux/mod_devicetable.h> |
|---|
| 13 | 11 | #include <linux/module.h> |
|---|
| 12 | +#include <linux/spi/spi.h> |
|---|
| 13 | + |
|---|
| 14 | 14 | #include <linux/iio/buffer.h> |
|---|
| 15 | 15 | #include <linux/iio/iio.h> |
|---|
| 16 | 16 | #include <linux/iio/sysfs.h> |
|---|
| 17 | | -#include <linux/spi/spi.h> |
|---|
| 18 | 17 | #include <linux/iio/trigger_consumer.h> |
|---|
| 19 | 18 | #include <linux/iio/triggered_buffer.h> |
|---|
| 20 | 19 | |
|---|
| .. | .. |
|---|
| 26 | 25 | #define BMA220_REG_SUSPEND 0x18 |
|---|
| 27 | 26 | |
|---|
| 28 | 27 | #define BMA220_CHIP_ID 0xDD |
|---|
| 29 | | -#define BMA220_READ_MASK 0x80 |
|---|
| 30 | | -#define BMA220_RANGE_MASK 0x03 |
|---|
| 28 | +#define BMA220_READ_MASK BIT(7) |
|---|
| 29 | +#define BMA220_RANGE_MASK GENMASK(1, 0) |
|---|
| 31 | 30 | #define BMA220_DATA_SHIFT 2 |
|---|
| 32 | 31 | #define BMA220_SUSPEND_SLEEP 0xFF |
|---|
| 33 | 32 | #define BMA220_SUSPEND_WAKE 0x00 |
|---|
| 34 | 33 | |
|---|
| 35 | 34 | #define BMA220_DEVICE_NAME "bma220" |
|---|
| 36 | | -#define BMA220_SCALE_AVAILABLE "0.623 1.248 2.491 4.983" |
|---|
| 37 | 35 | |
|---|
| 38 | 36 | #define BMA220_ACCEL_CHANNEL(index, reg, axis) { \ |
|---|
| 39 | 37 | .type = IIO_ACCEL, \ |
|---|
| .. | .. |
|---|
| 58 | 56 | AXIS_Z, |
|---|
| 59 | 57 | }; |
|---|
| 60 | 58 | |
|---|
| 61 | | -static IIO_CONST_ATTR(in_accel_scale_available, BMA220_SCALE_AVAILABLE); |
|---|
| 62 | | - |
|---|
| 63 | | -static struct attribute *bma220_attributes[] = { |
|---|
| 64 | | - &iio_const_attr_in_accel_scale_available.dev_attr.attr, |
|---|
| 65 | | - NULL, |
|---|
| 66 | | -}; |
|---|
| 67 | | - |
|---|
| 68 | | -static const struct attribute_group bma220_attribute_group = { |
|---|
| 69 | | - .attrs = bma220_attributes, |
|---|
| 70 | | -}; |
|---|
| 71 | | - |
|---|
| 72 | | -static const int bma220_scale_table[][4] = { |
|---|
| 73 | | - {0, 623000}, {1, 248000}, {2, 491000}, {4, 983000} |
|---|
| 59 | +static const int bma220_scale_table[][2] = { |
|---|
| 60 | + {0, 623000}, {1, 248000}, {2, 491000}, {4, 983000}, |
|---|
| 74 | 61 | }; |
|---|
| 75 | 62 | |
|---|
| 76 | 63 | struct bma220_data { |
|---|
| .. | .. |
|---|
| 189 | 176 | return -EINVAL; |
|---|
| 190 | 177 | } |
|---|
| 191 | 178 | |
|---|
| 179 | +static 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 | + |
|---|
| 192 | 195 | static const struct iio_info bma220_info = { |
|---|
| 193 | 196 | .read_raw = bma220_read_raw, |
|---|
| 194 | 197 | .write_raw = bma220_write_raw, |
|---|
| 195 | | - .attrs = &bma220_attribute_group, |
|---|
| 198 | + .read_avail = bma220_read_avail, |
|---|
| 196 | 199 | }; |
|---|
| 197 | 200 | |
|---|
| 198 | 201 | static int bma220_init(struct spi_device *spi) |
|---|
| .. | .. |
|---|
| 205 | 208 | |
|---|
| 206 | 209 | /* Make sure the chip is powered on */ |
|---|
| 207 | 210 | ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); |
|---|
| 211 | + if (ret == BMA220_SUSPEND_WAKE) |
|---|
| 212 | + ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); |
|---|
| 208 | 213 | if (ret < 0) |
|---|
| 209 | 214 | return ret; |
|---|
| 210 | | - else if (ret == BMA220_SUSPEND_WAKE) |
|---|
| 211 | | - return bma220_read_reg(spi, BMA220_REG_SUSPEND); |
|---|
| 215 | + if (ret == BMA220_SUSPEND_WAKE) |
|---|
| 216 | + return -EBUSY; |
|---|
| 212 | 217 | |
|---|
| 213 | 218 | return 0; |
|---|
| 214 | 219 | } |
|---|
| .. | .. |
|---|
| 219 | 224 | |
|---|
| 220 | 225 | /* Make sure the chip is powered off */ |
|---|
| 221 | 226 | ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); |
|---|
| 227 | + if (ret == BMA220_SUSPEND_SLEEP) |
|---|
| 228 | + ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); |
|---|
| 222 | 229 | if (ret < 0) |
|---|
| 223 | 230 | return ret; |
|---|
| 224 | | - else if (ret == BMA220_SUSPEND_SLEEP) |
|---|
| 225 | | - return bma220_read_reg(spi, BMA220_REG_SUSPEND); |
|---|
| 231 | + if (ret == BMA220_SUSPEND_SLEEP) |
|---|
| 232 | + return -EBUSY; |
|---|
| 226 | 233 | |
|---|
| 227 | 234 | return 0; |
|---|
| 228 | 235 | } |
|---|
| .. | .. |
|---|
| 244 | 251 | spi_set_drvdata(spi, indio_dev); |
|---|
| 245 | 252 | mutex_init(&data->lock); |
|---|
| 246 | 253 | |
|---|
| 247 | | - indio_dev->dev.parent = &spi->dev; |
|---|
| 248 | 254 | indio_dev->info = &bma220_info; |
|---|
| 249 | 255 | indio_dev->name = BMA220_DEVICE_NAME; |
|---|
| 250 | 256 | indio_dev->modes = INDIO_DIRECT_MODE; |
|---|
| .. | .. |
|---|
| 253 | 259 | indio_dev->available_scan_masks = bma220_accel_scan_masks; |
|---|
| 254 | 260 | |
|---|
| 255 | 261 | ret = bma220_init(data->spi_device); |
|---|
| 256 | | - if (ret < 0) |
|---|
| 262 | + if (ret) |
|---|
| 257 | 263 | return ret; |
|---|
| 258 | 264 | |
|---|
| 259 | 265 | ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time, |
|---|
| .. | .. |
|---|
| 286 | 292 | return bma220_deinit(spi); |
|---|
| 287 | 293 | } |
|---|
| 288 | 294 | |
|---|
| 289 | | -#ifdef CONFIG_PM_SLEEP |
|---|
| 290 | | -static int bma220_suspend(struct device *dev) |
|---|
| 295 | +static __maybe_unused int bma220_suspend(struct device *dev) |
|---|
| 291 | 296 | { |
|---|
| 292 | | - struct bma220_data *data = |
|---|
| 293 | | - iio_priv(spi_get_drvdata(to_spi_device(dev))); |
|---|
| 297 | + struct bma220_data *data = iio_priv(dev_get_drvdata(dev)); |
|---|
| 294 | 298 | |
|---|
| 295 | 299 | /* The chip can be suspended/woken up by a simple register read. */ |
|---|
| 296 | 300 | return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND); |
|---|
| 297 | 301 | } |
|---|
| 298 | 302 | |
|---|
| 299 | | -static int bma220_resume(struct device *dev) |
|---|
| 303 | +static __maybe_unused int bma220_resume(struct device *dev) |
|---|
| 300 | 304 | { |
|---|
| 301 | | - struct bma220_data *data = |
|---|
| 302 | | - iio_priv(spi_get_drvdata(to_spi_device(dev))); |
|---|
| 305 | + struct bma220_data *data = iio_priv(dev_get_drvdata(dev)); |
|---|
| 303 | 306 | |
|---|
| 304 | 307 | return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND); |
|---|
| 305 | 308 | } |
|---|
| 306 | | - |
|---|
| 307 | 309 | static SIMPLE_DEV_PM_OPS(bma220_pm_ops, bma220_suspend, bma220_resume); |
|---|
| 308 | | - |
|---|
| 309 | | -#define BMA220_PM_OPS (&bma220_pm_ops) |
|---|
| 310 | | -#else |
|---|
| 311 | | -#define BMA220_PM_OPS NULL |
|---|
| 312 | | -#endif |
|---|
| 313 | 310 | |
|---|
| 314 | 311 | static const struct spi_device_id bma220_spi_id[] = { |
|---|
| 315 | 312 | {"bma220", 0}, |
|---|
| .. | .. |
|---|
| 320 | 317 | {"BMA0220", 0}, |
|---|
| 321 | 318 | {} |
|---|
| 322 | 319 | }; |
|---|
| 323 | | - |
|---|
| 324 | 320 | MODULE_DEVICE_TABLE(spi, bma220_spi_id); |
|---|
| 325 | 321 | |
|---|
| 326 | 322 | static struct spi_driver bma220_driver = { |
|---|
| 327 | 323 | .driver = { |
|---|
| 328 | 324 | .name = "bma220_spi", |
|---|
| 329 | | - .pm = BMA220_PM_OPS, |
|---|
| 330 | | - .acpi_match_table = ACPI_PTR(bma220_acpi_id), |
|---|
| 325 | + .pm = &bma220_pm_ops, |
|---|
| 326 | + .acpi_match_table = bma220_acpi_id, |
|---|
| 331 | 327 | }, |
|---|
| 332 | 328 | .probe = bma220_probe, |
|---|
| 333 | 329 | .remove = bma220_remove, |
|---|
| 334 | 330 | .id_table = bma220_spi_id, |
|---|
| 335 | 331 | }; |
|---|
| 336 | | - |
|---|
| 337 | 332 | module_spi_driver(bma220_driver); |
|---|
| 338 | 333 | |
|---|
| 339 | 334 | MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>"); |
|---|