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