cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

inv_mpu_i2c.c (6321B)


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