174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 23ead8b5dSEric Miao /* 33ead8b5dSEric Miao * Driver for Freescale's 3-Axis Accelerometer MMA8450 43ead8b5dSEric Miao * 53ead8b5dSEric Miao * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. 63ead8b5dSEric Miao */ 73ead8b5dSEric Miao 83ead8b5dSEric Miao #include <linux/kernel.h> 93ead8b5dSEric Miao #include <linux/module.h> 103ead8b5dSEric Miao #include <linux/slab.h> 113ead8b5dSEric Miao #include <linux/delay.h> 123ead8b5dSEric Miao #include <linux/i2c.h> 133ead8b5dSEric Miao #include <linux/input-polldev.h> 1471ff069cSShawn Guo #include <linux/of_device.h> 153ead8b5dSEric Miao 163ead8b5dSEric Miao #define MMA8450_DRV_NAME "mma8450" 173ead8b5dSEric Miao 183ead8b5dSEric Miao #define MODE_CHANGE_DELAY_MS 100 193ead8b5dSEric Miao #define POLL_INTERVAL 100 203ead8b5dSEric Miao #define POLL_INTERVAL_MAX 500 213ead8b5dSEric Miao 223ead8b5dSEric Miao /* register definitions */ 233ead8b5dSEric Miao #define MMA8450_STATUS 0x00 243ead8b5dSEric Miao #define MMA8450_STATUS_ZXYDR 0x08 253ead8b5dSEric Miao 263ead8b5dSEric Miao #define MMA8450_OUT_X8 0x01 273ead8b5dSEric Miao #define MMA8450_OUT_Y8 0x02 283ead8b5dSEric Miao #define MMA8450_OUT_Z8 0x03 293ead8b5dSEric Miao 303ead8b5dSEric Miao #define MMA8450_OUT_X_LSB 0x05 313ead8b5dSEric Miao #define MMA8450_OUT_X_MSB 0x06 323ead8b5dSEric Miao #define MMA8450_OUT_Y_LSB 0x07 333ead8b5dSEric Miao #define MMA8450_OUT_Y_MSB 0x08 343ead8b5dSEric Miao #define MMA8450_OUT_Z_LSB 0x09 353ead8b5dSEric Miao #define MMA8450_OUT_Z_MSB 0x0a 363ead8b5dSEric Miao 373ead8b5dSEric Miao #define MMA8450_XYZ_DATA_CFG 0x16 383ead8b5dSEric Miao 393ead8b5dSEric Miao #define MMA8450_CTRL_REG1 0x38 403ead8b5dSEric Miao #define MMA8450_CTRL_REG2 0x39 413ead8b5dSEric Miao 423ead8b5dSEric Miao /* mma8450 status */ 433ead8b5dSEric Miao struct mma8450 { 443ead8b5dSEric Miao struct i2c_client *client; 453ead8b5dSEric Miao struct input_polled_dev *idev; 463ead8b5dSEric Miao }; 473ead8b5dSEric Miao 483ead8b5dSEric Miao static int mma8450_read(struct mma8450 *m, unsigned off) 493ead8b5dSEric Miao { 503ead8b5dSEric Miao struct i2c_client *c = m->client; 513ead8b5dSEric Miao int ret; 523ead8b5dSEric Miao 533ead8b5dSEric Miao ret = i2c_smbus_read_byte_data(c, off); 543ead8b5dSEric Miao if (ret < 0) 553ead8b5dSEric Miao dev_err(&c->dev, 563ead8b5dSEric Miao "failed to read register 0x%02x, error %d\n", 573ead8b5dSEric Miao off, ret); 583ead8b5dSEric Miao 593ead8b5dSEric Miao return ret; 603ead8b5dSEric Miao } 613ead8b5dSEric Miao 623ead8b5dSEric Miao static int mma8450_write(struct mma8450 *m, unsigned off, u8 v) 633ead8b5dSEric Miao { 643ead8b5dSEric Miao struct i2c_client *c = m->client; 653ead8b5dSEric Miao int error; 663ead8b5dSEric Miao 673ead8b5dSEric Miao error = i2c_smbus_write_byte_data(c, off, v); 683ead8b5dSEric Miao if (error < 0) { 693ead8b5dSEric Miao dev_err(&c->dev, 703ead8b5dSEric Miao "failed to write to register 0x%02x, error %d\n", 713ead8b5dSEric Miao off, error); 723ead8b5dSEric Miao return error; 733ead8b5dSEric Miao } 743ead8b5dSEric Miao 753ead8b5dSEric Miao return 0; 763ead8b5dSEric Miao } 773ead8b5dSEric Miao 78cb31f898SDmitry Torokhov static int mma8450_read_block(struct mma8450 *m, unsigned off, 79cb31f898SDmitry Torokhov u8 *buf, size_t size) 803ead8b5dSEric Miao { 813ead8b5dSEric Miao struct i2c_client *c = m->client; 823ead8b5dSEric Miao int err; 833ead8b5dSEric Miao 84cb31f898SDmitry Torokhov err = i2c_smbus_read_i2c_block_data(c, off, size, buf); 853ead8b5dSEric Miao if (err < 0) { 863ead8b5dSEric Miao dev_err(&c->dev, 873ead8b5dSEric Miao "failed to read block data at 0x%02x, error %d\n", 883ead8b5dSEric Miao MMA8450_OUT_X_LSB, err); 893ead8b5dSEric Miao return err; 903ead8b5dSEric Miao } 913ead8b5dSEric Miao 923ead8b5dSEric Miao return 0; 933ead8b5dSEric Miao } 943ead8b5dSEric Miao 953ead8b5dSEric Miao static void mma8450_poll(struct input_polled_dev *dev) 963ead8b5dSEric Miao { 973ead8b5dSEric Miao struct mma8450 *m = dev->private; 983ead8b5dSEric Miao int x, y, z; 993ead8b5dSEric Miao int ret; 100cb31f898SDmitry Torokhov u8 buf[6]; 1013ead8b5dSEric Miao 1023ead8b5dSEric Miao ret = mma8450_read(m, MMA8450_STATUS); 1033ead8b5dSEric Miao if (ret < 0) 1043ead8b5dSEric Miao return; 1053ead8b5dSEric Miao 1063ead8b5dSEric Miao if (!(ret & MMA8450_STATUS_ZXYDR)) 1073ead8b5dSEric Miao return; 1083ead8b5dSEric Miao 109cb31f898SDmitry Torokhov ret = mma8450_read_block(m, MMA8450_OUT_X_LSB, buf, sizeof(buf)); 110cb31f898SDmitry Torokhov if (ret < 0) 1113ead8b5dSEric Miao return; 1123ead8b5dSEric Miao 113257a1ec6SSebastien Royen x = ((int)(s8)buf[1] << 4) | (buf[0] & 0xf); 114257a1ec6SSebastien Royen y = ((int)(s8)buf[3] << 4) | (buf[2] & 0xf); 115257a1ec6SSebastien Royen z = ((int)(s8)buf[5] << 4) | (buf[4] & 0xf); 116cb31f898SDmitry Torokhov 1173ead8b5dSEric Miao input_report_abs(dev->input, ABS_X, x); 1183ead8b5dSEric Miao input_report_abs(dev->input, ABS_Y, y); 1193ead8b5dSEric Miao input_report_abs(dev->input, ABS_Z, z); 1203ead8b5dSEric Miao input_sync(dev->input); 1213ead8b5dSEric Miao } 1223ead8b5dSEric Miao 1233ead8b5dSEric Miao /* Initialize the MMA8450 chip */ 1243ead8b5dSEric Miao static void mma8450_open(struct input_polled_dev *dev) 1253ead8b5dSEric Miao { 1263ead8b5dSEric Miao struct mma8450 *m = dev->private; 1273ead8b5dSEric Miao int err; 1283ead8b5dSEric Miao 1293ead8b5dSEric Miao /* enable all events from X/Y/Z, no FIFO */ 1303ead8b5dSEric Miao err = mma8450_write(m, MMA8450_XYZ_DATA_CFG, 0x07); 1313ead8b5dSEric Miao if (err) 1323ead8b5dSEric Miao return; 1333ead8b5dSEric Miao 1343ead8b5dSEric Miao /* 1353ead8b5dSEric Miao * Sleep mode poll rate - 50Hz 1363ead8b5dSEric Miao * System output data rate - 400Hz 1373ead8b5dSEric Miao * Full scale selection - Active, +/- 2G 1383ead8b5dSEric Miao */ 1393ead8b5dSEric Miao err = mma8450_write(m, MMA8450_CTRL_REG1, 0x01); 1403ead8b5dSEric Miao if (err < 0) 1413ead8b5dSEric Miao return; 1423ead8b5dSEric Miao 1433ead8b5dSEric Miao msleep(MODE_CHANGE_DELAY_MS); 1443ead8b5dSEric Miao } 1453ead8b5dSEric Miao 1463ead8b5dSEric Miao static void mma8450_close(struct input_polled_dev *dev) 1473ead8b5dSEric Miao { 1483ead8b5dSEric Miao struct mma8450 *m = dev->private; 1493ead8b5dSEric Miao 1503ead8b5dSEric Miao mma8450_write(m, MMA8450_CTRL_REG1, 0x00); 1513ead8b5dSEric Miao mma8450_write(m, MMA8450_CTRL_REG2, 0x01); 1523ead8b5dSEric Miao } 1533ead8b5dSEric Miao 1543ead8b5dSEric Miao /* 1553ead8b5dSEric Miao * I2C init/probing/exit functions 1563ead8b5dSEric Miao */ 1575298cc4cSBill Pemberton static int mma8450_probe(struct i2c_client *c, 1583ead8b5dSEric Miao const struct i2c_device_id *id) 1593ead8b5dSEric Miao { 1603ead8b5dSEric Miao struct input_polled_dev *idev; 1613ead8b5dSEric Miao struct mma8450 *m; 1623ead8b5dSEric Miao int err; 1633ead8b5dSEric Miao 1645037a179SDmitry Torokhov m = devm_kzalloc(&c->dev, sizeof(*m), GFP_KERNEL); 1655037a179SDmitry Torokhov if (!m) 1665037a179SDmitry Torokhov return -ENOMEM; 1675037a179SDmitry Torokhov 1685037a179SDmitry Torokhov idev = devm_input_allocate_polled_device(&c->dev); 1695037a179SDmitry Torokhov if (!idev) 1705037a179SDmitry Torokhov return -ENOMEM; 1713ead8b5dSEric Miao 1723ead8b5dSEric Miao m->client = c; 1733ead8b5dSEric Miao m->idev = idev; 1743ead8b5dSEric Miao 1753ead8b5dSEric Miao idev->private = m; 1763ead8b5dSEric Miao idev->input->name = MMA8450_DRV_NAME; 1773ead8b5dSEric Miao idev->input->id.bustype = BUS_I2C; 1783ead8b5dSEric Miao idev->poll = mma8450_poll; 1793ead8b5dSEric Miao idev->poll_interval = POLL_INTERVAL; 1803ead8b5dSEric Miao idev->poll_interval_max = POLL_INTERVAL_MAX; 1813ead8b5dSEric Miao idev->open = mma8450_open; 1823ead8b5dSEric Miao idev->close = mma8450_close; 1833ead8b5dSEric Miao 1843ead8b5dSEric Miao __set_bit(EV_ABS, idev->input->evbit); 1853ead8b5dSEric Miao input_set_abs_params(idev->input, ABS_X, -2048, 2047, 32, 32); 1863ead8b5dSEric Miao input_set_abs_params(idev->input, ABS_Y, -2048, 2047, 32, 32); 1873ead8b5dSEric Miao input_set_abs_params(idev->input, ABS_Z, -2048, 2047, 32, 32); 1883ead8b5dSEric Miao 1893ead8b5dSEric Miao err = input_register_polled_device(idev); 1903ead8b5dSEric Miao if (err) { 1913ead8b5dSEric Miao dev_err(&c->dev, "failed to register polled input device\n"); 1923ead8b5dSEric Miao return err; 1933ead8b5dSEric Miao } 1943ead8b5dSEric Miao 1953ead8b5dSEric Miao return 0; 1963ead8b5dSEric Miao } 1973ead8b5dSEric Miao 1983ead8b5dSEric Miao static const struct i2c_device_id mma8450_id[] = { 1993ead8b5dSEric Miao { MMA8450_DRV_NAME, 0 }, 2003ead8b5dSEric Miao { }, 2013ead8b5dSEric Miao }; 2023ead8b5dSEric Miao MODULE_DEVICE_TABLE(i2c, mma8450_id); 2033ead8b5dSEric Miao 20471ff069cSShawn Guo static const struct of_device_id mma8450_dt_ids[] = { 20571ff069cSShawn Guo { .compatible = "fsl,mma8450", }, 20671ff069cSShawn Guo { /* sentinel */ } 20771ff069cSShawn Guo }; 208cd566c64SAxel Lin MODULE_DEVICE_TABLE(of, mma8450_dt_ids); 20971ff069cSShawn Guo 2103ead8b5dSEric Miao static struct i2c_driver mma8450_driver = { 2113ead8b5dSEric Miao .driver = { 2123ead8b5dSEric Miao .name = MMA8450_DRV_NAME, 21371ff069cSShawn Guo .of_match_table = mma8450_dt_ids, 2143ead8b5dSEric Miao }, 2153ead8b5dSEric Miao .probe = mma8450_probe, 2163ead8b5dSEric Miao .id_table = mma8450_id, 2173ead8b5dSEric Miao }; 2183ead8b5dSEric Miao 2191b92c1cfSAxel Lin module_i2c_driver(mma8450_driver); 2203ead8b5dSEric Miao 2213ead8b5dSEric Miao MODULE_AUTHOR("Freescale Semiconductor, Inc."); 2223ead8b5dSEric Miao MODULE_DESCRIPTION("MMA8450 3-Axis Accelerometer Driver"); 2233ead8b5dSEric Miao MODULE_LICENSE("GPL"); 224