xref: /openbmc/linux/drivers/iio/gyro/mpu3050-i2c.c (revision 6a95d825)
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;
736a95d825SPeter Rosin 		/* Ignore failure, not critical */
746a95d825SPeter Rosin 		i2c_mux_add_adapter(mpu3050->i2cmux, 0, 0, 0);
753904b28eSLinus Walleij 	}
763904b28eSLinus Walleij 
773904b28eSLinus Walleij 	return 0;
783904b28eSLinus Walleij }
793904b28eSLinus Walleij 
803904b28eSLinus Walleij static int mpu3050_i2c_remove(struct i2c_client *client)
813904b28eSLinus Walleij {
823904b28eSLinus Walleij 	struct iio_dev *indio_dev = dev_get_drvdata(&client->dev);
833904b28eSLinus Walleij 	struct mpu3050 *mpu3050 = iio_priv(indio_dev);
843904b28eSLinus Walleij 
853904b28eSLinus Walleij 	if (mpu3050->i2cmux)
863904b28eSLinus Walleij 		i2c_mux_del_adapters(mpu3050->i2cmux);
873904b28eSLinus Walleij 
883904b28eSLinus Walleij 	return mpu3050_common_remove(&client->dev);
893904b28eSLinus Walleij }
903904b28eSLinus Walleij 
913904b28eSLinus Walleij /*
923904b28eSLinus Walleij  * device id table is used to identify what device can be
933904b28eSLinus Walleij  * supported by this driver
943904b28eSLinus Walleij  */
953904b28eSLinus Walleij static const struct i2c_device_id mpu3050_i2c_id[] = {
963904b28eSLinus Walleij 	{ "mpu3050" },
973904b28eSLinus Walleij 	{}
983904b28eSLinus Walleij };
993904b28eSLinus Walleij MODULE_DEVICE_TABLE(i2c, mpu3050_i2c_id);
1003904b28eSLinus Walleij 
1013904b28eSLinus Walleij static const struct of_device_id mpu3050_i2c_of_match[] = {
1023904b28eSLinus Walleij 	{ .compatible = "invensense,mpu3050", .data = "mpu3050" },
1033904b28eSLinus Walleij 	/* Deprecated vendor ID from the Input driver */
1043904b28eSLinus Walleij 	{ .compatible = "invn,mpu3050", .data = "mpu3050" },
1053904b28eSLinus Walleij 	{ },
1063904b28eSLinus Walleij };
1073904b28eSLinus Walleij MODULE_DEVICE_TABLE(of, mpu3050_i2c_of_match);
1083904b28eSLinus Walleij 
1093904b28eSLinus Walleij static struct i2c_driver mpu3050_i2c_driver = {
1103904b28eSLinus Walleij 	.probe = mpu3050_i2c_probe,
1113904b28eSLinus Walleij 	.remove = mpu3050_i2c_remove,
1123904b28eSLinus Walleij 	.id_table = mpu3050_i2c_id,
1133904b28eSLinus Walleij 	.driver = {
1143904b28eSLinus Walleij 		.of_match_table = mpu3050_i2c_of_match,
1153904b28eSLinus Walleij 		.name = "mpu3050-i2c",
1163904b28eSLinus Walleij 		.pm = &mpu3050_dev_pm_ops,
1173904b28eSLinus Walleij 	},
1183904b28eSLinus Walleij };
1193904b28eSLinus Walleij module_i2c_driver(mpu3050_i2c_driver);
1203904b28eSLinus Walleij 
1213904b28eSLinus Walleij MODULE_AUTHOR("Linus Walleij");
1223904b28eSLinus Walleij MODULE_DESCRIPTION("Invensense MPU3050 gyroscope driver");
1233904b28eSLinus Walleij MODULE_LICENSE("GPL");
124