Path: blob/master/drivers/gpu/drm/bridge/lontium-lt9611.c
26494 views
// SPDX-License-Identifier: GPL-2.01/*2* Copyright (c) 2018, The Linux Foundation. All rights reserved.3* Copyright (c) 2019-2020. Linaro Limited.4*/56#include <linux/gpio/consumer.h>7#include <linux/i2c.h>8#include <linux/interrupt.h>9#include <linux/media-bus-format.h>10#include <linux/module.h>11#include <linux/of_graph.h>12#include <linux/platform_device.h>13#include <linux/regmap.h>14#include <linux/regulator/consumer.h>1516#include <sound/hdmi-codec.h>1718#include <drm/drm_atomic_helper.h>19#include <drm/drm_bridge.h>20#include <drm/drm_edid.h>21#include <drm/drm_mipi_dsi.h>22#include <drm/drm_of.h>23#include <drm/drm_print.h>24#include <drm/drm_probe_helper.h>25#include <drm/display/drm_hdmi_helper.h>26#include <drm/display/drm_hdmi_state_helper.h>2728#define EDID_SEG_SIZE 25629#define EDID_LEN 3230#define EDID_LOOP 831#define KEY_DDC_ACCS_DONE 0x0232#define DDC_NO_ACK 0x503334#define LT9611_4LANES 03536struct lt9611 {37struct device *dev;38struct drm_bridge bridge;39struct drm_bridge *next_bridge;4041struct regmap *regmap;4243struct device_node *dsi0_node;44struct device_node *dsi1_node;45struct mipi_dsi_device *dsi0;46struct mipi_dsi_device *dsi1;4748bool ac_mode;4950struct gpio_desc *reset_gpio;51struct gpio_desc *enable_gpio;5253bool power_on;54bool sleep;5556struct regulator_bulk_data supplies[2];5758struct i2c_client *client;5960enum drm_connector_status status;6162u8 edid_buf[EDID_SEG_SIZE];63};6465#define LT9611_PAGE_CONTROL 0xff6667static const struct regmap_range_cfg lt9611_ranges[] = {68{69.name = "register_range",70.range_min = 0,71.range_max = 0x85ff,72.selector_reg = LT9611_PAGE_CONTROL,73.selector_mask = 0xff,74.selector_shift = 0,75.window_start = 0,76.window_len = 0x100,77},78};7980static const struct regmap_config lt9611_regmap_config = {81.reg_bits = 8,82.val_bits = 8,83.max_register = 0xffff,84.ranges = lt9611_ranges,85.num_ranges = ARRAY_SIZE(lt9611_ranges),86};8788static struct lt9611 *bridge_to_lt9611(struct drm_bridge *bridge)89{90return container_of(bridge, struct lt9611, bridge);91}9293static int lt9611_mipi_input_analog(struct lt9611 *lt9611)94{95const struct reg_sequence reg_cfg[] = {96{ 0x8106, 0x40 }, /* port A rx current */97{ 0x810a, 0xfe }, /* port A ldo voltage set */98{ 0x810b, 0xbf }, /* enable port A lprx */99{ 0x8111, 0x40 }, /* port B rx current */100{ 0x8115, 0xfe }, /* port B ldo voltage set */101{ 0x8116, 0xbf }, /* enable port B lprx */102103{ 0x811c, 0x03 }, /* PortA clk lane no-LP mode */104{ 0x8120, 0x03 }, /* PortB clk lane with-LP mode */105};106107return regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg));108}109110static int lt9611_mipi_input_digital(struct lt9611 *lt9611,111const struct drm_display_mode *mode)112{113struct reg_sequence reg_cfg[] = {114{ 0x8300, LT9611_4LANES },115{ 0x830a, 0x00 },116{ 0x824f, 0x80 },117{ 0x8250, 0x10 },118{ 0x8302, 0x0a },119{ 0x8306, 0x0a },120};121122if (lt9611->dsi1_node)123reg_cfg[1].def = 0x03;124125return regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg));126}127128static void lt9611_mipi_video_setup(struct lt9611 *lt9611,129const struct drm_display_mode *mode)130{131u32 h_total, hactive, hsync_len, hfront_porch, hsync_porch;132u32 v_total, vactive, vsync_len, vfront_porch, vsync_porch;133134h_total = mode->htotal;135v_total = mode->vtotal;136137hactive = mode->hdisplay;138hsync_len = mode->hsync_end - mode->hsync_start;139hfront_porch = mode->hsync_start - mode->hdisplay;140hsync_porch = mode->htotal - mode->hsync_start;141142vactive = mode->vdisplay;143vsync_len = mode->vsync_end - mode->vsync_start;144vfront_porch = mode->vsync_start - mode->vdisplay;145vsync_porch = mode->vtotal - mode->vsync_start;146147regmap_write(lt9611->regmap, 0x830d, (u8)(v_total / 256));148regmap_write(lt9611->regmap, 0x830e, (u8)(v_total % 256));149150regmap_write(lt9611->regmap, 0x830f, (u8)(vactive / 256));151regmap_write(lt9611->regmap, 0x8310, (u8)(vactive % 256));152153regmap_write(lt9611->regmap, 0x8311, (u8)(h_total / 256));154regmap_write(lt9611->regmap, 0x8312, (u8)(h_total % 256));155156regmap_write(lt9611->regmap, 0x8313, (u8)(hactive / 256));157regmap_write(lt9611->regmap, 0x8314, (u8)(hactive % 256));158159regmap_write(lt9611->regmap, 0x8315, (u8)(vsync_len % 256));160regmap_write(lt9611->regmap, 0x8316, (u8)(hsync_len % 256));161162regmap_write(lt9611->regmap, 0x8317, (u8)(vfront_porch % 256));163164regmap_write(lt9611->regmap, 0x8318, (u8)(vsync_porch % 256));165166regmap_write(lt9611->regmap, 0x8319, (u8)(hfront_porch % 256));167168regmap_write(lt9611->regmap, 0x831a, (u8)(hsync_porch / 256) |169((hfront_porch / 256) << 4));170regmap_write(lt9611->regmap, 0x831b, (u8)(hsync_porch % 256));171}172173static void lt9611_pcr_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode, unsigned int postdiv)174{175unsigned int pcr_m = mode->clock * 5 * postdiv / 27000;176const struct reg_sequence reg_cfg[] = {177{ 0x830b, 0x01 },178{ 0x830c, 0x10 },179{ 0x8348, 0x00 },180{ 0x8349, 0x81 },181182/* stage 1 */183{ 0x8321, 0x4a },184{ 0x8324, 0x71 },185{ 0x8325, 0x30 },186{ 0x832a, 0x01 },187188/* stage 2 */189{ 0x834a, 0x40 },190191/* MK limit */192{ 0x832d, 0x38 },193{ 0x8331, 0x08 },194};195u8 pol = 0x10;196197if (mode->flags & DRM_MODE_FLAG_NHSYNC)198pol |= 0x2;199if (mode->flags & DRM_MODE_FLAG_NVSYNC)200pol |= 0x1;201regmap_write(lt9611->regmap, 0x831d, pol);202203regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg));204if (lt9611->dsi1_node) {205unsigned int hact = mode->hdisplay;206207hact >>= 2;208hact += 0x50;209hact = min(hact, 0x3e0U);210regmap_write(lt9611->regmap, 0x830b, hact / 256);211regmap_write(lt9611->regmap, 0x830c, hact % 256);212regmap_write(lt9611->regmap, 0x8348, hact / 256);213regmap_write(lt9611->regmap, 0x8349, hact % 256);214}215216regmap_write(lt9611->regmap, 0x8326, pcr_m);217218/* pcr rst */219regmap_write(lt9611->regmap, 0x8011, 0x5a);220regmap_write(lt9611->regmap, 0x8011, 0xfa);221}222223static int lt9611_pll_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode, unsigned int *postdiv)224{225unsigned int pclk = mode->clock;226const struct reg_sequence reg_cfg[] = {227/* txpll init */228{ 0x8123, 0x40 },229{ 0x8124, 0x64 },230{ 0x8125, 0x80 },231{ 0x8126, 0x55 },232{ 0x812c, 0x37 },233{ 0x812f, 0x01 },234{ 0x8126, 0x55 },235{ 0x8127, 0x66 },236{ 0x8128, 0x88 },237{ 0x812a, 0x20 },238};239240regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg));241242if (pclk > 150000) {243regmap_write(lt9611->regmap, 0x812d, 0x88);244*postdiv = 1;245} else if (pclk > 70000) {246regmap_write(lt9611->regmap, 0x812d, 0x99);247*postdiv = 2;248} else {249regmap_write(lt9611->regmap, 0x812d, 0xaa);250*postdiv = 4;251}252253/*254* first divide pclk by 2 first255* - write divide by 64k to 19:16 bits which means shift by 17256* - write divide by 256 to 15:8 bits which means shift by 9257* - write remainder to 7:0 bits, which means shift by 1258*/259regmap_write(lt9611->regmap, 0x82e3, pclk >> 17); /* pclk[19:16] */260regmap_write(lt9611->regmap, 0x82e4, pclk >> 9); /* pclk[15:8] */261regmap_write(lt9611->regmap, 0x82e5, pclk >> 1); /* pclk[7:0] */262263regmap_write(lt9611->regmap, 0x82de, 0x20);264regmap_write(lt9611->regmap, 0x82de, 0xe0);265266regmap_write(lt9611->regmap, 0x8016, 0xf1);267regmap_write(lt9611->regmap, 0x8016, 0xf3);268269return 0;270}271272static int lt9611_read_video_check(struct lt9611 *lt9611, unsigned int reg)273{274unsigned int temp, temp2;275int ret;276277ret = regmap_read(lt9611->regmap, reg, &temp);278if (ret)279return ret;280temp <<= 8;281ret = regmap_read(lt9611->regmap, reg + 1, &temp2);282if (ret)283return ret;284285return (temp + temp2);286}287288static int lt9611_video_check(struct lt9611 *lt9611)289{290u32 v_total, vactive, hactive_a, hactive_b, h_total_sysclk;291int temp;292293/* top module video check */294295/* vactive */296temp = lt9611_read_video_check(lt9611, 0x8282);297if (temp < 0)298goto end;299vactive = temp;300301/* v_total */302temp = lt9611_read_video_check(lt9611, 0x826c);303if (temp < 0)304goto end;305v_total = temp;306307/* h_total_sysclk */308temp = lt9611_read_video_check(lt9611, 0x8286);309if (temp < 0)310goto end;311h_total_sysclk = temp;312313/* hactive_a */314temp = lt9611_read_video_check(lt9611, 0x8382);315if (temp < 0)316goto end;317hactive_a = temp / 3;318319/* hactive_b */320temp = lt9611_read_video_check(lt9611, 0x8386);321if (temp < 0)322goto end;323hactive_b = temp / 3;324325dev_info(lt9611->dev,326"video check: hactive_a=%d, hactive_b=%d, vactive=%d, v_total=%d, h_total_sysclk=%d\n",327hactive_a, hactive_b, vactive, v_total, h_total_sysclk);328329return 0;330331end:332dev_err(lt9611->dev, "read video check error\n");333return temp;334}335336static void lt9611_hdmi_tx_digital(struct lt9611 *lt9611, bool is_hdmi)337{338if (is_hdmi)339regmap_write(lt9611->regmap, 0x82d6, 0x8c);340else341regmap_write(lt9611->regmap, 0x82d6, 0x0c);342regmap_write(lt9611->regmap, 0x82d7, 0x04);343}344345static void lt9611_hdmi_tx_phy(struct lt9611 *lt9611)346{347struct reg_sequence reg_cfg[] = {348{ 0x8130, 0x6a },349{ 0x8131, 0x44 }, /* HDMI DC mode */350{ 0x8132, 0x4a },351{ 0x8133, 0x0b },352{ 0x8134, 0x00 },353{ 0x8135, 0x00 },354{ 0x8136, 0x00 },355{ 0x8137, 0x44 },356{ 0x813f, 0x0f },357{ 0x8140, 0xa0 },358{ 0x8141, 0xa0 },359{ 0x8142, 0xa0 },360{ 0x8143, 0xa0 },361{ 0x8144, 0x0a },362};363364/* HDMI AC mode */365if (lt9611->ac_mode)366reg_cfg[2].def = 0x73;367368regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg));369}370371static irqreturn_t lt9611_irq_thread_handler(int irq, void *dev_id)372{373struct lt9611 *lt9611 = dev_id;374unsigned int irq_flag0 = 0;375unsigned int irq_flag3 = 0;376377regmap_read(lt9611->regmap, 0x820f, &irq_flag3);378regmap_read(lt9611->regmap, 0x820c, &irq_flag0);379380/* hpd changed low */381if (irq_flag3 & 0x80) {382dev_info(lt9611->dev, "hdmi cable disconnected\n");383384regmap_write(lt9611->regmap, 0x8207, 0xbf);385regmap_write(lt9611->regmap, 0x8207, 0x3f);386}387388/* hpd changed high */389if (irq_flag3 & 0x40) {390dev_info(lt9611->dev, "hdmi cable connected\n");391392regmap_write(lt9611->regmap, 0x8207, 0x7f);393regmap_write(lt9611->regmap, 0x8207, 0x3f);394}395396if (irq_flag3 & 0xc0 && lt9611->bridge.dev)397drm_kms_helper_hotplug_event(lt9611->bridge.dev);398399/* video input changed */400if (irq_flag0 & 0x01) {401dev_info(lt9611->dev, "video input changed\n");402regmap_write(lt9611->regmap, 0x829e, 0xff);403regmap_write(lt9611->regmap, 0x829e, 0xf7);404regmap_write(lt9611->regmap, 0x8204, 0xff);405regmap_write(lt9611->regmap, 0x8204, 0xfe);406}407408return IRQ_HANDLED;409}410411static void lt9611_enable_hpd_interrupts(struct lt9611 *lt9611)412{413unsigned int val;414415regmap_read(lt9611->regmap, 0x8203, &val);416417val &= ~0xc0;418regmap_write(lt9611->regmap, 0x8203, val);419regmap_write(lt9611->regmap, 0x8207, 0xff); /* clear */420regmap_write(lt9611->regmap, 0x8207, 0x3f);421}422423static void lt9611_sleep_setup(struct lt9611 *lt9611)424{425const struct reg_sequence sleep_setup[] = {426{ 0x8024, 0x76 },427{ 0x8023, 0x01 },428{ 0x8157, 0x03 }, /* set addr pin as output */429{ 0x8149, 0x0b },430431{ 0x8102, 0x48 }, /* MIPI Rx power down */432{ 0x8123, 0x80 },433{ 0x8130, 0x00 },434{ 0x8011, 0x0a },435};436437regmap_multi_reg_write(lt9611->regmap,438sleep_setup, ARRAY_SIZE(sleep_setup));439lt9611->sleep = true;440}441442static int lt9611_power_on(struct lt9611 *lt9611)443{444int ret;445const struct reg_sequence seq[] = {446/* LT9611_System_Init */447{ 0x8101, 0x18 }, /* sel xtal clock */448449/* timer for frequency meter */450{ 0x821b, 0x69 }, /* timer 2 */451{ 0x821c, 0x78 },452{ 0x82cb, 0x69 }, /* timer 1 */453{ 0x82cc, 0x78 },454455/* irq init */456{ 0x8251, 0x01 },457{ 0x8258, 0x0a }, /* hpd irq */458{ 0x8259, 0x80 }, /* hpd debounce width */459{ 0x829e, 0xf7 }, /* video check irq */460461/* power consumption for work */462{ 0x8004, 0xf0 },463{ 0x8006, 0xf0 },464{ 0x800a, 0x80 },465{ 0x800b, 0x40 },466{ 0x800d, 0xef },467{ 0x8011, 0xfa },468};469470if (lt9611->power_on)471return 0;472473ret = regmap_multi_reg_write(lt9611->regmap, seq, ARRAY_SIZE(seq));474if (!ret)475lt9611->power_on = true;476477return ret;478}479480static int lt9611_power_off(struct lt9611 *lt9611)481{482int ret;483484ret = regmap_write(lt9611->regmap, 0x8130, 0x6a);485if (!ret)486lt9611->power_on = false;487488return ret;489}490491static void lt9611_reset(struct lt9611 *lt9611)492{493gpiod_set_value_cansleep(lt9611->reset_gpio, 1);494msleep(20);495496gpiod_set_value_cansleep(lt9611->reset_gpio, 0);497msleep(20);498499gpiod_set_value_cansleep(lt9611->reset_gpio, 1);500msleep(100);501}502503static void lt9611_assert_5v(struct lt9611 *lt9611)504{505if (!lt9611->enable_gpio)506return;507508gpiod_set_value_cansleep(lt9611->enable_gpio, 1);509msleep(20);510}511512static int lt9611_regulator_init(struct lt9611 *lt9611)513{514int ret;515516lt9611->supplies[0].supply = "vdd";517lt9611->supplies[1].supply = "vcc";518519ret = devm_regulator_bulk_get(lt9611->dev, 2, lt9611->supplies);520if (ret < 0)521return ret;522523return regulator_set_load(lt9611->supplies[0].consumer, 300000);524}525526static int lt9611_regulator_enable(struct lt9611 *lt9611)527{528int ret;529530ret = regulator_enable(lt9611->supplies[0].consumer);531if (ret < 0)532return ret;533534usleep_range(1000, 10000);535536ret = regulator_enable(lt9611->supplies[1].consumer);537if (ret < 0) {538regulator_disable(lt9611->supplies[0].consumer);539return ret;540}541542return 0;543}544545static enum drm_connector_status546lt9611_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector)547{548struct lt9611 *lt9611 = bridge_to_lt9611(bridge);549unsigned int reg_val = 0;550int connected = 0;551552regmap_read(lt9611->regmap, 0x825e, ®_val);553connected = (reg_val & (BIT(2) | BIT(0)));554555lt9611->status = connected ? connector_status_connected :556connector_status_disconnected;557558return lt9611->status;559}560561static int lt9611_read_edid(struct lt9611 *lt9611)562{563unsigned int temp;564int ret = 0;565int i, j;566567/* memset to clear old buffer, if any */568memset(lt9611->edid_buf, 0, sizeof(lt9611->edid_buf));569570regmap_write(lt9611->regmap, 0x8503, 0xc9);571572/* 0xA0 is EDID device address */573regmap_write(lt9611->regmap, 0x8504, 0xa0);574/* 0x00 is EDID offset address */575regmap_write(lt9611->regmap, 0x8505, 0x00);576577/* length for read */578regmap_write(lt9611->regmap, 0x8506, EDID_LEN);579regmap_write(lt9611->regmap, 0x8514, 0x7f);580581for (i = 0; i < EDID_LOOP; i++) {582/* offset address */583regmap_write(lt9611->regmap, 0x8505, i * EDID_LEN);584regmap_write(lt9611->regmap, 0x8507, 0x36);585regmap_write(lt9611->regmap, 0x8507, 0x31);586regmap_write(lt9611->regmap, 0x8507, 0x37);587usleep_range(5000, 10000);588589regmap_read(lt9611->regmap, 0x8540, &temp);590591if (temp & KEY_DDC_ACCS_DONE) {592for (j = 0; j < EDID_LEN; j++) {593regmap_read(lt9611->regmap, 0x8583, &temp);594lt9611->edid_buf[i * EDID_LEN + j] = temp;595}596597} else if (temp & DDC_NO_ACK) { /* DDC No Ack or Abitration lost */598dev_err(lt9611->dev, "read edid failed: no ack\n");599ret = -EIO;600goto end;601602} else {603dev_err(lt9611->dev, "read edid failed: access not done\n");604ret = -EIO;605goto end;606}607}608609end:610regmap_write(lt9611->regmap, 0x8507, 0x1f);611return ret;612}613614static int615lt9611_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)616{617struct lt9611 *lt9611 = data;618int ret;619620if (len > 128)621return -EINVAL;622623/* supports up to 1 extension block */624/* TODO: add support for more extension blocks */625if (block > 1)626return -EINVAL;627628if (block == 0) {629ret = lt9611_read_edid(lt9611);630if (ret) {631dev_err(lt9611->dev, "edid read failed\n");632return ret;633}634}635636block %= 2;637memcpy(buf, lt9611->edid_buf + (block * 128), len);638639return 0;640}641642/* bridge funcs */643static void lt9611_bridge_atomic_enable(struct drm_bridge *bridge,644struct drm_atomic_state *state)645{646struct lt9611 *lt9611 = bridge_to_lt9611(bridge);647struct drm_connector *connector;648struct drm_connector_state *conn_state;649struct drm_crtc_state *crtc_state;650struct drm_display_mode *mode;651unsigned int postdiv;652653connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);654if (WARN_ON(!connector))655return;656657conn_state = drm_atomic_get_new_connector_state(state, connector);658if (WARN_ON(!conn_state))659return;660661crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);662if (WARN_ON(!crtc_state))663return;664665mode = &crtc_state->adjusted_mode;666667lt9611_mipi_input_digital(lt9611, mode);668lt9611_pll_setup(lt9611, mode, &postdiv);669lt9611_mipi_video_setup(lt9611, mode);670lt9611_pcr_setup(lt9611, mode, postdiv);671672if (lt9611_power_on(lt9611)) {673dev_err(lt9611->dev, "power on failed\n");674return;675}676677lt9611_mipi_input_analog(lt9611);678drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);679lt9611_hdmi_tx_digital(lt9611, connector->display_info.is_hdmi);680lt9611_hdmi_tx_phy(lt9611);681682msleep(500);683684lt9611_video_check(lt9611);685686/* Enable HDMI output */687regmap_write(lt9611->regmap, 0x8130, 0xea);688}689690static void lt9611_bridge_atomic_disable(struct drm_bridge *bridge,691struct drm_atomic_state *state)692{693struct lt9611 *lt9611 = bridge_to_lt9611(bridge);694int ret;695696/* Disable HDMI output */697ret = regmap_write(lt9611->regmap, 0x8130, 0x6a);698if (ret) {699dev_err(lt9611->dev, "video on failed\n");700return;701}702703if (lt9611_power_off(lt9611)) {704dev_err(lt9611->dev, "power on failed\n");705return;706}707}708709static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611,710struct device_node *dsi_node)711{712const struct mipi_dsi_device_info info = { "lt9611", 0, lt9611->dev->of_node};713struct mipi_dsi_device *dsi;714struct mipi_dsi_host *host;715struct device *dev = lt9611->dev;716int ret;717718host = of_find_mipi_dsi_host_by_node(dsi_node);719if (!host)720return ERR_PTR(dev_err_probe(lt9611->dev, -EPROBE_DEFER, "failed to find dsi host\n"));721722dsi = devm_mipi_dsi_device_register_full(dev, host, &info);723if (IS_ERR(dsi)) {724dev_err(lt9611->dev, "failed to create dsi device\n");725return dsi;726}727728dsi->lanes = 4;729dsi->format = MIPI_DSI_FMT_RGB888;730dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |731MIPI_DSI_MODE_VIDEO_HSE;732733ret = devm_mipi_dsi_attach(dev, dsi);734if (ret < 0) {735dev_err(dev, "failed to attach dsi to host\n");736return ERR_PTR(ret);737}738739return dsi;740}741742static int lt9611_bridge_attach(struct drm_bridge *bridge,743struct drm_encoder *encoder,744enum drm_bridge_attach_flags flags)745{746struct lt9611 *lt9611 = bridge_to_lt9611(bridge);747748return drm_bridge_attach(encoder, lt9611->next_bridge,749bridge, flags);750}751752static enum drm_mode_status lt9611_bridge_mode_valid(struct drm_bridge *bridge,753const struct drm_display_info *info,754const struct drm_display_mode *mode)755{756struct lt9611 *lt9611 = bridge_to_lt9611(bridge);757758if (mode->hdisplay > 3840)759return MODE_BAD_HVALUE;760761if (mode->hdisplay > 2000 && !lt9611->dsi1_node)762return MODE_PANEL;763764return MODE_OK;765}766767static void lt9611_bridge_atomic_pre_enable(struct drm_bridge *bridge,768struct drm_atomic_state *state)769{770struct lt9611 *lt9611 = bridge_to_lt9611(bridge);771static const struct reg_sequence reg_cfg[] = {772{ 0x8102, 0x12 },773{ 0x8123, 0x40 },774{ 0x8130, 0xea },775{ 0x8011, 0xfa },776};777778if (!lt9611->sleep)779return;780781regmap_multi_reg_write(lt9611->regmap,782reg_cfg, ARRAY_SIZE(reg_cfg));783784lt9611->sleep = false;785}786787static void lt9611_bridge_atomic_post_disable(struct drm_bridge *bridge,788struct drm_atomic_state *state)789{790struct lt9611 *lt9611 = bridge_to_lt9611(bridge);791792lt9611_sleep_setup(lt9611);793}794795static const struct drm_edid *lt9611_bridge_edid_read(struct drm_bridge *bridge,796struct drm_connector *connector)797{798struct lt9611 *lt9611 = bridge_to_lt9611(bridge);799800lt9611_power_on(lt9611);801return drm_edid_read_custom(connector, lt9611_get_edid_block, lt9611);802}803804static void lt9611_bridge_hpd_enable(struct drm_bridge *bridge)805{806struct lt9611 *lt9611 = bridge_to_lt9611(bridge);807808lt9611_enable_hpd_interrupts(lt9611);809}810811#define MAX_INPUT_SEL_FORMATS 1812813static u32 *814lt9611_atomic_get_input_bus_fmts(struct drm_bridge *bridge,815struct drm_bridge_state *bridge_state,816struct drm_crtc_state *crtc_state,817struct drm_connector_state *conn_state,818u32 output_fmt,819unsigned int *num_input_fmts)820{821u32 *input_fmts;822823*num_input_fmts = 0;824825input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),826GFP_KERNEL);827if (!input_fmts)828return NULL;829830/* This is the DSI-end bus format */831input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;832*num_input_fmts = 1;833834return input_fmts;835}836837/*838* Other working frames:839* - 0x01, 0x84df840* - 0x04, 0x84c0841*/842#define LT9611_INFOFRAME_AUDIO 0x02843#define LT9611_INFOFRAME_AVI 0x08844#define LT9611_INFOFRAME_SPD 0x10845#define LT9611_INFOFRAME_VENDOR 0x20846847static int lt9611_hdmi_clear_infoframe(struct drm_bridge *bridge,848enum hdmi_infoframe_type type)849{850struct lt9611 *lt9611 = bridge_to_lt9611(bridge);851unsigned int mask;852853switch (type) {854case HDMI_INFOFRAME_TYPE_AUDIO:855mask = LT9611_INFOFRAME_AUDIO;856break;857858case HDMI_INFOFRAME_TYPE_AVI:859mask = LT9611_INFOFRAME_AVI;860break;861862case HDMI_INFOFRAME_TYPE_SPD:863mask = LT9611_INFOFRAME_SPD;864break;865866case HDMI_INFOFRAME_TYPE_VENDOR:867mask = LT9611_INFOFRAME_VENDOR;868break;869870default:871drm_dbg_driver(lt9611->bridge.dev, "Unsupported HDMI InfoFrame %x\n", type);872mask = 0;873break;874}875876if (mask)877regmap_update_bits(lt9611->regmap, 0x843d, mask, 0);878879return 0;880}881882static int lt9611_hdmi_write_infoframe(struct drm_bridge *bridge,883enum hdmi_infoframe_type type,884const u8 *buffer, size_t len)885{886struct lt9611 *lt9611 = bridge_to_lt9611(bridge);887unsigned int mask, addr;888int i;889890switch (type) {891case HDMI_INFOFRAME_TYPE_AUDIO:892mask = LT9611_INFOFRAME_AUDIO;893addr = 0x84b2;894break;895896case HDMI_INFOFRAME_TYPE_AVI:897mask = LT9611_INFOFRAME_AVI;898addr = 0x8440;899break;900901case HDMI_INFOFRAME_TYPE_SPD:902mask = LT9611_INFOFRAME_SPD;903addr = 0x8493;904break;905906case HDMI_INFOFRAME_TYPE_VENDOR:907mask = LT9611_INFOFRAME_VENDOR;908addr = 0x8474;909break;910911default:912drm_dbg_driver(lt9611->bridge.dev, "Unsupported HDMI InfoFrame %x\n", type);913mask = 0;914break;915}916917if (mask) {918for (i = 0; i < len; i++)919regmap_write(lt9611->regmap, addr + i, buffer[i]);920921regmap_update_bits(lt9611->regmap, 0x843d, mask, mask);922}923924return 0;925}926927static enum drm_mode_status928lt9611_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,929const struct drm_display_mode *mode,930unsigned long long tmds_rate)931{932/* 297 MHz for 4k@30 mode */933if (tmds_rate > 297000000)934return MODE_CLOCK_HIGH;935936return MODE_OK;937}938939static int lt9611_hdmi_audio_startup(struct drm_bridge *bridge,940struct drm_connector *connector)941{942struct lt9611 *lt9611 = bridge_to_lt9611(bridge);943944regmap_write(lt9611->regmap, 0x82d6, 0x8c);945regmap_write(lt9611->regmap, 0x82d7, 0x04);946947regmap_write(lt9611->regmap, 0x8406, 0x08);948regmap_write(lt9611->regmap, 0x8407, 0x10);949950regmap_write(lt9611->regmap, 0x8434, 0xd5);951952return 0;953}954955static int lt9611_hdmi_audio_prepare(struct drm_bridge *bridge,956struct drm_connector *connector,957struct hdmi_codec_daifmt *fmt,958struct hdmi_codec_params *hparms)959{960struct lt9611 *lt9611 = bridge_to_lt9611(bridge);961962if (hparms->sample_rate == 48000)963regmap_write(lt9611->regmap, 0x840f, 0x2b);964else if (hparms->sample_rate == 96000)965regmap_write(lt9611->regmap, 0x840f, 0xab);966else967return -EINVAL;968969regmap_write(lt9611->regmap, 0x8435, 0x00);970regmap_write(lt9611->regmap, 0x8436, 0x18);971regmap_write(lt9611->regmap, 0x8437, 0x00);972973return drm_atomic_helper_connector_hdmi_update_audio_infoframe(connector,974&hparms->cea);975}976977static void lt9611_hdmi_audio_shutdown(struct drm_bridge *bridge,978struct drm_connector *connector)979{980struct lt9611 *lt9611 = bridge_to_lt9611(bridge);981982drm_atomic_helper_connector_hdmi_clear_audio_infoframe(connector);983984regmap_write(lt9611->regmap, 0x8406, 0x00);985regmap_write(lt9611->regmap, 0x8407, 0x00);986}987988static const struct drm_bridge_funcs lt9611_bridge_funcs = {989.attach = lt9611_bridge_attach,990.mode_valid = lt9611_bridge_mode_valid,991.detect = lt9611_bridge_detect,992.edid_read = lt9611_bridge_edid_read,993.hpd_enable = lt9611_bridge_hpd_enable,994995.atomic_pre_enable = lt9611_bridge_atomic_pre_enable,996.atomic_enable = lt9611_bridge_atomic_enable,997.atomic_disable = lt9611_bridge_atomic_disable,998.atomic_post_disable = lt9611_bridge_atomic_post_disable,999.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,1000.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,1001.atomic_reset = drm_atomic_helper_bridge_reset,1002.atomic_get_input_bus_fmts = lt9611_atomic_get_input_bus_fmts,10031004.hdmi_tmds_char_rate_valid = lt9611_hdmi_tmds_char_rate_valid,1005.hdmi_write_infoframe = lt9611_hdmi_write_infoframe,1006.hdmi_clear_infoframe = lt9611_hdmi_clear_infoframe,10071008.hdmi_audio_startup = lt9611_hdmi_audio_startup,1009.hdmi_audio_prepare = lt9611_hdmi_audio_prepare,1010.hdmi_audio_shutdown = lt9611_hdmi_audio_shutdown,1011};10121013static int lt9611_parse_dt(struct device *dev,1014struct lt9611 *lt9611)1015{1016lt9611->dsi0_node = of_graph_get_remote_node(dev->of_node, 0, -1);1017if (!lt9611->dsi0_node) {1018dev_err(lt9611->dev, "failed to get remote node for primary dsi\n");1019return -ENODEV;1020}10211022lt9611->dsi1_node = of_graph_get_remote_node(dev->of_node, 1, -1);10231024lt9611->ac_mode = of_property_read_bool(dev->of_node, "lt,ac-mode");10251026return drm_of_find_panel_or_bridge(dev->of_node, 2, -1, NULL, <9611->next_bridge);1027}10281029static int lt9611_gpio_init(struct lt9611 *lt9611)1030{1031struct device *dev = lt9611->dev;10321033lt9611->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);1034if (IS_ERR(lt9611->reset_gpio)) {1035dev_err(dev, "failed to acquire reset gpio\n");1036return PTR_ERR(lt9611->reset_gpio);1037}10381039lt9611->enable_gpio = devm_gpiod_get_optional(dev, "enable",1040GPIOD_OUT_LOW);1041if (IS_ERR(lt9611->enable_gpio)) {1042dev_err(dev, "failed to acquire enable gpio\n");1043return PTR_ERR(lt9611->enable_gpio);1044}10451046return 0;1047}10481049static int lt9611_read_device_rev(struct lt9611 *lt9611)1050{1051unsigned int rev;1052int ret;10531054regmap_write(lt9611->regmap, 0x80ee, 0x01);1055ret = regmap_read(lt9611->regmap, 0x8002, &rev);1056if (ret)1057dev_err(lt9611->dev, "failed to read revision: %d\n", ret);1058else1059dev_info(lt9611->dev, "LT9611 revision: 0x%x\n", rev);10601061return ret;1062}10631064static int lt9611_probe(struct i2c_client *client)1065{1066struct lt9611 *lt9611;1067struct device *dev = &client->dev;1068int ret;10691070if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {1071dev_err(dev, "device doesn't support I2C\n");1072return -ENODEV;1073}10741075lt9611 = devm_drm_bridge_alloc(dev, struct lt9611, bridge,1076<9611_bridge_funcs);1077if (IS_ERR(lt9611))1078return PTR_ERR(lt9611);10791080lt9611->dev = dev;1081lt9611->client = client;1082lt9611->sleep = false;10831084lt9611->regmap = devm_regmap_init_i2c(client, <9611_regmap_config);1085if (IS_ERR(lt9611->regmap)) {1086dev_err(lt9611->dev, "regmap i2c init failed\n");1087return PTR_ERR(lt9611->regmap);1088}10891090ret = lt9611_parse_dt(dev, lt9611);1091if (ret) {1092dev_err(dev, "failed to parse device tree\n");1093return ret;1094}10951096ret = lt9611_gpio_init(lt9611);1097if (ret < 0)1098goto err_of_put;10991100ret = lt9611_regulator_init(lt9611);1101if (ret < 0)1102goto err_of_put;11031104lt9611_assert_5v(lt9611);11051106ret = lt9611_regulator_enable(lt9611);1107if (ret)1108goto err_of_put;11091110lt9611_reset(lt9611);11111112ret = lt9611_read_device_rev(lt9611);1113if (ret) {1114dev_err(dev, "failed to read chip rev\n");1115goto err_disable_regulators;1116}11171118ret = devm_request_threaded_irq(dev, client->irq, NULL,1119lt9611_irq_thread_handler,1120IRQF_ONESHOT, "lt9611", lt9611);1121if (ret) {1122dev_err(dev, "failed to request irq\n");1123goto err_disable_regulators;1124}11251126i2c_set_clientdata(client, lt9611);11271128/* Disable Audio InfoFrame, enabled by default */1129regmap_update_bits(lt9611->regmap, 0x843d, LT9611_INFOFRAME_AUDIO, 0);11301131lt9611->bridge.of_node = client->dev.of_node;1132lt9611->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID |1133DRM_BRIDGE_OP_HPD | DRM_BRIDGE_OP_MODES |1134DRM_BRIDGE_OP_HDMI | DRM_BRIDGE_OP_HDMI_AUDIO;1135lt9611->bridge.type = DRM_MODE_CONNECTOR_HDMIA;1136lt9611->bridge.vendor = "Lontium";1137lt9611->bridge.product = "LT9611";1138lt9611->bridge.hdmi_audio_dev = dev;1139lt9611->bridge.hdmi_audio_max_i2s_playback_channels = 8;1140lt9611->bridge.hdmi_audio_dai_port = 2;11411142drm_bridge_add(<9611->bridge);11431144/* Attach primary DSI */1145lt9611->dsi0 = lt9611_attach_dsi(lt9611, lt9611->dsi0_node);1146if (IS_ERR(lt9611->dsi0)) {1147ret = PTR_ERR(lt9611->dsi0);1148goto err_remove_bridge;1149}11501151/* Attach secondary DSI, if specified */1152if (lt9611->dsi1_node) {1153lt9611->dsi1 = lt9611_attach_dsi(lt9611, lt9611->dsi1_node);1154if (IS_ERR(lt9611->dsi1)) {1155ret = PTR_ERR(lt9611->dsi1);1156goto err_remove_bridge;1157}1158}11591160lt9611_enable_hpd_interrupts(lt9611);11611162return 0;11631164err_remove_bridge:1165drm_bridge_remove(<9611->bridge);11661167err_disable_regulators:1168regulator_bulk_disable(ARRAY_SIZE(lt9611->supplies), lt9611->supplies);11691170err_of_put:1171of_node_put(lt9611->dsi1_node);1172of_node_put(lt9611->dsi0_node);11731174return ret;1175}11761177static void lt9611_remove(struct i2c_client *client)1178{1179struct lt9611 *lt9611 = i2c_get_clientdata(client);11801181disable_irq(client->irq);1182drm_bridge_remove(<9611->bridge);11831184regulator_bulk_disable(ARRAY_SIZE(lt9611->supplies), lt9611->supplies);11851186of_node_put(lt9611->dsi1_node);1187of_node_put(lt9611->dsi0_node);1188}11891190static const struct i2c_device_id lt9611_id[] = {1191{ "lontium,lt9611" },1192{}1193};1194MODULE_DEVICE_TABLE(i2c, lt9611_id);11951196static const struct of_device_id lt9611_match_table[] = {1197{ .compatible = "lontium,lt9611" },1198{ }1199};1200MODULE_DEVICE_TABLE(of, lt9611_match_table);12011202static struct i2c_driver lt9611_driver = {1203.driver = {1204.name = "lt9611",1205.of_match_table = lt9611_match_table,1206},1207.probe = lt9611_probe,1208.remove = lt9611_remove,1209.id_table = lt9611_id,1210};1211module_i2c_driver(lt9611_driver);12121213MODULE_DESCRIPTION("Lontium LT9611 DSI/HDMI bridge driver");1214MODULE_LICENSE("GPL v2");121512161217