1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2020 InvenSense, Inc. |
4 | */ |
5 | |
6 | #include <linux/kernel.h> |
7 | #include <linux/device.h> |
8 | #include <linux/module.h> |
9 | #include <linux/mod_devicetable.h> |
10 | #include <linux/i2c.h> |
11 | #include <linux/regmap.h> |
12 | #include <linux/property.h> |
13 | |
14 | #include "inv_icm42600.h" |
15 | |
16 | static int inv_icm42600_i2c_bus_setup(struct inv_icm42600_state *st) |
17 | { |
18 | unsigned int mask, val; |
19 | int ret; |
20 | |
21 | /* |
22 | * setup interface registers |
23 | * This register write to REG_INTF_CONFIG6 enables a spike filter that |
24 | * is impacting the line and can prevent the I2C ACK to be seen by the |
25 | * controller. So we don't test the return value. |
26 | */ |
27 | regmap_update_bits(map: st->map, INV_ICM42600_REG_INTF_CONFIG6, |
28 | INV_ICM42600_INTF_CONFIG6_MASK, |
29 | INV_ICM42600_INTF_CONFIG6_I3C_EN); |
30 | |
31 | ret = regmap_update_bits(map: st->map, INV_ICM42600_REG_INTF_CONFIG4, |
32 | INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY, val: 0); |
33 | if (ret) |
34 | return ret; |
35 | |
36 | /* set slew rates for I2C and SPI */ |
37 | mask = INV_ICM42600_DRIVE_CONFIG_I2C_MASK | |
38 | INV_ICM42600_DRIVE_CONFIG_SPI_MASK; |
39 | val = INV_ICM42600_DRIVE_CONFIG_I2C(INV_ICM42600_SLEW_RATE_12_36NS) | |
40 | INV_ICM42600_DRIVE_CONFIG_SPI(INV_ICM42600_SLEW_RATE_12_36NS); |
41 | ret = regmap_update_bits(map: st->map, INV_ICM42600_REG_DRIVE_CONFIG, |
42 | mask, val); |
43 | if (ret) |
44 | return ret; |
45 | |
46 | /* disable SPI bus */ |
47 | return regmap_update_bits(map: st->map, INV_ICM42600_REG_INTF_CONFIG0, |
48 | INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_MASK, |
49 | INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS); |
50 | } |
51 | |
52 | static int inv_icm42600_probe(struct i2c_client *client) |
53 | { |
54 | const void *match; |
55 | enum inv_icm42600_chip chip; |
56 | struct regmap *regmap; |
57 | |
58 | if (!i2c_check_functionality(adap: client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) |
59 | return -ENOTSUPP; |
60 | |
61 | match = device_get_match_data(dev: &client->dev); |
62 | if (!match) |
63 | return -EINVAL; |
64 | chip = (uintptr_t)match; |
65 | |
66 | regmap = devm_regmap_init_i2c(client, &inv_icm42600_regmap_config); |
67 | if (IS_ERR(ptr: regmap)) |
68 | return PTR_ERR(ptr: regmap); |
69 | |
70 | return inv_icm42600_core_probe(regmap, chip, irq: client->irq, |
71 | bus_setup: inv_icm42600_i2c_bus_setup); |
72 | } |
73 | |
74 | static const struct of_device_id inv_icm42600_of_matches[] = { |
75 | { |
76 | .compatible = "invensense,icm42600" , |
77 | .data = (void *)INV_CHIP_ICM42600, |
78 | }, { |
79 | .compatible = "invensense,icm42602" , |
80 | .data = (void *)INV_CHIP_ICM42602, |
81 | }, { |
82 | .compatible = "invensense,icm42605" , |
83 | .data = (void *)INV_CHIP_ICM42605, |
84 | }, { |
85 | .compatible = "invensense,icm42622" , |
86 | .data = (void *)INV_CHIP_ICM42622, |
87 | }, { |
88 | .compatible = "invensense,icm42631" , |
89 | .data = (void *)INV_CHIP_ICM42631, |
90 | }, |
91 | {} |
92 | }; |
93 | MODULE_DEVICE_TABLE(of, inv_icm42600_of_matches); |
94 | |
95 | static struct i2c_driver inv_icm42600_driver = { |
96 | .driver = { |
97 | .name = "inv-icm42600-i2c" , |
98 | .of_match_table = inv_icm42600_of_matches, |
99 | .pm = pm_ptr(&inv_icm42600_pm_ops), |
100 | }, |
101 | .probe = inv_icm42600_probe, |
102 | }; |
103 | module_i2c_driver(inv_icm42600_driver); |
104 | |
105 | MODULE_AUTHOR("InvenSense, Inc." ); |
106 | MODULE_DESCRIPTION("InvenSense ICM-426xx I2C driver" ); |
107 | MODULE_LICENSE("GPL" ); |
108 | MODULE_IMPORT_NS(IIO_ICM42600); |
109 | |