ps862x.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2015 Google, Inc
  4. * Written by Simon Glass <sjg@chromium.org>
  5. */
  6. #include <common.h>
  7. #include <dm.h>
  8. #include <errno.h>
  9. #include <i2c.h>
  10. #include <video_bridge.h>
  11. #include <power/regulator.h>
  12. DECLARE_GLOBAL_DATA_PTR;
  13. /*
  14. * Initialisation of the chip is a process of writing certain values into
  15. * certain registers over i2c bus. The chip in fact responds to a range of
  16. * addresses on the i2c bus, so for each written value three parameters are
  17. * required: i2c address, register address and the actual value.
  18. *
  19. * The base address is derived from the device tree, but oddly the chip
  20. * responds on several addresses with different register sets for each.
  21. */
  22. /**
  23. * ps8622_write() Write a PS8622 eDP bridge i2c register
  24. *
  25. * @param dev I2C device
  26. * @param addr_off offset from the i2c base address for ps8622
  27. * @param reg_addr register address to write
  28. * @param value value to be written
  29. * @return 0 on success, non-0 on failure
  30. */
  31. static int ps8622_write(struct udevice *dev, unsigned addr_off,
  32. unsigned char reg_addr, unsigned char value)
  33. {
  34. struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
  35. uint8_t buf[2];
  36. struct i2c_msg msg;
  37. int ret;
  38. msg.addr = chip->chip_addr + addr_off;
  39. msg.flags = 0;
  40. buf[0] = reg_addr;
  41. buf[1] = value;
  42. msg.buf = buf;
  43. msg.len = 2;
  44. ret = dm_i2c_xfer(dev, &msg, 1);
  45. if (ret) {
  46. debug("%s: write failed, reg=%#x, value=%#x, ret=%d\n",
  47. __func__, reg_addr, value, ret);
  48. return ret;
  49. }
  50. return 0;
  51. }
  52. static int ps8622_set_backlight(struct udevice *dev, int percent)
  53. {
  54. int level = percent * 255 / 100;
  55. debug("%s: level=%d\n", __func__, level);
  56. return ps8622_write(dev, 0x01, 0xa7, level);
  57. }
  58. static int ps8622_attach(struct udevice *dev)
  59. {
  60. const uint8_t *params;
  61. struct udevice *reg;
  62. int ret, i, len;
  63. debug("%s: %s\n", __func__, dev->name);
  64. /* set the LDO providing the 1.2V rail to the Parade bridge */
  65. ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
  66. "power-supply", &reg);
  67. if (!ret) {
  68. ret = regulator_autoset(reg);
  69. } else if (ret != -ENOENT) {
  70. debug("%s: Failed to enable power: ret=%d\n", __func__, ret);
  71. return ret;
  72. }
  73. ret = video_bridge_set_active(dev, true);
  74. if (ret)
  75. return ret;
  76. params = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "parade,regs",
  77. &len);
  78. if (!params || len % 3) {
  79. debug("%s: missing/invalid params=%p, len=%x\n", __func__,
  80. params, len);
  81. return -EINVAL;
  82. }
  83. /* need to wait 20ms after power on before doing I2C writes */
  84. mdelay(20);
  85. for (i = 0; i < len; i += 3) {
  86. ret = ps8622_write(dev, params[i + 0], params[i + 1],
  87. params[i + 2]);
  88. if (ret)
  89. return ret;
  90. }
  91. return 0;
  92. }
  93. static int ps8622_probe(struct udevice *dev)
  94. {
  95. debug("%s\n", __func__);
  96. if (device_get_uclass_id(dev->parent) != UCLASS_I2C)
  97. return -EPROTONOSUPPORT;
  98. return 0;
  99. }
  100. struct video_bridge_ops ps8622_ops = {
  101. .attach = ps8622_attach,
  102. .set_backlight = ps8622_set_backlight,
  103. };
  104. static const struct udevice_id ps8622_ids[] = {
  105. { .compatible = "parade,ps8622", },
  106. { .compatible = "parade,ps8625", },
  107. { }
  108. };
  109. U_BOOT_DRIVER(parade_ps8622) = {
  110. .name = "parade_ps8622",
  111. .id = UCLASS_VIDEO_BRIDGE,
  112. .of_match = ps8622_ids,
  113. .probe = ps8622_probe,
  114. .ops = &ps8622_ops,
  115. };