0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/mod_devicetable.h>
0010 #include <linux/i2c.h>
0011 #include <linux/iio/iio.h>
0012
0013 #define DMARD06_DRV_NAME "dmard06"
0014
0015
0016 #define DMARD06_CHIP_ID_REG 0x0f
0017 #define DMARD06_TOUT_REG 0x40
0018 #define DMARD06_XOUT_REG 0x41
0019 #define DMARD06_YOUT_REG 0x42
0020 #define DMARD06_ZOUT_REG 0x43
0021 #define DMARD06_CTRL1_REG 0x44
0022
0023
0024 #define DMARD05_CHIP_ID 0x05
0025 #define DMARD06_CHIP_ID 0x06
0026 #define DMARD07_CHIP_ID 0x07
0027
0028
0029 #define DMARD05_AXIS_SCALE_VAL 15625
0030 #define DMARD06_AXIS_SCALE_VAL 31250
0031 #define DMARD06_TEMP_CENTER_VAL 25
0032 #define DMARD06_SIGN_BIT 7
0033
0034
0035 #define DMARD06_MODE_NORMAL 0x27
0036 #define DMARD06_MODE_POWERDOWN 0x00
0037
0038
0039 #define DMARD06_ACCEL_CHANNEL(_axis, _reg) { \
0040 .type = IIO_ACCEL, \
0041 .address = _reg, \
0042 .channel2 = IIO_MOD_##_axis, \
0043 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
0044 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
0045 .modified = 1, \
0046 }
0047
0048 #define DMARD06_TEMP_CHANNEL(_reg) { \
0049 .type = IIO_TEMP, \
0050 .address = _reg, \
0051 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
0052 BIT(IIO_CHAN_INFO_OFFSET), \
0053 }
0054
0055 struct dmard06_data {
0056 struct i2c_client *client;
0057 u8 chip_id;
0058 };
0059
0060 static const struct iio_chan_spec dmard06_channels[] = {
0061 DMARD06_ACCEL_CHANNEL(X, DMARD06_XOUT_REG),
0062 DMARD06_ACCEL_CHANNEL(Y, DMARD06_YOUT_REG),
0063 DMARD06_ACCEL_CHANNEL(Z, DMARD06_ZOUT_REG),
0064 DMARD06_TEMP_CHANNEL(DMARD06_TOUT_REG),
0065 };
0066
0067 static int dmard06_read_raw(struct iio_dev *indio_dev,
0068 struct iio_chan_spec const *chan,
0069 int *val, int *val2, long mask)
0070 {
0071 struct dmard06_data *dmard06 = iio_priv(indio_dev);
0072 int ret;
0073
0074 switch (mask) {
0075 case IIO_CHAN_INFO_RAW:
0076 ret = i2c_smbus_read_byte_data(dmard06->client,
0077 chan->address);
0078 if (ret < 0) {
0079 dev_err(&dmard06->client->dev,
0080 "Error reading data: %d\n", ret);
0081 return ret;
0082 }
0083
0084 *val = sign_extend32(ret, DMARD06_SIGN_BIT);
0085
0086 if (dmard06->chip_id == DMARD06_CHIP_ID)
0087 *val = *val >> 1;
0088
0089 switch (chan->type) {
0090 case IIO_ACCEL:
0091 return IIO_VAL_INT;
0092 case IIO_TEMP:
0093 if (dmard06->chip_id != DMARD06_CHIP_ID)
0094 *val = *val / 2;
0095 return IIO_VAL_INT;
0096 default:
0097 return -EINVAL;
0098 }
0099 case IIO_CHAN_INFO_OFFSET:
0100 switch (chan->type) {
0101 case IIO_TEMP:
0102 *val = DMARD06_TEMP_CENTER_VAL;
0103 return IIO_VAL_INT;
0104 default:
0105 return -EINVAL;
0106 }
0107 case IIO_CHAN_INFO_SCALE:
0108 switch (chan->type) {
0109 case IIO_ACCEL:
0110 *val = 0;
0111 if (dmard06->chip_id == DMARD06_CHIP_ID)
0112 *val2 = DMARD06_AXIS_SCALE_VAL;
0113 else
0114 *val2 = DMARD05_AXIS_SCALE_VAL;
0115 return IIO_VAL_INT_PLUS_MICRO;
0116 default:
0117 return -EINVAL;
0118 }
0119 default:
0120 return -EINVAL;
0121 }
0122 }
0123
0124 static const struct iio_info dmard06_info = {
0125 .read_raw = dmard06_read_raw,
0126 };
0127
0128 static int dmard06_probe(struct i2c_client *client,
0129 const struct i2c_device_id *id)
0130 {
0131 int ret;
0132 struct iio_dev *indio_dev;
0133 struct dmard06_data *dmard06;
0134
0135 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
0136 dev_err(&client->dev, "I2C check functionality failed\n");
0137 return -ENXIO;
0138 }
0139
0140 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dmard06));
0141 if (!indio_dev) {
0142 dev_err(&client->dev, "Failed to allocate iio device\n");
0143 return -ENOMEM;
0144 }
0145
0146 dmard06 = iio_priv(indio_dev);
0147 dmard06->client = client;
0148
0149 ret = i2c_smbus_read_byte_data(dmard06->client, DMARD06_CHIP_ID_REG);
0150 if (ret < 0) {
0151 dev_err(&client->dev, "Error reading chip id: %d\n", ret);
0152 return ret;
0153 }
0154
0155 if (ret != DMARD05_CHIP_ID && ret != DMARD06_CHIP_ID &&
0156 ret != DMARD07_CHIP_ID) {
0157 dev_err(&client->dev, "Invalid chip id: %02d\n", ret);
0158 return -ENODEV;
0159 }
0160
0161 dmard06->chip_id = ret;
0162
0163 i2c_set_clientdata(client, indio_dev);
0164 indio_dev->name = DMARD06_DRV_NAME;
0165 indio_dev->modes = INDIO_DIRECT_MODE;
0166 indio_dev->channels = dmard06_channels;
0167 indio_dev->num_channels = ARRAY_SIZE(dmard06_channels);
0168 indio_dev->info = &dmard06_info;
0169
0170 return devm_iio_device_register(&client->dev, indio_dev);
0171 }
0172
0173 static int dmard06_suspend(struct device *dev)
0174 {
0175 struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
0176 struct dmard06_data *dmard06 = iio_priv(indio_dev);
0177 int ret;
0178
0179 ret = i2c_smbus_write_byte_data(dmard06->client, DMARD06_CTRL1_REG,
0180 DMARD06_MODE_POWERDOWN);
0181 if (ret < 0)
0182 return ret;
0183
0184 return 0;
0185 }
0186
0187 static int dmard06_resume(struct device *dev)
0188 {
0189 struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
0190 struct dmard06_data *dmard06 = iio_priv(indio_dev);
0191 int ret;
0192
0193 ret = i2c_smbus_write_byte_data(dmard06->client, DMARD06_CTRL1_REG,
0194 DMARD06_MODE_NORMAL);
0195 if (ret < 0)
0196 return ret;
0197
0198 return 0;
0199 }
0200
0201 static DEFINE_SIMPLE_DEV_PM_OPS(dmard06_pm_ops, dmard06_suspend,
0202 dmard06_resume);
0203
0204 static const struct i2c_device_id dmard06_id[] = {
0205 { "dmard05", 0 },
0206 { "dmard06", 0 },
0207 { "dmard07", 0 },
0208 { }
0209 };
0210 MODULE_DEVICE_TABLE(i2c, dmard06_id);
0211
0212 static const struct of_device_id dmard06_of_match[] = {
0213 { .compatible = "domintech,dmard05" },
0214 { .compatible = "domintech,dmard06" },
0215 { .compatible = "domintech,dmard07" },
0216 { }
0217 };
0218 MODULE_DEVICE_TABLE(of, dmard06_of_match);
0219
0220 static struct i2c_driver dmard06_driver = {
0221 .probe = dmard06_probe,
0222 .id_table = dmard06_id,
0223 .driver = {
0224 .name = DMARD06_DRV_NAME,
0225 .of_match_table = dmard06_of_match,
0226 .pm = pm_sleep_ptr(&dmard06_pm_ops),
0227 },
0228 };
0229 module_i2c_driver(dmard06_driver);
0230
0231 MODULE_AUTHOR("Aleksei Mamlin <mamlinav@gmail.com>");
0232 MODULE_DESCRIPTION("Domintech DMARD06 accelerometer driver");
0233 MODULE_LICENSE("GPL v2");