13ead8b5dSEric Miao /* 23ead8b5dSEric Miao * Driver for Freescale's 3-Axis Accelerometer MMA8450 33ead8b5dSEric Miao * 43ead8b5dSEric Miao * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. 53ead8b5dSEric Miao * 63ead8b5dSEric Miao * This program is free software; you can redistribute it and/or modify 73ead8b5dSEric Miao * it under the terms of the GNU General Public License as published by 83ead8b5dSEric Miao * the Free Software Foundation; either version 2 of the License, or 93ead8b5dSEric Miao * (at your option) any later version. 103ead8b5dSEric Miao * 113ead8b5dSEric Miao * This program is distributed in the hope that it will be useful, 123ead8b5dSEric Miao * but WITHOUT ANY WARRANTY; without even the implied warranty of 133ead8b5dSEric Miao * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 143ead8b5dSEric Miao * GNU General Public License for more details. 153ead8b5dSEric Miao * 163ead8b5dSEric Miao * You should have received a copy of the GNU General Public License 173ead8b5dSEric Miao * along with this program; if not, write to the Free Software 183ead8b5dSEric Miao * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 193ead8b5dSEric Miao */ 203ead8b5dSEric Miao 213ead8b5dSEric Miao #include <linux/kernel.h> 223ead8b5dSEric Miao #include <linux/module.h> 233ead8b5dSEric Miao #include <linux/slab.h> 243ead8b5dSEric Miao #include <linux/delay.h> 253ead8b5dSEric Miao #include <linux/i2c.h> 263ead8b5dSEric Miao #include <linux/input-polldev.h> 2771ff069cSShawn Guo #include <linux/of_device.h> 283ead8b5dSEric Miao 293ead8b5dSEric Miao #define MMA8450_DRV_NAME "mma8450" 303ead8b5dSEric Miao 313ead8b5dSEric Miao #define MODE_CHANGE_DELAY_MS 100 323ead8b5dSEric Miao #define POLL_INTERVAL 100 333ead8b5dSEric Miao #define POLL_INTERVAL_MAX 500 343ead8b5dSEric Miao 353ead8b5dSEric Miao /* register definitions */ 363ead8b5dSEric Miao #define MMA8450_STATUS 0x00 373ead8b5dSEric Miao #define MMA8450_STATUS_ZXYDR 0x08 383ead8b5dSEric Miao 393ead8b5dSEric Miao #define MMA8450_OUT_X8 0x01 403ead8b5dSEric Miao #define MMA8450_OUT_Y8 0x02 413ead8b5dSEric Miao #define MMA8450_OUT_Z8 0x03 423ead8b5dSEric Miao 433ead8b5dSEric Miao #define MMA8450_OUT_X_LSB 0x05 443ead8b5dSEric Miao #define MMA8450_OUT_X_MSB 0x06 453ead8b5dSEric Miao #define MMA8450_OUT_Y_LSB 0x07 463ead8b5dSEric Miao #define MMA8450_OUT_Y_MSB 0x08 473ead8b5dSEric Miao #define MMA8450_OUT_Z_LSB 0x09 483ead8b5dSEric Miao #define MMA8450_OUT_Z_MSB 0x0a 493ead8b5dSEric Miao 503ead8b5dSEric Miao #define MMA8450_XYZ_DATA_CFG 0x16 513ead8b5dSEric Miao 523ead8b5dSEric Miao #define MMA8450_CTRL_REG1 0x38 533ead8b5dSEric Miao #define MMA8450_CTRL_REG2 0x39 543ead8b5dSEric Miao 553ead8b5dSEric Miao /* mma8450 status */ 563ead8b5dSEric Miao struct mma8450 { 573ead8b5dSEric Miao struct i2c_client *client; 583ead8b5dSEric Miao struct input_polled_dev *idev; 593ead8b5dSEric Miao }; 603ead8b5dSEric Miao 613ead8b5dSEric Miao static int mma8450_read(struct mma8450 *m, unsigned off) 623ead8b5dSEric Miao { 633ead8b5dSEric Miao struct i2c_client *c = m->client; 643ead8b5dSEric Miao int ret; 653ead8b5dSEric Miao 663ead8b5dSEric Miao ret = i2c_smbus_read_byte_data(c, off); 673ead8b5dSEric Miao if (ret < 0) 683ead8b5dSEric Miao dev_err(&c->dev, 693ead8b5dSEric Miao "failed to read register 0x%02x, error %d\n", 703ead8b5dSEric Miao off, ret); 713ead8b5dSEric Miao 723ead8b5dSEric Miao return ret; 733ead8b5dSEric Miao } 743ead8b5dSEric Miao 753ead8b5dSEric Miao static int mma8450_write(struct mma8450 *m, unsigned off, u8 v) 763ead8b5dSEric Miao { 773ead8b5dSEric Miao struct i2c_client *c = m->client; 783ead8b5dSEric Miao int error; 793ead8b5dSEric Miao 803ead8b5dSEric Miao error = i2c_smbus_write_byte_data(c, off, v); 813ead8b5dSEric Miao if (error < 0) { 823ead8b5dSEric Miao dev_err(&c->dev, 833ead8b5dSEric Miao "failed to write to register 0x%02x, error %d\n", 843ead8b5dSEric Miao off, error); 853ead8b5dSEric Miao return error; 863ead8b5dSEric Miao } 873ead8b5dSEric Miao 883ead8b5dSEric Miao return 0; 893ead8b5dSEric Miao } 903ead8b5dSEric Miao 91cb31f898SDmitry Torokhov static int mma8450_read_block(struct mma8450 *m, unsigned off, 92cb31f898SDmitry Torokhov u8 *buf, size_t size) 933ead8b5dSEric Miao { 943ead8b5dSEric Miao struct i2c_client *c = m->client; 953ead8b5dSEric Miao int err; 963ead8b5dSEric Miao 97cb31f898SDmitry Torokhov err = i2c_smbus_read_i2c_block_data(c, off, size, buf); 983ead8b5dSEric Miao if (err < 0) { 993ead8b5dSEric Miao dev_err(&c->dev, 1003ead8b5dSEric Miao "failed to read block data at 0x%02x, error %d\n", 1013ead8b5dSEric Miao MMA8450_OUT_X_LSB, err); 1023ead8b5dSEric Miao return err; 1033ead8b5dSEric Miao } 1043ead8b5dSEric Miao 1053ead8b5dSEric Miao return 0; 1063ead8b5dSEric Miao } 1073ead8b5dSEric Miao 1083ead8b5dSEric Miao static void mma8450_poll(struct input_polled_dev *dev) 1093ead8b5dSEric Miao { 1103ead8b5dSEric Miao struct mma8450 *m = dev->private; 1113ead8b5dSEric Miao int x, y, z; 1123ead8b5dSEric Miao int ret; 113cb31f898SDmitry Torokhov u8 buf[6]; 1143ead8b5dSEric Miao 1153ead8b5dSEric Miao ret = mma8450_read(m, MMA8450_STATUS); 1163ead8b5dSEric Miao if (ret < 0) 1173ead8b5dSEric Miao return; 1183ead8b5dSEric Miao 1193ead8b5dSEric Miao if (!(ret & MMA8450_STATUS_ZXYDR)) 1203ead8b5dSEric Miao return; 1213ead8b5dSEric Miao 122cb31f898SDmitry Torokhov ret = mma8450_read_block(m, MMA8450_OUT_X_LSB, buf, sizeof(buf)); 123cb31f898SDmitry Torokhov if (ret < 0) 1243ead8b5dSEric Miao return; 1253ead8b5dSEric Miao 126257a1ec6SSebastien Royen x = ((int)(s8)buf[1] << 4) | (buf[0] & 0xf); 127257a1ec6SSebastien Royen y = ((int)(s8)buf[3] << 4) | (buf[2] & 0xf); 128257a1ec6SSebastien Royen z = ((int)(s8)buf[5] << 4) | (buf[4] & 0xf); 129cb31f898SDmitry Torokhov 1303ead8b5dSEric Miao input_report_abs(dev->input, ABS_X, x); 1313ead8b5dSEric Miao input_report_abs(dev->input, ABS_Y, y); 1323ead8b5dSEric Miao input_report_abs(dev->input, ABS_Z, z); 1333ead8b5dSEric Miao input_sync(dev->input); 1343ead8b5dSEric Miao } 1353ead8b5dSEric Miao 1363ead8b5dSEric Miao /* Initialize the MMA8450 chip */ 1373ead8b5dSEric Miao static void mma8450_open(struct input_polled_dev *dev) 1383ead8b5dSEric Miao { 1393ead8b5dSEric Miao struct mma8450 *m = dev->private; 1403ead8b5dSEric Miao int err; 1413ead8b5dSEric Miao 1423ead8b5dSEric Miao /* enable all events from X/Y/Z, no FIFO */ 1433ead8b5dSEric Miao err = mma8450_write(m, MMA8450_XYZ_DATA_CFG, 0x07); 1443ead8b5dSEric Miao if (err) 1453ead8b5dSEric Miao return; 1463ead8b5dSEric Miao 1473ead8b5dSEric Miao /* 1483ead8b5dSEric Miao * Sleep mode poll rate - 50Hz 1493ead8b5dSEric Miao * System output data rate - 400Hz 1503ead8b5dSEric Miao * Full scale selection - Active, +/- 2G 1513ead8b5dSEric Miao */ 1523ead8b5dSEric Miao err = mma8450_write(m, MMA8450_CTRL_REG1, 0x01); 1533ead8b5dSEric Miao if (err < 0) 1543ead8b5dSEric Miao return; 1553ead8b5dSEric Miao 1563ead8b5dSEric Miao msleep(MODE_CHANGE_DELAY_MS); 1573ead8b5dSEric Miao } 1583ead8b5dSEric Miao 1593ead8b5dSEric Miao static void mma8450_close(struct input_polled_dev *dev) 1603ead8b5dSEric Miao { 1613ead8b5dSEric Miao struct mma8450 *m = dev->private; 1623ead8b5dSEric Miao 1633ead8b5dSEric Miao mma8450_write(m, MMA8450_CTRL_REG1, 0x00); 1643ead8b5dSEric Miao mma8450_write(m, MMA8450_CTRL_REG2, 0x01); 1653ead8b5dSEric Miao } 1663ead8b5dSEric Miao 1673ead8b5dSEric Miao /* 1683ead8b5dSEric Miao * I2C init/probing/exit functions 1693ead8b5dSEric Miao */ 1705298cc4cSBill Pemberton static int mma8450_probe(struct i2c_client *c, 1713ead8b5dSEric Miao const struct i2c_device_id *id) 1723ead8b5dSEric Miao { 1733ead8b5dSEric Miao struct input_polled_dev *idev; 1743ead8b5dSEric Miao struct mma8450 *m; 1753ead8b5dSEric Miao int err; 1763ead8b5dSEric Miao 1773ead8b5dSEric Miao m = kzalloc(sizeof(struct mma8450), GFP_KERNEL); 1783ead8b5dSEric Miao idev = input_allocate_polled_device(); 1793ead8b5dSEric Miao if (!m || !idev) { 1803ead8b5dSEric Miao err = -ENOMEM; 1813ead8b5dSEric Miao goto err_free_mem; 1823ead8b5dSEric Miao } 1833ead8b5dSEric Miao 1843ead8b5dSEric Miao m->client = c; 1853ead8b5dSEric Miao m->idev = idev; 1863ead8b5dSEric Miao 1873ead8b5dSEric Miao idev->private = m; 1883ead8b5dSEric Miao idev->input->name = MMA8450_DRV_NAME; 1893ead8b5dSEric Miao idev->input->id.bustype = BUS_I2C; 1903ead8b5dSEric Miao idev->poll = mma8450_poll; 1913ead8b5dSEric Miao idev->poll_interval = POLL_INTERVAL; 1923ead8b5dSEric Miao idev->poll_interval_max = POLL_INTERVAL_MAX; 1933ead8b5dSEric Miao idev->open = mma8450_open; 1943ead8b5dSEric Miao idev->close = mma8450_close; 1953ead8b5dSEric Miao 1963ead8b5dSEric Miao __set_bit(EV_ABS, idev->input->evbit); 1973ead8b5dSEric Miao input_set_abs_params(idev->input, ABS_X, -2048, 2047, 32, 32); 1983ead8b5dSEric Miao input_set_abs_params(idev->input, ABS_Y, -2048, 2047, 32, 32); 1993ead8b5dSEric Miao input_set_abs_params(idev->input, ABS_Z, -2048, 2047, 32, 32); 2003ead8b5dSEric Miao 2013ead8b5dSEric Miao err = input_register_polled_device(idev); 2023ead8b5dSEric Miao if (err) { 2033ead8b5dSEric Miao dev_err(&c->dev, "failed to register polled input device\n"); 2043ead8b5dSEric Miao goto err_free_mem; 2053ead8b5dSEric Miao } 2063ead8b5dSEric Miao 2073ead8b5dSEric Miao return 0; 2083ead8b5dSEric Miao 2093ead8b5dSEric Miao err_free_mem: 2103ead8b5dSEric Miao input_free_polled_device(idev); 2113ead8b5dSEric Miao kfree(m); 2123ead8b5dSEric Miao return err; 2133ead8b5dSEric Miao } 2143ead8b5dSEric Miao 215e2619cf7SBill Pemberton static int mma8450_remove(struct i2c_client *c) 2163ead8b5dSEric Miao { 2173ead8b5dSEric Miao struct mma8450 *m = i2c_get_clientdata(c); 2183ead8b5dSEric Miao struct input_polled_dev *idev = m->idev; 2193ead8b5dSEric Miao 2203ead8b5dSEric Miao input_unregister_polled_device(idev); 2213ead8b5dSEric Miao input_free_polled_device(idev); 2223ead8b5dSEric Miao kfree(m); 2233ead8b5dSEric Miao 2243ead8b5dSEric Miao return 0; 2253ead8b5dSEric Miao } 2263ead8b5dSEric Miao 2273ead8b5dSEric Miao static const struct i2c_device_id mma8450_id[] = { 2283ead8b5dSEric Miao { MMA8450_DRV_NAME, 0 }, 2293ead8b5dSEric Miao { }, 2303ead8b5dSEric Miao }; 2313ead8b5dSEric Miao MODULE_DEVICE_TABLE(i2c, mma8450_id); 2323ead8b5dSEric Miao 23371ff069cSShawn Guo static const struct of_device_id mma8450_dt_ids[] = { 23471ff069cSShawn Guo { .compatible = "fsl,mma8450", }, 23571ff069cSShawn Guo { /* sentinel */ } 23671ff069cSShawn Guo }; 237cd566c64SAxel Lin MODULE_DEVICE_TABLE(of, mma8450_dt_ids); 23871ff069cSShawn Guo 2393ead8b5dSEric Miao static struct i2c_driver mma8450_driver = { 2403ead8b5dSEric Miao .driver = { 2413ead8b5dSEric Miao .name = MMA8450_DRV_NAME, 2423ead8b5dSEric Miao .owner = THIS_MODULE, 24371ff069cSShawn Guo .of_match_table = mma8450_dt_ids, 2443ead8b5dSEric Miao }, 2453ead8b5dSEric Miao .probe = mma8450_probe, 2461cb0aa88SBill Pemberton .remove = mma8450_remove, 2473ead8b5dSEric Miao .id_table = mma8450_id, 2483ead8b5dSEric Miao }; 2493ead8b5dSEric Miao 2501b92c1cfSAxel Lin module_i2c_driver(mma8450_driver); 2513ead8b5dSEric Miao 2523ead8b5dSEric Miao MODULE_AUTHOR("Freescale Semiconductor, Inc."); 2533ead8b5dSEric Miao MODULE_DESCRIPTION("MMA8450 3-Axis Accelerometer Driver"); 2543ead8b5dSEric Miao MODULE_LICENSE("GPL"); 255