menf21bmc.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * MEN 14F021P00 Board Management Controller (BMC) MFD Core Driver.
  4. *
  5. * Copyright (C) 2014 MEN Mikro Elektronik Nuernberg GmbH
  6. */
  7. #include <linux/kernel.h>
  8. #include <linux/device.h>
  9. #include <linux/module.h>
  10. #include <linux/i2c.h>
  11. #include <linux/mfd/core.h>
  12. #define BMC_CMD_WDT_EXIT_PROD 0x18
  13. #define BMC_CMD_WDT_PROD_STAT 0x19
  14. #define BMC_CMD_REV_MAJOR 0x80
  15. #define BMC_CMD_REV_MINOR 0x81
  16. #define BMC_CMD_REV_MAIN 0x82
  17. static struct mfd_cell menf21bmc_cell[] = {
  18. { .name = "menf21bmc_wdt", },
  19. { .name = "menf21bmc_led", },
  20. { .name = "menf21bmc_hwmon", }
  21. };
  22. static int menf21bmc_wdt_exit_prod_mode(struct i2c_client *client)
  23. {
  24. int val, ret;
  25. val = i2c_smbus_read_byte_data(client, BMC_CMD_WDT_PROD_STAT);
  26. if (val < 0)
  27. return val;
  28. /*
  29. * Production mode should be not active after delivery of the Board.
  30. * To be sure we check it, inform the user and exit the mode
  31. * if active.
  32. */
  33. if (val == 0x00) {
  34. dev_info(&client->dev,
  35. "BMC in production mode. Exit production mode\n");
  36. ret = i2c_smbus_write_byte(client, BMC_CMD_WDT_EXIT_PROD);
  37. if (ret < 0)
  38. return ret;
  39. }
  40. return 0;
  41. }
  42. static int
  43. menf21bmc_probe(struct i2c_client *client, const struct i2c_device_id *ids)
  44. {
  45. int rev_major, rev_minor, rev_main;
  46. int ret;
  47. ret = i2c_check_functionality(client->adapter,
  48. I2C_FUNC_SMBUS_BYTE_DATA |
  49. I2C_FUNC_SMBUS_WORD_DATA |
  50. I2C_FUNC_SMBUS_BYTE);
  51. if (!ret)
  52. return -ENODEV;
  53. rev_major = i2c_smbus_read_word_data(client, BMC_CMD_REV_MAJOR);
  54. if (rev_major < 0) {
  55. dev_err(&client->dev, "failed to get BMC major revision\n");
  56. return rev_major;
  57. }
  58. rev_minor = i2c_smbus_read_word_data(client, BMC_CMD_REV_MINOR);
  59. if (rev_minor < 0) {
  60. dev_err(&client->dev, "failed to get BMC minor revision\n");
  61. return rev_minor;
  62. }
  63. rev_main = i2c_smbus_read_word_data(client, BMC_CMD_REV_MAIN);
  64. if (rev_main < 0) {
  65. dev_err(&client->dev, "failed to get BMC main revision\n");
  66. return rev_main;
  67. }
  68. dev_info(&client->dev, "FW Revision: %02d.%02d.%02d\n",
  69. rev_major, rev_minor, rev_main);
  70. /*
  71. * We have to exit the Production Mode of the BMC to activate the
  72. * Watchdog functionality and the BIOS life sign monitoring.
  73. */
  74. ret = menf21bmc_wdt_exit_prod_mode(client);
  75. if (ret < 0) {
  76. dev_err(&client->dev, "failed to leave production mode\n");
  77. return ret;
  78. }
  79. ret = devm_mfd_add_devices(&client->dev, 0, menf21bmc_cell,
  80. ARRAY_SIZE(menf21bmc_cell), NULL, 0, NULL);
  81. if (ret < 0) {
  82. dev_err(&client->dev, "failed to add BMC sub-devices\n");
  83. return ret;
  84. }
  85. return 0;
  86. }
  87. static const struct i2c_device_id menf21bmc_id_table[] = {
  88. { "menf21bmc" },
  89. { }
  90. };
  91. MODULE_DEVICE_TABLE(i2c, menf21bmc_id_table);
  92. static struct i2c_driver menf21bmc_driver = {
  93. .driver.name = "menf21bmc",
  94. .id_table = menf21bmc_id_table,
  95. .probe = menf21bmc_probe,
  96. };
  97. module_i2c_driver(menf21bmc_driver);
  98. MODULE_DESCRIPTION("MEN 14F021P00 BMC mfd core driver");
  99. MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>");
  100. MODULE_LICENSE("GPL v2");