GNU Linux-libre 6.7.9-gnu
[releases.git] / drivers / input / misc / mma8450.c
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/mod_devicetable.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
42 static 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
55 static 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
70 static 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
86 static 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 */
115 static 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
138 static 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  */
149 static int mma8450_probe(struct i2c_client *c)
150 {
151         struct input_dev *input;
152         int err;
153
154         input = devm_input_allocate_device(&c->dev);
155         if (!input)
156                 return -ENOMEM;
157
158         input_set_drvdata(input, c);
159
160         input->name = MMA8450_DRV_NAME;
161         input->id.bustype = BUS_I2C;
162
163         input->open = mma8450_open;
164         input->close = mma8450_close;
165
166         input_set_abs_params(input, ABS_X, -2048, 2047, 32, 32);
167         input_set_abs_params(input, ABS_Y, -2048, 2047, 32, 32);
168         input_set_abs_params(input, ABS_Z, -2048, 2047, 32, 32);
169
170         err = input_setup_polling(input, mma8450_poll);
171         if (err) {
172                 dev_err(&c->dev, "failed to set up polling\n");
173                 return err;
174         }
175
176         input_set_poll_interval(input, POLL_INTERVAL);
177         input_set_max_poll_interval(input, POLL_INTERVAL_MAX);
178
179         err = input_register_device(input);
180         if (err) {
181                 dev_err(&c->dev, "failed to register input device\n");
182                 return err;
183         }
184
185         return 0;
186 }
187
188 static const struct i2c_device_id mma8450_id[] = {
189         { MMA8450_DRV_NAME, 0 },
190         { },
191 };
192 MODULE_DEVICE_TABLE(i2c, mma8450_id);
193
194 static const struct of_device_id mma8450_dt_ids[] = {
195         { .compatible = "fsl,mma8450", },
196         { /* sentinel */ }
197 };
198 MODULE_DEVICE_TABLE(of, mma8450_dt_ids);
199
200 static struct i2c_driver mma8450_driver = {
201         .driver = {
202                 .name   = MMA8450_DRV_NAME,
203                 .of_match_table = mma8450_dt_ids,
204         },
205         .probe          = mma8450_probe,
206         .id_table       = mma8450_id,
207 };
208
209 module_i2c_driver(mma8450_driver);
210
211 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
212 MODULE_DESCRIPTION("MMA8450 3-Axis Accelerometer Driver");
213 MODULE_LICENSE("GPL");