Commit | Line | Data |
---|---|---|
0f04a817 AS |
1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* MCP23S08 I2C GPIO driver */ | |
3 | ||
4 | #include <linux/i2c.h> | |
5 | #include <linux/mod_devicetable.h> | |
6 | #include <linux/module.h> | |
7 | #include <linux/regmap.h> | |
8 | ||
9 | #include "pinctrl-mcp23s08.h" | |
10 | ||
11 | static int mcp230xx_probe(struct i2c_client *client, const struct i2c_device_id *id) | |
12 | { | |
13 | struct device *dev = &client->dev; | |
14 | unsigned int type = id->driver_data; | |
15 | struct mcp23s08 *mcp; | |
16 | int ret; | |
17 | ||
18 | mcp = devm_kzalloc(dev, sizeof(*mcp), GFP_KERNEL); | |
19 | if (!mcp) | |
20 | return -ENOMEM; | |
21 | ||
22 | switch (type) { | |
23 | case MCP_TYPE_008: | |
24 | mcp->regmap = devm_regmap_init_i2c(client, &mcp23x08_regmap); | |
25 | mcp->reg_shift = 0; | |
26 | mcp->chip.ngpio = 8; | |
27 | mcp->chip.label = "mcp23008"; | |
28 | break; | |
29 | ||
30 | case MCP_TYPE_017: | |
31 | mcp->regmap = devm_regmap_init_i2c(client, &mcp23x17_regmap); | |
32 | mcp->reg_shift = 1; | |
33 | mcp->chip.ngpio = 16; | |
34 | mcp->chip.label = "mcp23017"; | |
35 | break; | |
36 | ||
37 | case MCP_TYPE_018: | |
38 | mcp->regmap = devm_regmap_init_i2c(client, &mcp23x17_regmap); | |
39 | mcp->reg_shift = 1; | |
40 | mcp->chip.ngpio = 16; | |
41 | mcp->chip.label = "mcp23018"; | |
42 | break; | |
43 | ||
44 | default: | |
45 | dev_err(dev, "invalid device type (%d)\n", type); | |
46 | return -EINVAL; | |
47 | } | |
48 | ||
49 | if (IS_ERR(mcp->regmap)) | |
50 | return PTR_ERR(mcp->regmap); | |
51 | ||
52 | mcp->irq = client->irq; | |
53 | mcp->pinctrl_desc.name = "mcp23xxx-pinctrl"; | |
54 | ||
55 | ret = mcp23s08_probe_one(mcp, dev, client->addr, type, -1); | |
56 | if (ret) | |
57 | return ret; | |
58 | ||
59 | i2c_set_clientdata(client, mcp); | |
60 | ||
61 | return 0; | |
62 | } | |
63 | ||
64 | static const struct i2c_device_id mcp230xx_id[] = { | |
65 | { "mcp23008", MCP_TYPE_008 }, | |
66 | { "mcp23017", MCP_TYPE_017 }, | |
67 | { "mcp23018", MCP_TYPE_018 }, | |
68 | { } | |
69 | }; | |
70 | MODULE_DEVICE_TABLE(i2c, mcp230xx_id); | |
71 | ||
72 | static const struct of_device_id mcp23s08_i2c_of_match[] = { | |
73 | { | |
74 | .compatible = "microchip,mcp23008", | |
75 | .data = (void *) MCP_TYPE_008, | |
76 | }, | |
77 | { | |
78 | .compatible = "microchip,mcp23017", | |
79 | .data = (void *) MCP_TYPE_017, | |
80 | }, | |
81 | { | |
82 | .compatible = "microchip,mcp23018", | |
83 | .data = (void *) MCP_TYPE_018, | |
84 | }, | |
85 | /* NOTE: The use of the mcp prefix is deprecated and will be removed. */ | |
86 | { | |
87 | .compatible = "mcp,mcp23008", | |
88 | .data = (void *) MCP_TYPE_008, | |
89 | }, | |
90 | { | |
91 | .compatible = "mcp,mcp23017", | |
92 | .data = (void *) MCP_TYPE_017, | |
93 | }, | |
94 | { } | |
95 | }; | |
96 | MODULE_DEVICE_TABLE(of, mcp23s08_i2c_of_match); | |
97 | ||
98 | static struct i2c_driver mcp230xx_driver = { | |
99 | .driver = { | |
100 | .name = "mcp230xx", | |
101 | .of_match_table = mcp23s08_i2c_of_match, | |
102 | }, | |
103 | .probe = mcp230xx_probe, | |
104 | .id_table = mcp230xx_id, | |
105 | }; | |
106 | ||
107 | static int __init mcp23s08_i2c_init(void) | |
108 | { | |
109 | return i2c_add_driver(&mcp230xx_driver); | |
110 | } | |
111 | ||
112 | /* | |
113 | * Register after I²C postcore initcall and before | |
114 | * subsys initcalls that may rely on these GPIOs. | |
115 | */ | |
116 | subsys_initcall(mcp23s08_i2c_init); | |
117 | ||
118 | static void mcp23s08_i2c_exit(void) | |
119 | { | |
120 | i2c_del_driver(&mcp230xx_driver); | |
121 | } | |
122 | module_exit(mcp23s08_i2c_exit); | |
123 | ||
124 | MODULE_LICENSE("GPL"); |