Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.13 298 lines 7.1 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Freescale MMA7660FC 3-Axis Accelerometer 4 * 5 * Copyright (c) 2016, Intel Corporation. 6 * 7 * IIO driver for Freescale MMA7660FC; 7-bit I2C address: 0x4c. 8 */ 9 10#include <linux/i2c.h> 11#include <linux/mod_devicetable.h> 12#include <linux/module.h> 13#include <linux/iio/iio.h> 14#include <linux/iio/sysfs.h> 15 16#define MMA7660_DRIVER_NAME "mma7660" 17 18#define MMA7660_REG_XOUT 0x00 19#define MMA7660_REG_YOUT 0x01 20#define MMA7660_REG_ZOUT 0x02 21#define MMA7660_REG_OUT_BIT_ALERT BIT(6) 22 23#define MMA7660_REG_MODE 0x07 24#define MMA7660_REG_MODE_BIT_MODE BIT(0) 25#define MMA7660_REG_MODE_BIT_TON BIT(2) 26 27#define MMA7660_I2C_READ_RETRIES 5 28 29/* 30 * The accelerometer has one measurement range: 31 * 32 * -1.5g - +1.5g (6-bit, signed) 33 * 34 * scale = (1.5 + 1.5) * 9.81 / (2^6 - 1) = 0.467142857 35 */ 36 37#define MMA7660_SCALE_AVAIL "0.467142857" 38 39static const int mma7660_nscale = 467142857; 40 41enum mma7660_mode { 42 MMA7660_MODE_STANDBY, 43 MMA7660_MODE_ACTIVE 44}; 45 46struct mma7660_data { 47 struct i2c_client *client; 48 struct mutex lock; 49 enum mma7660_mode mode; 50 struct iio_mount_matrix orientation; 51}; 52 53static const struct iio_mount_matrix * 54mma7660_get_mount_matrix(const struct iio_dev *indio_dev, 55 const struct iio_chan_spec *chan) 56{ 57 struct mma7660_data *data = iio_priv(indio_dev); 58 59 return &data->orientation; 60} 61 62static const struct iio_chan_spec_ext_info mma7660_ext_info[] = { 63 IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, mma7660_get_mount_matrix), 64 { } 65}; 66 67static IIO_CONST_ATTR(in_accel_scale_available, MMA7660_SCALE_AVAIL); 68 69static struct attribute *mma7660_attributes[] = { 70 &iio_const_attr_in_accel_scale_available.dev_attr.attr, 71 NULL, 72}; 73 74static const struct attribute_group mma7660_attribute_group = { 75 .attrs = mma7660_attributes 76}; 77 78#define MMA7660_CHANNEL(reg, axis) { \ 79 .type = IIO_ACCEL, \ 80 .address = reg, \ 81 .modified = 1, \ 82 .channel2 = IIO_MOD_##axis, \ 83 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 84 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 85 .ext_info = mma7660_ext_info, \ 86} 87 88static const struct iio_chan_spec mma7660_channels[] = { 89 MMA7660_CHANNEL(MMA7660_REG_XOUT, X), 90 MMA7660_CHANNEL(MMA7660_REG_YOUT, Y), 91 MMA7660_CHANNEL(MMA7660_REG_ZOUT, Z), 92}; 93 94static int mma7660_set_mode(struct mma7660_data *data, 95 enum mma7660_mode mode) 96{ 97 int ret; 98 struct i2c_client *client = data->client; 99 100 if (mode == data->mode) 101 return 0; 102 103 ret = i2c_smbus_read_byte_data(client, MMA7660_REG_MODE); 104 if (ret < 0) { 105 dev_err(&client->dev, "failed to read sensor mode\n"); 106 return ret; 107 } 108 109 if (mode == MMA7660_MODE_ACTIVE) { 110 ret &= ~MMA7660_REG_MODE_BIT_TON; 111 ret |= MMA7660_REG_MODE_BIT_MODE; 112 } else { 113 ret &= ~MMA7660_REG_MODE_BIT_TON; 114 ret &= ~MMA7660_REG_MODE_BIT_MODE; 115 } 116 117 ret = i2c_smbus_write_byte_data(client, MMA7660_REG_MODE, ret); 118 if (ret < 0) { 119 dev_err(&client->dev, "failed to change sensor mode\n"); 120 return ret; 121 } 122 123 data->mode = mode; 124 125 return ret; 126} 127 128static int mma7660_read_accel(struct mma7660_data *data, u8 address) 129{ 130 int ret, retries = MMA7660_I2C_READ_RETRIES; 131 struct i2c_client *client = data->client; 132 133 /* 134 * Read data. If the Alert bit is set, the register was read at 135 * the same time as the device was attempting to update the content. 136 * The solution is to read the register again. Do this only 137 * MMA7660_I2C_READ_RETRIES times to avoid spending too much time 138 * in the kernel. 139 */ 140 do { 141 ret = i2c_smbus_read_byte_data(client, address); 142 if (ret < 0) { 143 dev_err(&client->dev, "register read failed\n"); 144 return ret; 145 } 146 } while (retries-- > 0 && ret & MMA7660_REG_OUT_BIT_ALERT); 147 148 if (ret & MMA7660_REG_OUT_BIT_ALERT) { 149 dev_err(&client->dev, "all register read retries failed\n"); 150 return -ETIMEDOUT; 151 } 152 153 return ret; 154} 155 156static int mma7660_read_raw(struct iio_dev *indio_dev, 157 struct iio_chan_spec const *chan, 158 int *val, int *val2, long mask) 159{ 160 struct mma7660_data *data = iio_priv(indio_dev); 161 int ret; 162 163 switch (mask) { 164 case IIO_CHAN_INFO_RAW: 165 mutex_lock(&data->lock); 166 ret = mma7660_read_accel(data, chan->address); 167 mutex_unlock(&data->lock); 168 if (ret < 0) 169 return ret; 170 *val = sign_extend32(ret, 5); 171 return IIO_VAL_INT; 172 case IIO_CHAN_INFO_SCALE: 173 *val = 0; 174 *val2 = mma7660_nscale; 175 return IIO_VAL_INT_PLUS_NANO; 176 default: 177 return -EINVAL; 178 } 179 180 return -EINVAL; 181} 182 183static const struct iio_info mma7660_info = { 184 .read_raw = mma7660_read_raw, 185 .attrs = &mma7660_attribute_group, 186}; 187 188static int mma7660_probe(struct i2c_client *client) 189{ 190 int ret; 191 struct iio_dev *indio_dev; 192 struct mma7660_data *data; 193 194 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 195 if (!indio_dev) { 196 dev_err(&client->dev, "iio allocation failed!\n"); 197 return -ENOMEM; 198 } 199 200 data = iio_priv(indio_dev); 201 data->client = client; 202 i2c_set_clientdata(client, indio_dev); 203 mutex_init(&data->lock); 204 data->mode = MMA7660_MODE_STANDBY; 205 206 ret = iio_read_mount_matrix(&client->dev, &data->orientation); 207 if (ret) 208 return ret; 209 210 indio_dev->info = &mma7660_info; 211 indio_dev->name = MMA7660_DRIVER_NAME; 212 indio_dev->modes = INDIO_DIRECT_MODE; 213 indio_dev->channels = mma7660_channels; 214 indio_dev->num_channels = ARRAY_SIZE(mma7660_channels); 215 216 ret = mma7660_set_mode(data, MMA7660_MODE_ACTIVE); 217 if (ret < 0) 218 return ret; 219 220 ret = iio_device_register(indio_dev); 221 if (ret < 0) { 222 dev_err(&client->dev, "device_register failed\n"); 223 mma7660_set_mode(data, MMA7660_MODE_STANDBY); 224 } 225 226 return ret; 227} 228 229static void mma7660_remove(struct i2c_client *client) 230{ 231 struct iio_dev *indio_dev = i2c_get_clientdata(client); 232 int ret; 233 234 iio_device_unregister(indio_dev); 235 236 ret = mma7660_set_mode(iio_priv(indio_dev), MMA7660_MODE_STANDBY); 237 if (ret) 238 dev_warn(&client->dev, "Failed to put device in stand-by mode (%pe), ignoring\n", 239 ERR_PTR(ret)); 240} 241 242static int mma7660_suspend(struct device *dev) 243{ 244 struct mma7660_data *data; 245 246 data = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); 247 248 return mma7660_set_mode(data, MMA7660_MODE_STANDBY); 249} 250 251static int mma7660_resume(struct device *dev) 252{ 253 struct mma7660_data *data; 254 255 data = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); 256 257 return mma7660_set_mode(data, MMA7660_MODE_ACTIVE); 258} 259 260static DEFINE_SIMPLE_DEV_PM_OPS(mma7660_pm_ops, mma7660_suspend, 261 mma7660_resume); 262 263static const struct i2c_device_id mma7660_i2c_id[] = { 264 { "mma7660" }, 265 {} 266}; 267MODULE_DEVICE_TABLE(i2c, mma7660_i2c_id); 268 269static const struct of_device_id mma7660_of_match[] = { 270 { .compatible = "fsl,mma7660" }, 271 { } 272}; 273MODULE_DEVICE_TABLE(of, mma7660_of_match); 274 275static const struct acpi_device_id mma7660_acpi_id[] = { 276 {"MMA7660", 0}, 277 {} 278}; 279 280MODULE_DEVICE_TABLE(acpi, mma7660_acpi_id); 281 282static struct i2c_driver mma7660_driver = { 283 .driver = { 284 .name = "mma7660", 285 .pm = pm_sleep_ptr(&mma7660_pm_ops), 286 .of_match_table = mma7660_of_match, 287 .acpi_match_table = mma7660_acpi_id, 288 }, 289 .probe = mma7660_probe, 290 .remove = mma7660_remove, 291 .id_table = mma7660_i2c_id, 292}; 293 294module_i2c_driver(mma7660_driver); 295 296MODULE_AUTHOR("Constantin Musca <constantin.musca@intel.com>"); 297MODULE_DESCRIPTION("Freescale MMA7660FC 3-Axis Accelerometer driver"); 298MODULE_LICENSE("GPL v2");