linux/drivers/input/misc/mma8450.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  Driver for Freescale's 3-Axis Accelerometer MMA8450
   4 *
   5 *  Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
   6 */
   7
   8#include <linux/kernel.h>
   9#include <linux/module.h>
  10#include <linux/slab.h>
  11#include <linux/delay.h>
  12#include <linux/i2c.h>
  13#include <linux/input.h>
  14#include <linux/of_device.h>
  15
  16#define MMA8450_DRV_NAME        "mma8450"
  17
  18#define MODE_CHANGE_DELAY_MS    100
  19#define POLL_INTERVAL           100
  20#define POLL_INTERVAL_MAX       500
  21
  22/* register definitions */
  23#define MMA8450_STATUS          0x00
  24#define MMA8450_STATUS_ZXYDR    0x08
  25
  26#define MMA8450_OUT_X8          0x01
  27#define MMA8450_OUT_Y8          0x02
  28#define MMA8450_OUT_Z8          0x03
  29
  30#define MMA8450_OUT_X_LSB       0x05
  31#define MMA8450_OUT_X_MSB       0x06
  32#define MMA8450_OUT_Y_LSB       0x07
  33#define MMA8450_OUT_Y_MSB       0x08
  34#define MMA8450_OUT_Z_LSB       0x09
  35#define MMA8450_OUT_Z_MSB       0x0a
  36
  37#define MMA8450_XYZ_DATA_CFG    0x16
  38
  39#define MMA8450_CTRL_REG1       0x38
  40#define MMA8450_CTRL_REG2       0x39
  41
  42static int mma8450_read(struct i2c_client *c, unsigned int off)
  43{
  44        int ret;
  45
  46        ret = i2c_smbus_read_byte_data(c, off);
  47        if (ret < 0)
  48                dev_err(&c->dev,
  49                        "failed to read register 0x%02x, error %d\n",
  50                        off, ret);
  51
  52        return ret;
  53}
  54
  55static int mma8450_write(struct i2c_client *c, unsigned int off, u8 v)
  56{
  57        int error;
  58
  59        error = i2c_smbus_write_byte_data(c, off, v);
  60        if (error < 0) {
  61                dev_err(&c->dev,
  62                        "failed to write to register 0x%02x, error %d\n",
  63                        off, error);
  64                return error;
  65        }
  66
  67        return 0;
  68}
  69
  70static int mma8450_read_block(struct i2c_client *c, unsigned int off,
  71                              u8 *buf, size_t size)
  72{
  73        int err;
  74
  75        err = i2c_smbus_read_i2c_block_data(c, off, size, buf);
  76        if (err < 0) {
  77                dev_err(&c->dev,
  78                        "failed to read block data at 0x%02x, error %d\n",
  79                        MMA8450_OUT_X_LSB, err);
  80                return err;
  81        }
  82
  83        return 0;
  84}
  85
  86static void mma8450_poll(struct input_dev *input)
  87{
  88        struct i2c_client *c = input_get_drvdata(input);
  89        int x, y, z;
  90        int ret;
  91        u8 buf[6];
  92
  93        ret = mma8450_read(c, MMA8450_STATUS);
  94        if (ret < 0)
  95                return;
  96
  97        if (!(ret & MMA8450_STATUS_ZXYDR))
  98                return;
  99
 100        ret = mma8450_read_block(c, MMA8450_OUT_X_LSB, buf, sizeof(buf));
 101        if (ret < 0)
 102                return;
 103
 104        x = ((int)(s8)buf[1] << 4) | (buf[0] & 0xf);
 105        y = ((int)(s8)buf[3] << 4) | (buf[2] & 0xf);
 106        z = ((int)(s8)buf[5] << 4) | (buf[4] & 0xf);
 107
 108        input_report_abs(input, ABS_X, x);
 109        input_report_abs(input, ABS_Y, y);
 110        input_report_abs(input, ABS_Z, z);
 111        input_sync(input);
 112}
 113
 114/* Initialize the MMA8450 chip */
 115static int mma8450_open(struct input_dev *input)
 116{
 117        struct i2c_client *c = input_get_drvdata(input);
 118        int err;
 119
 120        /* enable all events from X/Y/Z, no FIFO */
 121        err = mma8450_write(c, MMA8450_XYZ_DATA_CFG, 0x07);
 122        if (err)
 123                return err;
 124
 125        /*
 126         * Sleep mode poll rate - 50Hz
 127         * System output data rate - 400Hz
 128         * Full scale selection - Active, +/- 2G
 129         */
 130        err = mma8450_write(c, MMA8450_CTRL_REG1, 0x01);
 131        if (err)
 132                return err;
 133
 134        msleep(MODE_CHANGE_DELAY_MS);
 135        return 0;
 136}
 137
 138static void mma8450_close(struct input_dev *input)
 139{
 140        struct i2c_client *c = input_get_drvdata(input);
 141
 142        mma8450_write(c, MMA8450_CTRL_REG1, 0x00);
 143        mma8450_write(c, MMA8450_CTRL_REG2, 0x01);
 144}
 145
 146/*
 147 * I2C init/probing/exit functions
 148 */
 149static int mma8450_probe(struct i2c_client *c,
 150                         const struct i2c_device_id *id)
 151{
 152        struct input_dev *input;
 153        int err;
 154
 155        input = devm_input_allocate_device(&c->dev);
 156        if (!input)
 157                return -ENOMEM;
 158
 159        input_set_drvdata(input, c);
 160
 161        input->name = MMA8450_DRV_NAME;
 162        input->id.bustype = BUS_I2C;
 163
 164        input->open = mma8450_open;
 165        input->close = mma8450_close;
 166
 167        input_set_abs_params(input, ABS_X, -2048, 2047, 32, 32);
 168        input_set_abs_params(input, ABS_Y, -2048, 2047, 32, 32);
 169        input_set_abs_params(input, ABS_Z, -2048, 2047, 32, 32);
 170
 171        err = input_setup_polling(input, mma8450_poll);
 172        if (err) {
 173                dev_err(&c->dev, "failed to set up polling\n");
 174                return err;
 175        }
 176
 177        input_set_poll_interval(input, POLL_INTERVAL);
 178        input_set_max_poll_interval(input, POLL_INTERVAL_MAX);
 179
 180        err = input_register_device(input);
 181        if (err) {
 182                dev_err(&c->dev, "failed to register input device\n");
 183                return err;
 184        }
 185
 186        return 0;
 187}
 188
 189static const struct i2c_device_id mma8450_id[] = {
 190        { MMA8450_DRV_NAME, 0 },
 191        { },
 192};
 193MODULE_DEVICE_TABLE(i2c, mma8450_id);
 194
 195static const struct of_device_id mma8450_dt_ids[] = {
 196        { .compatible = "fsl,mma8450", },
 197        { /* sentinel */ }
 198};
 199MODULE_DEVICE_TABLE(of, mma8450_dt_ids);
 200
 201static struct i2c_driver mma8450_driver = {
 202        .driver = {
 203                .name   = MMA8450_DRV_NAME,
 204                .of_match_table = mma8450_dt_ids,
 205        },
 206        .probe          = mma8450_probe,
 207        .id_table       = mma8450_id,
 208};
 209
 210module_i2c_driver(mma8450_driver);
 211
 212MODULE_AUTHOR("Freescale Semiconductor, Inc.");
 213MODULE_DESCRIPTION("MMA8450 3-Axis Accelerometer Driver");
 214MODULE_LICENSE("GPL");
 215