blob: a325d54fd78eb4253a81476dd3541ef7897d8a45 [file] [log] [blame]
Yan Zhang7d417c62013-02-01 11:15:51 +08001/*
2 * mma8x5x.c - Linux kernel modules for 3-Axis Orientation/Motion
3 * Detection Sensor MMA8451/MMA8452/MMA8453
4 *
Bingzhe Caid24b8e72013-07-05 17:50:38 +08005 * Copyright (c) 2013, The Linux Foundation. All Rights Reserved.
6 * Linux Foundation chooses to take subject only to the GPLv2 license
7 * terms, and distributes only under these terms.
Yan Zhang7d417c62013-02-01 11:15:51 +08008 * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
Bingzhe Caid24b8e72013-07-05 17:50:38 +080024#include <linux/kernel.h>
Yan Zhang7d417c62013-02-01 11:15:51 +080025#include <linux/module.h>
Yan Zhang7d417c62013-02-01 11:15:51 +080026#include <linux/slab.h>
Yan Zhang7d417c62013-02-01 11:15:51 +080027#include <linux/delay.h>
Bingzhe Caid24b8e72013-07-05 17:50:38 +080028#include <linux/i2c.h>
Yan Zhang7d417c62013-02-01 11:15:51 +080029#include <linux/input-polldev.h>
Richard Liu1d49d4a2013-04-14 17:01:26 -070030#include <linux/regulator/consumer.h>
Bingzhe Caid24b8e72013-07-05 17:50:38 +080031#include <linux/of_gpio.h>
Yan Zhang7d417c62013-02-01 11:15:51 +080032
Bingzhe Caid24b8e72013-07-05 17:50:38 +080033#define ACCEL_INPUT_DEV_NAME "accelerometer"
Yan Zhang7d417c62013-02-01 11:15:51 +080034#define MMA8451_ID 0x1A
35#define MMA8452_ID 0x2A
36#define MMA8453_ID 0x3A
37#define MMA8652_ID 0x4A
38#define MMA8653_ID 0x5A
39
40
41#define POLL_INTERVAL_MIN 1
42#define POLL_INTERVAL_MAX 500
43#define POLL_INTERVAL 100 /* msecs */
44
45/* if sensor is standby ,set POLL_STOP_TIME to slow down the poll */
Bingzhe Caibe5348a2013-09-05 18:27:19 +080046#define POLL_STOP_TIME 10000
Yan Zhang7d417c62013-02-01 11:15:51 +080047#define INPUT_FUZZ 32
48#define INPUT_FLAT 32
Xiaocheng Li7c0abb42013-07-12 15:41:56 -070049#define INPUT_DATA_DIVIDER 16
Yan Zhang7d417c62013-02-01 11:15:51 +080050#define MODE_CHANGE_DELAY_MS 100
51
52#define MMA8X5X_STATUS_ZYXDR 0x08
53#define MMA8X5X_BUF_SIZE 7
Richard Liu1d49d4a2013-04-14 17:01:26 -070054
mengmengc36b2f62013-07-23 07:46:28 +080055#define MMA_SHUTTEDDOWN (1 << 31)
56
Richard Liu1d49d4a2013-04-14 17:01:26 -070057struct sensor_regulator {
58 struct regulator *vreg;
59 const char *name;
60 u32 min_uV;
61 u32 max_uV;
62};
63
64static struct sensor_regulator mma_vreg[] = {
65 {NULL, "vdd", 2850000, 2850000},
66 {NULL, "vio", 1800000, 1800000},
67};
68
Yan Zhang7d417c62013-02-01 11:15:51 +080069/* register enum for mma8x5x registers */
70enum {
71 MMA8X5X_STATUS = 0x00,
72 MMA8X5X_OUT_X_MSB,
73 MMA8X5X_OUT_X_LSB,
74 MMA8X5X_OUT_Y_MSB,
75 MMA8X5X_OUT_Y_LSB,
76 MMA8X5X_OUT_Z_MSB,
77 MMA8X5X_OUT_Z_LSB,
78
79 MMA8X5X_F_SETUP = 0x09,
80 MMA8X5X_TRIG_CFG,
81 MMA8X5X_SYSMOD,
82 MMA8X5X_INT_SOURCE,
83 MMA8X5X_WHO_AM_I,
84 MMA8X5X_XYZ_DATA_CFG,
85 MMA8X5X_HP_FILTER_CUTOFF,
86
87 MMA8X5X_PL_STATUS,
88 MMA8X5X_PL_CFG,
89 MMA8X5X_PL_COUNT,
90 MMA8X5X_PL_BF_ZCOMP,
91 MMA8X5X_P_L_THS_REG,
92
93 MMA8X5X_FF_MT_CFG,
94 MMA8X5X_FF_MT_SRC,
95 MMA8X5X_FF_MT_THS,
96 MMA8X5X_FF_MT_COUNT,
97
98 MMA8X5X_TRANSIENT_CFG = 0x1D,
99 MMA8X5X_TRANSIENT_SRC,
100 MMA8X5X_TRANSIENT_THS,
101 MMA8X5X_TRANSIENT_COUNT,
102
103 MMA8X5X_PULSE_CFG,
104 MMA8X5X_PULSE_SRC,
105 MMA8X5X_PULSE_THSX,
106 MMA8X5X_PULSE_THSY,
107 MMA8X5X_PULSE_THSZ,
108 MMA8X5X_PULSE_TMLT,
109 MMA8X5X_PULSE_LTCY,
110 MMA8X5X_PULSE_WIND,
111
112 MMA8X5X_ASLP_COUNT,
113 MMA8X5X_CTRL_REG1,
114 MMA8X5X_CTRL_REG2,
115 MMA8X5X_CTRL_REG3,
116 MMA8X5X_CTRL_REG4,
117 MMA8X5X_CTRL_REG5,
118
119 MMA8X5X_OFF_X,
120 MMA8X5X_OFF_Y,
121 MMA8X5X_OFF_Z,
122
123 MMA8X5X_REG_END,
124};
125
126/* The sensitivity is represented in counts/g. In 2g mode the
127sensitivity is 1024 counts/g. In 4g mode the sensitivity is 512
128counts/g and in 8g mode the sensitivity is 256 counts/g.
129 */
130enum {
131 MODE_2G = 0,
132 MODE_4G,
133 MODE_8G,
134};
135
136enum {
137 MMA_STANDBY = 0,
138 MMA_ACTIVED,
139};
140struct mma8x5x_data_axis {
141 short x;
142 short y;
143 short z;
144};
145struct mma8x5x_data {
146 struct i2c_client *client;
147 struct input_polled_dev *poll_dev;
148 struct mutex data_lock;
149 int active;
150 int position;
151 u8 chip_id;
152 int mode;
Bingzhe Caid24b8e72013-07-05 17:50:38 +0800153 int int_pin;
154 u32 int_flags;
Yan Zhang7d417c62013-02-01 11:15:51 +0800155};
156/* Addresses scanned */
157static const unsigned short normal_i2c[] = {0x1c, 0x1d, I2C_CLIENT_END};
158
159static int mma8x5x_chip_id[] = {
160 MMA8451_ID,
161 MMA8452_ID,
162 MMA8453_ID,
163 MMA8652_ID,
164 MMA8653_ID,
165};
166static char *mma8x5x_names[] = {
167 "mma8451",
168 "mma8452",
169 "mma8453",
170 "mma8652",
171 "mma8653",
172};
173static int mma8x5x_position_setting[8][3][3] = {
174 {{ 0, -1, 0}, { 1, 0, 0}, {0, 0, 1} },
175 {{-1, 0, 0}, { 0, -1, 0}, {0, 0, 1} },
176 {{ 0, 1, 0}, {-1, 0, 0}, {0, 0, 1} },
177 {{ 1, 0, 0}, { 0, 1, 0}, {0, 0, 1} },
178 {{ 0, -1, 0}, {-1, 0, 0}, {0, 0, -1} },
179 {{-1, 0, 0}, { 0, 1, 0}, {0, 0, -1} },
180 {{ 0, 1, 0}, { 1, 0, 0}, {0, 0, -1} },
181 {{ 1, 0, 0}, { 0, -1, 0}, {0, 0, -1} },
182};
183
Richard Liu1d49d4a2013-04-14 17:01:26 -0700184static int mma8x5x_config_regulator(struct i2c_client *client, bool on)
185{
186 int rc = 0, i;
187 int num_vreg = sizeof(mma_vreg)/sizeof(struct sensor_regulator);
188
189 if (on) {
190 for (i = 0; i < num_vreg; i++) {
191 mma_vreg[i].vreg = regulator_get(&client->dev,
192 mma_vreg[i].name);
193 if (IS_ERR(mma_vreg[i].vreg)) {
194 rc = PTR_ERR(mma_vreg[i].vreg);
195 dev_err(&client->dev, "%s:regulator get failed rc=%d\n",
196 __func__, rc);
197 mma_vreg[i].vreg = NULL;
198 goto error_vdd;
199 }
200 if (regulator_count_voltages(mma_vreg[i].vreg) > 0) {
201 rc = regulator_set_voltage(mma_vreg[i].vreg,
202 mma_vreg[i].min_uV, mma_vreg[i].max_uV);
203 if (rc) {
204 dev_err(&client->dev, "%s:set_voltage failed rc=%d\n",
205 __func__, rc);
206 regulator_put(mma_vreg[i].vreg);
207 mma_vreg[i].vreg = NULL;
208 goto error_vdd;
209 }
210 }
211 rc = regulator_enable(mma_vreg[i].vreg);
212 if (rc) {
213 dev_err(&client->dev, "%s: regulator_enable failed rc =%d\n",
214 __func__, rc);
215 if (regulator_count_voltages(mma_vreg[i].vreg)
216 > 0) {
217 regulator_set_voltage(mma_vreg[i].vreg,
218 0, mma_vreg[i].max_uV);
219 }
220 regulator_put(mma_vreg[i].vreg);
221 mma_vreg[i].vreg = NULL;
222 goto error_vdd;
223 }
224 }
225 return rc;
226 } else {
227 i = num_vreg;
228 }
229error_vdd:
230 while (--i >= 0) {
231 if (!IS_ERR_OR_NULL(mma_vreg[i].vreg)) {
232 if (regulator_count_voltages(
233 mma_vreg[i].vreg) > 0) {
234 regulator_set_voltage(mma_vreg[i].vreg, 0,
235 mma_vreg[i].max_uV);
236 }
237 regulator_disable(mma_vreg[i].vreg);
238 regulator_put(mma_vreg[i].vreg);
239 mma_vreg[i].vreg = NULL;
240 }
241 }
242 return rc;
243}
244
Yan Zhang7d417c62013-02-01 11:15:51 +0800245static int mma8x5x_data_convert(struct mma8x5x_data *pdata,
246 struct mma8x5x_data_axis *axis_data)
247{
248 short rawdata[3], data[3];
249 int i, j;
250 int position = pdata->position ;
251 if (position < 0 || position > 7)
252 position = 0;
253 rawdata[0] = axis_data->x;
254 rawdata[1] = axis_data->y;
255 rawdata[2] = axis_data->z;
256 for (i = 0; i < 3 ; i++) {
257 data[i] = 0;
258 for (j = 0; j < 3; j++)
259 data[i] += rawdata[j] *
260 mma8x5x_position_setting[position][i][j];
261 }
Xiaocheng Li7c0abb42013-07-12 15:41:56 -0700262 axis_data->x = data[0]/INPUT_DATA_DIVIDER;
263 axis_data->y = data[1]/INPUT_DATA_DIVIDER;
264 axis_data->z = data[2]/INPUT_DATA_DIVIDER;
Yan Zhang7d417c62013-02-01 11:15:51 +0800265 return 0;
266}
267static int mma8x5x_check_id(int id)
268{
269 int i = 0;
270 for (i = 0; i < sizeof(mma8x5x_chip_id)/sizeof(mma8x5x_chip_id[0]);
271 i++)
272 if (id == mma8x5x_chip_id[i])
273 return 1;
274 return 0;
275}
276static char *mma8x5x_id2name(u8 id)
277{
278 return mma8x5x_names[(id >> 4)-1];
279}
280static int mma8x5x_device_init(struct i2c_client *client)
281{
282 int result;
283 struct mma8x5x_data *pdata = i2c_get_clientdata(client);
284 result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, 0);
285 if (result < 0)
286 goto out;
287
288 result = i2c_smbus_write_byte_data(client, MMA8X5X_XYZ_DATA_CFG,
289 pdata->mode);
290 if (result < 0)
291 goto out;
292 pdata->active = MMA_STANDBY;
293 msleep(MODE_CHANGE_DELAY_MS);
294 return 0;
295out:
296 dev_err(&client->dev, "error when init mma8x5x:(%d)", result);
297 return result;
298}
299static int mma8x5x_device_stop(struct i2c_client *client)
300{
301 u8 val;
302 val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
303 i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, val & 0xfe);
304 return 0;
305}
306
Bingzhe Cai70626742013-10-15 13:35:15 +0800307static int mma8x5x_device_start(struct i2c_client *client)
308{
309 struct mma8x5x_data *pdata = i2c_get_clientdata(client);
310
311 if (i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, 0))
312 goto err_out;
313 if (i2c_smbus_write_byte_data(client, MMA8X5X_XYZ_DATA_CFG,
314 pdata->mode))
315 goto err_out;
316
317 /* The BT(boot time) for mma8x5x is 1.55ms according to
318 *Freescale mma8450Q document. Document Number:MMA8450Q
319 *Rev: 9.1, 04/2012
320 */
321 usleep_range(1600, 2000);
322 return 0;
323
324err_out:
325 dev_err(&client->dev, "%s:start device failed", __func__);
326 return -EIO;
327}
328
Yan Zhang7d417c62013-02-01 11:15:51 +0800329static int mma8x5x_read_data(struct i2c_client *client,
330 struct mma8x5x_data_axis *data)
331{
332 u8 tmp_data[MMA8X5X_BUF_SIZE];
333 int ret;
334
335 ret = i2c_smbus_read_i2c_block_data(client,
336 MMA8X5X_OUT_X_MSB, 7, tmp_data);
337 if (ret < MMA8X5X_BUF_SIZE) {
338 dev_err(&client->dev, "i2c block read failed\n");
339 return -EIO;
340 }
341 data->x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1];
342 data->y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3];
343 data->z = ((tmp_data[4] << 8) & 0xff00) | tmp_data[5];
344 return 0;
345}
346
347static void mma8x5x_report_data(struct mma8x5x_data *pdata)
348{
349 struct input_polled_dev *poll_dev = pdata->poll_dev;
350 struct mma8x5x_data_axis data;
351 mutex_lock(&pdata->data_lock);
352 if (pdata->active == MMA_STANDBY) {
353 poll_dev->poll_interval = POLL_STOP_TIME;
354 /* if standby ,set as 10s to slow the poll. */
355 goto out;
356 } else {
357 if (poll_dev->poll_interval == POLL_STOP_TIME)
358 poll_dev->poll_interval = POLL_INTERVAL;
359 }
360 if (mma8x5x_read_data(pdata->client, &data) != 0)
361 goto out;
362 mma8x5x_data_convert(pdata, &data);
363 input_report_abs(poll_dev->input, ABS_X, data.x);
364 input_report_abs(poll_dev->input, ABS_Y, data.y);
365 input_report_abs(poll_dev->input, ABS_Z, data.z);
366 input_sync(poll_dev->input);
367out:
368 mutex_unlock(&pdata->data_lock);
369}
370
371static void mma8x5x_dev_poll(struct input_polled_dev *dev)
372{
373 struct mma8x5x_data *pdata = (struct mma8x5x_data *)dev->private;
374 mma8x5x_report_data(pdata);
375}
376
377static ssize_t mma8x5x_enable_show(struct device *dev,
378 struct device_attribute *attr, char *buf)
379{
380 struct input_polled_dev *poll_dev = dev_get_drvdata(dev);
381 struct mma8x5x_data *pdata = (struct mma8x5x_data *)(poll_dev->private);
382 struct i2c_client *client = pdata->client;
383 u8 val;
384 int enable;
385
386 mutex_lock(&pdata->data_lock);
387 val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
388 if ((val & 0x01) && pdata->active == MMA_ACTIVED)
389 enable = 1;
390 else
391 enable = 0;
392 mutex_unlock(&pdata->data_lock);
393 return snprintf(buf, PAGE_SIZE, "%d\n", enable);
394}
395
396static ssize_t mma8x5x_enable_store(struct device *dev,
397 struct device_attribute *attr,
398 const char *buf, size_t count)
399{
400 struct input_polled_dev *poll_dev = dev_get_drvdata(dev);
401 struct mma8x5x_data *pdata = (struct mma8x5x_data *)(poll_dev->private);
402 struct i2c_client *client = pdata->client;
403 int ret;
404 unsigned long enable;
405 u8 val = 0;
Bingzhe Cai70626742013-10-15 13:35:15 +0800406
Yan Zhang7d417c62013-02-01 11:15:51 +0800407 ret = kstrtoul(buf, 10, &enable);
408 if (ret)
409 return ret;
410 mutex_lock(&pdata->data_lock);
411 enable = (enable > 0) ? 1 : 0;
Bingzhe Cai70626742013-10-15 13:35:15 +0800412 if (enable) {
413 if (pdata->active & MMA_SHUTTEDDOWN) {
414 ret = mma8x5x_config_regulator(client, 1);
415 if (ret)
416 goto err_failed;
417
418 ret = mma8x5x_device_start(client);
419 if (ret)
420 goto err_failed;
421
422 pdata->active &= ~MMA_SHUTTEDDOWN;
423 }
424 if (pdata->active == MMA_STANDBY) {
425 val = i2c_smbus_read_byte_data(client,
426 MMA8X5X_CTRL_REG1);
427 if (val < 0) {
428 dev_err(dev, "read device state failed!");
429 ret = val;
430 goto err_failed;
431 }
432
433 ret = i2c_smbus_write_byte_data(client,
434 MMA8X5X_CTRL_REG1, val | 0x01);
435 if (ret) {
436 dev_err(dev, "change device state failed!");
437 goto err_failed;
438 }
Yan Zhang7d417c62013-02-01 11:15:51 +0800439 pdata->active = MMA_ACTIVED;
Bingzhe Cai70626742013-10-15 13:35:15 +0800440 dev_dbg(dev, "%s:mma enable setting active.\n",
441 __func__);
Yan Zhang7d417c62013-02-01 11:15:51 +0800442 }
Bingzhe Cai70626742013-10-15 13:35:15 +0800443 } else if (enable == 0) {
444 if (pdata->active == MMA_ACTIVED) {
445 val = i2c_smbus_read_byte_data(client,
446 MMA8X5X_CTRL_REG1);
447 if (val < 0) {
448 dev_err(dev, "read device state failed!");
449 ret = val;
450 goto err_failed;
451 }
452
453 ret = i2c_smbus_write_byte_data(client,
454 MMA8X5X_CTRL_REG1, val & 0xFE);
455 if (ret) {
456 dev_err(dev, "change device state failed!");
457 goto err_failed;
458 }
459
Yan Zhang7d417c62013-02-01 11:15:51 +0800460 pdata->active = MMA_STANDBY;
Bingzhe Cai70626742013-10-15 13:35:15 +0800461 dev_dbg(dev, "%s:mma enable setting inactive.\n",
462 __func__);
Yan Zhang7d417c62013-02-01 11:15:51 +0800463 }
Bingzhe Cai70626742013-10-15 13:35:15 +0800464 if (!mma8x5x_config_regulator(client, 0))
465 pdata->active |= MMA_SHUTTEDDOWN;
Yan Zhang7d417c62013-02-01 11:15:51 +0800466 }
467 mutex_unlock(&pdata->data_lock);
468 return count;
Bingzhe Cai70626742013-10-15 13:35:15 +0800469
470err_failed:
471 mutex_unlock(&pdata->data_lock);
472 return ret;
Yan Zhang7d417c62013-02-01 11:15:51 +0800473}
474static ssize_t mma8x5x_position_show(struct device *dev,
475 struct device_attribute *attr, char *buf)
476{
477 struct input_polled_dev *poll_dev = dev_get_drvdata(dev);
478 struct mma8x5x_data *pdata = (struct mma8x5x_data *)(poll_dev->private);
479 int position = 0;
480 mutex_lock(&pdata->data_lock);
481 position = pdata->position ;
482 mutex_unlock(&pdata->data_lock);
483 return snprintf(buf, PAGE_SIZE, "%d\n", position);
484}
485
486static ssize_t mma8x5x_position_store(struct device *dev,
487 struct device_attribute *attr,
488 const char *buf, size_t count)
489{
490 struct input_polled_dev *poll_dev = dev_get_drvdata(dev);
491 struct mma8x5x_data *pdata = (struct mma8x5x_data *)(poll_dev->private);
492 int position;
493 int ret;
494 ret = kstrtoint(buf, 10, &position);
495 if (ret)
496 return ret;
497 mutex_lock(&pdata->data_lock);
498 pdata->position = position;
499 mutex_unlock(&pdata->data_lock);
500 return count;
501}
502
503static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO,
504 mma8x5x_enable_show, mma8x5x_enable_store);
505static DEVICE_ATTR(position, S_IWUSR | S_IRUGO,
506 mma8x5x_position_show, mma8x5x_position_store);
507
508static struct attribute *mma8x5x_attributes[] = {
509 &dev_attr_enable.attr,
510 &dev_attr_position.attr,
511 NULL
512};
513
514static const struct attribute_group mma8x5x_attr_group = {
515 .attrs = mma8x5x_attributes,
516};
517static int mma8x5x_detect(struct i2c_client *client,
518 struct i2c_board_info *info)
519{
520 struct i2c_adapter *adapter = client->adapter;
521 int chip_id;
522 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA))
523 return -ENODEV;
524 chip_id = i2c_smbus_read_byte_data(client, MMA8X5X_WHO_AM_I);
525 if (!mma8x5x_check_id(chip_id))
526 return -ENODEV;
Bingzhe Caid24b8e72013-07-05 17:50:38 +0800527 dev_dbg(&client->dev, "%s,check %s i2c address 0x%x.\n",
528 __func__, mma8x5x_id2name(chip_id), client->addr);
Yan Zhang7d417c62013-02-01 11:15:51 +0800529 strlcpy(info->type, "mma8x5x", I2C_NAME_SIZE);
530 return 0;
531}
Bingzhe Caid24b8e72013-07-05 17:50:38 +0800532
533static int mma8x5x_parse_dt(struct device *dev, struct mma8x5x_data *data)
534{
535 int rc;
536 struct device_node *np = dev->of_node;
537 u32 temp_val;
538
539 data->int_pin = of_get_named_gpio_flags(np, "fsl,irq-gpio",
540 0, &data->int_flags);
541 if (data->int_pin < 0) {
542 dev_err(dev, "Unable to read irq-gpio\n");
543 return data->int_pin;
544 }
545
546 rc = of_property_read_u32(np, "fsl,sensors-position", &temp_val);
547 if (!rc)
548 data->position = temp_val;
549 else {
550 dev_err(dev, "Unable to read sensors-position\n");
551 return rc;
552 }
553
554 return 0;
555}
556
Yan Zhang7d417c62013-02-01 11:15:51 +0800557static int __devinit mma8x5x_probe(struct i2c_client *client,
558 const struct i2c_device_id *id)
559{
560 int result, chip_id;
561 struct input_dev *idev;
562 struct mma8x5x_data *pdata;
563 struct i2c_adapter *adapter;
564 struct input_polled_dev *poll_dev;
565 adapter = to_i2c_adapter(client->dev.parent);
Richard Liu1d49d4a2013-04-14 17:01:26 -0700566 /* power on the device */
567 result = mma8x5x_config_regulator(client, 1);
568 if (result)
569 goto err_power_on;
570
Yan Zhang7d417c62013-02-01 11:15:51 +0800571 result = i2c_check_functionality(adapter,
572 I2C_FUNC_SMBUS_BYTE |
573 I2C_FUNC_SMBUS_BYTE_DATA);
574 if (!result)
575 goto err_out;
576
577 chip_id = i2c_smbus_read_byte_data(client, MMA8X5X_WHO_AM_I);
578
579 if (!mma8x5x_check_id(chip_id)) {
580 dev_err(&client->dev,
581 "read chip ID 0x%x is not equal to 0x%x,0x%x,0x%x,0x%x,0x%x!\n",
582 chip_id, MMA8451_ID, MMA8452_ID, MMA8453_ID,
583 MMA8652_ID, MMA8653_ID);
584 result = -EINVAL;
585 goto err_out;
586 }
Richard Liu1d49d4a2013-04-14 17:01:26 -0700587 /* set the private data */
Yan Zhang7d417c62013-02-01 11:15:51 +0800588 pdata = kzalloc(sizeof(struct mma8x5x_data), GFP_KERNEL);
589 if (!pdata) {
590 result = -ENOMEM;
591 dev_err(&client->dev, "alloc data memory error!\n");
592 goto err_out;
593 }
Bingzhe Caid24b8e72013-07-05 17:50:38 +0800594
595 if (client->dev.of_node) {
596 result = mma8x5x_parse_dt(&client->dev, pdata);
597 if (result)
598 return result;
599 } else {
600 pdata->position = CONFIG_SENSORS_MMA_POSITION;
601 pdata->int_pin = -1;
602 pdata->int_flags = 0;
603 }
604
Yan Zhang7d417c62013-02-01 11:15:51 +0800605 /* Initialize the MMA8X5X chip */
606 pdata->client = client;
607 pdata->chip_id = chip_id;
608 pdata->mode = MODE_2G;
Bingzhe Caid24b8e72013-07-05 17:50:38 +0800609
Yan Zhang7d417c62013-02-01 11:15:51 +0800610 mutex_init(&pdata->data_lock);
611 i2c_set_clientdata(client, pdata);
Richard Liu1d49d4a2013-04-14 17:01:26 -0700612 /* Initialize the MMA8X5X chip */
Yan Zhang7d417c62013-02-01 11:15:51 +0800613 mma8x5x_device_init(client);
Richard Liu1d49d4a2013-04-14 17:01:26 -0700614 /* create the input poll device */
Yan Zhang7d417c62013-02-01 11:15:51 +0800615 poll_dev = input_allocate_polled_device();
616 if (!poll_dev) {
617 result = -ENOMEM;
618 dev_err(&client->dev, "alloc poll device failed!\n");
619 goto err_alloc_poll_device;
620 }
621 poll_dev->poll = mma8x5x_dev_poll;
622 poll_dev->poll_interval = POLL_STOP_TIME;
623 poll_dev->poll_interval_min = POLL_INTERVAL_MIN;
624 poll_dev->poll_interval_max = POLL_INTERVAL_MAX;
625 poll_dev->private = pdata;
626 idev = poll_dev->input;
Bingzhe Caid24b8e72013-07-05 17:50:38 +0800627 idev->name = ACCEL_INPUT_DEV_NAME;
Yan Zhang7d417c62013-02-01 11:15:51 +0800628 idev->uniq = mma8x5x_id2name(pdata->chip_id);
629 idev->id.bustype = BUS_I2C;
630 idev->evbit[0] = BIT_MASK(EV_ABS);
631 input_set_abs_params(idev, ABS_X, -0x7fff, 0x7fff, 0, 0);
632 input_set_abs_params(idev, ABS_Y, -0x7fff, 0x7fff, 0, 0);
633 input_set_abs_params(idev, ABS_Z, -0x7fff, 0x7fff, 0, 0);
634 pdata->poll_dev = poll_dev;
635 result = input_register_polled_device(pdata->poll_dev);
636 if (result) {
637 dev_err(&client->dev, "register poll device failed!\n");
638 goto err_register_polled_device;
639 }
640 result = sysfs_create_group(&idev->dev.kobj, &mma8x5x_attr_group);
641 if (result) {
642 dev_err(&client->dev, "create device file failed!\n");
643 result = -EINVAL;
644 goto err_create_sysfs;
645 }
Bingzhe Caid24b8e72013-07-05 17:50:38 +0800646 dev_info(&client->dev,
647 "%s:mma8x5x device driver probe successfully, position =%d\n",
648 __func__, pdata->position);
649
Yan Zhang7d417c62013-02-01 11:15:51 +0800650 return 0;
651err_create_sysfs:
652 input_unregister_polled_device(pdata->poll_dev);
653err_register_polled_device:
654 input_free_polled_device(poll_dev);
655err_alloc_poll_device:
656 kfree(pdata);
657err_out:
Richard Liu1d49d4a2013-04-14 17:01:26 -0700658 mma8x5x_config_regulator(client, 0);
659err_power_on:
Yan Zhang7d417c62013-02-01 11:15:51 +0800660 return result;
661}
662static int __devexit mma8x5x_remove(struct i2c_client *client)
663{
664 struct mma8x5x_data *pdata = i2c_get_clientdata(client);
Richard Liu1d49d4a2013-04-14 17:01:26 -0700665 struct input_polled_dev *poll_dev;
Yan Zhang7d417c62013-02-01 11:15:51 +0800666 mma8x5x_device_stop(client);
667 if (pdata) {
Richard Liu1d49d4a2013-04-14 17:01:26 -0700668 poll_dev = pdata->poll_dev;
Yan Zhang7d417c62013-02-01 11:15:51 +0800669 input_unregister_polled_device(poll_dev);
670 input_free_polled_device(poll_dev);
671 kfree(pdata);
672 }
673 return 0;
674}
675
676#ifdef CONFIG_PM_SLEEP
677static int mma8x5x_suspend(struct device *dev)
678{
679 struct i2c_client *client = to_i2c_client(dev);
680 struct mma8x5x_data *pdata = i2c_get_clientdata(client);
681 if (pdata->active == MMA_ACTIVED)
682 mma8x5x_device_stop(client);
Bingzhe Cai70626742013-10-15 13:35:15 +0800683 if (pdata->active & MMA_SHUTTEDDOWN)
684 return 0;
mengmengc36b2f62013-07-23 07:46:28 +0800685 if (!mma8x5x_config_regulator(client, 0))
686 /* The highest bit sotres the power state */
687 pdata->active |= MMA_SHUTTEDDOWN;
Yan Zhang7d417c62013-02-01 11:15:51 +0800688 return 0;
689}
690
691static int mma8x5x_resume(struct device *dev)
692{
693 int val = 0;
694 struct i2c_client *client = to_i2c_client(dev);
695 struct mma8x5x_data *pdata = i2c_get_clientdata(client);
Bingzhe Cai70626742013-10-15 13:35:15 +0800696
697 /* No need to power on while device is shutdowned from standby state */
698 if (pdata->active == (MMA_SHUTTEDDOWN | MMA_STANDBY))
699 return 0;
mengmengc36b2f62013-07-23 07:46:28 +0800700 if (pdata->active & MMA_SHUTTEDDOWN) {
701 if (mma8x5x_config_regulator(client, 1))
702 goto out;
703
Bingzhe Cai70626742013-10-15 13:35:15 +0800704 if (mma8x5x_device_start(client))
mengmengc36b2f62013-07-23 07:46:28 +0800705 goto out;
mengmengc36b2f62013-07-23 07:46:28 +0800706 pdata->active &= ~MMA_SHUTTEDDOWN;
707 }
Yan Zhang7d417c62013-02-01 11:15:51 +0800708 if (pdata->active == MMA_ACTIVED) {
709 val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
710 i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, val|0x01);
711 }
mengmengc36b2f62013-07-23 07:46:28 +0800712
Yan Zhang7d417c62013-02-01 11:15:51 +0800713 return 0;
mengmengc36b2f62013-07-23 07:46:28 +0800714out:
715 dev_err(&client->dev, "%s:failed during resume operation", __func__);
716 return -EIO;
Yan Zhang7d417c62013-02-01 11:15:51 +0800717
718}
719#endif
720
721static const struct i2c_device_id mma8x5x_id[] = {
722 {"mma8x5x", 0},
723 { }
724};
725MODULE_DEVICE_TABLE(i2c, mma8x5x_id);
726
Richard Liu1d49d4a2013-04-14 17:01:26 -0700727static const struct of_device_id mma8x5x_of_match[] = {
728 { .compatible = "fsl,mma8x5x", },
729 { },
730};
731
Yan Zhang7d417c62013-02-01 11:15:51 +0800732static SIMPLE_DEV_PM_OPS(mma8x5x_pm_ops, mma8x5x_suspend, mma8x5x_resume);
733static struct i2c_driver mma8x5x_driver = {
734 .class = I2C_CLASS_HWMON,
735 .driver = {
Richard Liu1d49d4a2013-04-14 17:01:26 -0700736 .name = "mma8x5x",
737 .owner = THIS_MODULE,
738 .pm = &mma8x5x_pm_ops,
739 .of_match_table = mma8x5x_of_match,
740 },
Yan Zhang7d417c62013-02-01 11:15:51 +0800741 .probe = mma8x5x_probe,
742 .remove = __devexit_p(mma8x5x_remove),
743 .id_table = mma8x5x_id,
744 .detect = mma8x5x_detect,
745 .address_list = normal_i2c,
746};
747
748static int __init mma8x5x_init(void)
749{
750 /* register driver */
751 int res;
752
753 res = i2c_add_driver(&mma8x5x_driver);
754 if (res < 0) {
Bingzhe Caid24b8e72013-07-05 17:50:38 +0800755 pr_info("%s:add mma8x5x i2c driver failed\n", __func__);
Yan Zhang7d417c62013-02-01 11:15:51 +0800756 return -ENODEV;
757 }
758 return res;
759}
760
761static void __exit mma8x5x_exit(void)
762{
763 i2c_del_driver(&mma8x5x_driver);
764}
765
766MODULE_AUTHOR("Freescale Semiconductor, Inc.");
767MODULE_DESCRIPTION("MMA8X5X 3-Axis Orientation/Motion Detection Sensor driver");
768MODULE_LICENSE("GPL");
769
770module_init(mma8x5x_init);
771module_exit(mma8x5x_exit);