Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Driver for Freescale's 3-Axis Accelerometer MMA8450
0004  *
0005  *  Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/slab.h>
0011 #include <linux/delay.h>
0012 #include <linux/i2c.h>
0013 #include <linux/input.h>
0014 #include <linux/of_device.h>
0015 
0016 #define MMA8450_DRV_NAME    "mma8450"
0017 
0018 #define MODE_CHANGE_DELAY_MS    100
0019 #define POLL_INTERVAL       100
0020 #define POLL_INTERVAL_MAX   500
0021 
0022 /* register definitions */
0023 #define MMA8450_STATUS      0x00
0024 #define MMA8450_STATUS_ZXYDR    0x08
0025 
0026 #define MMA8450_OUT_X8      0x01
0027 #define MMA8450_OUT_Y8      0x02
0028 #define MMA8450_OUT_Z8      0x03
0029 
0030 #define MMA8450_OUT_X_LSB   0x05
0031 #define MMA8450_OUT_X_MSB   0x06
0032 #define MMA8450_OUT_Y_LSB   0x07
0033 #define MMA8450_OUT_Y_MSB   0x08
0034 #define MMA8450_OUT_Z_LSB   0x09
0035 #define MMA8450_OUT_Z_MSB   0x0a
0036 
0037 #define MMA8450_XYZ_DATA_CFG    0x16
0038 
0039 #define MMA8450_CTRL_REG1   0x38
0040 #define MMA8450_CTRL_REG2   0x39
0041 
0042 static int mma8450_read(struct i2c_client *c, unsigned int off)
0043 {
0044     int ret;
0045 
0046     ret = i2c_smbus_read_byte_data(c, off);
0047     if (ret < 0)
0048         dev_err(&c->dev,
0049             "failed to read register 0x%02x, error %d\n",
0050             off, ret);
0051 
0052     return ret;
0053 }
0054 
0055 static int mma8450_write(struct i2c_client *c, unsigned int off, u8 v)
0056 {
0057     int error;
0058 
0059     error = i2c_smbus_write_byte_data(c, off, v);
0060     if (error < 0) {
0061         dev_err(&c->dev,
0062             "failed to write to register 0x%02x, error %d\n",
0063             off, error);
0064         return error;
0065     }
0066 
0067     return 0;
0068 }
0069 
0070 static int mma8450_read_block(struct i2c_client *c, unsigned int off,
0071                   u8 *buf, size_t size)
0072 {
0073     int err;
0074 
0075     err = i2c_smbus_read_i2c_block_data(c, off, size, buf);
0076     if (err < 0) {
0077         dev_err(&c->dev,
0078             "failed to read block data at 0x%02x, error %d\n",
0079             MMA8450_OUT_X_LSB, err);
0080         return err;
0081     }
0082 
0083     return 0;
0084 }
0085 
0086 static void mma8450_poll(struct input_dev *input)
0087 {
0088     struct i2c_client *c = input_get_drvdata(input);
0089     int x, y, z;
0090     int ret;
0091     u8 buf[6];
0092 
0093     ret = mma8450_read(c, MMA8450_STATUS);
0094     if (ret < 0)
0095         return;
0096 
0097     if (!(ret & MMA8450_STATUS_ZXYDR))
0098         return;
0099 
0100     ret = mma8450_read_block(c, MMA8450_OUT_X_LSB, buf, sizeof(buf));
0101     if (ret < 0)
0102         return;
0103 
0104     x = ((int)(s8)buf[1] << 4) | (buf[0] & 0xf);
0105     y = ((int)(s8)buf[3] << 4) | (buf[2] & 0xf);
0106     z = ((int)(s8)buf[5] << 4) | (buf[4] & 0xf);
0107 
0108     input_report_abs(input, ABS_X, x);
0109     input_report_abs(input, ABS_Y, y);
0110     input_report_abs(input, ABS_Z, z);
0111     input_sync(input);
0112 }
0113 
0114 /* Initialize the MMA8450 chip */
0115 static int mma8450_open(struct input_dev *input)
0116 {
0117     struct i2c_client *c = input_get_drvdata(input);
0118     int err;
0119 
0120     /* enable all events from X/Y/Z, no FIFO */
0121     err = mma8450_write(c, MMA8450_XYZ_DATA_CFG, 0x07);
0122     if (err)
0123         return err;
0124 
0125     /*
0126      * Sleep mode poll rate - 50Hz
0127      * System output data rate - 400Hz
0128      * Full scale selection - Active, +/- 2G
0129      */
0130     err = mma8450_write(c, MMA8450_CTRL_REG1, 0x01);
0131     if (err)
0132         return err;
0133 
0134     msleep(MODE_CHANGE_DELAY_MS);
0135     return 0;
0136 }
0137 
0138 static void mma8450_close(struct input_dev *input)
0139 {
0140     struct i2c_client *c = input_get_drvdata(input);
0141 
0142     mma8450_write(c, MMA8450_CTRL_REG1, 0x00);
0143     mma8450_write(c, MMA8450_CTRL_REG2, 0x01);
0144 }
0145 
0146 /*
0147  * I2C init/probing/exit functions
0148  */
0149 static int mma8450_probe(struct i2c_client *c,
0150              const struct i2c_device_id *id)
0151 {
0152     struct input_dev *input;
0153     int err;
0154 
0155     input = devm_input_allocate_device(&c->dev);
0156     if (!input)
0157         return -ENOMEM;
0158 
0159     input_set_drvdata(input, c);
0160 
0161     input->name = MMA8450_DRV_NAME;
0162     input->id.bustype = BUS_I2C;
0163 
0164     input->open = mma8450_open;
0165     input->close = mma8450_close;
0166 
0167     input_set_abs_params(input, ABS_X, -2048, 2047, 32, 32);
0168     input_set_abs_params(input, ABS_Y, -2048, 2047, 32, 32);
0169     input_set_abs_params(input, ABS_Z, -2048, 2047, 32, 32);
0170 
0171     err = input_setup_polling(input, mma8450_poll);
0172     if (err) {
0173         dev_err(&c->dev, "failed to set up polling\n");
0174         return err;
0175     }
0176 
0177     input_set_poll_interval(input, POLL_INTERVAL);
0178     input_set_max_poll_interval(input, POLL_INTERVAL_MAX);
0179 
0180     err = input_register_device(input);
0181     if (err) {
0182         dev_err(&c->dev, "failed to register input device\n");
0183         return err;
0184     }
0185 
0186     return 0;
0187 }
0188 
0189 static const struct i2c_device_id mma8450_id[] = {
0190     { MMA8450_DRV_NAME, 0 },
0191     { },
0192 };
0193 MODULE_DEVICE_TABLE(i2c, mma8450_id);
0194 
0195 static const struct of_device_id mma8450_dt_ids[] = {
0196     { .compatible = "fsl,mma8450", },
0197     { /* sentinel */ }
0198 };
0199 MODULE_DEVICE_TABLE(of, mma8450_dt_ids);
0200 
0201 static struct i2c_driver mma8450_driver = {
0202     .driver = {
0203         .name   = MMA8450_DRV_NAME,
0204         .of_match_table = mma8450_dt_ids,
0205     },
0206     .probe      = mma8450_probe,
0207     .id_table   = mma8450_id,
0208 };
0209 
0210 module_i2c_driver(mma8450_driver);
0211 
0212 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
0213 MODULE_DESCRIPTION("MMA8450 3-Axis Accelerometer Driver");
0214 MODULE_LICENSE("GPL");