552 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Parade PS8622 eDP/LVDS bridge driver4 *5 * Copyright (C) 2014 Google, Inc.6 */7 8#include <linux/backlight.h>9#include <linux/delay.h>10#include <linux/err.h>11#include <linux/gpio/consumer.h>12#include <linux/i2c.h>13#include <linux/module.h>14#include <linux/of.h>15#include <linux/pm.h>16#include <linux/regulator/consumer.h>17 18#include <drm/drm_atomic_helper.h>19#include <drm/drm_bridge.h>20#include <drm/drm_crtc.h>21#include <drm/drm_of.h>22#include <drm/drm_panel.h>23#include <drm/drm_print.h>24#include <drm/drm_probe_helper.h>25 26/* Brightness scale on the Parade chip */27#define PS8622_MAX_BRIGHTNESS 0xff28 29/* Timings taken from the version 1.7 datasheet for the PS8622/PS8625 */30#define PS8622_POWER_RISE_T1_MIN_US 1031#define PS8622_POWER_RISE_T1_MAX_US 1000032#define PS8622_RST_HIGH_T2_MIN_US 300033#define PS8622_RST_HIGH_T2_MAX_US 3000034#define PS8622_PWMO_END_T12_MS 20035#define PS8622_POWER_FALL_T16_MAX_US 1000036#define PS8622_POWER_OFF_T17_MS 50037 38#if ((PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US) > \39 (PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US))40#error "T2.min + T1.max must be less than T2.max + T1.min"41#endif42 43struct ps8622_bridge {44 struct i2c_client *client;45 struct drm_bridge bridge;46 struct drm_bridge *panel_bridge;47 struct regulator *v12;48 struct backlight_device *bl;49 50 struct gpio_desc *gpio_slp;51 struct gpio_desc *gpio_rst;52 53 u32 max_lane_count;54 u32 lane_count;55 56 bool enabled;57};58 59static inline struct ps8622_bridge *60 bridge_to_ps8622(struct drm_bridge *bridge)61{62 return container_of(bridge, struct ps8622_bridge, bridge);63}64 65static int ps8622_set(struct i2c_client *client, u8 page, u8 reg, u8 val)66{67 int ret;68 struct i2c_adapter *adap = client->adapter;69 struct i2c_msg msg;70 u8 data[] = {reg, val};71 72 msg.addr = client->addr + page;73 msg.flags = 0;74 msg.len = sizeof(data);75 msg.buf = data;76 77 ret = i2c_transfer(adap, &msg, 1);78 if (ret != 1)79 pr_warn("PS8622 I2C write (0x%02x,0x%02x,0x%02x) failed: %d\n",80 client->addr + page, reg, val, ret);81 return !(ret == 1);82}83 84static int ps8622_send_config(struct ps8622_bridge *ps8622)85{86 struct i2c_client *cl = ps8622->client;87 int err = 0;88 89 /* HPD low */90 err = ps8622_set(cl, 0x02, 0xa1, 0x01);91 if (err)92 goto error;93 94 /* SW setting: [1:0] SW output 1.2V voltage is lower to 96% */95 err = ps8622_set(cl, 0x04, 0x14, 0x01);96 if (err)97 goto error;98 99 /* RCO SS setting: [5:4] = b01 0.5%, b10 1%, b11 1.5% */100 err = ps8622_set(cl, 0x04, 0xe3, 0x20);101 if (err)102 goto error;103 104 /* [7] RCO SS enable */105 err = ps8622_set(cl, 0x04, 0xe2, 0x80);106 if (err)107 goto error;108 109 /* RPHY Setting110 * [3:2] CDR tune wait cycle before measure for fine tune111 * b00: 1us b01: 0.5us b10:2us, b11: 4us112 */113 err = ps8622_set(cl, 0x04, 0x8a, 0x0c);114 if (err)115 goto error;116 117 /* [3] RFD always on */118 err = ps8622_set(cl, 0x04, 0x89, 0x08);119 if (err)120 goto error;121 122 /* CTN lock in/out: 20000ppm/80000ppm. Lock out 2 times. */123 err = ps8622_set(cl, 0x04, 0x71, 0x2d);124 if (err)125 goto error;126 127 /* 2.7G CDR settings: NOF=40LSB for HBR CDR setting */128 err = ps8622_set(cl, 0x04, 0x7d, 0x07);129 if (err)130 goto error;131 132 /* [1:0] Fmin=+4bands */133 err = ps8622_set(cl, 0x04, 0x7b, 0x00);134 if (err)135 goto error;136 137 /* [7:5] DCO_FTRNG=+-40% */138 err = ps8622_set(cl, 0x04, 0x7a, 0xfd);139 if (err)140 goto error;141 142 /* 1.62G CDR settings: [5:2]NOF=64LSB [1:0]DCO scale is 2/5 */143 err = ps8622_set(cl, 0x04, 0xc0, 0x12);144 if (err)145 goto error;146 147 /* Gitune=-37% */148 err = ps8622_set(cl, 0x04, 0xc1, 0x92);149 if (err)150 goto error;151 152 /* Fbstep=100% */153 err = ps8622_set(cl, 0x04, 0xc2, 0x1c);154 if (err)155 goto error;156 157 /* [7] LOS signal disable */158 err = ps8622_set(cl, 0x04, 0x32, 0x80);159 if (err)160 goto error;161 162 /* RPIO Setting: [7:4] LVDS driver bias current : 75% (250mV swing) */163 err = ps8622_set(cl, 0x04, 0x00, 0xb0);164 if (err)165 goto error;166 167 /* [7:6] Right-bar GPIO output strength is 8mA */168 err = ps8622_set(cl, 0x04, 0x15, 0x40);169 if (err)170 goto error;171 172 /* EQ Training State Machine Setting, RCO calibration start */173 err = ps8622_set(cl, 0x04, 0x54, 0x10);174 if (err)175 goto error;176 177 /* Logic, needs more than 10 I2C command */178 /* [4:0] MAX_LANE_COUNT set to max supported lanes */179 err = ps8622_set(cl, 0x01, 0x02, 0x80 | ps8622->max_lane_count);180 if (err)181 goto error;182 183 /* [4:0] LANE_COUNT_SET set to chosen lane count */184 err = ps8622_set(cl, 0x01, 0x21, 0x80 | ps8622->lane_count);185 if (err)186 goto error;187 188 err = ps8622_set(cl, 0x00, 0x52, 0x20);189 if (err)190 goto error;191 192 /* HPD CP toggle enable */193 err = ps8622_set(cl, 0x00, 0xf1, 0x03);194 if (err)195 goto error;196 197 err = ps8622_set(cl, 0x00, 0x62, 0x41);198 if (err)199 goto error;200 201 /* Counter number, add 1ms counter delay */202 err = ps8622_set(cl, 0x00, 0xf6, 0x01);203 if (err)204 goto error;205 206 /* [6]PWM function control by DPCD0040f[7], default is PWM block */207 err = ps8622_set(cl, 0x00, 0x77, 0x06);208 if (err)209 goto error;210 211 /* 04h Adjust VTotal toleranceto fix the 30Hz no display issue */212 err = ps8622_set(cl, 0x00, 0x4c, 0x04);213 if (err)214 goto error;215 216 /* DPCD00400='h00, Parade OUI ='h001cf8 */217 err = ps8622_set(cl, 0x01, 0xc0, 0x00);218 if (err)219 goto error;220 221 /* DPCD00401='h1c */222 err = ps8622_set(cl, 0x01, 0xc1, 0x1c);223 if (err)224 goto error;225 226 /* DPCD00402='hf8 */227 err = ps8622_set(cl, 0x01, 0xc2, 0xf8);228 if (err)229 goto error;230 231 /* DPCD403~408 = ASCII code, D2SLV5='h4432534c5635 */232 err = ps8622_set(cl, 0x01, 0xc3, 0x44);233 if (err)234 goto error;235 236 /* DPCD404 */237 err = ps8622_set(cl, 0x01, 0xc4, 0x32);238 if (err)239 goto error;240 241 /* DPCD405 */242 err = ps8622_set(cl, 0x01, 0xc5, 0x53);243 if (err)244 goto error;245 246 /* DPCD406 */247 err = ps8622_set(cl, 0x01, 0xc6, 0x4c);248 if (err)249 goto error;250 251 /* DPCD407 */252 err = ps8622_set(cl, 0x01, 0xc7, 0x56);253 if (err)254 goto error;255 256 /* DPCD408 */257 err = ps8622_set(cl, 0x01, 0xc8, 0x35);258 if (err)259 goto error;260 261 /* DPCD40A, Initial Code major revision '01' */262 err = ps8622_set(cl, 0x01, 0xca, 0x01);263 if (err)264 goto error;265 266 /* DPCD40B, Initial Code minor revision '05' */267 err = ps8622_set(cl, 0x01, 0xcb, 0x05);268 if (err)269 goto error;270 271 272 if (ps8622->bl) {273 /* DPCD720, internal PWM */274 err = ps8622_set(cl, 0x01, 0xa5, 0xa0);275 if (err)276 goto error;277 278 /* FFh for 100% brightness, 0h for 0% brightness */279 err = ps8622_set(cl, 0x01, 0xa7,280 ps8622->bl->props.brightness);281 if (err)282 goto error;283 } else {284 /* DPCD720, external PWM */285 err = ps8622_set(cl, 0x01, 0xa5, 0x80);286 if (err)287 goto error;288 }289 290 /* Set LVDS output as 6bit-VESA mapping, single LVDS channel */291 err = ps8622_set(cl, 0x01, 0xcc, 0x13);292 if (err)293 goto error;294 295 /* Enable SSC set by register */296 err = ps8622_set(cl, 0x02, 0xb1, 0x20);297 if (err)298 goto error;299 300 /* Set SSC enabled and +/-1% central spreading */301 err = ps8622_set(cl, 0x04, 0x10, 0x16);302 if (err)303 goto error;304 305 /* Logic end */306 /* MPU Clock source: LC => RCO */307 err = ps8622_set(cl, 0x04, 0x59, 0x60);308 if (err)309 goto error;310 311 /* LC -> RCO */312 err = ps8622_set(cl, 0x04, 0x54, 0x14);313 if (err)314 goto error;315 316 /* HPD high */317 err = ps8622_set(cl, 0x02, 0xa1, 0x91);318 319error:320 return err ? -EIO : 0;321}322 323static int ps8622_backlight_update(struct backlight_device *bl)324{325 struct ps8622_bridge *ps8622 = dev_get_drvdata(&bl->dev);326 int ret, brightness = backlight_get_brightness(bl);327 328 if (!ps8622->enabled)329 return -EINVAL;330 331 ret = ps8622_set(ps8622->client, 0x01, 0xa7, brightness);332 333 return ret;334}335 336static const struct backlight_ops ps8622_backlight_ops = {337 .update_status = ps8622_backlight_update,338};339 340static void ps8622_pre_enable(struct drm_bridge *bridge)341{342 struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);343 int ret;344 345 if (ps8622->enabled)346 return;347 348 gpiod_set_value(ps8622->gpio_rst, 0);349 350 if (ps8622->v12) {351 ret = regulator_enable(ps8622->v12);352 if (ret)353 DRM_ERROR("fails to enable ps8622->v12");354 }355 356 gpiod_set_value(ps8622->gpio_slp, 1);357 358 /*359 * T1 is the range of time that it takes for the power to rise after we360 * enable the lcd/ps8622 fet. T2 is the range of time in which the361 * data sheet specifies we should deassert the reset pin.362 *363 * If it takes T1.max for the power to rise, we need to wait atleast364 * T2.min before deasserting the reset pin. If it takes T1.min for the365 * power to rise, we need to wait at most T2.max before deasserting the366 * reset pin.367 */368 usleep_range(PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US,369 PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US);370 371 gpiod_set_value(ps8622->gpio_rst, 1);372 373 /* wait 20ms after RST high */374 usleep_range(20000, 30000);375 376 ret = ps8622_send_config(ps8622);377 if (ret) {378 DRM_ERROR("Failed to send config to bridge (%d)\n", ret);379 return;380 }381 382 ps8622->enabled = true;383}384 385static void ps8622_disable(struct drm_bridge *bridge)386{387 /* Delay after panel is disabled */388 msleep(PS8622_PWMO_END_T12_MS);389}390 391static void ps8622_post_disable(struct drm_bridge *bridge)392{393 struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);394 395 if (!ps8622->enabled)396 return;397 398 ps8622->enabled = false;399 400 /*401 * This doesn't matter if the regulators are turned off, but something402 * else might keep them on. In that case, we want to assert the slp gpio403 * to lower power.404 */405 gpiod_set_value(ps8622->gpio_slp, 0);406 407 if (ps8622->v12)408 regulator_disable(ps8622->v12);409 410 /*411 * Sleep for at least the amount of time that it takes the power rail to412 * fall to prevent asserting the rst gpio from doing anything.413 */414 usleep_range(PS8622_POWER_FALL_T16_MAX_US,415 2 * PS8622_POWER_FALL_T16_MAX_US);416 gpiod_set_value(ps8622->gpio_rst, 0);417 418 msleep(PS8622_POWER_OFF_T17_MS);419}420 421static int ps8622_attach(struct drm_bridge *bridge,422 enum drm_bridge_attach_flags flags)423{424 struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);425 426 return drm_bridge_attach(ps8622->bridge.encoder, ps8622->panel_bridge,427 &ps8622->bridge, flags);428}429 430static const struct drm_bridge_funcs ps8622_bridge_funcs = {431 .pre_enable = ps8622_pre_enable,432 .disable = ps8622_disable,433 .post_disable = ps8622_post_disable,434 .attach = ps8622_attach,435};436 437static const struct of_device_id ps8622_devices[] = {438 {.compatible = "parade,ps8622",},439 {.compatible = "parade,ps8625",},440 {}441};442MODULE_DEVICE_TABLE(of, ps8622_devices);443 444static int ps8622_probe(struct i2c_client *client)445{446 const struct i2c_device_id *id = i2c_client_get_device_id(client);447 struct device *dev = &client->dev;448 struct ps8622_bridge *ps8622;449 struct drm_bridge *panel_bridge;450 int ret;451 452 ps8622 = devm_kzalloc(dev, sizeof(*ps8622), GFP_KERNEL);453 if (!ps8622)454 return -ENOMEM;455 456 panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0);457 if (IS_ERR(panel_bridge))458 return PTR_ERR(panel_bridge);459 460 ps8622->panel_bridge = panel_bridge;461 ps8622->client = client;462 463 ps8622->v12 = devm_regulator_get(dev, "vdd12");464 if (IS_ERR(ps8622->v12)) {465 dev_info(dev, "no 1.2v regulator found for PS8622\n");466 ps8622->v12 = NULL;467 }468 469 ps8622->gpio_slp = devm_gpiod_get(dev, "sleep", GPIOD_OUT_HIGH);470 if (IS_ERR(ps8622->gpio_slp)) {471 ret = PTR_ERR(ps8622->gpio_slp);472 dev_err(dev, "cannot get gpio_slp %d\n", ret);473 return ret;474 }475 476 /*477 * Assert the reset pin high to avoid the bridge being478 * initialized prematurely479 */480 ps8622->gpio_rst = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);481 if (IS_ERR(ps8622->gpio_rst)) {482 ret = PTR_ERR(ps8622->gpio_rst);483 dev_err(dev, "cannot get gpio_rst %d\n", ret);484 return ret;485 }486 487 ps8622->max_lane_count = id->driver_data;488 489 if (of_property_read_u32(dev->of_node, "lane-count",490 &ps8622->lane_count)) {491 ps8622->lane_count = ps8622->max_lane_count;492 } else if (ps8622->lane_count > ps8622->max_lane_count) {493 dev_info(dev, "lane-count property is too high,"494 "using max_lane_count\n");495 ps8622->lane_count = ps8622->max_lane_count;496 }497 498 if (!of_property_read_bool(dev->of_node, "use-external-pwm")) {499 ps8622->bl = backlight_device_register("ps8622-backlight",500 dev, ps8622, &ps8622_backlight_ops,501 NULL);502 if (IS_ERR(ps8622->bl)) {503 DRM_ERROR("failed to register backlight\n");504 ret = PTR_ERR(ps8622->bl);505 ps8622->bl = NULL;506 return ret;507 }508 ps8622->bl->props.max_brightness = PS8622_MAX_BRIGHTNESS;509 ps8622->bl->props.brightness = PS8622_MAX_BRIGHTNESS;510 }511 512 ps8622->bridge.funcs = &ps8622_bridge_funcs;513 ps8622->bridge.type = DRM_MODE_CONNECTOR_LVDS;514 ps8622->bridge.of_node = dev->of_node;515 drm_bridge_add(&ps8622->bridge);516 517 i2c_set_clientdata(client, ps8622);518 519 return 0;520}521 522static void ps8622_remove(struct i2c_client *client)523{524 struct ps8622_bridge *ps8622 = i2c_get_clientdata(client);525 526 backlight_device_unregister(ps8622->bl);527 drm_bridge_remove(&ps8622->bridge);528}529 530static const struct i2c_device_id ps8622_i2c_table[] = {531 /* Device type, max_lane_count */532 {"ps8622", 1},533 {"ps8625", 2},534 {},535};536MODULE_DEVICE_TABLE(i2c, ps8622_i2c_table);537 538static struct i2c_driver ps8622_driver = {539 .id_table = ps8622_i2c_table,540 .probe = ps8622_probe,541 .remove = ps8622_remove,542 .driver = {543 .name = "ps8622",544 .of_match_table = ps8622_devices,545 },546};547module_i2c_driver(ps8622_driver);548 549MODULE_AUTHOR("Vincent Palatin <vpalatin@chromium.org>");550MODULE_DESCRIPTION("Parade ps8622/ps8625 eDP-LVDS converter driver");551MODULE_LICENSE("GPL v2");552