mmio.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * MMIO register bitfield-controlled multiplexer driver
  4. * Based on the linux mmio multiplexer driver
  5. *
  6. * Copyright (C) 2017 Pengutronix, Philipp Zabel <kernel@pengutronix.de>
  7. * Copyright (C) 2019 Texas Instrument, Jean-jacques Hiblot <jjhiblot@ti.com>
  8. */
  9. #include <common.h>
  10. #include <dm.h>
  11. #include <mux-internal.h>
  12. #include <regmap.h>
  13. #include <syscon.h>
  14. #include <dm/device.h>
  15. #include <dm/device_compat.h>
  16. #include <dm/read.h>
  17. #include <dm/devres.h>
  18. #include <dt-bindings/mux/mux.h>
  19. #include <linux/bitops.h>
  20. static int mux_mmio_set(struct mux_control *mux, int state)
  21. {
  22. struct regmap_field **fields = dev_get_priv(mux->dev);
  23. return regmap_field_write(fields[mux_control_get_index(mux)], state);
  24. }
  25. static const struct mux_control_ops mux_mmio_ops = {
  26. .set = mux_mmio_set,
  27. };
  28. static const struct udevice_id mmio_mux_of_match[] = {
  29. { .compatible = "mmio-mux" },
  30. { /* sentinel */ },
  31. };
  32. static int mmio_mux_probe(struct udevice *dev)
  33. {
  34. struct regmap_field **fields;
  35. struct mux_chip *mux_chip = dev_get_uclass_priv(dev);
  36. struct regmap *regmap;
  37. u32 *mux_reg_masks;
  38. u32 *idle_states;
  39. int num_fields;
  40. int ret;
  41. int i;
  42. regmap = syscon_node_to_regmap(dev_ofnode(dev->parent));
  43. if (IS_ERR(regmap)) {
  44. ret = PTR_ERR(regmap);
  45. dev_err(dev, "failed to get regmap: %d\n", ret);
  46. return ret;
  47. }
  48. num_fields = dev_read_size(dev, "mux-reg-masks");
  49. if (num_fields < 0)
  50. return log_msg_ret("mux-reg-masks missing", -EINVAL);
  51. num_fields /= sizeof(u32);
  52. if (num_fields == 0 || num_fields % 2)
  53. ret = -EINVAL;
  54. num_fields = num_fields / 2;
  55. ret = mux_alloc_controllers(dev, num_fields);
  56. if (ret < 0)
  57. return log_msg_ret("mux_alloc_controllers", ret);
  58. fields = devm_kmalloc(dev, num_fields * sizeof(*fields), __GFP_ZERO);
  59. if (!fields)
  60. return -ENOMEM;
  61. dev->priv = fields;
  62. mux_reg_masks = devm_kmalloc(dev, num_fields * 2 * sizeof(u32),
  63. __GFP_ZERO);
  64. if (!mux_reg_masks)
  65. return -ENOMEM;
  66. ret = dev_read_u32_array(dev, "mux-reg-masks", mux_reg_masks,
  67. num_fields * 2);
  68. if (ret < 0)
  69. return log_msg_ret("mux-reg-masks read", ret);
  70. idle_states = devm_kmalloc(dev, num_fields * sizeof(u32), __GFP_ZERO);
  71. if (!idle_states)
  72. return -ENOMEM;
  73. ret = dev_read_u32_array(dev, "idle-states", idle_states, num_fields);
  74. if (ret < 0) {
  75. log_err("idle-states");
  76. devm_kfree(dev, idle_states);
  77. idle_states = NULL;
  78. }
  79. for (i = 0; i < num_fields; i++) {
  80. struct mux_control *mux = &mux_chip->mux[i];
  81. struct reg_field field;
  82. u32 reg, mask;
  83. int bits;
  84. reg = mux_reg_masks[2 * i];
  85. mask = mux_reg_masks[2 * i + 1];
  86. field.reg = reg;
  87. field.msb = fls(mask) - 1;
  88. field.lsb = ffs(mask) - 1;
  89. if (mask != GENMASK(field.msb, field.lsb))
  90. return log_msg_ret("invalid mask", -EINVAL);
  91. fields[i] = devm_regmap_field_alloc(dev, regmap, field);
  92. if (IS_ERR(fields[i])) {
  93. ret = PTR_ERR(fields[i]);
  94. return log_msg_ret("regmap_field_alloc", ret);
  95. }
  96. bits = 1 + field.msb - field.lsb;
  97. mux->states = 1 << bits;
  98. if (!idle_states)
  99. continue;
  100. if (idle_states[i] != MUX_IDLE_AS_IS &&
  101. idle_states[i] >= mux->states)
  102. return log_msg_ret("idle-states range", -EINVAL);
  103. mux->idle_state = idle_states[i];
  104. }
  105. devm_kfree(dev, mux_reg_masks);
  106. if (idle_states)
  107. devm_kfree(dev, idle_states);
  108. return 0;
  109. }
  110. U_BOOT_DRIVER(mmio_mux) = {
  111. .name = "mmio-mux",
  112. .id = UCLASS_MUX,
  113. .of_match = mmio_mux_of_match,
  114. .probe = mmio_mux_probe,
  115. .ops = &mux_mmio_ops,
  116. };