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