Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v5.3-rc1 223 lines 4.9 kB view raw
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-polldev.h> 14#include <linux/of_device.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/* mma8450 status */ 43struct mma8450 { 44 struct i2c_client *client; 45 struct input_polled_dev *idev; 46}; 47 48static int mma8450_read(struct mma8450 *m, unsigned off) 49{ 50 struct i2c_client *c = m->client; 51 int ret; 52 53 ret = i2c_smbus_read_byte_data(c, off); 54 if (ret < 0) 55 dev_err(&c->dev, 56 "failed to read register 0x%02x, error %d\n", 57 off, ret); 58 59 return ret; 60} 61 62static int mma8450_write(struct mma8450 *m, unsigned off, u8 v) 63{ 64 struct i2c_client *c = m->client; 65 int error; 66 67 error = i2c_smbus_write_byte_data(c, off, v); 68 if (error < 0) { 69 dev_err(&c->dev, 70 "failed to write to register 0x%02x, error %d\n", 71 off, error); 72 return error; 73 } 74 75 return 0; 76} 77 78static int mma8450_read_block(struct mma8450 *m, unsigned off, 79 u8 *buf, size_t size) 80{ 81 struct i2c_client *c = m->client; 82 int err; 83 84 err = i2c_smbus_read_i2c_block_data(c, off, size, buf); 85 if (err < 0) { 86 dev_err(&c->dev, 87 "failed to read block data at 0x%02x, error %d\n", 88 MMA8450_OUT_X_LSB, err); 89 return err; 90 } 91 92 return 0; 93} 94 95static void mma8450_poll(struct input_polled_dev *dev) 96{ 97 struct mma8450 *m = dev->private; 98 int x, y, z; 99 int ret; 100 u8 buf[6]; 101 102 ret = mma8450_read(m, MMA8450_STATUS); 103 if (ret < 0) 104 return; 105 106 if (!(ret & MMA8450_STATUS_ZXYDR)) 107 return; 108 109 ret = mma8450_read_block(m, MMA8450_OUT_X_LSB, buf, sizeof(buf)); 110 if (ret < 0) 111 return; 112 113 x = ((int)(s8)buf[1] << 4) | (buf[0] & 0xf); 114 y = ((int)(s8)buf[3] << 4) | (buf[2] & 0xf); 115 z = ((int)(s8)buf[5] << 4) | (buf[4] & 0xf); 116 117 input_report_abs(dev->input, ABS_X, x); 118 input_report_abs(dev->input, ABS_Y, y); 119 input_report_abs(dev->input, ABS_Z, z); 120 input_sync(dev->input); 121} 122 123/* Initialize the MMA8450 chip */ 124static void mma8450_open(struct input_polled_dev *dev) 125{ 126 struct mma8450 *m = dev->private; 127 int err; 128 129 /* enable all events from X/Y/Z, no FIFO */ 130 err = mma8450_write(m, MMA8450_XYZ_DATA_CFG, 0x07); 131 if (err) 132 return; 133 134 /* 135 * Sleep mode poll rate - 50Hz 136 * System output data rate - 400Hz 137 * Full scale selection - Active, +/- 2G 138 */ 139 err = mma8450_write(m, MMA8450_CTRL_REG1, 0x01); 140 if (err < 0) 141 return; 142 143 msleep(MODE_CHANGE_DELAY_MS); 144} 145 146static void mma8450_close(struct input_polled_dev *dev) 147{ 148 struct mma8450 *m = dev->private; 149 150 mma8450_write(m, MMA8450_CTRL_REG1, 0x00); 151 mma8450_write(m, MMA8450_CTRL_REG2, 0x01); 152} 153 154/* 155 * I2C init/probing/exit functions 156 */ 157static int mma8450_probe(struct i2c_client *c, 158 const struct i2c_device_id *id) 159{ 160 struct input_polled_dev *idev; 161 struct mma8450 *m; 162 int err; 163 164 m = devm_kzalloc(&c->dev, sizeof(*m), GFP_KERNEL); 165 if (!m) 166 return -ENOMEM; 167 168 idev = devm_input_allocate_polled_device(&c->dev); 169 if (!idev) 170 return -ENOMEM; 171 172 m->client = c; 173 m->idev = idev; 174 175 idev->private = m; 176 idev->input->name = MMA8450_DRV_NAME; 177 idev->input->id.bustype = BUS_I2C; 178 idev->poll = mma8450_poll; 179 idev->poll_interval = POLL_INTERVAL; 180 idev->poll_interval_max = POLL_INTERVAL_MAX; 181 idev->open = mma8450_open; 182 idev->close = mma8450_close; 183 184 __set_bit(EV_ABS, idev->input->evbit); 185 input_set_abs_params(idev->input, ABS_X, -2048, 2047, 32, 32); 186 input_set_abs_params(idev->input, ABS_Y, -2048, 2047, 32, 32); 187 input_set_abs_params(idev->input, ABS_Z, -2048, 2047, 32, 32); 188 189 err = input_register_polled_device(idev); 190 if (err) { 191 dev_err(&c->dev, "failed to register polled input device\n"); 192 return err; 193 } 194 195 return 0; 196} 197 198static const struct i2c_device_id mma8450_id[] = { 199 { MMA8450_DRV_NAME, 0 }, 200 { }, 201}; 202MODULE_DEVICE_TABLE(i2c, mma8450_id); 203 204static const struct of_device_id mma8450_dt_ids[] = { 205 { .compatible = "fsl,mma8450", }, 206 { /* sentinel */ } 207}; 208MODULE_DEVICE_TABLE(of, mma8450_dt_ids); 209 210static struct i2c_driver mma8450_driver = { 211 .driver = { 212 .name = MMA8450_DRV_NAME, 213 .of_match_table = mma8450_dt_ids, 214 }, 215 .probe = mma8450_probe, 216 .id_table = mma8450_id, 217}; 218 219module_i2c_driver(mma8450_driver); 220 221MODULE_AUTHOR("Freescale Semiconductor, Inc."); 222MODULE_DESCRIPTION("MMA8450 3-Axis Accelerometer Driver"); 223MODULE_LICENSE("GPL");