root/drivers/iio/accel/dmard09.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dmard09_read_raw
  2. dmard09_probe

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

/* [<][>][^][v][top][bottom][index][help] */