162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Parade PS8622 eDP/LVDS bridge driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2014 Google, Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/backlight.h> 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <linux/err.h> 1162306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1262306a36Sopenharmony_ci#include <linux/i2c.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/of.h> 1562306a36Sopenharmony_ci#include <linux/pm.h> 1662306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <drm/drm_atomic_helper.h> 1962306a36Sopenharmony_ci#include <drm/drm_bridge.h> 2062306a36Sopenharmony_ci#include <drm/drm_crtc.h> 2162306a36Sopenharmony_ci#include <drm/drm_of.h> 2262306a36Sopenharmony_ci#include <drm/drm_panel.h> 2362306a36Sopenharmony_ci#include <drm/drm_print.h> 2462306a36Sopenharmony_ci#include <drm/drm_probe_helper.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* Brightness scale on the Parade chip */ 2762306a36Sopenharmony_ci#define PS8622_MAX_BRIGHTNESS 0xff 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* Timings taken from the version 1.7 datasheet for the PS8622/PS8625 */ 3062306a36Sopenharmony_ci#define PS8622_POWER_RISE_T1_MIN_US 10 3162306a36Sopenharmony_ci#define PS8622_POWER_RISE_T1_MAX_US 10000 3262306a36Sopenharmony_ci#define PS8622_RST_HIGH_T2_MIN_US 3000 3362306a36Sopenharmony_ci#define PS8622_RST_HIGH_T2_MAX_US 30000 3462306a36Sopenharmony_ci#define PS8622_PWMO_END_T12_MS 200 3562306a36Sopenharmony_ci#define PS8622_POWER_FALL_T16_MAX_US 10000 3662306a36Sopenharmony_ci#define PS8622_POWER_OFF_T17_MS 500 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#if ((PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US) > \ 3962306a36Sopenharmony_ci (PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US)) 4062306a36Sopenharmony_ci#error "T2.min + T1.max must be less than T2.max + T1.min" 4162306a36Sopenharmony_ci#endif 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistruct ps8622_bridge { 4462306a36Sopenharmony_ci struct i2c_client *client; 4562306a36Sopenharmony_ci struct drm_bridge bridge; 4662306a36Sopenharmony_ci struct drm_bridge *panel_bridge; 4762306a36Sopenharmony_ci struct regulator *v12; 4862306a36Sopenharmony_ci struct backlight_device *bl; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci struct gpio_desc *gpio_slp; 5162306a36Sopenharmony_ci struct gpio_desc *gpio_rst; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci u32 max_lane_count; 5462306a36Sopenharmony_ci u32 lane_count; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci bool enabled; 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic inline struct ps8622_bridge * 6062306a36Sopenharmony_ci bridge_to_ps8622(struct drm_bridge *bridge) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci return container_of(bridge, struct ps8622_bridge, bridge); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic int ps8622_set(struct i2c_client *client, u8 page, u8 reg, u8 val) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci int ret; 6862306a36Sopenharmony_ci struct i2c_adapter *adap = client->adapter; 6962306a36Sopenharmony_ci struct i2c_msg msg; 7062306a36Sopenharmony_ci u8 data[] = {reg, val}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci msg.addr = client->addr + page; 7362306a36Sopenharmony_ci msg.flags = 0; 7462306a36Sopenharmony_ci msg.len = sizeof(data); 7562306a36Sopenharmony_ci msg.buf = data; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci ret = i2c_transfer(adap, &msg, 1); 7862306a36Sopenharmony_ci if (ret != 1) 7962306a36Sopenharmony_ci pr_warn("PS8622 I2C write (0x%02x,0x%02x,0x%02x) failed: %d\n", 8062306a36Sopenharmony_ci client->addr + page, reg, val, ret); 8162306a36Sopenharmony_ci return !(ret == 1); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic int ps8622_send_config(struct ps8622_bridge *ps8622) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct i2c_client *cl = ps8622->client; 8762306a36Sopenharmony_ci int err = 0; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* HPD low */ 9062306a36Sopenharmony_ci err = ps8622_set(cl, 0x02, 0xa1, 0x01); 9162306a36Sopenharmony_ci if (err) 9262306a36Sopenharmony_ci goto error; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* SW setting: [1:0] SW output 1.2V voltage is lower to 96% */ 9562306a36Sopenharmony_ci err = ps8622_set(cl, 0x04, 0x14, 0x01); 9662306a36Sopenharmony_ci if (err) 9762306a36Sopenharmony_ci goto error; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* RCO SS setting: [5:4] = b01 0.5%, b10 1%, b11 1.5% */ 10062306a36Sopenharmony_ci err = ps8622_set(cl, 0x04, 0xe3, 0x20); 10162306a36Sopenharmony_ci if (err) 10262306a36Sopenharmony_ci goto error; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci /* [7] RCO SS enable */ 10562306a36Sopenharmony_ci err = ps8622_set(cl, 0x04, 0xe2, 0x80); 10662306a36Sopenharmony_ci if (err) 10762306a36Sopenharmony_ci goto error; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* RPHY Setting 11062306a36Sopenharmony_ci * [3:2] CDR tune wait cycle before measure for fine tune 11162306a36Sopenharmony_ci * b00: 1us b01: 0.5us b10:2us, b11: 4us 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_ci err = ps8622_set(cl, 0x04, 0x8a, 0x0c); 11462306a36Sopenharmony_ci if (err) 11562306a36Sopenharmony_ci goto error; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci /* [3] RFD always on */ 11862306a36Sopenharmony_ci err = ps8622_set(cl, 0x04, 0x89, 0x08); 11962306a36Sopenharmony_ci if (err) 12062306a36Sopenharmony_ci goto error; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* CTN lock in/out: 20000ppm/80000ppm. Lock out 2 times. */ 12362306a36Sopenharmony_ci err = ps8622_set(cl, 0x04, 0x71, 0x2d); 12462306a36Sopenharmony_ci if (err) 12562306a36Sopenharmony_ci goto error; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* 2.7G CDR settings: NOF=40LSB for HBR CDR setting */ 12862306a36Sopenharmony_ci err = ps8622_set(cl, 0x04, 0x7d, 0x07); 12962306a36Sopenharmony_ci if (err) 13062306a36Sopenharmony_ci goto error; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* [1:0] Fmin=+4bands */ 13362306a36Sopenharmony_ci err = ps8622_set(cl, 0x04, 0x7b, 0x00); 13462306a36Sopenharmony_ci if (err) 13562306a36Sopenharmony_ci goto error; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* [7:5] DCO_FTRNG=+-40% */ 13862306a36Sopenharmony_ci err = ps8622_set(cl, 0x04, 0x7a, 0xfd); 13962306a36Sopenharmony_ci if (err) 14062306a36Sopenharmony_ci goto error; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* 1.62G CDR settings: [5:2]NOF=64LSB [1:0]DCO scale is 2/5 */ 14362306a36Sopenharmony_ci err = ps8622_set(cl, 0x04, 0xc0, 0x12); 14462306a36Sopenharmony_ci if (err) 14562306a36Sopenharmony_ci goto error; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* Gitune=-37% */ 14862306a36Sopenharmony_ci err = ps8622_set(cl, 0x04, 0xc1, 0x92); 14962306a36Sopenharmony_ci if (err) 15062306a36Sopenharmony_ci goto error; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* Fbstep=100% */ 15362306a36Sopenharmony_ci err = ps8622_set(cl, 0x04, 0xc2, 0x1c); 15462306a36Sopenharmony_ci if (err) 15562306a36Sopenharmony_ci goto error; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* [7] LOS signal disable */ 15862306a36Sopenharmony_ci err = ps8622_set(cl, 0x04, 0x32, 0x80); 15962306a36Sopenharmony_ci if (err) 16062306a36Sopenharmony_ci goto error; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* RPIO Setting: [7:4] LVDS driver bias current : 75% (250mV swing) */ 16362306a36Sopenharmony_ci err = ps8622_set(cl, 0x04, 0x00, 0xb0); 16462306a36Sopenharmony_ci if (err) 16562306a36Sopenharmony_ci goto error; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* [7:6] Right-bar GPIO output strength is 8mA */ 16862306a36Sopenharmony_ci err = ps8622_set(cl, 0x04, 0x15, 0x40); 16962306a36Sopenharmony_ci if (err) 17062306a36Sopenharmony_ci goto error; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* EQ Training State Machine Setting, RCO calibration start */ 17362306a36Sopenharmony_ci err = ps8622_set(cl, 0x04, 0x54, 0x10); 17462306a36Sopenharmony_ci if (err) 17562306a36Sopenharmony_ci goto error; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* Logic, needs more than 10 I2C command */ 17862306a36Sopenharmony_ci /* [4:0] MAX_LANE_COUNT set to max supported lanes */ 17962306a36Sopenharmony_ci err = ps8622_set(cl, 0x01, 0x02, 0x80 | ps8622->max_lane_count); 18062306a36Sopenharmony_ci if (err) 18162306a36Sopenharmony_ci goto error; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci /* [4:0] LANE_COUNT_SET set to chosen lane count */ 18462306a36Sopenharmony_ci err = ps8622_set(cl, 0x01, 0x21, 0x80 | ps8622->lane_count); 18562306a36Sopenharmony_ci if (err) 18662306a36Sopenharmony_ci goto error; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci err = ps8622_set(cl, 0x00, 0x52, 0x20); 18962306a36Sopenharmony_ci if (err) 19062306a36Sopenharmony_ci goto error; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* HPD CP toggle enable */ 19362306a36Sopenharmony_ci err = ps8622_set(cl, 0x00, 0xf1, 0x03); 19462306a36Sopenharmony_ci if (err) 19562306a36Sopenharmony_ci goto error; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci err = ps8622_set(cl, 0x00, 0x62, 0x41); 19862306a36Sopenharmony_ci if (err) 19962306a36Sopenharmony_ci goto error; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci /* Counter number, add 1ms counter delay */ 20262306a36Sopenharmony_ci err = ps8622_set(cl, 0x00, 0xf6, 0x01); 20362306a36Sopenharmony_ci if (err) 20462306a36Sopenharmony_ci goto error; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* [6]PWM function control by DPCD0040f[7], default is PWM block */ 20762306a36Sopenharmony_ci err = ps8622_set(cl, 0x00, 0x77, 0x06); 20862306a36Sopenharmony_ci if (err) 20962306a36Sopenharmony_ci goto error; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* 04h Adjust VTotal toleranceto fix the 30Hz no display issue */ 21262306a36Sopenharmony_ci err = ps8622_set(cl, 0x00, 0x4c, 0x04); 21362306a36Sopenharmony_ci if (err) 21462306a36Sopenharmony_ci goto error; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* DPCD00400='h00, Parade OUI ='h001cf8 */ 21762306a36Sopenharmony_ci err = ps8622_set(cl, 0x01, 0xc0, 0x00); 21862306a36Sopenharmony_ci if (err) 21962306a36Sopenharmony_ci goto error; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* DPCD00401='h1c */ 22262306a36Sopenharmony_ci err = ps8622_set(cl, 0x01, 0xc1, 0x1c); 22362306a36Sopenharmony_ci if (err) 22462306a36Sopenharmony_ci goto error; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* DPCD00402='hf8 */ 22762306a36Sopenharmony_ci err = ps8622_set(cl, 0x01, 0xc2, 0xf8); 22862306a36Sopenharmony_ci if (err) 22962306a36Sopenharmony_ci goto error; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci /* DPCD403~408 = ASCII code, D2SLV5='h4432534c5635 */ 23262306a36Sopenharmony_ci err = ps8622_set(cl, 0x01, 0xc3, 0x44); 23362306a36Sopenharmony_ci if (err) 23462306a36Sopenharmony_ci goto error; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci /* DPCD404 */ 23762306a36Sopenharmony_ci err = ps8622_set(cl, 0x01, 0xc4, 0x32); 23862306a36Sopenharmony_ci if (err) 23962306a36Sopenharmony_ci goto error; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* DPCD405 */ 24262306a36Sopenharmony_ci err = ps8622_set(cl, 0x01, 0xc5, 0x53); 24362306a36Sopenharmony_ci if (err) 24462306a36Sopenharmony_ci goto error; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* DPCD406 */ 24762306a36Sopenharmony_ci err = ps8622_set(cl, 0x01, 0xc6, 0x4c); 24862306a36Sopenharmony_ci if (err) 24962306a36Sopenharmony_ci goto error; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* DPCD407 */ 25262306a36Sopenharmony_ci err = ps8622_set(cl, 0x01, 0xc7, 0x56); 25362306a36Sopenharmony_ci if (err) 25462306a36Sopenharmony_ci goto error; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci /* DPCD408 */ 25762306a36Sopenharmony_ci err = ps8622_set(cl, 0x01, 0xc8, 0x35); 25862306a36Sopenharmony_ci if (err) 25962306a36Sopenharmony_ci goto error; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* DPCD40A, Initial Code major revision '01' */ 26262306a36Sopenharmony_ci err = ps8622_set(cl, 0x01, 0xca, 0x01); 26362306a36Sopenharmony_ci if (err) 26462306a36Sopenharmony_ci goto error; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* DPCD40B, Initial Code minor revision '05' */ 26762306a36Sopenharmony_ci err = ps8622_set(cl, 0x01, 0xcb, 0x05); 26862306a36Sopenharmony_ci if (err) 26962306a36Sopenharmony_ci goto error; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (ps8622->bl) { 27362306a36Sopenharmony_ci /* DPCD720, internal PWM */ 27462306a36Sopenharmony_ci err = ps8622_set(cl, 0x01, 0xa5, 0xa0); 27562306a36Sopenharmony_ci if (err) 27662306a36Sopenharmony_ci goto error; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* FFh for 100% brightness, 0h for 0% brightness */ 27962306a36Sopenharmony_ci err = ps8622_set(cl, 0x01, 0xa7, 28062306a36Sopenharmony_ci ps8622->bl->props.brightness); 28162306a36Sopenharmony_ci if (err) 28262306a36Sopenharmony_ci goto error; 28362306a36Sopenharmony_ci } else { 28462306a36Sopenharmony_ci /* DPCD720, external PWM */ 28562306a36Sopenharmony_ci err = ps8622_set(cl, 0x01, 0xa5, 0x80); 28662306a36Sopenharmony_ci if (err) 28762306a36Sopenharmony_ci goto error; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* Set LVDS output as 6bit-VESA mapping, single LVDS channel */ 29162306a36Sopenharmony_ci err = ps8622_set(cl, 0x01, 0xcc, 0x13); 29262306a36Sopenharmony_ci if (err) 29362306a36Sopenharmony_ci goto error; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* Enable SSC set by register */ 29662306a36Sopenharmony_ci err = ps8622_set(cl, 0x02, 0xb1, 0x20); 29762306a36Sopenharmony_ci if (err) 29862306a36Sopenharmony_ci goto error; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci /* Set SSC enabled and +/-1% central spreading */ 30162306a36Sopenharmony_ci err = ps8622_set(cl, 0x04, 0x10, 0x16); 30262306a36Sopenharmony_ci if (err) 30362306a36Sopenharmony_ci goto error; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* Logic end */ 30662306a36Sopenharmony_ci /* MPU Clock source: LC => RCO */ 30762306a36Sopenharmony_ci err = ps8622_set(cl, 0x04, 0x59, 0x60); 30862306a36Sopenharmony_ci if (err) 30962306a36Sopenharmony_ci goto error; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci /* LC -> RCO */ 31262306a36Sopenharmony_ci err = ps8622_set(cl, 0x04, 0x54, 0x14); 31362306a36Sopenharmony_ci if (err) 31462306a36Sopenharmony_ci goto error; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* HPD high */ 31762306a36Sopenharmony_ci err = ps8622_set(cl, 0x02, 0xa1, 0x91); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cierror: 32062306a36Sopenharmony_ci return err ? -EIO : 0; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic int ps8622_backlight_update(struct backlight_device *bl) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct ps8622_bridge *ps8622 = dev_get_drvdata(&bl->dev); 32662306a36Sopenharmony_ci int ret, brightness = backlight_get_brightness(bl); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (!ps8622->enabled) 32962306a36Sopenharmony_ci return -EINVAL; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci ret = ps8622_set(ps8622->client, 0x01, 0xa7, brightness); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci return ret; 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic const struct backlight_ops ps8622_backlight_ops = { 33762306a36Sopenharmony_ci .update_status = ps8622_backlight_update, 33862306a36Sopenharmony_ci}; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic void ps8622_pre_enable(struct drm_bridge *bridge) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); 34362306a36Sopenharmony_ci int ret; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (ps8622->enabled) 34662306a36Sopenharmony_ci return; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci gpiod_set_value(ps8622->gpio_rst, 0); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (ps8622->v12) { 35162306a36Sopenharmony_ci ret = regulator_enable(ps8622->v12); 35262306a36Sopenharmony_ci if (ret) 35362306a36Sopenharmony_ci DRM_ERROR("fails to enable ps8622->v12"); 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci gpiod_set_value(ps8622->gpio_slp, 1); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* 35962306a36Sopenharmony_ci * T1 is the range of time that it takes for the power to rise after we 36062306a36Sopenharmony_ci * enable the lcd/ps8622 fet. T2 is the range of time in which the 36162306a36Sopenharmony_ci * data sheet specifies we should deassert the reset pin. 36262306a36Sopenharmony_ci * 36362306a36Sopenharmony_ci * If it takes T1.max for the power to rise, we need to wait atleast 36462306a36Sopenharmony_ci * T2.min before deasserting the reset pin. If it takes T1.min for the 36562306a36Sopenharmony_ci * power to rise, we need to wait at most T2.max before deasserting the 36662306a36Sopenharmony_ci * reset pin. 36762306a36Sopenharmony_ci */ 36862306a36Sopenharmony_ci usleep_range(PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US, 36962306a36Sopenharmony_ci PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci gpiod_set_value(ps8622->gpio_rst, 1); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci /* wait 20ms after RST high */ 37462306a36Sopenharmony_ci usleep_range(20000, 30000); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci ret = ps8622_send_config(ps8622); 37762306a36Sopenharmony_ci if (ret) { 37862306a36Sopenharmony_ci DRM_ERROR("Failed to send config to bridge (%d)\n", ret); 37962306a36Sopenharmony_ci return; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci ps8622->enabled = true; 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic void ps8622_disable(struct drm_bridge *bridge) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci /* Delay after panel is disabled */ 38862306a36Sopenharmony_ci msleep(PS8622_PWMO_END_T12_MS); 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic void ps8622_post_disable(struct drm_bridge *bridge) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (!ps8622->enabled) 39662306a36Sopenharmony_ci return; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci ps8622->enabled = false; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* 40162306a36Sopenharmony_ci * This doesn't matter if the regulators are turned off, but something 40262306a36Sopenharmony_ci * else might keep them on. In that case, we want to assert the slp gpio 40362306a36Sopenharmony_ci * to lower power. 40462306a36Sopenharmony_ci */ 40562306a36Sopenharmony_ci gpiod_set_value(ps8622->gpio_slp, 0); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (ps8622->v12) 40862306a36Sopenharmony_ci regulator_disable(ps8622->v12); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* 41162306a36Sopenharmony_ci * Sleep for at least the amount of time that it takes the power rail to 41262306a36Sopenharmony_ci * fall to prevent asserting the rst gpio from doing anything. 41362306a36Sopenharmony_ci */ 41462306a36Sopenharmony_ci usleep_range(PS8622_POWER_FALL_T16_MAX_US, 41562306a36Sopenharmony_ci 2 * PS8622_POWER_FALL_T16_MAX_US); 41662306a36Sopenharmony_ci gpiod_set_value(ps8622->gpio_rst, 0); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci msleep(PS8622_POWER_OFF_T17_MS); 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic int ps8622_attach(struct drm_bridge *bridge, 42262306a36Sopenharmony_ci enum drm_bridge_attach_flags flags) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci return drm_bridge_attach(ps8622->bridge.encoder, ps8622->panel_bridge, 42762306a36Sopenharmony_ci &ps8622->bridge, flags); 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic const struct drm_bridge_funcs ps8622_bridge_funcs = { 43162306a36Sopenharmony_ci .pre_enable = ps8622_pre_enable, 43262306a36Sopenharmony_ci .disable = ps8622_disable, 43362306a36Sopenharmony_ci .post_disable = ps8622_post_disable, 43462306a36Sopenharmony_ci .attach = ps8622_attach, 43562306a36Sopenharmony_ci}; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic const struct of_device_id ps8622_devices[] = { 43862306a36Sopenharmony_ci {.compatible = "parade,ps8622",}, 43962306a36Sopenharmony_ci {.compatible = "parade,ps8625",}, 44062306a36Sopenharmony_ci {} 44162306a36Sopenharmony_ci}; 44262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ps8622_devices); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic int ps8622_probe(struct i2c_client *client) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci const struct i2c_device_id *id = i2c_client_get_device_id(client); 44762306a36Sopenharmony_ci struct device *dev = &client->dev; 44862306a36Sopenharmony_ci struct ps8622_bridge *ps8622; 44962306a36Sopenharmony_ci struct drm_bridge *panel_bridge; 45062306a36Sopenharmony_ci int ret; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci ps8622 = devm_kzalloc(dev, sizeof(*ps8622), GFP_KERNEL); 45362306a36Sopenharmony_ci if (!ps8622) 45462306a36Sopenharmony_ci return -ENOMEM; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0); 45762306a36Sopenharmony_ci if (IS_ERR(panel_bridge)) 45862306a36Sopenharmony_ci return PTR_ERR(panel_bridge); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci ps8622->panel_bridge = panel_bridge; 46162306a36Sopenharmony_ci ps8622->client = client; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci ps8622->v12 = devm_regulator_get(dev, "vdd12"); 46462306a36Sopenharmony_ci if (IS_ERR(ps8622->v12)) { 46562306a36Sopenharmony_ci dev_info(dev, "no 1.2v regulator found for PS8622\n"); 46662306a36Sopenharmony_ci ps8622->v12 = NULL; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci ps8622->gpio_slp = devm_gpiod_get(dev, "sleep", GPIOD_OUT_HIGH); 47062306a36Sopenharmony_ci if (IS_ERR(ps8622->gpio_slp)) { 47162306a36Sopenharmony_ci ret = PTR_ERR(ps8622->gpio_slp); 47262306a36Sopenharmony_ci dev_err(dev, "cannot get gpio_slp %d\n", ret); 47362306a36Sopenharmony_ci return ret; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci /* 47762306a36Sopenharmony_ci * Assert the reset pin high to avoid the bridge being 47862306a36Sopenharmony_ci * initialized prematurely 47962306a36Sopenharmony_ci */ 48062306a36Sopenharmony_ci ps8622->gpio_rst = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 48162306a36Sopenharmony_ci if (IS_ERR(ps8622->gpio_rst)) { 48262306a36Sopenharmony_ci ret = PTR_ERR(ps8622->gpio_rst); 48362306a36Sopenharmony_ci dev_err(dev, "cannot get gpio_rst %d\n", ret); 48462306a36Sopenharmony_ci return ret; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci ps8622->max_lane_count = id->driver_data; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (of_property_read_u32(dev->of_node, "lane-count", 49062306a36Sopenharmony_ci &ps8622->lane_count)) { 49162306a36Sopenharmony_ci ps8622->lane_count = ps8622->max_lane_count; 49262306a36Sopenharmony_ci } else if (ps8622->lane_count > ps8622->max_lane_count) { 49362306a36Sopenharmony_ci dev_info(dev, "lane-count property is too high," 49462306a36Sopenharmony_ci "using max_lane_count\n"); 49562306a36Sopenharmony_ci ps8622->lane_count = ps8622->max_lane_count; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (!of_property_read_bool(dev->of_node, "use-external-pwm")) { 49962306a36Sopenharmony_ci ps8622->bl = backlight_device_register("ps8622-backlight", 50062306a36Sopenharmony_ci dev, ps8622, &ps8622_backlight_ops, 50162306a36Sopenharmony_ci NULL); 50262306a36Sopenharmony_ci if (IS_ERR(ps8622->bl)) { 50362306a36Sopenharmony_ci DRM_ERROR("failed to register backlight\n"); 50462306a36Sopenharmony_ci ret = PTR_ERR(ps8622->bl); 50562306a36Sopenharmony_ci ps8622->bl = NULL; 50662306a36Sopenharmony_ci return ret; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci ps8622->bl->props.max_brightness = PS8622_MAX_BRIGHTNESS; 50962306a36Sopenharmony_ci ps8622->bl->props.brightness = PS8622_MAX_BRIGHTNESS; 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci ps8622->bridge.funcs = &ps8622_bridge_funcs; 51362306a36Sopenharmony_ci ps8622->bridge.type = DRM_MODE_CONNECTOR_LVDS; 51462306a36Sopenharmony_ci ps8622->bridge.of_node = dev->of_node; 51562306a36Sopenharmony_ci drm_bridge_add(&ps8622->bridge); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci i2c_set_clientdata(client, ps8622); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci return 0; 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_cistatic void ps8622_remove(struct i2c_client *client) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci struct ps8622_bridge *ps8622 = i2c_get_clientdata(client); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci backlight_device_unregister(ps8622->bl); 52762306a36Sopenharmony_ci drm_bridge_remove(&ps8622->bridge); 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic const struct i2c_device_id ps8622_i2c_table[] = { 53162306a36Sopenharmony_ci /* Device type, max_lane_count */ 53262306a36Sopenharmony_ci {"ps8622", 1}, 53362306a36Sopenharmony_ci {"ps8625", 2}, 53462306a36Sopenharmony_ci {}, 53562306a36Sopenharmony_ci}; 53662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, ps8622_i2c_table); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic struct i2c_driver ps8622_driver = { 53962306a36Sopenharmony_ci .id_table = ps8622_i2c_table, 54062306a36Sopenharmony_ci .probe = ps8622_probe, 54162306a36Sopenharmony_ci .remove = ps8622_remove, 54262306a36Sopenharmony_ci .driver = { 54362306a36Sopenharmony_ci .name = "ps8622", 54462306a36Sopenharmony_ci .of_match_table = ps8622_devices, 54562306a36Sopenharmony_ci }, 54662306a36Sopenharmony_ci}; 54762306a36Sopenharmony_cimodule_i2c_driver(ps8622_driver); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ciMODULE_AUTHOR("Vincent Palatin <vpalatin@chromium.org>"); 55062306a36Sopenharmony_ciMODULE_DESCRIPTION("Parade ps8622/ps8625 eDP-LVDS converter driver"); 55162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 552