1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2022 Rockchip Electronics Co., Ltd 4 */ 5 6 #include <common.h> 7 #include <dm.h> 8 #include <errno.h> 9 #include <i2c.h> 10 #include <video_bridge.h> 11 #include <asm/unaligned.h> 12 #include <linux/media-bus-format.h> 13 #include <power/regulator.h> 14 15 #include "rockchip_bridge.h" 16 #include "rockchip_display.h" 17 #include "rockchip_panel.h" 18 19 struct ser_reg_sequence { 20 uint reg; 21 uint def; 22 }; 23 24 struct serdes_init_seq { 25 struct ser_reg_sequence *reg_sequence; 26 uint reg_seq_cnt; 27 }; 28 29 struct bu18tl82_priv { 30 struct udevice *dev; 31 struct udevice *power_supply; 32 struct gpio_desc enable_gpio; 33 struct serdes_init_seq *serdes_init_seq; 34 }; 35 36 static void bu18tl82_serdes_init_sequence_write(struct bu18tl82_priv *priv) 37 { 38 struct serdes_init_seq *serdes_init_seq = priv->serdes_init_seq; 39 struct ser_reg_sequence *reg_sequence = serdes_init_seq->reg_sequence; 40 uint cnt = serdes_init_seq->reg_seq_cnt; 41 struct udevice *dev = priv->dev; 42 uint i; 43 int ret; 44 45 for (i = 0; i < cnt; i++) { 46 ret = dm_i2c_reg_write(dev, reg_sequence[i].reg, reg_sequence[i].def); 47 if (ret < 0) 48 dev_err(priv->dev, "write reg: 0x%04x\n", reg_sequence[i].reg); 49 } 50 51 mdelay(1000); 52 } 53 54 static void bu18tl82_bridge_enable(struct rockchip_bridge *bridge) 55 { 56 struct udevice *dev = bridge->dev; 57 struct bu18tl82_priv *priv = dev_get_priv(dev); 58 59 bu18tl82_serdes_init_sequence_write(priv); 60 } 61 62 static void bu18tl82_bridge_disable(struct rockchip_bridge *bridge) 63 { 64 } 65 66 static void bu18tl82_bridge_pre_enable(struct rockchip_bridge *bridge) 67 { 68 struct udevice *dev = bridge->dev; 69 struct bu18tl82_priv *priv = dev_get_priv(dev); 70 71 if (priv->power_supply) 72 regulator_set_enable(priv->power_supply, true); 73 74 if (dm_gpio_is_valid(&priv->enable_gpio)) 75 dm_gpio_set_value(&priv->enable_gpio, 1); 76 77 mdelay(120); 78 79 video_bridge_set_active(priv->dev, true); 80 } 81 82 static void bu18tl82_bridge_post_disable(struct rockchip_bridge *bridge) 83 { 84 struct udevice *dev = bridge->dev; 85 struct bu18tl82_priv *priv = dev_get_priv(dev); 86 87 video_bridge_set_active(priv->dev, false); 88 89 if (dm_gpio_is_valid(&priv->enable_gpio)) 90 dm_gpio_set_value(&priv->enable_gpio, 0); 91 92 if (priv->power_supply) 93 regulator_set_enable(priv->power_supply, false); 94 } 95 96 static const struct rockchip_bridge_funcs bu18tl82_bridge_funcs = { 97 .enable = bu18tl82_bridge_enable, 98 .disable = bu18tl82_bridge_disable, 99 .pre_enable = bu18tl82_bridge_pre_enable, 100 .post_disable = bu18tl82_bridge_post_disable, 101 }; 102 103 static int bu18tl82_parse_init_seq(struct udevice *dev, const u16 *data, 104 int length, struct serdes_init_seq *seq) 105 { 106 struct ser_reg_sequence *reg_sequence; 107 u16 *buf, *d; 108 unsigned int i, cnt; 109 int ret; 110 111 if (!seq) 112 return -EINVAL; 113 114 buf = calloc(1, length); 115 if (!buf) 116 return -ENOMEM; 117 118 memcpy(buf, data, length); 119 120 d = buf; 121 cnt = length / 4; 122 seq->reg_seq_cnt = cnt; 123 124 seq->reg_sequence = calloc(cnt, sizeof(struct ser_reg_sequence)); 125 if (!seq->reg_sequence) { 126 ret = -ENOMEM; 127 goto free_buf; 128 } 129 130 for (i = 0; i < cnt; i++) { 131 reg_sequence = &seq->reg_sequence[i]; 132 reg_sequence->reg = get_unaligned_be16(&d[0]); 133 reg_sequence->def = get_unaligned_be16(&d[1]); 134 d += 2; 135 } 136 137 return 0; 138 139 free_buf: 140 free(buf); 141 142 return ret; 143 } 144 145 static int bu18tl82_get_init_seq(struct bu18tl82_priv *priv) 146 { 147 const void *data = NULL; 148 int len, err; 149 150 data = dev_read_prop(priv->dev, "serdes-init-sequence", &len); 151 if (!data) { 152 printf("failed to get serdes-init-sequence\n"); 153 return -EINVAL; 154 } 155 156 priv->serdes_init_seq = calloc(1, sizeof(*priv->serdes_init_seq)); 157 if (!priv->serdes_init_seq) 158 return -ENOMEM; 159 160 err = bu18tl82_parse_init_seq(priv->dev, data, len, priv->serdes_init_seq); 161 if (err) { 162 printf("failed to parse serdes-init-sequence\n"); 163 goto free_init_seq; 164 } 165 166 return 0; 167 168 free_init_seq: 169 free(priv->serdes_init_seq); 170 171 return err; 172 } 173 174 static int bu18tl82_probe(struct udevice *dev) 175 { 176 struct bu18tl82_priv *priv = dev_get_priv(dev); 177 struct rockchip_bridge *bridge; 178 int ret; 179 180 ret = i2c_set_chip_offset_len(dev, 2); 181 if (ret) 182 return ret; 183 184 priv->dev = dev; 185 186 ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev, 187 "power-supply", &priv->power_supply); 188 if (ret && ret != -ENOENT) { 189 printf("%s: Cannot get power supply: %d\n", __func__, ret); 190 return ret; 191 } 192 193 ret = gpio_request_by_name(dev, "enable-gpios", 0, 194 &priv->enable_gpio, GPIOD_IS_OUT); 195 if (ret && ret != -ENOENT) { 196 dev_err(dev, "%s: failed to get enable GPIO: %d\n", __func__, ret); 197 return ret; 198 } 199 200 bridge = calloc(1, sizeof(*bridge)); 201 if (!bridge) 202 return -ENOMEM; 203 204 ret = bu18tl82_get_init_seq(priv); 205 if (ret) 206 goto free_bridge; 207 208 dev->driver_data = (ulong)bridge; 209 bridge->dev = dev; 210 bridge->funcs = &bu18tl82_bridge_funcs; 211 212 return 0; 213 214 free_bridge: 215 free(bridge); 216 217 return ret; 218 } 219 220 static const struct udevice_id bu18tl82_of_match[] = { 221 { .compatible = "rohm,bu18tl82", }, 222 {} 223 }; 224 225 U_BOOT_DRIVER(bu18tl82) = { 226 .name = "bu18tl82", 227 .id = UCLASS_VIDEO_BRIDGE, 228 .of_match = bu18tl82_of_match, 229 .probe = bu18tl82_probe, 230 .priv_auto_alloc_size = sizeof(struct bu18tl82_priv), 231 }; 232