linux/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3* Copyright (C) 2012 Invensense, Inc.
   4*/
   5
   6#include <linux/acpi.h>
   7#include <linux/delay.h>
   8#include <linux/err.h>
   9#include <linux/i2c.h>
  10#include <linux/iio/iio.h>
  11#include <linux/module.h>
  12#include <linux/of_device.h>
  13#include <linux/property.h>
  14#include "inv_mpu_iio.h"
  15
  16static const struct regmap_config inv_mpu_regmap_config = {
  17        .reg_bits = 8,
  18        .val_bits = 8,
  19};
  20
  21static int inv_mpu6050_select_bypass(struct i2c_mux_core *muxc, u32 chan_id)
  22{
  23        return 0;
  24}
  25
  26static bool inv_mpu_i2c_aux_bus(struct device *dev)
  27{
  28        struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev));
  29
  30        switch (st->chip_type) {
  31        case INV_ICM20608:
  32        case INV_ICM20609:
  33        case INV_ICM20689:
  34        case INV_ICM20602:
  35        case INV_IAM20680:
  36                /* no i2c auxiliary bus on the chip */
  37                return false;
  38        case INV_MPU9150:
  39        case INV_MPU9250:
  40        case INV_MPU9255:
  41                if (st->magn_disabled)
  42                        return true;
  43                else
  44                        return false;
  45        default:
  46                return true;
  47        }
  48}
  49
  50static int inv_mpu_i2c_aux_setup(struct iio_dev *indio_dev)
  51{
  52        struct inv_mpu6050_state *st = iio_priv(indio_dev);
  53        struct device *dev = indio_dev->dev.parent;
  54        struct device_node *mux_node;
  55        int ret;
  56
  57        /*
  58         * MPU9xxx magnetometer support requires to disable i2c auxiliary bus.
  59         * To ensure backward compatibility with existing setups, do not disable
  60         * i2c auxiliary bus if it used.
  61         * Check for i2c-gate node in devicetree and set magnetometer disabled.
  62         * Only MPU6500 is supported by ACPI, no need to check.
  63         */
  64        switch (st->chip_type) {
  65        case INV_MPU9150:
  66        case INV_MPU9250:
  67        case INV_MPU9255:
  68                mux_node = of_get_child_by_name(dev->of_node, "i2c-gate");
  69                if (mux_node != NULL) {
  70                        st->magn_disabled = true;
  71                        dev_warn(dev, "disable internal use of magnetometer\n");
  72                }
  73                of_node_put(mux_node);
  74                break;
  75        default:
  76                break;
  77        }
  78
  79        /* enable i2c bypass when using i2c auxiliary bus */
  80        if (inv_mpu_i2c_aux_bus(dev)) {
  81                ret = regmap_write(st->map, st->reg->int_pin_cfg,
  82                                   st->irq_mask | INV_MPU6050_BIT_BYPASS_EN);
  83                if (ret)
  84                        return ret;
  85        }
  86
  87        return 0;
  88}
  89
  90/**
  91 *  inv_mpu_probe() - probe function.
  92 *  @client:          i2c client.
  93 *  @id:              i2c device id.
  94 *
  95 *  Returns 0 on success, a negative error code otherwise.
  96 */
  97static int inv_mpu_probe(struct i2c_client *client,
  98                         const struct i2c_device_id *id)
  99{
 100        const void *match;
 101        struct inv_mpu6050_state *st;
 102        int result;
 103        enum inv_devices chip_type;
 104        struct regmap *regmap;
 105        const char *name;
 106
 107        if (!i2c_check_functionality(client->adapter,
 108                                     I2C_FUNC_SMBUS_I2C_BLOCK))
 109                return -EOPNOTSUPP;
 110
 111        match = device_get_match_data(&client->dev);
 112        if (match) {
 113                chip_type = (uintptr_t)match;
 114                name = client->name;
 115        } else if (id) {
 116                chip_type = (enum inv_devices)
 117                        id->driver_data;
 118                name = id->name;
 119        } else {
 120                return -ENOSYS;
 121        }
 122
 123        regmap = devm_regmap_init_i2c(client, &inv_mpu_regmap_config);
 124        if (IS_ERR(regmap)) {
 125                dev_err(&client->dev, "Failed to register i2c regmap: %pe\n",
 126                        regmap);
 127                return PTR_ERR(regmap);
 128        }
 129
 130        result = inv_mpu_core_probe(regmap, client->irq, name,
 131                                    inv_mpu_i2c_aux_setup, chip_type);
 132        if (result < 0)
 133                return result;
 134
 135        st = iio_priv(dev_get_drvdata(&client->dev));
 136        if (inv_mpu_i2c_aux_bus(&client->dev)) {
 137                /* declare i2c auxiliary bus */
 138                st->muxc = i2c_mux_alloc(client->adapter, &client->dev,
 139                                         1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE,
 140                                         inv_mpu6050_select_bypass, NULL);
 141                if (!st->muxc)
 142                        return -ENOMEM;
 143                st->muxc->priv = dev_get_drvdata(&client->dev);
 144                result = i2c_mux_add_adapter(st->muxc, 0, 0, 0);
 145                if (result)
 146                        return result;
 147                result = inv_mpu_acpi_create_mux_client(client);
 148                if (result)
 149                        goto out_del_mux;
 150        }
 151
 152        return 0;
 153
 154out_del_mux:
 155        i2c_mux_del_adapters(st->muxc);
 156        return result;
 157}
 158
 159static int inv_mpu_remove(struct i2c_client *client)
 160{
 161        struct iio_dev *indio_dev = i2c_get_clientdata(client);
 162        struct inv_mpu6050_state *st = iio_priv(indio_dev);
 163
 164        if (st->muxc) {
 165                inv_mpu_acpi_delete_mux_client(client);
 166                i2c_mux_del_adapters(st->muxc);
 167        }
 168
 169        return 0;
 170}
 171
 172/*
 173 * device id table is used to identify what device can be
 174 * supported by this driver
 175 */
 176static const struct i2c_device_id inv_mpu_id[] = {
 177        {"mpu6050", INV_MPU6050},
 178        {"mpu6500", INV_MPU6500},
 179        {"mpu6515", INV_MPU6515},
 180        {"mpu6880", INV_MPU6880},
 181        {"mpu9150", INV_MPU9150},
 182        {"mpu9250", INV_MPU9250},
 183        {"mpu9255", INV_MPU9255},
 184        {"icm20608", INV_ICM20608},
 185        {"icm20609", INV_ICM20609},
 186        {"icm20689", INV_ICM20689},
 187        {"icm20602", INV_ICM20602},
 188        {"icm20690", INV_ICM20690},
 189        {"iam20680", INV_IAM20680},
 190        {}
 191};
 192
 193MODULE_DEVICE_TABLE(i2c, inv_mpu_id);
 194
 195static const struct of_device_id inv_of_match[] = {
 196        {
 197                .compatible = "invensense,mpu6050",
 198                .data = (void *)INV_MPU6050
 199        },
 200        {
 201                .compatible = "invensense,mpu6500",
 202                .data = (void *)INV_MPU6500
 203        },
 204        {
 205                .compatible = "invensense,mpu6515",
 206                .data = (void *)INV_MPU6515
 207        },
 208        {
 209                .compatible = "invensense,mpu6880",
 210                .data = (void *)INV_MPU6880
 211        },
 212        {
 213                .compatible = "invensense,mpu9150",
 214                .data = (void *)INV_MPU9150
 215        },
 216        {
 217                .compatible = "invensense,mpu9250",
 218                .data = (void *)INV_MPU9250
 219        },
 220        {
 221                .compatible = "invensense,mpu9255",
 222                .data = (void *)INV_MPU9255
 223        },
 224        {
 225                .compatible = "invensense,icm20608",
 226                .data = (void *)INV_ICM20608
 227        },
 228        {
 229                .compatible = "invensense,icm20609",
 230                .data = (void *)INV_ICM20609
 231        },
 232        {
 233                .compatible = "invensense,icm20689",
 234                .data = (void *)INV_ICM20689
 235        },
 236        {
 237                .compatible = "invensense,icm20602",
 238                .data = (void *)INV_ICM20602
 239        },
 240        {
 241                .compatible = "invensense,icm20690",
 242                .data = (void *)INV_ICM20690
 243        },
 244        {
 245                .compatible = "invensense,iam20680",
 246                .data = (void *)INV_IAM20680
 247        },
 248        { }
 249};
 250MODULE_DEVICE_TABLE(of, inv_of_match);
 251
 252static const struct acpi_device_id __maybe_unused inv_acpi_match[] = {
 253        {"INVN6500", INV_MPU6500},
 254        { },
 255};
 256
 257MODULE_DEVICE_TABLE(acpi, inv_acpi_match);
 258
 259static struct i2c_driver inv_mpu_driver = {
 260        .probe          =       inv_mpu_probe,
 261        .remove         =       inv_mpu_remove,
 262        .id_table       =       inv_mpu_id,
 263        .driver = {
 264                .of_match_table = inv_of_match,
 265                .acpi_match_table = ACPI_PTR(inv_acpi_match),
 266                .name   =       "inv-mpu6050-i2c",
 267                .pm     =       &inv_mpu_pmops,
 268        },
 269};
 270
 271module_i2c_driver(inv_mpu_driver);
 272
 273MODULE_AUTHOR("Invensense Corporation");
 274MODULE_DESCRIPTION("Invensense device MPU6050 driver");
 275MODULE_LICENSE("GPL");
 276