1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * IIO driver for the 3-axis accelerometer Domintech DMARD09. 4 * 5 * Copyright (c) 2016, Jelle van der Waa <jelle@vdwaa.nl> 6 */ 7 8 #include <linux/unaligned.h> 9 #include <linux/module.h> 10 #include <linux/i2c.h> 11 #include <linux/units.h> 12 #include <linux/iio/iio.h> 13 14 #define DMARD09_DRV_NAME "dmard09" 15 16 #define DMARD09_REG_CHIPID 0x18 17 #define DMARD09_REG_STAT 0x0A 18 #define DMARD09_REG_X 0x0C 19 #define DMARD09_REG_Y 0x0E 20 #define DMARD09_REG_Z 0x10 21 #define DMARD09_CHIPID 0x95 22 23 #define DMARD09_BUF_LEN 8 24 #define DMARD09_AXIS_X 0 25 #define DMARD09_AXIS_Y 1 26 #define DMARD09_AXIS_Z 2 27 #define DMARD09_AXIS_X_OFFSET ((DMARD09_AXIS_X + 1) * 2) 28 #define DMARD09_AXIS_Y_OFFSET ((DMARD09_AXIS_Y + 1) * 2) 29 #define DMARD09_AXIS_Z_OFFSET ((DMARD09_AXIS_Z + 1) * 2) 30 31 struct dmard09_data { 32 struct i2c_client *client; 33 }; 34 35 #define DMARD09_CHANNEL(_axis, offset) { \ 36 .type = IIO_ACCEL, \ 37 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 38 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 39 .modified = 1, \ 40 .address = offset, \ 41 .channel2 = IIO_MOD_##_axis, \ 42 } 43 44 static const struct iio_chan_spec dmard09_channels[] = { 45 DMARD09_CHANNEL(X, DMARD09_AXIS_X_OFFSET), 46 DMARD09_CHANNEL(Y, DMARD09_AXIS_Y_OFFSET), 47 DMARD09_CHANNEL(Z, DMARD09_AXIS_Z_OFFSET), 48 }; 49 50 static int dmard09_read_raw(struct iio_dev *indio_dev, 51 struct iio_chan_spec const *chan, 52 int *val, int *val2, long mask) 53 { 54 struct dmard09_data *data = iio_priv(indio_dev); 55 u8 buf[DMARD09_BUF_LEN]; 56 int ret; 57 s16 accel; 58 59 switch (mask) { 60 case IIO_CHAN_INFO_RAW: 61 /* 62 * Read from the DMAR09_REG_STAT register, since the chip 63 * caches reads from the individual X, Y, Z registers. 64 */ 65 ret = i2c_smbus_read_i2c_block_data(data->client, 66 DMARD09_REG_STAT, 67 DMARD09_BUF_LEN, buf); 68 if (ret < 0) { 69 dev_err(&data->client->dev, "Error reading reg %d\n", 70 DMARD09_REG_STAT); 71 return ret; 72 } 73 74 accel = get_unaligned_le16(&buf[chan->address]); 75 76 /* Remove lower 3 bits and sign extend */ 77 accel <<= 4; 78 accel >>= 7; 79 80 *val = accel; 81 82 return IIO_VAL_INT; 83 case IIO_CHAN_INFO_SCALE: 84 *val = 0; 85 /* 1 g / 32 LSB, in m/s^2 */ 86 *val2 = IIO_G_TO_M_S_2(NANO / 32); 87 88 return IIO_VAL_INT_PLUS_NANO; 89 default: 90 return -EINVAL; 91 } 92 } 93 94 static const struct iio_info dmard09_info = { 95 .read_raw = dmard09_read_raw, 96 }; 97 98 static int dmard09_probe(struct i2c_client *client) 99 { 100 int ret; 101 struct iio_dev *indio_dev; 102 struct dmard09_data *data; 103 104 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 105 if (!indio_dev) 106 return -ENOMEM; 107 108 data = iio_priv(indio_dev); 109 data->client = client; 110 111 ret = i2c_smbus_read_byte_data(data->client, DMARD09_REG_CHIPID); 112 if (ret < 0) { 113 dev_err(&client->dev, "Error reading chip id %d\n", ret); 114 return ret; 115 } 116 117 if (ret != DMARD09_CHIPID) { 118 dev_err(&client->dev, "Invalid chip id %d\n", ret); 119 return -ENODEV; 120 } 121 122 i2c_set_clientdata(client, indio_dev); 123 indio_dev->name = DMARD09_DRV_NAME; 124 indio_dev->modes = INDIO_DIRECT_MODE; 125 indio_dev->channels = dmard09_channels; 126 indio_dev->num_channels = ARRAY_SIZE(dmard09_channels); 127 indio_dev->info = &dmard09_info; 128 129 return devm_iio_device_register(&client->dev, indio_dev); 130 } 131 132 static const struct i2c_device_id dmard09_id[] = { 133 { .name = "dmard09" }, 134 { } 135 }; 136 137 MODULE_DEVICE_TABLE(i2c, dmard09_id); 138 139 static struct i2c_driver dmard09_driver = { 140 .driver = { 141 .name = DMARD09_DRV_NAME 142 }, 143 .probe = dmard09_probe, 144 .id_table = dmard09_id, 145 }; 146 147 module_i2c_driver(dmard09_driver); 148 149 MODULE_AUTHOR("Jelle van der Waa <jelle@vdwaa.nl>"); 150 MODULE_DESCRIPTION("DMARD09 3-axis accelerometer driver"); 151 MODULE_LICENSE("GPL"); 152