khadas-mcu.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Driver for Khadas System control Microcontroller
  4. *
  5. * Copyright (C) 2020 BayLibre SAS
  6. *
  7. * Author(s): Neil Armstrong <narmstrong@baylibre.com>
  8. */
  9. #include <linux/bitfield.h>
  10. #include <linux/i2c.h>
  11. #include <linux/mfd/core.h>
  12. #include <linux/mfd/khadas-mcu.h>
  13. #include <linux/module.h>
  14. #include <linux/regmap.h>
  15. static bool khadas_mcu_reg_volatile(struct device *dev, unsigned int reg)
  16. {
  17. if (reg >= KHADAS_MCU_USER_DATA_0_REG &&
  18. reg < KHADAS_MCU_PWR_OFF_CMD_REG)
  19. return true;
  20. switch (reg) {
  21. case KHADAS_MCU_PWR_OFF_CMD_REG:
  22. case KHADAS_MCU_PASSWD_START_REG:
  23. case KHADAS_MCU_CHECK_VEN_PASSWD_REG:
  24. case KHADAS_MCU_CHECK_USER_PASSWD_REG:
  25. case KHADAS_MCU_WOL_INIT_START_REG:
  26. case KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG:
  27. return true;
  28. default:
  29. return false;
  30. }
  31. }
  32. static bool khadas_mcu_reg_writeable(struct device *dev, unsigned int reg)
  33. {
  34. switch (reg) {
  35. case KHADAS_MCU_PASSWD_VEN_0_REG:
  36. case KHADAS_MCU_PASSWD_VEN_1_REG:
  37. case KHADAS_MCU_PASSWD_VEN_2_REG:
  38. case KHADAS_MCU_PASSWD_VEN_3_REG:
  39. case KHADAS_MCU_PASSWD_VEN_4_REG:
  40. case KHADAS_MCU_PASSWD_VEN_5_REG:
  41. case KHADAS_MCU_MAC_0_REG:
  42. case KHADAS_MCU_MAC_1_REG:
  43. case KHADAS_MCU_MAC_2_REG:
  44. case KHADAS_MCU_MAC_3_REG:
  45. case KHADAS_MCU_MAC_4_REG:
  46. case KHADAS_MCU_MAC_5_REG:
  47. case KHADAS_MCU_USID_0_REG:
  48. case KHADAS_MCU_USID_1_REG:
  49. case KHADAS_MCU_USID_2_REG:
  50. case KHADAS_MCU_USID_3_REG:
  51. case KHADAS_MCU_USID_4_REG:
  52. case KHADAS_MCU_USID_5_REG:
  53. case KHADAS_MCU_VERSION_0_REG:
  54. case KHADAS_MCU_VERSION_1_REG:
  55. case KHADAS_MCU_DEVICE_NO_0_REG:
  56. case KHADAS_MCU_DEVICE_NO_1_REG:
  57. case KHADAS_MCU_FACTORY_TEST_REG:
  58. case KHADAS_MCU_SHUTDOWN_NORMAL_STATUS_REG:
  59. return false;
  60. default:
  61. return true;
  62. }
  63. }
  64. static const struct regmap_config khadas_mcu_regmap_config = {
  65. .reg_bits = 8,
  66. .reg_stride = 1,
  67. .val_bits = 8,
  68. .max_register = KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG,
  69. .volatile_reg = khadas_mcu_reg_volatile,
  70. .writeable_reg = khadas_mcu_reg_writeable,
  71. .cache_type = REGCACHE_RBTREE,
  72. };
  73. static struct mfd_cell khadas_mcu_fan_cells[] = {
  74. /* VIM1/2 Rev13+ and VIM3 only */
  75. { .name = "khadas-mcu-fan-ctrl", },
  76. };
  77. static struct mfd_cell khadas_mcu_cells[] = {
  78. { .name = "khadas-mcu-user-mem", },
  79. };
  80. static int khadas_mcu_probe(struct i2c_client *client,
  81. const struct i2c_device_id *id)
  82. {
  83. struct device *dev = &client->dev;
  84. struct khadas_mcu *ddata;
  85. int ret;
  86. ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
  87. if (!ddata)
  88. return -ENOMEM;
  89. i2c_set_clientdata(client, ddata);
  90. ddata->dev = dev;
  91. ddata->regmap = devm_regmap_init_i2c(client, &khadas_mcu_regmap_config);
  92. if (IS_ERR(ddata->regmap)) {
  93. ret = PTR_ERR(ddata->regmap);
  94. dev_err(dev, "Failed to allocate register map: %d\n", ret);
  95. return ret;
  96. }
  97. ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
  98. khadas_mcu_cells,
  99. ARRAY_SIZE(khadas_mcu_cells),
  100. NULL, 0, NULL);
  101. if (ret)
  102. return ret;
  103. if (of_find_property(dev->of_node, "#cooling-cells", NULL))
  104. return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
  105. khadas_mcu_fan_cells,
  106. ARRAY_SIZE(khadas_mcu_fan_cells),
  107. NULL, 0, NULL);
  108. return 0;
  109. }
  110. #ifdef CONFIG_OF
  111. static const struct of_device_id khadas_mcu_of_match[] = {
  112. { .compatible = "khadas,mcu", },
  113. {},
  114. };
  115. MODULE_DEVICE_TABLE(of, khadas_mcu_of_match);
  116. #endif
  117. static struct i2c_driver khadas_mcu_driver = {
  118. .driver = {
  119. .name = "khadas-mcu-core",
  120. .of_match_table = of_match_ptr(khadas_mcu_of_match),
  121. },
  122. .probe = khadas_mcu_probe,
  123. };
  124. module_i2c_driver(khadas_mcu_driver);
  125. MODULE_DESCRIPTION("Khadas MCU core driver");
  126. MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
  127. MODULE_LICENSE("GPL v2");