dmard09.c 3.5 KB

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