18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/** 38c2ecf20Sopenharmony_ci * BMA220 Digital triaxial acceleration sensor driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2016,2020 Intel Corporation. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/bits.h> 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/iio/buffer.h> 158c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 168c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h> 178c2ecf20Sopenharmony_ci#include <linux/iio/trigger_consumer.h> 188c2ecf20Sopenharmony_ci#include <linux/iio/triggered_buffer.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define BMA220_REG_ID 0x00 218c2ecf20Sopenharmony_ci#define BMA220_REG_ACCEL_X 0x02 228c2ecf20Sopenharmony_ci#define BMA220_REG_ACCEL_Y 0x03 238c2ecf20Sopenharmony_ci#define BMA220_REG_ACCEL_Z 0x04 248c2ecf20Sopenharmony_ci#define BMA220_REG_RANGE 0x11 258c2ecf20Sopenharmony_ci#define BMA220_REG_SUSPEND 0x18 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define BMA220_CHIP_ID 0xDD 288c2ecf20Sopenharmony_ci#define BMA220_READ_MASK BIT(7) 298c2ecf20Sopenharmony_ci#define BMA220_RANGE_MASK GENMASK(1, 0) 308c2ecf20Sopenharmony_ci#define BMA220_DATA_SHIFT 2 318c2ecf20Sopenharmony_ci#define BMA220_SUSPEND_SLEEP 0xFF 328c2ecf20Sopenharmony_ci#define BMA220_SUSPEND_WAKE 0x00 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define BMA220_DEVICE_NAME "bma220" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define BMA220_ACCEL_CHANNEL(index, reg, axis) { \ 378c2ecf20Sopenharmony_ci .type = IIO_ACCEL, \ 388c2ecf20Sopenharmony_ci .address = reg, \ 398c2ecf20Sopenharmony_ci .modified = 1, \ 408c2ecf20Sopenharmony_ci .channel2 = IIO_MOD_##axis, \ 418c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 428c2ecf20Sopenharmony_ci .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 438c2ecf20Sopenharmony_ci .scan_index = index, \ 448c2ecf20Sopenharmony_ci .scan_type = { \ 458c2ecf20Sopenharmony_ci .sign = 's', \ 468c2ecf20Sopenharmony_ci .realbits = 6, \ 478c2ecf20Sopenharmony_ci .storagebits = 8, \ 488c2ecf20Sopenharmony_ci .shift = BMA220_DATA_SHIFT, \ 498c2ecf20Sopenharmony_ci .endianness = IIO_CPU, \ 508c2ecf20Sopenharmony_ci }, \ 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cienum bma220_axis { 548c2ecf20Sopenharmony_ci AXIS_X, 558c2ecf20Sopenharmony_ci AXIS_Y, 568c2ecf20Sopenharmony_ci AXIS_Z, 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic const int bma220_scale_table[][2] = { 608c2ecf20Sopenharmony_ci {0, 623000}, {1, 248000}, {2, 491000}, {4, 983000}, 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistruct bma220_data { 648c2ecf20Sopenharmony_ci struct spi_device *spi_device; 658c2ecf20Sopenharmony_ci struct mutex lock; 668c2ecf20Sopenharmony_ci struct { 678c2ecf20Sopenharmony_ci s8 chans[3]; 688c2ecf20Sopenharmony_ci /* Ensure timestamp is naturally aligned. */ 698c2ecf20Sopenharmony_ci s64 timestamp __aligned(8); 708c2ecf20Sopenharmony_ci } scan; 718c2ecf20Sopenharmony_ci u8 tx_buf[2] ____cacheline_aligned; 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic const struct iio_chan_spec bma220_channels[] = { 758c2ecf20Sopenharmony_ci BMA220_ACCEL_CHANNEL(0, BMA220_REG_ACCEL_X, X), 768c2ecf20Sopenharmony_ci BMA220_ACCEL_CHANNEL(1, BMA220_REG_ACCEL_Y, Y), 778c2ecf20Sopenharmony_ci BMA220_ACCEL_CHANNEL(2, BMA220_REG_ACCEL_Z, Z), 788c2ecf20Sopenharmony_ci IIO_CHAN_SOFT_TIMESTAMP(3), 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic inline int bma220_read_reg(struct spi_device *spi, u8 reg) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci return spi_w8r8(spi, reg | BMA220_READ_MASK); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic const unsigned long bma220_accel_scan_masks[] = { 878c2ecf20Sopenharmony_ci BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), 888c2ecf20Sopenharmony_ci 0 898c2ecf20Sopenharmony_ci}; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic irqreturn_t bma220_trigger_handler(int irq, void *p) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci int ret; 948c2ecf20Sopenharmony_ci struct iio_poll_func *pf = p; 958c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = pf->indio_dev; 968c2ecf20Sopenharmony_ci struct bma220_data *data = iio_priv(indio_dev); 978c2ecf20Sopenharmony_ci struct spi_device *spi = data->spi_device; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci mutex_lock(&data->lock); 1008c2ecf20Sopenharmony_ci data->tx_buf[0] = BMA220_REG_ACCEL_X | BMA220_READ_MASK; 1018c2ecf20Sopenharmony_ci ret = spi_write_then_read(spi, data->tx_buf, 1, &data->scan.chans, 1028c2ecf20Sopenharmony_ci ARRAY_SIZE(bma220_channels) - 1); 1038c2ecf20Sopenharmony_ci if (ret < 0) 1048c2ecf20Sopenharmony_ci goto err; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, 1078c2ecf20Sopenharmony_ci pf->timestamp); 1088c2ecf20Sopenharmony_cierr: 1098c2ecf20Sopenharmony_ci mutex_unlock(&data->lock); 1108c2ecf20Sopenharmony_ci iio_trigger_notify_done(indio_dev->trig); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int bma220_read_raw(struct iio_dev *indio_dev, 1168c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 1178c2ecf20Sopenharmony_ci int *val, int *val2, long mask) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci int ret; 1208c2ecf20Sopenharmony_ci u8 range_idx; 1218c2ecf20Sopenharmony_ci struct bma220_data *data = iio_priv(indio_dev); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci switch (mask) { 1248c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 1258c2ecf20Sopenharmony_ci ret = bma220_read_reg(data->spi_device, chan->address); 1268c2ecf20Sopenharmony_ci if (ret < 0) 1278c2ecf20Sopenharmony_ci return -EINVAL; 1288c2ecf20Sopenharmony_ci *val = sign_extend32(ret >> BMA220_DATA_SHIFT, 5); 1298c2ecf20Sopenharmony_ci return IIO_VAL_INT; 1308c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 1318c2ecf20Sopenharmony_ci ret = bma220_read_reg(data->spi_device, BMA220_REG_RANGE); 1328c2ecf20Sopenharmony_ci if (ret < 0) 1338c2ecf20Sopenharmony_ci return ret; 1348c2ecf20Sopenharmony_ci range_idx = ret & BMA220_RANGE_MASK; 1358c2ecf20Sopenharmony_ci *val = bma220_scale_table[range_idx][0]; 1368c2ecf20Sopenharmony_ci *val2 = bma220_scale_table[range_idx][1]; 1378c2ecf20Sopenharmony_ci return IIO_VAL_INT_PLUS_MICRO; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci return -EINVAL; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic int bma220_write_raw(struct iio_dev *indio_dev, 1448c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 1458c2ecf20Sopenharmony_ci int val, int val2, long mask) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci int i; 1488c2ecf20Sopenharmony_ci int ret; 1498c2ecf20Sopenharmony_ci int index = -1; 1508c2ecf20Sopenharmony_ci struct bma220_data *data = iio_priv(indio_dev); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci switch (mask) { 1538c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 1548c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bma220_scale_table); i++) 1558c2ecf20Sopenharmony_ci if (val == bma220_scale_table[i][0] && 1568c2ecf20Sopenharmony_ci val2 == bma220_scale_table[i][1]) { 1578c2ecf20Sopenharmony_ci index = i; 1588c2ecf20Sopenharmony_ci break; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci if (index < 0) 1618c2ecf20Sopenharmony_ci return -EINVAL; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci mutex_lock(&data->lock); 1648c2ecf20Sopenharmony_ci data->tx_buf[0] = BMA220_REG_RANGE; 1658c2ecf20Sopenharmony_ci data->tx_buf[1] = index; 1668c2ecf20Sopenharmony_ci ret = spi_write(data->spi_device, data->tx_buf, 1678c2ecf20Sopenharmony_ci sizeof(data->tx_buf)); 1688c2ecf20Sopenharmony_ci if (ret < 0) 1698c2ecf20Sopenharmony_ci dev_err(&data->spi_device->dev, 1708c2ecf20Sopenharmony_ci "failed to set measurement range\n"); 1718c2ecf20Sopenharmony_ci mutex_unlock(&data->lock); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return 0; 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci return -EINVAL; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic int bma220_read_avail(struct iio_dev *indio_dev, 1808c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 1818c2ecf20Sopenharmony_ci const int **vals, int *type, int *length, 1828c2ecf20Sopenharmony_ci long mask) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci switch (mask) { 1858c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 1868c2ecf20Sopenharmony_ci *vals = (int *)bma220_scale_table; 1878c2ecf20Sopenharmony_ci *type = IIO_VAL_INT_PLUS_MICRO; 1888c2ecf20Sopenharmony_ci *length = ARRAY_SIZE(bma220_scale_table) * 2; 1898c2ecf20Sopenharmony_ci return IIO_AVAIL_LIST; 1908c2ecf20Sopenharmony_ci default: 1918c2ecf20Sopenharmony_ci return -EINVAL; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic const struct iio_info bma220_info = { 1968c2ecf20Sopenharmony_ci .read_raw = bma220_read_raw, 1978c2ecf20Sopenharmony_ci .write_raw = bma220_write_raw, 1988c2ecf20Sopenharmony_ci .read_avail = bma220_read_avail, 1998c2ecf20Sopenharmony_ci}; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic int bma220_init(struct spi_device *spi) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci int ret; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci ret = bma220_read_reg(spi, BMA220_REG_ID); 2068c2ecf20Sopenharmony_ci if (ret != BMA220_CHIP_ID) 2078c2ecf20Sopenharmony_ci return -ENODEV; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* Make sure the chip is powered on */ 2108c2ecf20Sopenharmony_ci ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); 2118c2ecf20Sopenharmony_ci if (ret == BMA220_SUSPEND_WAKE) 2128c2ecf20Sopenharmony_ci ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); 2138c2ecf20Sopenharmony_ci if (ret < 0) 2148c2ecf20Sopenharmony_ci return ret; 2158c2ecf20Sopenharmony_ci if (ret == BMA220_SUSPEND_WAKE) 2168c2ecf20Sopenharmony_ci return -EBUSY; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int bma220_deinit(struct spi_device *spi) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci int ret; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* Make sure the chip is powered off */ 2268c2ecf20Sopenharmony_ci ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); 2278c2ecf20Sopenharmony_ci if (ret == BMA220_SUSPEND_SLEEP) 2288c2ecf20Sopenharmony_ci ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); 2298c2ecf20Sopenharmony_ci if (ret < 0) 2308c2ecf20Sopenharmony_ci return ret; 2318c2ecf20Sopenharmony_ci if (ret == BMA220_SUSPEND_SLEEP) 2328c2ecf20Sopenharmony_ci return -EBUSY; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci return 0; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic int bma220_probe(struct spi_device *spi) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci int ret; 2408c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 2418c2ecf20Sopenharmony_ci struct bma220_data *data; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data)); 2448c2ecf20Sopenharmony_ci if (!indio_dev) { 2458c2ecf20Sopenharmony_ci dev_err(&spi->dev, "iio allocation failed!\n"); 2468c2ecf20Sopenharmony_ci return -ENOMEM; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci data = iio_priv(indio_dev); 2508c2ecf20Sopenharmony_ci data->spi_device = spi; 2518c2ecf20Sopenharmony_ci spi_set_drvdata(spi, indio_dev); 2528c2ecf20Sopenharmony_ci mutex_init(&data->lock); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci indio_dev->info = &bma220_info; 2558c2ecf20Sopenharmony_ci indio_dev->name = BMA220_DEVICE_NAME; 2568c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 2578c2ecf20Sopenharmony_ci indio_dev->channels = bma220_channels; 2588c2ecf20Sopenharmony_ci indio_dev->num_channels = ARRAY_SIZE(bma220_channels); 2598c2ecf20Sopenharmony_ci indio_dev->available_scan_masks = bma220_accel_scan_masks; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci ret = bma220_init(data->spi_device); 2628c2ecf20Sopenharmony_ci if (ret) 2638c2ecf20Sopenharmony_ci return ret; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time, 2668c2ecf20Sopenharmony_ci bma220_trigger_handler, NULL); 2678c2ecf20Sopenharmony_ci if (ret < 0) { 2688c2ecf20Sopenharmony_ci dev_err(&spi->dev, "iio triggered buffer setup failed\n"); 2698c2ecf20Sopenharmony_ci goto err_suspend; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci ret = iio_device_register(indio_dev); 2738c2ecf20Sopenharmony_ci if (ret < 0) { 2748c2ecf20Sopenharmony_ci dev_err(&spi->dev, "iio_device_register failed\n"); 2758c2ecf20Sopenharmony_ci iio_triggered_buffer_cleanup(indio_dev); 2768c2ecf20Sopenharmony_ci goto err_suspend; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci return 0; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cierr_suspend: 2828c2ecf20Sopenharmony_ci return bma220_deinit(spi); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic int bma220_remove(struct spi_device *spi) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = spi_get_drvdata(spi); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci iio_device_unregister(indio_dev); 2908c2ecf20Sopenharmony_ci iio_triggered_buffer_cleanup(indio_dev); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return bma220_deinit(spi); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic __maybe_unused int bma220_suspend(struct device *dev) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct bma220_data *data = iio_priv(dev_get_drvdata(dev)); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* The chip can be suspended/woken up by a simple register read. */ 3008c2ecf20Sopenharmony_ci return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND); 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic __maybe_unused int bma220_resume(struct device *dev) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci struct bma220_data *data = iio_priv(dev_get_drvdata(dev)); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND); 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(bma220_pm_ops, bma220_suspend, bma220_resume); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic const struct spi_device_id bma220_spi_id[] = { 3128c2ecf20Sopenharmony_ci {"bma220", 0}, 3138c2ecf20Sopenharmony_ci {} 3148c2ecf20Sopenharmony_ci}; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic const struct acpi_device_id bma220_acpi_id[] = { 3178c2ecf20Sopenharmony_ci {"BMA0220", 0}, 3188c2ecf20Sopenharmony_ci {} 3198c2ecf20Sopenharmony_ci}; 3208c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, bma220_spi_id); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic struct spi_driver bma220_driver = { 3238c2ecf20Sopenharmony_ci .driver = { 3248c2ecf20Sopenharmony_ci .name = "bma220_spi", 3258c2ecf20Sopenharmony_ci .pm = &bma220_pm_ops, 3268c2ecf20Sopenharmony_ci .acpi_match_table = bma220_acpi_id, 3278c2ecf20Sopenharmony_ci }, 3288c2ecf20Sopenharmony_ci .probe = bma220_probe, 3298c2ecf20Sopenharmony_ci .remove = bma220_remove, 3308c2ecf20Sopenharmony_ci .id_table = bma220_spi_id, 3318c2ecf20Sopenharmony_ci}; 3328c2ecf20Sopenharmony_cimodule_spi_driver(bma220_driver); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ciMODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>"); 3358c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("BMA220 acceleration sensor driver"); 3368c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 337