linux/drivers/iio/accel/dmard10.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * IIO driver for the 3-axis accelerometer Domintech ARD10.
   4 *
   5 * Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com>
   6 * Copyright (c) 2012 Domintech Technology Co., Ltd
   7 */
   8
   9#include <linux/module.h>
  10#include <linux/i2c.h>
  11#include <linux/iio/iio.h>
  12#include <linux/iio/sysfs.h>
  13#include <linux/byteorder/generic.h>
  14
  15#define DMARD10_REG_ACTR                        0x00
  16#define DMARD10_REG_AFEM                        0x0c
  17#define DMARD10_REG_STADR                       0x12
  18#define DMARD10_REG_STAINT                      0x1c
  19#define DMARD10_REG_MISC2                       0x1f
  20#define DMARD10_REG_PD                          0x21
  21
  22#define DMARD10_MODE_OFF                        0x00
  23#define DMARD10_MODE_STANDBY                    0x02
  24#define DMARD10_MODE_ACTIVE                     0x06
  25#define DMARD10_MODE_READ_OTP                   0x12
  26#define DMARD10_MODE_RESET_DATA_PATH            0x82
  27
  28/* AFEN set 1, ATM[2:0]=b'000 (normal), EN_Z/Y/X/T=1 */
  29#define DMARD10_VALUE_AFEM_AFEN_NORMAL          0x8f
  30/* ODR[3:0]=b'0111 (100Hz), CCK[3:0]=b'0100 (204.8kHZ) */
  31#define DMARD10_VALUE_CKSEL_ODR_100_204         0x74
  32/* INTC[6:5]=b'00 */
  33#define DMARD10_VALUE_INTC                      0x00
  34/* TAP1/TAP2 Average 2 */
  35#define DMARD10_VALUE_TAPNS_AVE_2               0x11
  36
  37#define DMARD10_VALUE_STADR                     0x55
  38#define DMARD10_VALUE_STAINT                    0xaa
  39#define DMARD10_VALUE_MISC2_OSCA_EN             0x08
  40#define DMARD10_VALUE_PD_RST                    0x52
  41
  42/* Offsets into the buffer read in dmard10_read_raw() */
  43#define DMARD10_X_OFFSET                        1
  44#define DMARD10_Y_OFFSET                        2
  45#define DMARD10_Z_OFFSET                        3
  46
  47/*
  48 * a value of + or -128 corresponds to + or - 1G
  49 * scale = 9.81 / 128 = 0.076640625
  50 */
  51
  52static const int dmard10_nscale = 76640625;
  53
  54#define DMARD10_CHANNEL(reg, axis) {    \
  55        .type = IIO_ACCEL,      \
  56        .address = reg, \
  57        .modified = 1,  \
  58        .channel2 = IIO_MOD_##axis,     \
  59        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),   \
  60        .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),   \
  61}
  62
  63static const struct iio_chan_spec dmard10_channels[] = {
  64        DMARD10_CHANNEL(DMARD10_X_OFFSET, X),
  65        DMARD10_CHANNEL(DMARD10_Y_OFFSET, Y),
  66        DMARD10_CHANNEL(DMARD10_Z_OFFSET, Z),
  67};
  68
  69struct dmard10_data {
  70        struct i2c_client *client;
  71};
  72
  73/* Init sequence taken from the android driver */
  74static int dmard10_reset(struct i2c_client *client)
  75{
  76        unsigned char buffer[7];
  77        int ret;
  78
  79        /* 1. Powerdown reset */
  80        ret = i2c_smbus_write_byte_data(client, DMARD10_REG_PD,
  81                                                DMARD10_VALUE_PD_RST);
  82        if (ret < 0)
  83                return ret;
  84
  85        /*
  86         * 2. ACTR => Standby mode => Download OTP to parameter reg =>
  87         *    Standby mode => Reset data path => Standby mode
  88         */
  89        buffer[0] = DMARD10_REG_ACTR;
  90        buffer[1] = DMARD10_MODE_STANDBY;
  91        buffer[2] = DMARD10_MODE_READ_OTP;
  92        buffer[3] = DMARD10_MODE_STANDBY;
  93        buffer[4] = DMARD10_MODE_RESET_DATA_PATH;
  94        buffer[5] = DMARD10_MODE_STANDBY;
  95        ret = i2c_master_send(client, buffer, 6);
  96        if (ret < 0)
  97                return ret;
  98
  99        /* 3. OSCA_EN = 1, TSTO = b'000 (INT1 = normal, TEST0 = normal) */
 100        ret = i2c_smbus_write_byte_data(client, DMARD10_REG_MISC2,
 101                                                DMARD10_VALUE_MISC2_OSCA_EN);
 102        if (ret < 0)
 103                return ret;
 104
 105        /* 4. AFEN = 1 (AFE will powerdown after ADC) */
 106        buffer[0] = DMARD10_REG_AFEM;
 107        buffer[1] = DMARD10_VALUE_AFEM_AFEN_NORMAL;
 108        buffer[2] = DMARD10_VALUE_CKSEL_ODR_100_204;
 109        buffer[3] = DMARD10_VALUE_INTC;
 110        buffer[4] = DMARD10_VALUE_TAPNS_AVE_2;
 111        buffer[5] = 0x00; /* DLYC, no delay timing */
 112        buffer[6] = 0x07; /* INTD=1 push-pull, INTA=1 active high, AUTOT=1 */
 113        ret = i2c_master_send(client, buffer, 7);
 114        if (ret < 0)
 115                return ret;
 116
 117        /* 5. Activation mode */
 118        ret = i2c_smbus_write_byte_data(client, DMARD10_REG_ACTR,
 119                                                DMARD10_MODE_ACTIVE);
 120        if (ret < 0)
 121                return ret;
 122
 123        return 0;
 124}
 125
 126/* Shutdown sequence taken from the android driver */
 127static int dmard10_shutdown(struct i2c_client *client)
 128{
 129        unsigned char buffer[3];
 130
 131        buffer[0] = DMARD10_REG_ACTR;
 132        buffer[1] = DMARD10_MODE_STANDBY;
 133        buffer[2] = DMARD10_MODE_OFF;
 134
 135        return i2c_master_send(client, buffer, 3);
 136}
 137
 138static int dmard10_read_raw(struct iio_dev *indio_dev,
 139                                struct iio_chan_spec const *chan,
 140                                int *val, int *val2, long mask)
 141{
 142        struct dmard10_data *data = iio_priv(indio_dev);
 143        __le16 buf[4];
 144        int ret;
 145
 146        switch (mask) {
 147        case IIO_CHAN_INFO_RAW:
 148                /*
 149                 * Read 8 bytes starting at the REG_STADR register, trying to
 150                 * read the individual X, Y, Z registers will always read 0.
 151                 */
 152                ret = i2c_smbus_read_i2c_block_data(data->client,
 153                                                    DMARD10_REG_STADR,
 154                                                    sizeof(buf), (u8 *)buf);
 155                if (ret < 0)
 156                        return ret;
 157                ret = le16_to_cpu(buf[chan->address]);
 158                *val = sign_extend32(ret, 12);
 159                return IIO_VAL_INT;
 160        case IIO_CHAN_INFO_SCALE:
 161                *val = 0;
 162                *val2 = dmard10_nscale;
 163                return IIO_VAL_INT_PLUS_NANO;
 164        default:
 165                return -EINVAL;
 166        }
 167}
 168
 169static const struct iio_info dmard10_info = {
 170        .read_raw       = dmard10_read_raw,
 171};
 172
 173static void dmard10_shutdown_cleanup(void *client)
 174{
 175        dmard10_shutdown(client);
 176}
 177
 178static int dmard10_probe(struct i2c_client *client,
 179                        const struct i2c_device_id *id)
 180{
 181        int ret;
 182        struct iio_dev *indio_dev;
 183        struct dmard10_data *data;
 184
 185        /* These 2 registers have special POR reset values used for id */
 186        ret = i2c_smbus_read_byte_data(client, DMARD10_REG_STADR);
 187        if (ret != DMARD10_VALUE_STADR)
 188                return (ret < 0) ? ret : -ENODEV;
 189
 190        ret = i2c_smbus_read_byte_data(client, DMARD10_REG_STAINT);
 191        if (ret != DMARD10_VALUE_STAINT)
 192                return (ret < 0) ? ret : -ENODEV;
 193
 194        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 195        if (!indio_dev) {
 196                dev_err(&client->dev, "iio allocation failed!\n");
 197                return -ENOMEM;
 198        }
 199
 200        data = iio_priv(indio_dev);
 201        data->client = client;
 202
 203        indio_dev->info = &dmard10_info;
 204        indio_dev->name = "dmard10";
 205        indio_dev->modes = INDIO_DIRECT_MODE;
 206        indio_dev->channels = dmard10_channels;
 207        indio_dev->num_channels = ARRAY_SIZE(dmard10_channels);
 208
 209        ret = dmard10_reset(client);
 210        if (ret < 0)
 211                return ret;
 212
 213        ret = devm_add_action_or_reset(&client->dev, dmard10_shutdown_cleanup,
 214                                       client);
 215        if (ret)
 216                return ret;
 217
 218        return devm_iio_device_register(&client->dev, indio_dev);
 219}
 220
 221#ifdef CONFIG_PM_SLEEP
 222static int dmard10_suspend(struct device *dev)
 223{
 224        return dmard10_shutdown(to_i2c_client(dev));
 225}
 226
 227static int dmard10_resume(struct device *dev)
 228{
 229        return dmard10_reset(to_i2c_client(dev));
 230}
 231#endif
 232
 233static SIMPLE_DEV_PM_OPS(dmard10_pm_ops, dmard10_suspend, dmard10_resume);
 234
 235static const struct i2c_device_id dmard10_i2c_id[] = {
 236        {"dmard10", 0},
 237        {}
 238};
 239MODULE_DEVICE_TABLE(i2c, dmard10_i2c_id);
 240
 241static struct i2c_driver dmard10_driver = {
 242        .driver = {
 243                .name = "dmard10",
 244                .pm = &dmard10_pm_ops,
 245        },
 246        .probe          = dmard10_probe,
 247        .id_table       = dmard10_i2c_id,
 248};
 249
 250module_i2c_driver(dmard10_driver);
 251
 252MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 253MODULE_DESCRIPTION("Domintech ARD10 3-Axis Accelerometer driver");
 254MODULE_LICENSE("GPL v2");
 255