brintos

brintos / linux-shallow public Read only

0
0
Text · 6.3 KiB · 0e03137 Raw
285 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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_ICM20600:36	case INV_ICM20602:37	case INV_IAM20680:38		/* no i2c auxiliary bus on the chip */39		return false;40	case INV_MPU9150:41	case INV_MPU9250:42	case INV_MPU9255:43		if (st->magn_disabled)44			return true;45		else46			return false;47	default:48		return true;49	}50}51 52static int inv_mpu_i2c_aux_setup(struct iio_dev *indio_dev)53{54	struct inv_mpu6050_state *st = iio_priv(indio_dev);55	struct device *dev = indio_dev->dev.parent;56	struct fwnode_handle *mux_node;57	int ret;58 59	/*60	 * MPU9xxx magnetometer support requires to disable i2c auxiliary bus.61	 * To ensure backward compatibility with existing setups, do not disable62	 * i2c auxiliary bus if it used.63	 * Check for i2c-gate node in devicetree and set magnetometer disabled.64	 * Only MPU6500 is supported by ACPI, no need to check.65	 */66	switch (st->chip_type) {67	case INV_MPU9150:68	case INV_MPU9250:69	case INV_MPU9255:70		mux_node = device_get_named_child_node(dev, "i2c-gate");71		if (mux_node != NULL) {72			st->magn_disabled = true;73			dev_warn(dev, "disable internal use of magnetometer\n");74		}75		fwnode_handle_put(mux_node);76		break;77	default:78		break;79	}80 81	/* enable i2c bypass when using i2c auxiliary bus */82	if (inv_mpu_i2c_aux_bus(dev)) {83		ret = regmap_write(st->map, st->reg->int_pin_cfg,84				   st->irq_mask | INV_MPU6050_BIT_BYPASS_EN);85		if (ret)86			return ret;87	}88 89	return 0;90}91 92/**93 *  inv_mpu_probe() - probe function.94 *  @client:          i2c client.95 *96 *  Returns 0 on success, a negative error code otherwise.97 */98static int inv_mpu_probe(struct i2c_client *client)99{100	const struct i2c_device_id *id = i2c_client_get_device_id(client);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);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 void 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 171/*172 * device id table is used to identify what device can be173 * supported by this driver174 */175static const struct i2c_device_id inv_mpu_id[] = {176	{"mpu6050", INV_MPU6050},177	{"mpu6500", INV_MPU6500},178	{"mpu6515", INV_MPU6515},179	{"mpu6880", INV_MPU6880},180	{"mpu9150", INV_MPU9150},181	{"mpu9250", INV_MPU9250},182	{"mpu9255", INV_MPU9255},183	{"icm20608", INV_ICM20608},184	{"icm20608d", INV_ICM20608D},185	{"icm20609", INV_ICM20609},186	{"icm20689", INV_ICM20689},187	{"icm20600", INV_ICM20600},188	{"icm20602", INV_ICM20602},189	{"icm20690", INV_ICM20690},190	{"iam20680", INV_IAM20680},191	{}192};193 194MODULE_DEVICE_TABLE(i2c, inv_mpu_id);195 196static const struct of_device_id inv_of_match[] = {197	{198		.compatible = "invensense,mpu6050",199		.data = (void *)INV_MPU6050200	},201	{202		.compatible = "invensense,mpu6500",203		.data = (void *)INV_MPU6500204	},205	{206		.compatible = "invensense,mpu6515",207		.data = (void *)INV_MPU6515208	},209	{210		.compatible = "invensense,mpu6880",211		.data = (void *)INV_MPU6880212	},213	{214		.compatible = "invensense,mpu9150",215		.data = (void *)INV_MPU9150216	},217	{218		.compatible = "invensense,mpu9250",219		.data = (void *)INV_MPU9250220	},221	{222		.compatible = "invensense,mpu9255",223		.data = (void *)INV_MPU9255224	},225	{226		.compatible = "invensense,icm20608",227		.data = (void *)INV_ICM20608228	},229	{230		.compatible = "invensense,icm20608d",231		.data = (void *)INV_ICM20608D232	},233	{234		.compatible = "invensense,icm20609",235		.data = (void *)INV_ICM20609236	},237	{238		.compatible = "invensense,icm20689",239		.data = (void *)INV_ICM20689240	},241	{242		.compatible = "invensense,icm20600",243		.data = (void *)INV_ICM20600244	},245	{246		.compatible = "invensense,icm20602",247		.data = (void *)INV_ICM20602248	},249	{250		.compatible = "invensense,icm20690",251		.data = (void *)INV_ICM20690252	},253	{254		.compatible = "invensense,iam20680",255		.data = (void *)INV_IAM20680256	},257	{ }258};259MODULE_DEVICE_TABLE(of, inv_of_match);260 261static const struct acpi_device_id inv_acpi_match[] = {262	{"INVN6500", INV_MPU6500},263	{ },264};265MODULE_DEVICE_TABLE(acpi, inv_acpi_match);266 267static struct i2c_driver inv_mpu_driver = {268	.probe		=	inv_mpu_probe,269	.remove		=	inv_mpu_remove,270	.id_table	=	inv_mpu_id,271	.driver = {272		.of_match_table = inv_of_match,273		.acpi_match_table = inv_acpi_match,274		.name	=	"inv-mpu6050-i2c",275		.pm     =       pm_ptr(&inv_mpu_pmops),276	},277};278 279module_i2c_driver(inv_mpu_driver);280 281MODULE_AUTHOR("Invensense Corporation");282MODULE_DESCRIPTION("Invensense device MPU6050 driver");283MODULE_LICENSE("GPL");284MODULE_IMPORT_NS(IIO_MPU6050);285