Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * MXC6255 - MEMSIC orientation sensing accelerometer
0004  *
0005  * Copyright (c) 2015, Intel Corporation.
0006  *
0007  * IIO driver for MXC6255 (7-bit I2C slave address 0x15).
0008  */
0009 
0010 #include <linux/module.h>
0011 #include <linux/i2c.h>
0012 #include <linux/init.h>
0013 #include <linux/iio/iio.h>
0014 #include <linux/delay.h>
0015 #include <linux/acpi.h>
0016 #include <linux/regmap.h>
0017 #include <linux/iio/sysfs.h>
0018 
0019 #define MXC6255_DRV_NAME        "mxc6255"
0020 #define MXC6255_REGMAP_NAME     "mxc6255_regmap"
0021 
0022 #define MXC6255_REG_XOUT        0x00
0023 #define MXC6255_REG_YOUT        0x01
0024 #define MXC6255_REG_CHIP_ID     0x08
0025 
0026 #define MXC6255_CHIP_ID         0x05
0027 
0028 /*
0029  * MXC6255 has only one measurement range: +/- 2G.
0030  * The acceleration output is an 8-bit value.
0031  *
0032  * Scale is calculated as follows:
0033  * (2 + 2) * 9.80665 / (2^8 - 1) = 0.153829
0034  *
0035  * Scale value for +/- 2G measurement range
0036  */
0037 #define MXC6255_SCALE           153829
0038 
0039 enum mxc6255_axis {
0040     AXIS_X,
0041     AXIS_Y,
0042 };
0043 
0044 struct mxc6255_data {
0045     struct i2c_client *client;
0046     struct regmap *regmap;
0047 };
0048 
0049 static int mxc6255_read_raw(struct iio_dev *indio_dev,
0050                 struct iio_chan_spec const *chan,
0051                 int *val, int *val2, long mask)
0052 {
0053     struct mxc6255_data *data = iio_priv(indio_dev);
0054     unsigned int reg;
0055     int ret;
0056 
0057     switch (mask) {
0058     case IIO_CHAN_INFO_RAW:
0059         ret = regmap_read(data->regmap, chan->address, &reg);
0060         if (ret < 0) {
0061             dev_err(&data->client->dev,
0062                 "Error reading reg %lu\n", chan->address);
0063             return ret;
0064         }
0065 
0066         *val = sign_extend32(reg, 7);
0067         return IIO_VAL_INT;
0068     case IIO_CHAN_INFO_SCALE:
0069         *val = 0;
0070         *val2 = MXC6255_SCALE;
0071         return IIO_VAL_INT_PLUS_MICRO;
0072     default:
0073         return -EINVAL;
0074     }
0075 }
0076 
0077 static const struct iio_info mxc6255_info = {
0078     .read_raw   = mxc6255_read_raw,
0079 };
0080 
0081 #define MXC6255_CHANNEL(_axis, reg) {               \
0082     .type = IIO_ACCEL,                  \
0083     .modified = 1,                      \
0084     .channel2 = IIO_MOD_##_axis,                \
0085     .address = reg,                     \
0086     .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),       \
0087     .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),   \
0088 }
0089 
0090 static const struct iio_chan_spec mxc6255_channels[] = {
0091     MXC6255_CHANNEL(X, MXC6255_REG_XOUT),
0092     MXC6255_CHANNEL(Y, MXC6255_REG_YOUT),
0093 };
0094 
0095 static bool mxc6255_is_readable_reg(struct device *dev, unsigned int reg)
0096 {
0097     switch (reg) {
0098     case MXC6255_REG_XOUT:
0099     case MXC6255_REG_YOUT:
0100     case MXC6255_REG_CHIP_ID:
0101         return true;
0102     default:
0103         return false;
0104     }
0105 }
0106 
0107 static const struct regmap_config mxc6255_regmap_config = {
0108     .name = MXC6255_REGMAP_NAME,
0109 
0110     .reg_bits = 8,
0111     .val_bits = 8,
0112 
0113     .readable_reg = mxc6255_is_readable_reg,
0114 };
0115 
0116 static int mxc6255_probe(struct i2c_client *client,
0117              const struct i2c_device_id *id)
0118 {
0119     struct mxc6255_data *data;
0120     struct iio_dev *indio_dev;
0121     struct regmap *regmap;
0122     unsigned int chip_id;
0123     int ret;
0124 
0125     indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
0126     if (!indio_dev)
0127         return -ENOMEM;
0128 
0129     regmap = devm_regmap_init_i2c(client, &mxc6255_regmap_config);
0130     if (IS_ERR(regmap)) {
0131         dev_err(&client->dev, "Error initializing regmap\n");
0132         return PTR_ERR(regmap);
0133     }
0134 
0135     data = iio_priv(indio_dev);
0136     i2c_set_clientdata(client, indio_dev);
0137     data->client = client;
0138     data->regmap = regmap;
0139 
0140     indio_dev->name = MXC6255_DRV_NAME;
0141     indio_dev->channels = mxc6255_channels;
0142     indio_dev->num_channels = ARRAY_SIZE(mxc6255_channels);
0143     indio_dev->modes = INDIO_DIRECT_MODE;
0144     indio_dev->info = &mxc6255_info;
0145 
0146     ret = regmap_read(data->regmap, MXC6255_REG_CHIP_ID, &chip_id);
0147     if (ret < 0) {
0148         dev_err(&client->dev, "Error reading chip id %d\n", ret);
0149         return ret;
0150     }
0151 
0152     if ((chip_id & 0x1f) != MXC6255_CHIP_ID) {
0153         dev_err(&client->dev, "Invalid chip id %x\n", chip_id);
0154         return -ENODEV;
0155     }
0156 
0157     dev_dbg(&client->dev, "Chip id %x\n", chip_id);
0158 
0159     ret = devm_iio_device_register(&client->dev, indio_dev);
0160     if (ret < 0) {
0161         dev_err(&client->dev, "Could not register IIO device\n");
0162         return ret;
0163     }
0164 
0165     return 0;
0166 }
0167 
0168 static const struct acpi_device_id mxc6255_acpi_match[] = {
0169     {"MXC6225", 0},
0170     {"MXC6255", 0},
0171     { }
0172 };
0173 MODULE_DEVICE_TABLE(acpi, mxc6255_acpi_match);
0174 
0175 static const struct i2c_device_id mxc6255_id[] = {
0176     {"mxc6225", 0},
0177     {"mxc6255", 0},
0178     { }
0179 };
0180 MODULE_DEVICE_TABLE(i2c, mxc6255_id);
0181 
0182 static struct i2c_driver mxc6255_driver = {
0183     .driver = {
0184         .name = MXC6255_DRV_NAME,
0185         .acpi_match_table = ACPI_PTR(mxc6255_acpi_match),
0186     },
0187     .probe      = mxc6255_probe,
0188     .id_table   = mxc6255_id,
0189 };
0190 
0191 module_i2c_driver(mxc6255_driver);
0192 
0193 MODULE_AUTHOR("Teodora Baluta <teodora.baluta@intel.com>");
0194 MODULE_DESCRIPTION("MEMSIC MXC6255 orientation sensing accelerometer driver");
0195 MODULE_LICENSE("GPL v2");