109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23904b28eSLinus Walleij #include <linux/err.h>
33904b28eSLinus Walleij #include <linux/i2c.h>
43904b28eSLinus Walleij #include <linux/i2c-mux.h>
53904b28eSLinus Walleij #include <linux/iio/iio.h>
63904b28eSLinus Walleij #include <linux/module.h>
73904b28eSLinus Walleij #include <linux/regmap.h>
83904b28eSLinus Walleij #include <linux/pm_runtime.h>
93904b28eSLinus Walleij
103904b28eSLinus Walleij #include "mpu3050.h"
113904b28eSLinus Walleij
123904b28eSLinus Walleij static const struct regmap_config mpu3050_i2c_regmap_config = {
133904b28eSLinus Walleij .reg_bits = 8,
143904b28eSLinus Walleij .val_bits = 8,
153904b28eSLinus Walleij };
163904b28eSLinus Walleij
mpu3050_i2c_bypass_select(struct i2c_mux_core * mux,u32 chan_id)173904b28eSLinus Walleij static int mpu3050_i2c_bypass_select(struct i2c_mux_core *mux, u32 chan_id)
183904b28eSLinus Walleij {
193904b28eSLinus Walleij struct mpu3050 *mpu3050 = i2c_mux_priv(mux);
203904b28eSLinus Walleij
213904b28eSLinus Walleij /* Just power up the device, that is all that is needed */
223904b28eSLinus Walleij pm_runtime_get_sync(mpu3050->dev);
233904b28eSLinus Walleij return 0;
243904b28eSLinus Walleij }
253904b28eSLinus Walleij
mpu3050_i2c_bypass_deselect(struct i2c_mux_core * mux,u32 chan_id)263904b28eSLinus Walleij static int mpu3050_i2c_bypass_deselect(struct i2c_mux_core *mux, u32 chan_id)
273904b28eSLinus Walleij {
283904b28eSLinus Walleij struct mpu3050 *mpu3050 = i2c_mux_priv(mux);
293904b28eSLinus Walleij
303904b28eSLinus Walleij pm_runtime_mark_last_busy(mpu3050->dev);
313904b28eSLinus Walleij pm_runtime_put_autosuspend(mpu3050->dev);
323904b28eSLinus Walleij return 0;
333904b28eSLinus Walleij }
343904b28eSLinus Walleij
mpu3050_i2c_probe(struct i2c_client * client)35b97db528SUwe Kleine-König static int mpu3050_i2c_probe(struct i2c_client *client)
363904b28eSLinus Walleij {
37b97db528SUwe Kleine-König const struct i2c_device_id *id = i2c_client_get_device_id(client);
383904b28eSLinus Walleij struct regmap *regmap;
393904b28eSLinus Walleij const char *name;
403904b28eSLinus Walleij struct mpu3050 *mpu3050;
413904b28eSLinus Walleij int ret;
423904b28eSLinus Walleij
433904b28eSLinus Walleij if (!i2c_check_functionality(client->adapter,
443904b28eSLinus Walleij I2C_FUNC_SMBUS_I2C_BLOCK))
453904b28eSLinus Walleij return -EOPNOTSUPP;
463904b28eSLinus Walleij
473904b28eSLinus Walleij if (id)
483904b28eSLinus Walleij name = id->name;
493904b28eSLinus Walleij else
503904b28eSLinus Walleij return -ENODEV;
513904b28eSLinus Walleij
523904b28eSLinus Walleij regmap = devm_regmap_init_i2c(client, &mpu3050_i2c_regmap_config);
533904b28eSLinus Walleij if (IS_ERR(regmap)) {
540e5fd387SNishant Malpani dev_err(&client->dev, "Failed to register i2c regmap: %pe\n",
550e5fd387SNishant Malpani regmap);
563904b28eSLinus Walleij return PTR_ERR(regmap);
573904b28eSLinus Walleij }
583904b28eSLinus Walleij
593904b28eSLinus Walleij ret = mpu3050_common_probe(&client->dev, regmap, client->irq, name);
603904b28eSLinus Walleij if (ret)
613904b28eSLinus Walleij return ret;
623904b28eSLinus Walleij
633904b28eSLinus Walleij /* The main driver is up, now register the I2C mux */
643904b28eSLinus Walleij mpu3050 = iio_priv(dev_get_drvdata(&client->dev));
653904b28eSLinus Walleij mpu3050->i2cmux = i2c_mux_alloc(client->adapter, &client->dev,
663904b28eSLinus Walleij 1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE,
673904b28eSLinus Walleij mpu3050_i2c_bypass_select,
683904b28eSLinus Walleij mpu3050_i2c_bypass_deselect);
693904b28eSLinus Walleij /* Just fail the mux, there is no point in killing the driver */
703904b28eSLinus Walleij if (!mpu3050->i2cmux)
713904b28eSLinus Walleij dev_err(&client->dev, "failed to allocate I2C mux\n");
723904b28eSLinus Walleij else {
733904b28eSLinus Walleij mpu3050->i2cmux->priv = mpu3050;
746a95d825SPeter Rosin /* Ignore failure, not critical */
756a95d825SPeter Rosin i2c_mux_add_adapter(mpu3050->i2cmux, 0, 0, 0);
763904b28eSLinus Walleij }
773904b28eSLinus Walleij
783904b28eSLinus Walleij return 0;
793904b28eSLinus Walleij }
803904b28eSLinus Walleij
mpu3050_i2c_remove(struct i2c_client * client)81ed5c2f5fSUwe Kleine-König static void 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
89d3beaf18SUwe Kleine-König 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 = {
111*7cf15f42SUwe Kleine-König .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",
117feb0bd2bSJonathan Cameron .pm = pm_ptr(&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