1 | // SPDX-License-Identifier: GPL-2.0-only |
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(muxc: mux); |
20 | |
21 | /* Just power up the device, that is all that is needed */ |
22 | pm_runtime_get_sync(dev: 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(muxc: mux); |
29 | |
30 | pm_runtime_mark_last_busy(dev: mpu3050->dev); |
31 | pm_runtime_put_autosuspend(dev: mpu3050->dev); |
32 | return 0; |
33 | } |
34 | |
35 | static int mpu3050_i2c_probe(struct i2c_client *client) |
36 | { |
37 | const struct i2c_device_id *id = i2c_client_get_device_id(client); |
38 | struct regmap *regmap; |
39 | const char *name; |
40 | struct mpu3050 *mpu3050; |
41 | int ret; |
42 | |
43 | if (!i2c_check_functionality(adap: 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(ptr: regmap)) { |
54 | dev_err(&client->dev, "Failed to register i2c regmap: %pe\n" , |
55 | regmap); |
56 | return PTR_ERR(ptr: regmap); |
57 | } |
58 | |
59 | ret = mpu3050_common_probe(dev: &client->dev, map: regmap, irq: 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(indio_dev: dev_get_drvdata(dev: &client->dev)); |
65 | mpu3050->i2cmux = i2c_mux_alloc(parent: client->adapter, dev: &client->dev, |
66 | max_adapters: 1, sizeof_priv: 0, I2C_MUX_LOCKED | I2C_MUX_GATE, |
67 | select: mpu3050_i2c_bypass_select, |
68 | deselect: 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; |
74 | /* Ignore failure, not critical */ |
75 | i2c_mux_add_adapter(muxc: mpu3050->i2cmux, force_nr: 0, chan_id: 0, class: 0); |
76 | } |
77 | |
78 | return 0; |
79 | } |
80 | |
81 | static void mpu3050_i2c_remove(struct i2c_client *client) |
82 | { |
83 | struct iio_dev *indio_dev = dev_get_drvdata(dev: &client->dev); |
84 | struct mpu3050 *mpu3050 = iio_priv(indio_dev); |
85 | |
86 | if (mpu3050->i2cmux) |
87 | i2c_mux_del_adapters(muxc: mpu3050->i2cmux); |
88 | |
89 | mpu3050_common_remove(dev: &client->dev); |
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 = { |
111 | .probe = mpu3050_i2c_probe, |
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" , |
117 | .pm = pm_ptr(&mpu3050_dev_pm_ops), |
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" ); |
125 | |