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