pinctrl-mcp23s08_i2c.c 2.8 KB

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