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