xref: /openbmc/linux/drivers/iio/gyro/mpu3050-i2c.c (revision 3904b28e)
13904b28eSLinus Walleij #include <linux/err.h>
23904b28eSLinus Walleij #include <linux/i2c.h>
33904b28eSLinus Walleij #include <linux/i2c-mux.h>
43904b28eSLinus Walleij #include <linux/iio/iio.h>
53904b28eSLinus Walleij #include <linux/module.h>
63904b28eSLinus Walleij #include <linux/regmap.h>
73904b28eSLinus Walleij #include <linux/pm_runtime.h>
83904b28eSLinus Walleij 
93904b28eSLinus Walleij #include "mpu3050.h"
103904b28eSLinus Walleij 
113904b28eSLinus Walleij static const struct regmap_config mpu3050_i2c_regmap_config = {
123904b28eSLinus Walleij 	.reg_bits = 8,
133904b28eSLinus Walleij 	.val_bits = 8,
143904b28eSLinus Walleij };
153904b28eSLinus Walleij 
163904b28eSLinus Walleij static int mpu3050_i2c_bypass_select(struct i2c_mux_core *mux, u32 chan_id)
173904b28eSLinus Walleij {
183904b28eSLinus Walleij 	struct mpu3050 *mpu3050 = i2c_mux_priv(mux);
193904b28eSLinus Walleij 
203904b28eSLinus Walleij 	/* Just power up the device, that is all that is needed */
213904b28eSLinus Walleij 	pm_runtime_get_sync(mpu3050->dev);
223904b28eSLinus Walleij 	return 0;
233904b28eSLinus Walleij }
243904b28eSLinus Walleij 
253904b28eSLinus Walleij static int mpu3050_i2c_bypass_deselect(struct i2c_mux_core *mux, u32 chan_id)
263904b28eSLinus Walleij {
273904b28eSLinus Walleij 	struct mpu3050 *mpu3050 = i2c_mux_priv(mux);
283904b28eSLinus Walleij 
293904b28eSLinus Walleij 	pm_runtime_mark_last_busy(mpu3050->dev);
303904b28eSLinus Walleij 	pm_runtime_put_autosuspend(mpu3050->dev);
313904b28eSLinus Walleij 	return 0;
323904b28eSLinus Walleij }
333904b28eSLinus Walleij 
343904b28eSLinus Walleij static int mpu3050_i2c_probe(struct i2c_client *client,
353904b28eSLinus Walleij 			     const struct i2c_device_id *id)
363904b28eSLinus Walleij {
373904b28eSLinus Walleij 	struct regmap *regmap;
383904b28eSLinus Walleij 	const char *name;
393904b28eSLinus Walleij 	struct mpu3050 *mpu3050;
403904b28eSLinus Walleij 	int ret;
413904b28eSLinus Walleij 
423904b28eSLinus Walleij 	if (!i2c_check_functionality(client->adapter,
433904b28eSLinus Walleij 				     I2C_FUNC_SMBUS_I2C_BLOCK))
443904b28eSLinus Walleij 		return -EOPNOTSUPP;
453904b28eSLinus Walleij 
463904b28eSLinus Walleij 	if (id)
473904b28eSLinus Walleij 		name = id->name;
483904b28eSLinus Walleij 	else
493904b28eSLinus Walleij 		return -ENODEV;
503904b28eSLinus Walleij 
513904b28eSLinus Walleij 	regmap = devm_regmap_init_i2c(client, &mpu3050_i2c_regmap_config);
523904b28eSLinus Walleij 	if (IS_ERR(regmap)) {
533904b28eSLinus Walleij 		dev_err(&client->dev, "Failed to register i2c regmap %d\n",
543904b28eSLinus Walleij 			(int)PTR_ERR(regmap));
553904b28eSLinus Walleij 		return PTR_ERR(regmap);
563904b28eSLinus Walleij 	}
573904b28eSLinus Walleij 
583904b28eSLinus Walleij 	ret = mpu3050_common_probe(&client->dev, regmap, client->irq, name);
593904b28eSLinus Walleij 	if (ret)
603904b28eSLinus Walleij 		return ret;
613904b28eSLinus Walleij 
623904b28eSLinus Walleij 	/* The main driver is up, now register the I2C mux */
633904b28eSLinus Walleij 	mpu3050 = iio_priv(dev_get_drvdata(&client->dev));
643904b28eSLinus Walleij 	mpu3050->i2cmux = i2c_mux_alloc(client->adapter, &client->dev,
653904b28eSLinus Walleij 					1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE,
663904b28eSLinus Walleij 					mpu3050_i2c_bypass_select,
673904b28eSLinus Walleij 					mpu3050_i2c_bypass_deselect);
683904b28eSLinus Walleij 	/* Just fail the mux, there is no point in killing the driver */
693904b28eSLinus Walleij 	if (!mpu3050->i2cmux)
703904b28eSLinus Walleij 		dev_err(&client->dev, "failed to allocate I2C mux\n");
713904b28eSLinus Walleij 	else {
723904b28eSLinus Walleij 		mpu3050->i2cmux->priv = mpu3050;
733904b28eSLinus Walleij 		ret = i2c_mux_add_adapter(mpu3050->i2cmux, 0, 0, 0);
743904b28eSLinus Walleij 		if (ret)
753904b28eSLinus Walleij 			dev_err(&client->dev, "failed to add I2C mux\n");
763904b28eSLinus Walleij 	}
773904b28eSLinus Walleij 
783904b28eSLinus Walleij 	return 0;
793904b28eSLinus Walleij }
803904b28eSLinus Walleij 
813904b28eSLinus Walleij static int mpu3050_i2c_remove(struct i2c_client *client)
823904b28eSLinus Walleij {
833904b28eSLinus Walleij 	struct iio_dev *indio_dev = dev_get_drvdata(&client->dev);
843904b28eSLinus Walleij 	struct mpu3050 *mpu3050 = iio_priv(indio_dev);
853904b28eSLinus Walleij 
863904b28eSLinus Walleij 	if (mpu3050->i2cmux)
873904b28eSLinus Walleij 		i2c_mux_del_adapters(mpu3050->i2cmux);
883904b28eSLinus Walleij 
893904b28eSLinus Walleij 	return mpu3050_common_remove(&client->dev);
903904b28eSLinus Walleij }
913904b28eSLinus Walleij 
923904b28eSLinus Walleij /*
933904b28eSLinus Walleij  * device id table is used to identify what device can be
943904b28eSLinus Walleij  * supported by this driver
953904b28eSLinus Walleij  */
963904b28eSLinus Walleij static const struct i2c_device_id mpu3050_i2c_id[] = {
973904b28eSLinus Walleij 	{ "mpu3050" },
983904b28eSLinus Walleij 	{}
993904b28eSLinus Walleij };
1003904b28eSLinus Walleij MODULE_DEVICE_TABLE(i2c, mpu3050_i2c_id);
1013904b28eSLinus Walleij 
1023904b28eSLinus Walleij static const struct of_device_id mpu3050_i2c_of_match[] = {
1033904b28eSLinus Walleij 	{ .compatible = "invensense,mpu3050", .data = "mpu3050" },
1043904b28eSLinus Walleij 	/* Deprecated vendor ID from the Input driver */
1053904b28eSLinus Walleij 	{ .compatible = "invn,mpu3050", .data = "mpu3050" },
1063904b28eSLinus Walleij 	{ },
1073904b28eSLinus Walleij };
1083904b28eSLinus Walleij MODULE_DEVICE_TABLE(of, mpu3050_i2c_of_match);
1093904b28eSLinus Walleij 
1103904b28eSLinus Walleij static struct i2c_driver mpu3050_i2c_driver = {
1113904b28eSLinus Walleij 	.probe = mpu3050_i2c_probe,
1123904b28eSLinus Walleij 	.remove = mpu3050_i2c_remove,
1133904b28eSLinus Walleij 	.id_table = mpu3050_i2c_id,
1143904b28eSLinus Walleij 	.driver = {
1153904b28eSLinus Walleij 		.of_match_table = mpu3050_i2c_of_match,
1163904b28eSLinus Walleij 		.name = "mpu3050-i2c",
1173904b28eSLinus Walleij 		.pm = &mpu3050_dev_pm_ops,
1183904b28eSLinus Walleij 	},
1193904b28eSLinus Walleij };
1203904b28eSLinus Walleij module_i2c_driver(mpu3050_i2c_driver);
1213904b28eSLinus Walleij 
1223904b28eSLinus Walleij MODULE_AUTHOR("Linus Walleij");
1233904b28eSLinus Walleij MODULE_DESCRIPTION("Invensense MPU3050 gyroscope driver");
1243904b28eSLinus Walleij MODULE_LICENSE("GPL");
125