Commit | Line | Data |
---|---|---|
09c434b8 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
3904b28e LW |
2 | #include <linux/err.h> |
3 | #include <linux/i2c.h> | |
4 | #include <linux/i2c-mux.h> | |
5 | #include <linux/iio/iio.h> | |
6 | #include <linux/module.h> | |
7 | #include <linux/regmap.h> | |
8 | #include <linux/pm_runtime.h> | |
9 | ||
10 | #include "mpu3050.h" | |
11 | ||
12 | static const struct regmap_config mpu3050_i2c_regmap_config = { | |
13 | .reg_bits = 8, | |
14 | .val_bits = 8, | |
15 | }; | |
16 | ||
17 | static int mpu3050_i2c_bypass_select(struct i2c_mux_core *mux, u32 chan_id) | |
18 | { | |
19 | struct mpu3050 *mpu3050 = i2c_mux_priv(mux); | |
20 | ||
21 | /* Just power up the device, that is all that is needed */ | |
22 | pm_runtime_get_sync(mpu3050->dev); | |
23 | return 0; | |
24 | } | |
25 | ||
26 | static int mpu3050_i2c_bypass_deselect(struct i2c_mux_core *mux, u32 chan_id) | |
27 | { | |
28 | struct mpu3050 *mpu3050 = i2c_mux_priv(mux); | |
29 | ||
30 | pm_runtime_mark_last_busy(mpu3050->dev); | |
31 | pm_runtime_put_autosuspend(mpu3050->dev); | |
32 | return 0; | |
33 | } | |
34 | ||
b97db528 | 35 | static int mpu3050_i2c_probe(struct i2c_client *client) |
3904b28e | 36 | { |
b97db528 | 37 | const struct i2c_device_id *id = i2c_client_get_device_id(client); |
3904b28e LW |
38 | struct regmap *regmap; |
39 | const char *name; | |
40 | struct mpu3050 *mpu3050; | |
41 | int ret; | |
42 | ||
43 | if (!i2c_check_functionality(client->adapter, | |
44 | I2C_FUNC_SMBUS_I2C_BLOCK)) | |
45 | return -EOPNOTSUPP; | |
46 | ||
47 | if (id) | |
48 | name = id->name; | |
49 | else | |
50 | return -ENODEV; | |
51 | ||
52 | regmap = devm_regmap_init_i2c(client, &mpu3050_i2c_regmap_config); | |
53 | if (IS_ERR(regmap)) { | |
0e5fd387 NM |
54 | dev_err(&client->dev, "Failed to register i2c regmap: %pe\n", |
55 | regmap); | |
3904b28e LW |
56 | return PTR_ERR(regmap); |
57 | } | |
58 | ||
59 | ret = mpu3050_common_probe(&client->dev, regmap, client->irq, name); | |
60 | if (ret) | |
61 | return ret; | |
62 | ||
63 | /* The main driver is up, now register the I2C mux */ | |
64 | mpu3050 = iio_priv(dev_get_drvdata(&client->dev)); | |
65 | mpu3050->i2cmux = i2c_mux_alloc(client->adapter, &client->dev, | |
66 | 1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE, | |
67 | mpu3050_i2c_bypass_select, | |
68 | mpu3050_i2c_bypass_deselect); | |
69 | /* Just fail the mux, there is no point in killing the driver */ | |
70 | if (!mpu3050->i2cmux) | |
71 | dev_err(&client->dev, "failed to allocate I2C mux\n"); | |
72 | else { | |
73 | mpu3050->i2cmux->priv = mpu3050; | |
6a95d825 | 74 | /* Ignore failure, not critical */ |
fec1982d | 75 | i2c_mux_add_adapter(mpu3050->i2cmux, 0, 0); |
3904b28e LW |
76 | } |
77 | ||
78 | return 0; | |
79 | } | |
80 | ||
ed5c2f5f | 81 | static void mpu3050_i2c_remove(struct i2c_client *client) |
3904b28e LW |
82 | { |
83 | struct iio_dev *indio_dev = dev_get_drvdata(&client->dev); | |
84 | struct mpu3050 *mpu3050 = iio_priv(indio_dev); | |
85 | ||
86 | if (mpu3050->i2cmux) | |
87 | i2c_mux_del_adapters(mpu3050->i2cmux); | |
88 | ||
d3beaf18 | 89 | mpu3050_common_remove(&client->dev); |
3904b28e LW |
90 | } |
91 | ||
92 | /* | |
93 | * device id table is used to identify what device can be | |
94 | * supported by this driver | |
95 | */ | |
96 | static const struct i2c_device_id mpu3050_i2c_id[] = { | |
97 | { "mpu3050" }, | |
98 | {} | |
99 | }; | |
100 | MODULE_DEVICE_TABLE(i2c, mpu3050_i2c_id); | |
101 | ||
102 | static const struct of_device_id mpu3050_i2c_of_match[] = { | |
103 | { .compatible = "invensense,mpu3050", .data = "mpu3050" }, | |
104 | /* Deprecated vendor ID from the Input driver */ | |
105 | { .compatible = "invn,mpu3050", .data = "mpu3050" }, | |
106 | { }, | |
107 | }; | |
108 | MODULE_DEVICE_TABLE(of, mpu3050_i2c_of_match); | |
109 | ||
110 | static struct i2c_driver mpu3050_i2c_driver = { | |
7cf15f42 | 111 | .probe = mpu3050_i2c_probe, |
3904b28e LW |
112 | .remove = mpu3050_i2c_remove, |
113 | .id_table = mpu3050_i2c_id, | |
114 | .driver = { | |
115 | .of_match_table = mpu3050_i2c_of_match, | |
116 | .name = "mpu3050-i2c", | |
feb0bd2b | 117 | .pm = pm_ptr(&mpu3050_dev_pm_ops), |
3904b28e LW |
118 | }, |
119 | }; | |
120 | module_i2c_driver(mpu3050_i2c_driver); | |
121 | ||
122 | MODULE_AUTHOR("Linus Walleij"); | |
123 | MODULE_DESCRIPTION("Invensense MPU3050 gyroscope driver"); | |
124 | MODULE_LICENSE("GPL"); |