18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Analog Devices ADV7511 HDMI transmitter driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2012 Analog Devices Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/clk.h> 98c2ecf20Sopenharmony_ci#include <linux/device.h> 108c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/of_device.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <media/cec.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <drm/drm_atomic.h> 188c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h> 198c2ecf20Sopenharmony_ci#include <drm/drm_edid.h> 208c2ecf20Sopenharmony_ci#include <drm/drm_print.h> 218c2ecf20Sopenharmony_ci#include <drm/drm_probe_helper.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "adv7511.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* ADI recommended values for proper operation. */ 268c2ecf20Sopenharmony_cistatic const struct reg_sequence adv7511_fixed_registers[] = { 278c2ecf20Sopenharmony_ci { 0x98, 0x03 }, 288c2ecf20Sopenharmony_ci { 0x9a, 0xe0 }, 298c2ecf20Sopenharmony_ci { 0x9c, 0x30 }, 308c2ecf20Sopenharmony_ci { 0x9d, 0x61 }, 318c2ecf20Sopenharmony_ci { 0xa2, 0xa4 }, 328c2ecf20Sopenharmony_ci { 0xa3, 0xa4 }, 338c2ecf20Sopenharmony_ci { 0xe0, 0xd0 }, 348c2ecf20Sopenharmony_ci { 0xf9, 0x00 }, 358c2ecf20Sopenharmony_ci { 0x55, 0x02 }, 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 398c2ecf20Sopenharmony_ci * Register access 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic const uint8_t adv7511_register_defaults[] = { 438c2ecf20Sopenharmony_ci 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00 */ 448c2ecf20Sopenharmony_ci 0x00, 0x00, 0x01, 0x0e, 0xbc, 0x18, 0x01, 0x13, 458c2ecf20Sopenharmony_ci 0x25, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10 */ 468c2ecf20Sopenharmony_ci 0x46, 0x62, 0x04, 0xa8, 0x00, 0x00, 0x1c, 0x84, 478c2ecf20Sopenharmony_ci 0x1c, 0xbf, 0x04, 0xa8, 0x1e, 0x70, 0x02, 0x1e, /* 20 */ 488c2ecf20Sopenharmony_ci 0x00, 0x00, 0x04, 0xa8, 0x08, 0x12, 0x1b, 0xac, 498c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 30 */ 508c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 518c2ecf20Sopenharmony_ci 0x00, 0x50, 0x90, 0x7e, 0x79, 0x70, 0x00, 0x00, /* 40 */ 528c2ecf20Sopenharmony_ci 0x00, 0xa8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 538c2ecf20Sopenharmony_ci 0x00, 0x00, 0x02, 0x0d, 0x00, 0x00, 0x00, 0x00, /* 50 */ 548c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 558c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 60 */ 568c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 578c2ecf20Sopenharmony_ci 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 70 */ 588c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 598c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 80 */ 608c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 618c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 90 */ 628c2ecf20Sopenharmony_ci 0x0b, 0x02, 0x00, 0x18, 0x5a, 0x60, 0x00, 0x00, 638c2ecf20Sopenharmony_ci 0x00, 0x00, 0x80, 0x80, 0x08, 0x04, 0x00, 0x00, /* a0 */ 648c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x14, 658c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b0 */ 668c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 678c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c0 */ 688c2ecf20Sopenharmony_ci 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x01, 0x04, 698c2ecf20Sopenharmony_ci 0x30, 0xff, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, /* d0 */ 708c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 718c2ecf20Sopenharmony_ci 0x80, 0x75, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, /* e0 */ 728c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 738c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x11, 0x00, /* f0 */ 748c2ecf20Sopenharmony_ci 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic bool adv7511_register_volatile(struct device *dev, unsigned int reg) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci switch (reg) { 808c2ecf20Sopenharmony_ci case ADV7511_REG_CHIP_REVISION: 818c2ecf20Sopenharmony_ci case ADV7511_REG_SPDIF_FREQ: 828c2ecf20Sopenharmony_ci case ADV7511_REG_CTS_AUTOMATIC1: 838c2ecf20Sopenharmony_ci case ADV7511_REG_CTS_AUTOMATIC2: 848c2ecf20Sopenharmony_ci case ADV7511_REG_VIC_DETECTED: 858c2ecf20Sopenharmony_ci case ADV7511_REG_VIC_SEND: 868c2ecf20Sopenharmony_ci case ADV7511_REG_AUX_VIC_DETECTED: 878c2ecf20Sopenharmony_ci case ADV7511_REG_STATUS: 888c2ecf20Sopenharmony_ci case ADV7511_REG_GC(1): 898c2ecf20Sopenharmony_ci case ADV7511_REG_INT(0): 908c2ecf20Sopenharmony_ci case ADV7511_REG_INT(1): 918c2ecf20Sopenharmony_ci case ADV7511_REG_PLL_STATUS: 928c2ecf20Sopenharmony_ci case ADV7511_REG_AN(0): 938c2ecf20Sopenharmony_ci case ADV7511_REG_AN(1): 948c2ecf20Sopenharmony_ci case ADV7511_REG_AN(2): 958c2ecf20Sopenharmony_ci case ADV7511_REG_AN(3): 968c2ecf20Sopenharmony_ci case ADV7511_REG_AN(4): 978c2ecf20Sopenharmony_ci case ADV7511_REG_AN(5): 988c2ecf20Sopenharmony_ci case ADV7511_REG_AN(6): 998c2ecf20Sopenharmony_ci case ADV7511_REG_AN(7): 1008c2ecf20Sopenharmony_ci case ADV7511_REG_HDCP_STATUS: 1018c2ecf20Sopenharmony_ci case ADV7511_REG_BCAPS: 1028c2ecf20Sopenharmony_ci case ADV7511_REG_BKSV(0): 1038c2ecf20Sopenharmony_ci case ADV7511_REG_BKSV(1): 1048c2ecf20Sopenharmony_ci case ADV7511_REG_BKSV(2): 1058c2ecf20Sopenharmony_ci case ADV7511_REG_BKSV(3): 1068c2ecf20Sopenharmony_ci case ADV7511_REG_BKSV(4): 1078c2ecf20Sopenharmony_ci case ADV7511_REG_DDC_STATUS: 1088c2ecf20Sopenharmony_ci case ADV7511_REG_EDID_READ_CTRL: 1098c2ecf20Sopenharmony_ci case ADV7511_REG_BSTATUS(0): 1108c2ecf20Sopenharmony_ci case ADV7511_REG_BSTATUS(1): 1118c2ecf20Sopenharmony_ci case ADV7511_REG_CHIP_ID_HIGH: 1128c2ecf20Sopenharmony_ci case ADV7511_REG_CHIP_ID_LOW: 1138c2ecf20Sopenharmony_ci return true; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return false; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic const struct regmap_config adv7511_regmap_config = { 1208c2ecf20Sopenharmony_ci .reg_bits = 8, 1218c2ecf20Sopenharmony_ci .val_bits = 8, 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci .max_register = 0xff, 1248c2ecf20Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 1258c2ecf20Sopenharmony_ci .reg_defaults_raw = adv7511_register_defaults, 1268c2ecf20Sopenharmony_ci .num_reg_defaults_raw = ARRAY_SIZE(adv7511_register_defaults), 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci .volatile_reg = adv7511_register_volatile, 1298c2ecf20Sopenharmony_ci}; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 1328c2ecf20Sopenharmony_ci * Hardware configuration 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic void adv7511_set_colormap(struct adv7511 *adv7511, bool enable, 1368c2ecf20Sopenharmony_ci const uint16_t *coeff, 1378c2ecf20Sopenharmony_ci unsigned int scaling_factor) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci unsigned int i; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(1), 1428c2ecf20Sopenharmony_ci ADV7511_CSC_UPDATE_MODE, ADV7511_CSC_UPDATE_MODE); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (enable) { 1458c2ecf20Sopenharmony_ci for (i = 0; i < 12; ++i) { 1468c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, 1478c2ecf20Sopenharmony_ci ADV7511_REG_CSC_UPPER(i), 1488c2ecf20Sopenharmony_ci 0x1f, coeff[i] >> 8); 1498c2ecf20Sopenharmony_ci regmap_write(adv7511->regmap, 1508c2ecf20Sopenharmony_ci ADV7511_REG_CSC_LOWER(i), 1518c2ecf20Sopenharmony_ci coeff[i] & 0xff); 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (enable) 1568c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(0), 1578c2ecf20Sopenharmony_ci 0xe0, 0x80 | (scaling_factor << 5)); 1588c2ecf20Sopenharmony_ci else 1598c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(0), 1608c2ecf20Sopenharmony_ci 0x80, 0x00); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(1), 1638c2ecf20Sopenharmony_ci ADV7511_CSC_UPDATE_MODE, 0); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic int adv7511_packet_enable(struct adv7511 *adv7511, unsigned int packet) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci if (packet & 0xff) 1698c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE0, 1708c2ecf20Sopenharmony_ci packet, 0xff); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (packet & 0xff00) { 1738c2ecf20Sopenharmony_ci packet >>= 8; 1748c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1, 1758c2ecf20Sopenharmony_ci packet, 0xff); 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return 0; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int adv7511_packet_disable(struct adv7511 *adv7511, unsigned int packet) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci if (packet & 0xff) 1848c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE0, 1858c2ecf20Sopenharmony_ci packet, 0x00); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (packet & 0xff00) { 1888c2ecf20Sopenharmony_ci packet >>= 8; 1898c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1, 1908c2ecf20Sopenharmony_ci packet, 0x00); 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci return 0; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* Coefficients for adv7511 color space conversion */ 1978c2ecf20Sopenharmony_cistatic const uint16_t adv7511_csc_ycbcr_to_rgb[] = { 1988c2ecf20Sopenharmony_ci 0x0734, 0x04ad, 0x0000, 0x1c1b, 1998c2ecf20Sopenharmony_ci 0x1ddc, 0x04ad, 0x1f24, 0x0135, 2008c2ecf20Sopenharmony_ci 0x0000, 0x04ad, 0x087c, 0x1b77, 2018c2ecf20Sopenharmony_ci}; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic void adv7511_set_config_csc(struct adv7511 *adv7511, 2048c2ecf20Sopenharmony_ci struct drm_connector *connector, 2058c2ecf20Sopenharmony_ci bool rgb, bool hdmi_mode) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct adv7511_video_config config; 2088c2ecf20Sopenharmony_ci bool output_format_422, output_format_ycbcr; 2098c2ecf20Sopenharmony_ci unsigned int mode; 2108c2ecf20Sopenharmony_ci uint8_t infoframe[17]; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci config.hdmi_mode = hdmi_mode; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci hdmi_avi_infoframe_init(&config.avi_infoframe); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci config.avi_infoframe.scan_mode = HDMI_SCAN_MODE_UNDERSCAN; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (rgb) { 2198c2ecf20Sopenharmony_ci config.csc_enable = false; 2208c2ecf20Sopenharmony_ci config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB; 2218c2ecf20Sopenharmony_ci } else { 2228c2ecf20Sopenharmony_ci config.csc_scaling_factor = ADV7511_CSC_SCALING_4; 2238c2ecf20Sopenharmony_ci config.csc_coefficents = adv7511_csc_ycbcr_to_rgb; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if ((connector->display_info.color_formats & 2268c2ecf20Sopenharmony_ci DRM_COLOR_FORMAT_YCRCB422) && 2278c2ecf20Sopenharmony_ci config.hdmi_mode) { 2288c2ecf20Sopenharmony_ci config.csc_enable = false; 2298c2ecf20Sopenharmony_ci config.avi_infoframe.colorspace = 2308c2ecf20Sopenharmony_ci HDMI_COLORSPACE_YUV422; 2318c2ecf20Sopenharmony_ci } else { 2328c2ecf20Sopenharmony_ci config.csc_enable = true; 2338c2ecf20Sopenharmony_ci config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (config.hdmi_mode) { 2388c2ecf20Sopenharmony_ci mode = ADV7511_HDMI_CFG_MODE_HDMI; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci switch (config.avi_infoframe.colorspace) { 2418c2ecf20Sopenharmony_ci case HDMI_COLORSPACE_YUV444: 2428c2ecf20Sopenharmony_ci output_format_422 = false; 2438c2ecf20Sopenharmony_ci output_format_ycbcr = true; 2448c2ecf20Sopenharmony_ci break; 2458c2ecf20Sopenharmony_ci case HDMI_COLORSPACE_YUV422: 2468c2ecf20Sopenharmony_ci output_format_422 = true; 2478c2ecf20Sopenharmony_ci output_format_ycbcr = true; 2488c2ecf20Sopenharmony_ci break; 2498c2ecf20Sopenharmony_ci default: 2508c2ecf20Sopenharmony_ci output_format_422 = false; 2518c2ecf20Sopenharmony_ci output_format_ycbcr = false; 2528c2ecf20Sopenharmony_ci break; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci } else { 2558c2ecf20Sopenharmony_ci mode = ADV7511_HDMI_CFG_MODE_DVI; 2568c2ecf20Sopenharmony_ci output_format_422 = false; 2578c2ecf20Sopenharmony_ci output_format_ycbcr = false; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci adv7511_set_colormap(adv7511, config.csc_enable, 2638c2ecf20Sopenharmony_ci config.csc_coefficents, 2648c2ecf20Sopenharmony_ci config.csc_scaling_factor); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG1, 0x81, 2678c2ecf20Sopenharmony_ci (output_format_422 << 7) | output_format_ycbcr); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, ADV7511_REG_HDCP_HDMI_CFG, 2708c2ecf20Sopenharmony_ci ADV7511_HDMI_CFG_MODE_MASK, mode); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci hdmi_avi_infoframe_pack(&config.avi_infoframe, infoframe, 2738c2ecf20Sopenharmony_ci sizeof(infoframe)); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* The AVI infoframe id is not configurable */ 2768c2ecf20Sopenharmony_ci regmap_bulk_write(adv7511->regmap, ADV7511_REG_AVI_INFOFRAME_VERSION, 2778c2ecf20Sopenharmony_ci infoframe + 1, sizeof(infoframe) - 1); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME); 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic void adv7511_set_link_config(struct adv7511 *adv7511, 2838c2ecf20Sopenharmony_ci const struct adv7511_link_config *config) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci /* 2868c2ecf20Sopenharmony_ci * The input style values documented in the datasheet don't match the 2878c2ecf20Sopenharmony_ci * hardware register field values :-( 2888c2ecf20Sopenharmony_ci */ 2898c2ecf20Sopenharmony_ci static const unsigned int input_styles[4] = { 0, 2, 1, 3 }; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci unsigned int clock_delay; 2928c2ecf20Sopenharmony_ci unsigned int color_depth; 2938c2ecf20Sopenharmony_ci unsigned int input_id; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci clock_delay = (config->clock_delay + 1200) / 400; 2968c2ecf20Sopenharmony_ci color_depth = config->input_color_depth == 8 ? 3 2978c2ecf20Sopenharmony_ci : (config->input_color_depth == 10 ? 1 : 2); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* TODO Support input ID 6 */ 3008c2ecf20Sopenharmony_ci if (config->input_colorspace != HDMI_COLORSPACE_YUV422) 3018c2ecf20Sopenharmony_ci input_id = config->input_clock == ADV7511_INPUT_CLOCK_DDR 3028c2ecf20Sopenharmony_ci ? 5 : 0; 3038c2ecf20Sopenharmony_ci else if (config->input_clock == ADV7511_INPUT_CLOCK_DDR) 3048c2ecf20Sopenharmony_ci input_id = config->embedded_sync ? 8 : 7; 3058c2ecf20Sopenharmony_ci else if (config->input_clock == ADV7511_INPUT_CLOCK_2X) 3068c2ecf20Sopenharmony_ci input_id = config->embedded_sync ? 4 : 3; 3078c2ecf20Sopenharmony_ci else 3088c2ecf20Sopenharmony_ci input_id = config->embedded_sync ? 2 : 1; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, ADV7511_REG_I2C_FREQ_ID_CFG, 0xf, 3118c2ecf20Sopenharmony_ci input_id); 3128c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG1, 0x7e, 3138c2ecf20Sopenharmony_ci (color_depth << 4) | 3148c2ecf20Sopenharmony_ci (input_styles[config->input_style] << 2)); 3158c2ecf20Sopenharmony_ci regmap_write(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG2, 3168c2ecf20Sopenharmony_ci config->input_justification << 3); 3178c2ecf20Sopenharmony_ci regmap_write(adv7511->regmap, ADV7511_REG_TIMING_GEN_SEQ, 3188c2ecf20Sopenharmony_ci config->sync_pulse << 2); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci regmap_write(adv7511->regmap, 0xba, clock_delay << 5); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci adv7511->embedded_sync = config->embedded_sync; 3238c2ecf20Sopenharmony_ci adv7511->hsync_polarity = config->hsync_polarity; 3248c2ecf20Sopenharmony_ci adv7511->vsync_polarity = config->vsync_polarity; 3258c2ecf20Sopenharmony_ci adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic void __adv7511_power_on(struct adv7511 *adv7511) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci adv7511->current_edid_segment = -1; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, 3338c2ecf20Sopenharmony_ci ADV7511_POWER_POWER_DOWN, 0); 3348c2ecf20Sopenharmony_ci if (adv7511->i2c_main->irq) { 3358c2ecf20Sopenharmony_ci /* 3368c2ecf20Sopenharmony_ci * Documentation says the INT_ENABLE registers are reset in 3378c2ecf20Sopenharmony_ci * POWER_DOWN mode. My 7511w preserved the bits, however. 3388c2ecf20Sopenharmony_ci * Still, let's be safe and stick to the documentation. 3398c2ecf20Sopenharmony_ci */ 3408c2ecf20Sopenharmony_ci regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0), 3418c2ecf20Sopenharmony_ci ADV7511_INT0_EDID_READY | ADV7511_INT0_HPD); 3428c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, 3438c2ecf20Sopenharmony_ci ADV7511_REG_INT_ENABLE(1), 3448c2ecf20Sopenharmony_ci ADV7511_INT1_DDC_ERROR, 3458c2ecf20Sopenharmony_ci ADV7511_INT1_DDC_ERROR); 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* 3498c2ecf20Sopenharmony_ci * Per spec it is allowed to pulse the HPD signal to indicate that the 3508c2ecf20Sopenharmony_ci * EDID information has changed. Some monitors do this when they wakeup 3518c2ecf20Sopenharmony_ci * from standby or are enabled. When the HPD goes low the adv7511 is 3528c2ecf20Sopenharmony_ci * reset and the outputs are disabled which might cause the monitor to 3538c2ecf20Sopenharmony_ci * go to standby again. To avoid this we ignore the HPD pin for the 3548c2ecf20Sopenharmony_ci * first few seconds after enabling the output. On the other hand 3558c2ecf20Sopenharmony_ci * adv7535 require to enable HPD Override bit for proper HPD. 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_ci if (adv7511->type == ADV7535) 3588c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, 3598c2ecf20Sopenharmony_ci ADV7535_REG_POWER2_HPD_OVERRIDE, 3608c2ecf20Sopenharmony_ci ADV7535_REG_POWER2_HPD_OVERRIDE); 3618c2ecf20Sopenharmony_ci else 3628c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, 3638c2ecf20Sopenharmony_ci ADV7511_REG_POWER2_HPD_SRC_MASK, 3648c2ecf20Sopenharmony_ci ADV7511_REG_POWER2_HPD_SRC_NONE); 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic void adv7511_power_on(struct adv7511 *adv7511) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci __adv7511_power_on(adv7511); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* 3728c2ecf20Sopenharmony_ci * Most of the registers are reset during power down or when HPD is low. 3738c2ecf20Sopenharmony_ci */ 3748c2ecf20Sopenharmony_ci regcache_sync(adv7511->regmap); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (adv7511->type == ADV7533 || adv7511->type == ADV7535) 3778c2ecf20Sopenharmony_ci adv7533_dsi_power_on(adv7511); 3788c2ecf20Sopenharmony_ci adv7511->powered = true; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic void __adv7511_power_off(struct adv7511 *adv7511) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci /* TODO: setup additional power down modes */ 3848c2ecf20Sopenharmony_ci if (adv7511->type == ADV7535) 3858c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, 3868c2ecf20Sopenharmony_ci ADV7535_REG_POWER2_HPD_OVERRIDE, 0); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, 3898c2ecf20Sopenharmony_ci ADV7511_POWER_POWER_DOWN, 3908c2ecf20Sopenharmony_ci ADV7511_POWER_POWER_DOWN); 3918c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, 3928c2ecf20Sopenharmony_ci ADV7511_REG_INT_ENABLE(1), 3938c2ecf20Sopenharmony_ci ADV7511_INT1_DDC_ERROR, 0); 3948c2ecf20Sopenharmony_ci regcache_mark_dirty(adv7511->regmap); 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic void adv7511_power_off(struct adv7511 *adv7511) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci __adv7511_power_off(adv7511); 4008c2ecf20Sopenharmony_ci if (adv7511->type == ADV7533 || adv7511->type == ADV7535) 4018c2ecf20Sopenharmony_ci adv7533_dsi_power_off(adv7511); 4028c2ecf20Sopenharmony_ci adv7511->powered = false; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 4068c2ecf20Sopenharmony_ci * Interrupt and hotplug detection 4078c2ecf20Sopenharmony_ci */ 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic bool adv7511_hpd(struct adv7511 *adv7511) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci unsigned int irq0; 4128c2ecf20Sopenharmony_ci int ret; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0); 4158c2ecf20Sopenharmony_ci if (ret < 0) 4168c2ecf20Sopenharmony_ci return false; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (irq0 & ADV7511_INT0_HPD) { 4198c2ecf20Sopenharmony_ci regmap_write(adv7511->regmap, ADV7511_REG_INT(0), 4208c2ecf20Sopenharmony_ci ADV7511_INT0_HPD); 4218c2ecf20Sopenharmony_ci return true; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci return false; 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic void adv7511_hpd_work(struct work_struct *work) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci struct adv7511 *adv7511 = container_of(work, struct adv7511, hpd_work); 4308c2ecf20Sopenharmony_ci enum drm_connector_status status; 4318c2ecf20Sopenharmony_ci unsigned int val; 4328c2ecf20Sopenharmony_ci int ret; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci ret = regmap_read(adv7511->regmap, ADV7511_REG_STATUS, &val); 4358c2ecf20Sopenharmony_ci if (ret < 0) 4368c2ecf20Sopenharmony_ci status = connector_status_disconnected; 4378c2ecf20Sopenharmony_ci else if (val & ADV7511_STATUS_HPD) 4388c2ecf20Sopenharmony_ci status = connector_status_connected; 4398c2ecf20Sopenharmony_ci else 4408c2ecf20Sopenharmony_ci status = connector_status_disconnected; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci /* 4438c2ecf20Sopenharmony_ci * The bridge resets its registers on unplug. So when we get a plug 4448c2ecf20Sopenharmony_ci * event and we're already supposed to be powered, cycle the bridge to 4458c2ecf20Sopenharmony_ci * restore its state. 4468c2ecf20Sopenharmony_ci */ 4478c2ecf20Sopenharmony_ci if (status == connector_status_connected && 4488c2ecf20Sopenharmony_ci adv7511->connector.status == connector_status_disconnected && 4498c2ecf20Sopenharmony_ci adv7511->powered) { 4508c2ecf20Sopenharmony_ci regcache_mark_dirty(adv7511->regmap); 4518c2ecf20Sopenharmony_ci adv7511_power_on(adv7511); 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (adv7511->connector.status != status) { 4558c2ecf20Sopenharmony_ci adv7511->connector.status = status; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (adv7511->connector.dev) { 4588c2ecf20Sopenharmony_ci if (status == connector_status_disconnected) 4598c2ecf20Sopenharmony_ci cec_phys_addr_invalidate(adv7511->cec_adap); 4608c2ecf20Sopenharmony_ci drm_kms_helper_hotplug_event(adv7511->connector.dev); 4618c2ecf20Sopenharmony_ci } else { 4628c2ecf20Sopenharmony_ci drm_bridge_hpd_notify(&adv7511->bridge, status); 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci unsigned int irq0, irq1; 4708c2ecf20Sopenharmony_ci int ret; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0); 4738c2ecf20Sopenharmony_ci if (ret < 0) 4748c2ecf20Sopenharmony_ci return ret; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(1), &irq1); 4778c2ecf20Sopenharmony_ci if (ret < 0) 4788c2ecf20Sopenharmony_ci return ret; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0); 4818c2ecf20Sopenharmony_ci regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (process_hpd && irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder) 4848c2ecf20Sopenharmony_ci schedule_work(&adv7511->hpd_work); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) { 4878c2ecf20Sopenharmony_ci adv7511->edid_read = true; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci if (adv7511->i2c_main->irq) 4908c2ecf20Sopenharmony_ci wake_up_all(&adv7511->wq); 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci#ifdef CONFIG_DRM_I2C_ADV7511_CEC 4948c2ecf20Sopenharmony_ci adv7511_cec_irq_process(adv7511, irq1); 4958c2ecf20Sopenharmony_ci#endif 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci return 0; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cistatic irqreturn_t adv7511_irq_handler(int irq, void *devid) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci struct adv7511 *adv7511 = devid; 5038c2ecf20Sopenharmony_ci int ret; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci ret = adv7511_irq_process(adv7511, true); 5068c2ecf20Sopenharmony_ci return ret < 0 ? IRQ_NONE : IRQ_HANDLED; 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 5108c2ecf20Sopenharmony_ci * EDID retrieval 5118c2ecf20Sopenharmony_ci */ 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cistatic int adv7511_wait_for_edid(struct adv7511 *adv7511, int timeout) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci int ret; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (adv7511->i2c_main->irq) { 5188c2ecf20Sopenharmony_ci ret = wait_event_interruptible_timeout(adv7511->wq, 5198c2ecf20Sopenharmony_ci adv7511->edid_read, msecs_to_jiffies(timeout)); 5208c2ecf20Sopenharmony_ci } else { 5218c2ecf20Sopenharmony_ci for (; timeout > 0; timeout -= 25) { 5228c2ecf20Sopenharmony_ci ret = adv7511_irq_process(adv7511, false); 5238c2ecf20Sopenharmony_ci if (ret < 0) 5248c2ecf20Sopenharmony_ci break; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if (adv7511->edid_read) 5278c2ecf20Sopenharmony_ci break; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci msleep(25); 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci return adv7511->edid_read ? 0 : -EIO; 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block, 5378c2ecf20Sopenharmony_ci size_t len) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci struct adv7511 *adv7511 = data; 5408c2ecf20Sopenharmony_ci struct i2c_msg xfer[2]; 5418c2ecf20Sopenharmony_ci uint8_t offset; 5428c2ecf20Sopenharmony_ci unsigned int i; 5438c2ecf20Sopenharmony_ci int ret; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (len > 128) 5468c2ecf20Sopenharmony_ci return -EINVAL; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (adv7511->current_edid_segment != block / 2) { 5498c2ecf20Sopenharmony_ci unsigned int status; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci ret = regmap_read(adv7511->regmap, ADV7511_REG_DDC_STATUS, 5528c2ecf20Sopenharmony_ci &status); 5538c2ecf20Sopenharmony_ci if (ret < 0) 5548c2ecf20Sopenharmony_ci return ret; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci if (status != 2) { 5578c2ecf20Sopenharmony_ci adv7511->edid_read = false; 5588c2ecf20Sopenharmony_ci regmap_write(adv7511->regmap, ADV7511_REG_EDID_SEGMENT, 5598c2ecf20Sopenharmony_ci block); 5608c2ecf20Sopenharmony_ci ret = adv7511_wait_for_edid(adv7511, 200); 5618c2ecf20Sopenharmony_ci if (ret < 0) 5628c2ecf20Sopenharmony_ci return ret; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* Break this apart, hopefully more I2C controllers will 5668c2ecf20Sopenharmony_ci * support 64 byte transfers than 256 byte transfers 5678c2ecf20Sopenharmony_ci */ 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci xfer[0].addr = adv7511->i2c_edid->addr; 5708c2ecf20Sopenharmony_ci xfer[0].flags = 0; 5718c2ecf20Sopenharmony_ci xfer[0].len = 1; 5728c2ecf20Sopenharmony_ci xfer[0].buf = &offset; 5738c2ecf20Sopenharmony_ci xfer[1].addr = adv7511->i2c_edid->addr; 5748c2ecf20Sopenharmony_ci xfer[1].flags = I2C_M_RD; 5758c2ecf20Sopenharmony_ci xfer[1].len = 64; 5768c2ecf20Sopenharmony_ci xfer[1].buf = adv7511->edid_buf; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci offset = 0; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci for (i = 0; i < 4; ++i) { 5818c2ecf20Sopenharmony_ci ret = i2c_transfer(adv7511->i2c_edid->adapter, xfer, 5828c2ecf20Sopenharmony_ci ARRAY_SIZE(xfer)); 5838c2ecf20Sopenharmony_ci if (ret < 0) 5848c2ecf20Sopenharmony_ci return ret; 5858c2ecf20Sopenharmony_ci else if (ret != 2) 5868c2ecf20Sopenharmony_ci return -EIO; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci xfer[1].buf += 64; 5898c2ecf20Sopenharmony_ci offset += 64; 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci adv7511->current_edid_segment = block / 2; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci if (block % 2 == 0) 5968c2ecf20Sopenharmony_ci memcpy(buf, adv7511->edid_buf, len); 5978c2ecf20Sopenharmony_ci else 5988c2ecf20Sopenharmony_ci memcpy(buf, adv7511->edid_buf + 128, len); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci return 0; 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 6048c2ecf20Sopenharmony_ci * ADV75xx helpers 6058c2ecf20Sopenharmony_ci */ 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic struct edid *adv7511_get_edid(struct adv7511 *adv7511, 6088c2ecf20Sopenharmony_ci struct drm_connector *connector) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci struct edid *edid; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci /* Reading the EDID only works if the device is powered */ 6138c2ecf20Sopenharmony_ci if (!adv7511->powered) { 6148c2ecf20Sopenharmony_ci unsigned int edid_i2c_addr = 6158c2ecf20Sopenharmony_ci (adv7511->i2c_edid->addr << 1); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci __adv7511_power_on(adv7511); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci /* Reset the EDID_I2C_ADDR register as it might be cleared */ 6208c2ecf20Sopenharmony_ci regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, 6218c2ecf20Sopenharmony_ci edid_i2c_addr); 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (!adv7511->powered) 6278c2ecf20Sopenharmony_ci __adv7511_power_off(adv7511); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci adv7511_set_config_csc(adv7511, connector, adv7511->rgb, 6308c2ecf20Sopenharmony_ci drm_detect_hdmi_monitor(edid)); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci cec_s_phys_addr_from_edid(adv7511->cec_adap, edid); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci return edid; 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cistatic int adv7511_get_modes(struct adv7511 *adv7511, 6388c2ecf20Sopenharmony_ci struct drm_connector *connector) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci struct edid *edid; 6418c2ecf20Sopenharmony_ci unsigned int count; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci edid = adv7511_get_edid(adv7511, connector); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci drm_connector_update_edid_property(connector, edid); 6468c2ecf20Sopenharmony_ci count = drm_add_edid_modes(connector, edid); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci kfree(edid); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci return count; 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_cistatic enum drm_connector_status 6548c2ecf20Sopenharmony_ciadv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci enum drm_connector_status status; 6578c2ecf20Sopenharmony_ci unsigned int val; 6588c2ecf20Sopenharmony_ci bool hpd; 6598c2ecf20Sopenharmony_ci int ret; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci ret = regmap_read(adv7511->regmap, ADV7511_REG_STATUS, &val); 6628c2ecf20Sopenharmony_ci if (ret < 0) 6638c2ecf20Sopenharmony_ci return connector_status_disconnected; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (val & ADV7511_STATUS_HPD) 6668c2ecf20Sopenharmony_ci status = connector_status_connected; 6678c2ecf20Sopenharmony_ci else 6688c2ecf20Sopenharmony_ci status = connector_status_disconnected; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci hpd = adv7511_hpd(adv7511); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci /* The chip resets itself when the cable is disconnected, so in case 6738c2ecf20Sopenharmony_ci * there is a pending HPD interrupt and the cable is connected there was 6748c2ecf20Sopenharmony_ci * at least one transition from disconnected to connected and the chip 6758c2ecf20Sopenharmony_ci * has to be reinitialized. */ 6768c2ecf20Sopenharmony_ci if (status == connector_status_connected && hpd && adv7511->powered) { 6778c2ecf20Sopenharmony_ci regcache_mark_dirty(adv7511->regmap); 6788c2ecf20Sopenharmony_ci adv7511_power_on(adv7511); 6798c2ecf20Sopenharmony_ci if (connector) 6808c2ecf20Sopenharmony_ci adv7511_get_modes(adv7511, connector); 6818c2ecf20Sopenharmony_ci if (adv7511->status == connector_status_connected) 6828c2ecf20Sopenharmony_ci status = connector_status_disconnected; 6838c2ecf20Sopenharmony_ci } else { 6848c2ecf20Sopenharmony_ci /* Renable HPD sensing */ 6858c2ecf20Sopenharmony_ci if (adv7511->type == ADV7535) 6868c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, 6878c2ecf20Sopenharmony_ci ADV7535_REG_POWER2_HPD_OVERRIDE, 6888c2ecf20Sopenharmony_ci ADV7535_REG_POWER2_HPD_OVERRIDE); 6898c2ecf20Sopenharmony_ci else 6908c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, 6918c2ecf20Sopenharmony_ci ADV7511_REG_POWER2_HPD_SRC_MASK, 6928c2ecf20Sopenharmony_ci ADV7511_REG_POWER2_HPD_SRC_BOTH); 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci adv7511->status = status; 6968c2ecf20Sopenharmony_ci return status; 6978c2ecf20Sopenharmony_ci} 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_cistatic enum drm_mode_status adv7511_mode_valid(struct adv7511 *adv7511, 7008c2ecf20Sopenharmony_ci const struct drm_display_mode *mode) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci if (mode->clock > 165000) 7038c2ecf20Sopenharmony_ci return MODE_CLOCK_HIGH; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci return MODE_OK; 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic void adv7511_mode_set(struct adv7511 *adv7511, 7098c2ecf20Sopenharmony_ci const struct drm_display_mode *mode, 7108c2ecf20Sopenharmony_ci const struct drm_display_mode *adj_mode) 7118c2ecf20Sopenharmony_ci{ 7128c2ecf20Sopenharmony_ci unsigned int low_refresh_rate; 7138c2ecf20Sopenharmony_ci unsigned int hsync_polarity = 0; 7148c2ecf20Sopenharmony_ci unsigned int vsync_polarity = 0; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (adv7511->embedded_sync) { 7178c2ecf20Sopenharmony_ci unsigned int hsync_offset, hsync_len; 7188c2ecf20Sopenharmony_ci unsigned int vsync_offset, vsync_len; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci hsync_offset = adj_mode->crtc_hsync_start - 7218c2ecf20Sopenharmony_ci adj_mode->crtc_hdisplay; 7228c2ecf20Sopenharmony_ci vsync_offset = adj_mode->crtc_vsync_start - 7238c2ecf20Sopenharmony_ci adj_mode->crtc_vdisplay; 7248c2ecf20Sopenharmony_ci hsync_len = adj_mode->crtc_hsync_end - 7258c2ecf20Sopenharmony_ci adj_mode->crtc_hsync_start; 7268c2ecf20Sopenharmony_ci vsync_len = adj_mode->crtc_vsync_end - 7278c2ecf20Sopenharmony_ci adj_mode->crtc_vsync_start; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci /* The hardware vsync generator has a off-by-one bug */ 7308c2ecf20Sopenharmony_ci vsync_offset += 1; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci regmap_write(adv7511->regmap, ADV7511_REG_HSYNC_PLACEMENT_MSB, 7338c2ecf20Sopenharmony_ci ((hsync_offset >> 10) & 0x7) << 5); 7348c2ecf20Sopenharmony_ci regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(0), 7358c2ecf20Sopenharmony_ci (hsync_offset >> 2) & 0xff); 7368c2ecf20Sopenharmony_ci regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(1), 7378c2ecf20Sopenharmony_ci ((hsync_offset & 0x3) << 6) | 7388c2ecf20Sopenharmony_ci ((hsync_len >> 4) & 0x3f)); 7398c2ecf20Sopenharmony_ci regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(2), 7408c2ecf20Sopenharmony_ci ((hsync_len & 0xf) << 4) | 7418c2ecf20Sopenharmony_ci ((vsync_offset >> 6) & 0xf)); 7428c2ecf20Sopenharmony_ci regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(3), 7438c2ecf20Sopenharmony_ci ((vsync_offset & 0x3f) << 2) | 7448c2ecf20Sopenharmony_ci ((vsync_len >> 8) & 0x3)); 7458c2ecf20Sopenharmony_ci regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(4), 7468c2ecf20Sopenharmony_ci vsync_len & 0xff); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci hsync_polarity = !(adj_mode->flags & DRM_MODE_FLAG_PHSYNC); 7498c2ecf20Sopenharmony_ci vsync_polarity = !(adj_mode->flags & DRM_MODE_FLAG_PVSYNC); 7508c2ecf20Sopenharmony_ci } else { 7518c2ecf20Sopenharmony_ci enum adv7511_sync_polarity mode_hsync_polarity; 7528c2ecf20Sopenharmony_ci enum adv7511_sync_polarity mode_vsync_polarity; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /** 7558c2ecf20Sopenharmony_ci * If the input signal is always low or always high we want to 7568c2ecf20Sopenharmony_ci * invert or let it passthrough depending on the polarity of the 7578c2ecf20Sopenharmony_ci * current mode. 7588c2ecf20Sopenharmony_ci **/ 7598c2ecf20Sopenharmony_ci if (adj_mode->flags & DRM_MODE_FLAG_NHSYNC) 7608c2ecf20Sopenharmony_ci mode_hsync_polarity = ADV7511_SYNC_POLARITY_LOW; 7618c2ecf20Sopenharmony_ci else 7628c2ecf20Sopenharmony_ci mode_hsync_polarity = ADV7511_SYNC_POLARITY_HIGH; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci if (adj_mode->flags & DRM_MODE_FLAG_NVSYNC) 7658c2ecf20Sopenharmony_ci mode_vsync_polarity = ADV7511_SYNC_POLARITY_LOW; 7668c2ecf20Sopenharmony_ci else 7678c2ecf20Sopenharmony_ci mode_vsync_polarity = ADV7511_SYNC_POLARITY_HIGH; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci if (adv7511->hsync_polarity != mode_hsync_polarity && 7708c2ecf20Sopenharmony_ci adv7511->hsync_polarity != 7718c2ecf20Sopenharmony_ci ADV7511_SYNC_POLARITY_PASSTHROUGH) 7728c2ecf20Sopenharmony_ci hsync_polarity = 1; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (adv7511->vsync_polarity != mode_vsync_polarity && 7758c2ecf20Sopenharmony_ci adv7511->vsync_polarity != 7768c2ecf20Sopenharmony_ci ADV7511_SYNC_POLARITY_PASSTHROUGH) 7778c2ecf20Sopenharmony_ci vsync_polarity = 1; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci if (drm_mode_vrefresh(mode) <= 24) 7818c2ecf20Sopenharmony_ci low_refresh_rate = ADV7511_LOW_REFRESH_RATE_24HZ; 7828c2ecf20Sopenharmony_ci else if (drm_mode_vrefresh(mode) <= 25) 7838c2ecf20Sopenharmony_ci low_refresh_rate = ADV7511_LOW_REFRESH_RATE_25HZ; 7848c2ecf20Sopenharmony_ci else if (drm_mode_vrefresh(mode) <= 30) 7858c2ecf20Sopenharmony_ci low_refresh_rate = ADV7511_LOW_REFRESH_RATE_30HZ; 7868c2ecf20Sopenharmony_ci else 7878c2ecf20Sopenharmony_ci low_refresh_rate = ADV7511_LOW_REFRESH_RATE_NONE; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci if (adv7511->type == ADV7511) 7908c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, 0xfb, 7918c2ecf20Sopenharmony_ci 0x6, low_refresh_rate << 1); 7928c2ecf20Sopenharmony_ci else 7938c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, 0x4a, 7948c2ecf20Sopenharmony_ci 0xc, low_refresh_rate << 2); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci regmap_update_bits(adv7511->regmap, 0x17, 7978c2ecf20Sopenharmony_ci 0x60, (vsync_polarity << 6) | (hsync_polarity << 5)); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci drm_mode_copy(&adv7511->curr_mode, adj_mode); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci /* 8028c2ecf20Sopenharmony_ci * TODO Test first order 4:2:2 to 4:4:4 up conversion method, which is 8038c2ecf20Sopenharmony_ci * supposed to give better results. 8048c2ecf20Sopenharmony_ci */ 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci adv7511->f_tmds = mode->clock; 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 8108c2ecf20Sopenharmony_ci * DRM Connector Operations 8118c2ecf20Sopenharmony_ci */ 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cistatic struct adv7511 *connector_to_adv7511(struct drm_connector *connector) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci return container_of(connector, struct adv7511, connector); 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_cistatic int adv7511_connector_get_modes(struct drm_connector *connector) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci struct adv7511 *adv = connector_to_adv7511(connector); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci return adv7511_get_modes(adv, connector); 8238c2ecf20Sopenharmony_ci} 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_cistatic enum drm_mode_status 8268c2ecf20Sopenharmony_ciadv7511_connector_mode_valid(struct drm_connector *connector, 8278c2ecf20Sopenharmony_ci struct drm_display_mode *mode) 8288c2ecf20Sopenharmony_ci{ 8298c2ecf20Sopenharmony_ci struct adv7511 *adv = connector_to_adv7511(connector); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci return adv7511_mode_valid(adv, mode); 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_cistatic struct drm_connector_helper_funcs adv7511_connector_helper_funcs = { 8358c2ecf20Sopenharmony_ci .get_modes = adv7511_connector_get_modes, 8368c2ecf20Sopenharmony_ci .mode_valid = adv7511_connector_mode_valid, 8378c2ecf20Sopenharmony_ci}; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_cistatic enum drm_connector_status 8408c2ecf20Sopenharmony_ciadv7511_connector_detect(struct drm_connector *connector, bool force) 8418c2ecf20Sopenharmony_ci{ 8428c2ecf20Sopenharmony_ci struct adv7511 *adv = connector_to_adv7511(connector); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci return adv7511_detect(adv, connector); 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs adv7511_connector_funcs = { 8488c2ecf20Sopenharmony_ci .fill_modes = drm_helper_probe_single_connector_modes, 8498c2ecf20Sopenharmony_ci .detect = adv7511_connector_detect, 8508c2ecf20Sopenharmony_ci .destroy = drm_connector_cleanup, 8518c2ecf20Sopenharmony_ci .reset = drm_atomic_helper_connector_reset, 8528c2ecf20Sopenharmony_ci .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 8538c2ecf20Sopenharmony_ci .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 8548c2ecf20Sopenharmony_ci}; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_cistatic int adv7511_connector_init(struct adv7511 *adv) 8578c2ecf20Sopenharmony_ci{ 8588c2ecf20Sopenharmony_ci struct drm_bridge *bridge = &adv->bridge; 8598c2ecf20Sopenharmony_ci int ret; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci if (!bridge->encoder) { 8628c2ecf20Sopenharmony_ci DRM_ERROR("Parent encoder object not found"); 8638c2ecf20Sopenharmony_ci return -ENODEV; 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if (adv->i2c_main->irq) 8678c2ecf20Sopenharmony_ci adv->connector.polled = DRM_CONNECTOR_POLL_HPD; 8688c2ecf20Sopenharmony_ci else 8698c2ecf20Sopenharmony_ci adv->connector.polled = DRM_CONNECTOR_POLL_CONNECT | 8708c2ecf20Sopenharmony_ci DRM_CONNECTOR_POLL_DISCONNECT; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci ret = drm_connector_init(bridge->dev, &adv->connector, 8738c2ecf20Sopenharmony_ci &adv7511_connector_funcs, 8748c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_HDMIA); 8758c2ecf20Sopenharmony_ci if (ret < 0) { 8768c2ecf20Sopenharmony_ci DRM_ERROR("Failed to initialize connector with drm\n"); 8778c2ecf20Sopenharmony_ci return ret; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci drm_connector_helper_add(&adv->connector, 8808c2ecf20Sopenharmony_ci &adv7511_connector_helper_funcs); 8818c2ecf20Sopenharmony_ci drm_connector_attach_encoder(&adv->connector, bridge->encoder); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci return 0; 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 8878c2ecf20Sopenharmony_ci * DRM Bridge Operations 8888c2ecf20Sopenharmony_ci */ 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_cistatic struct adv7511 *bridge_to_adv7511(struct drm_bridge *bridge) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci return container_of(bridge, struct adv7511, bridge); 8938c2ecf20Sopenharmony_ci} 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_cistatic void adv7511_bridge_enable(struct drm_bridge *bridge) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci struct adv7511 *adv = bridge_to_adv7511(bridge); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci adv7511_power_on(adv); 9008c2ecf20Sopenharmony_ci} 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_cistatic void adv7511_bridge_disable(struct drm_bridge *bridge) 9038c2ecf20Sopenharmony_ci{ 9048c2ecf20Sopenharmony_ci struct adv7511 *adv = bridge_to_adv7511(bridge); 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci adv7511_power_off(adv); 9078c2ecf20Sopenharmony_ci} 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_cistatic void adv7511_bridge_mode_set(struct drm_bridge *bridge, 9108c2ecf20Sopenharmony_ci const struct drm_display_mode *mode, 9118c2ecf20Sopenharmony_ci const struct drm_display_mode *adj_mode) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci struct adv7511 *adv = bridge_to_adv7511(bridge); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci adv7511_mode_set(adv, mode, adj_mode); 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_cistatic enum drm_mode_status adv7511_bridge_mode_valid(struct drm_bridge *bridge, 9198c2ecf20Sopenharmony_ci const struct drm_display_info *info, 9208c2ecf20Sopenharmony_ci const struct drm_display_mode *mode) 9218c2ecf20Sopenharmony_ci{ 9228c2ecf20Sopenharmony_ci struct adv7511 *adv = bridge_to_adv7511(bridge); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci if (adv->type == ADV7533 || adv->type == ADV7535) 9258c2ecf20Sopenharmony_ci return adv7533_mode_valid(adv, mode); 9268c2ecf20Sopenharmony_ci else 9278c2ecf20Sopenharmony_ci return adv7511_mode_valid(adv, mode); 9288c2ecf20Sopenharmony_ci} 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_cistatic int adv7511_bridge_attach(struct drm_bridge *bridge, 9318c2ecf20Sopenharmony_ci enum drm_bridge_attach_flags flags) 9328c2ecf20Sopenharmony_ci{ 9338c2ecf20Sopenharmony_ci struct adv7511 *adv = bridge_to_adv7511(bridge); 9348c2ecf20Sopenharmony_ci int ret = 0; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) { 9378c2ecf20Sopenharmony_ci ret = adv7511_connector_init(adv); 9388c2ecf20Sopenharmony_ci if (ret < 0) 9398c2ecf20Sopenharmony_ci return ret; 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci if (adv->type == ADV7533 || adv->type == ADV7535) 9438c2ecf20Sopenharmony_ci ret = adv7533_attach_dsi(adv); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci if (adv->i2c_main->irq) 9468c2ecf20Sopenharmony_ci regmap_write(adv->regmap, ADV7511_REG_INT_ENABLE(0), 9478c2ecf20Sopenharmony_ci ADV7511_INT0_HPD); 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci return ret; 9508c2ecf20Sopenharmony_ci} 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_cistatic enum drm_connector_status adv7511_bridge_detect(struct drm_bridge *bridge) 9538c2ecf20Sopenharmony_ci{ 9548c2ecf20Sopenharmony_ci struct adv7511 *adv = bridge_to_adv7511(bridge); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci return adv7511_detect(adv, NULL); 9578c2ecf20Sopenharmony_ci} 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_cistatic struct edid *adv7511_bridge_get_edid(struct drm_bridge *bridge, 9608c2ecf20Sopenharmony_ci struct drm_connector *connector) 9618c2ecf20Sopenharmony_ci{ 9628c2ecf20Sopenharmony_ci struct adv7511 *adv = bridge_to_adv7511(bridge); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci return adv7511_get_edid(adv, connector); 9658c2ecf20Sopenharmony_ci} 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_cistatic void adv7511_bridge_hpd_notify(struct drm_bridge *bridge, 9688c2ecf20Sopenharmony_ci enum drm_connector_status status) 9698c2ecf20Sopenharmony_ci{ 9708c2ecf20Sopenharmony_ci struct adv7511 *adv = bridge_to_adv7511(bridge); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci if (status == connector_status_disconnected) 9738c2ecf20Sopenharmony_ci cec_phys_addr_invalidate(adv->cec_adap); 9748c2ecf20Sopenharmony_ci} 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_cistatic const struct drm_bridge_funcs adv7511_bridge_funcs = { 9778c2ecf20Sopenharmony_ci .enable = adv7511_bridge_enable, 9788c2ecf20Sopenharmony_ci .disable = adv7511_bridge_disable, 9798c2ecf20Sopenharmony_ci .mode_set = adv7511_bridge_mode_set, 9808c2ecf20Sopenharmony_ci .mode_valid = adv7511_bridge_mode_valid, 9818c2ecf20Sopenharmony_ci .attach = adv7511_bridge_attach, 9828c2ecf20Sopenharmony_ci .detect = adv7511_bridge_detect, 9838c2ecf20Sopenharmony_ci .get_edid = adv7511_bridge_get_edid, 9848c2ecf20Sopenharmony_ci .hpd_notify = adv7511_bridge_hpd_notify, 9858c2ecf20Sopenharmony_ci}; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 9888c2ecf20Sopenharmony_ci * Probe & remove 9898c2ecf20Sopenharmony_ci */ 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_cistatic const char * const adv7511_supply_names[] = { 9928c2ecf20Sopenharmony_ci "avdd", 9938c2ecf20Sopenharmony_ci "dvdd", 9948c2ecf20Sopenharmony_ci "pvdd", 9958c2ecf20Sopenharmony_ci "bgvdd", 9968c2ecf20Sopenharmony_ci "dvdd-3v", 9978c2ecf20Sopenharmony_ci}; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_cistatic const char * const adv7533_supply_names[] = { 10008c2ecf20Sopenharmony_ci "avdd", 10018c2ecf20Sopenharmony_ci "dvdd", 10028c2ecf20Sopenharmony_ci "pvdd", 10038c2ecf20Sopenharmony_ci "a2vdd", 10048c2ecf20Sopenharmony_ci "v3p3", 10058c2ecf20Sopenharmony_ci "v1p2", 10068c2ecf20Sopenharmony_ci}; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_cistatic int adv7511_init_regulators(struct adv7511 *adv) 10098c2ecf20Sopenharmony_ci{ 10108c2ecf20Sopenharmony_ci struct device *dev = &adv->i2c_main->dev; 10118c2ecf20Sopenharmony_ci const char * const *supply_names; 10128c2ecf20Sopenharmony_ci unsigned int i; 10138c2ecf20Sopenharmony_ci int ret; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci if (adv->type == ADV7511) { 10168c2ecf20Sopenharmony_ci supply_names = adv7511_supply_names; 10178c2ecf20Sopenharmony_ci adv->num_supplies = ARRAY_SIZE(adv7511_supply_names); 10188c2ecf20Sopenharmony_ci } else { 10198c2ecf20Sopenharmony_ci supply_names = adv7533_supply_names; 10208c2ecf20Sopenharmony_ci adv->num_supplies = ARRAY_SIZE(adv7533_supply_names); 10218c2ecf20Sopenharmony_ci } 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci adv->supplies = devm_kcalloc(dev, adv->num_supplies, 10248c2ecf20Sopenharmony_ci sizeof(*adv->supplies), GFP_KERNEL); 10258c2ecf20Sopenharmony_ci if (!adv->supplies) 10268c2ecf20Sopenharmony_ci return -ENOMEM; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci for (i = 0; i < adv->num_supplies; i++) 10298c2ecf20Sopenharmony_ci adv->supplies[i].supply = supply_names[i]; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci ret = devm_regulator_bulk_get(dev, adv->num_supplies, adv->supplies); 10328c2ecf20Sopenharmony_ci if (ret) 10338c2ecf20Sopenharmony_ci return ret; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci return regulator_bulk_enable(adv->num_supplies, adv->supplies); 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_cistatic void adv7511_uninit_regulators(struct adv7511 *adv) 10398c2ecf20Sopenharmony_ci{ 10408c2ecf20Sopenharmony_ci regulator_bulk_disable(adv->num_supplies, adv->supplies); 10418c2ecf20Sopenharmony_ci} 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_cistatic bool adv7511_cec_register_volatile(struct device *dev, unsigned int reg) 10448c2ecf20Sopenharmony_ci{ 10458c2ecf20Sopenharmony_ci struct i2c_client *i2c = to_i2c_client(dev); 10468c2ecf20Sopenharmony_ci struct adv7511 *adv7511 = i2c_get_clientdata(i2c); 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci if (adv7511->type == ADV7533 || adv7511->type == ADV7535) 10498c2ecf20Sopenharmony_ci reg -= ADV7533_REG_CEC_OFFSET; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci switch (reg) { 10528c2ecf20Sopenharmony_ci case ADV7511_REG_CEC_RX_FRAME_HDR: 10538c2ecf20Sopenharmony_ci case ADV7511_REG_CEC_RX_FRAME_DATA0... 10548c2ecf20Sopenharmony_ci ADV7511_REG_CEC_RX_FRAME_DATA0 + 14: 10558c2ecf20Sopenharmony_ci case ADV7511_REG_CEC_RX_FRAME_LEN: 10568c2ecf20Sopenharmony_ci case ADV7511_REG_CEC_RX_BUFFERS: 10578c2ecf20Sopenharmony_ci case ADV7511_REG_CEC_TX_LOW_DRV_CNT: 10588c2ecf20Sopenharmony_ci return true; 10598c2ecf20Sopenharmony_ci } 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci return false; 10628c2ecf20Sopenharmony_ci} 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_cistatic const struct regmap_config adv7511_cec_regmap_config = { 10658c2ecf20Sopenharmony_ci .reg_bits = 8, 10668c2ecf20Sopenharmony_ci .val_bits = 8, 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci .max_register = 0xff, 10698c2ecf20Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 10708c2ecf20Sopenharmony_ci .volatile_reg = adv7511_cec_register_volatile, 10718c2ecf20Sopenharmony_ci}; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_cistatic int adv7511_init_cec_regmap(struct adv7511 *adv) 10748c2ecf20Sopenharmony_ci{ 10758c2ecf20Sopenharmony_ci int ret; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci adv->i2c_cec = i2c_new_ancillary_device(adv->i2c_main, "cec", 10788c2ecf20Sopenharmony_ci ADV7511_CEC_I2C_ADDR_DEFAULT); 10798c2ecf20Sopenharmony_ci if (IS_ERR(adv->i2c_cec)) 10808c2ecf20Sopenharmony_ci return PTR_ERR(adv->i2c_cec); 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci regmap_write(adv->regmap, ADV7511_REG_CEC_I2C_ADDR, 10838c2ecf20Sopenharmony_ci adv->i2c_cec->addr << 1); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci i2c_set_clientdata(adv->i2c_cec, adv); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci adv->regmap_cec = devm_regmap_init_i2c(adv->i2c_cec, 10888c2ecf20Sopenharmony_ci &adv7511_cec_regmap_config); 10898c2ecf20Sopenharmony_ci if (IS_ERR(adv->regmap_cec)) { 10908c2ecf20Sopenharmony_ci ret = PTR_ERR(adv->regmap_cec); 10918c2ecf20Sopenharmony_ci goto err; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci if (adv->type == ADV7533 || adv->type == ADV7535) { 10958c2ecf20Sopenharmony_ci ret = adv7533_patch_cec_registers(adv); 10968c2ecf20Sopenharmony_ci if (ret) 10978c2ecf20Sopenharmony_ci goto err; 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci return 0; 11018c2ecf20Sopenharmony_cierr: 11028c2ecf20Sopenharmony_ci i2c_unregister_device(adv->i2c_cec); 11038c2ecf20Sopenharmony_ci return ret; 11048c2ecf20Sopenharmony_ci} 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_cistatic int adv7511_parse_dt(struct device_node *np, 11078c2ecf20Sopenharmony_ci struct adv7511_link_config *config) 11088c2ecf20Sopenharmony_ci{ 11098c2ecf20Sopenharmony_ci const char *str; 11108c2ecf20Sopenharmony_ci int ret; 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci of_property_read_u32(np, "adi,input-depth", &config->input_color_depth); 11138c2ecf20Sopenharmony_ci if (config->input_color_depth != 8 && config->input_color_depth != 10 && 11148c2ecf20Sopenharmony_ci config->input_color_depth != 12) 11158c2ecf20Sopenharmony_ci return -EINVAL; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci ret = of_property_read_string(np, "adi,input-colorspace", &str); 11188c2ecf20Sopenharmony_ci if (ret < 0) 11198c2ecf20Sopenharmony_ci return ret; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci if (!strcmp(str, "rgb")) 11228c2ecf20Sopenharmony_ci config->input_colorspace = HDMI_COLORSPACE_RGB; 11238c2ecf20Sopenharmony_ci else if (!strcmp(str, "yuv422")) 11248c2ecf20Sopenharmony_ci config->input_colorspace = HDMI_COLORSPACE_YUV422; 11258c2ecf20Sopenharmony_ci else if (!strcmp(str, "yuv444")) 11268c2ecf20Sopenharmony_ci config->input_colorspace = HDMI_COLORSPACE_YUV444; 11278c2ecf20Sopenharmony_ci else 11288c2ecf20Sopenharmony_ci return -EINVAL; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci ret = of_property_read_string(np, "adi,input-clock", &str); 11318c2ecf20Sopenharmony_ci if (ret < 0) 11328c2ecf20Sopenharmony_ci return ret; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci if (!strcmp(str, "1x")) 11358c2ecf20Sopenharmony_ci config->input_clock = ADV7511_INPUT_CLOCK_1X; 11368c2ecf20Sopenharmony_ci else if (!strcmp(str, "2x")) 11378c2ecf20Sopenharmony_ci config->input_clock = ADV7511_INPUT_CLOCK_2X; 11388c2ecf20Sopenharmony_ci else if (!strcmp(str, "ddr")) 11398c2ecf20Sopenharmony_ci config->input_clock = ADV7511_INPUT_CLOCK_DDR; 11408c2ecf20Sopenharmony_ci else 11418c2ecf20Sopenharmony_ci return -EINVAL; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci if (config->input_colorspace == HDMI_COLORSPACE_YUV422 || 11448c2ecf20Sopenharmony_ci config->input_clock != ADV7511_INPUT_CLOCK_1X) { 11458c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "adi,input-style", 11468c2ecf20Sopenharmony_ci &config->input_style); 11478c2ecf20Sopenharmony_ci if (ret) 11488c2ecf20Sopenharmony_ci return ret; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci if (config->input_style < 1 || config->input_style > 3) 11518c2ecf20Sopenharmony_ci return -EINVAL; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci ret = of_property_read_string(np, "adi,input-justification", 11548c2ecf20Sopenharmony_ci &str); 11558c2ecf20Sopenharmony_ci if (ret < 0) 11568c2ecf20Sopenharmony_ci return ret; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci if (!strcmp(str, "left")) 11598c2ecf20Sopenharmony_ci config->input_justification = 11608c2ecf20Sopenharmony_ci ADV7511_INPUT_JUSTIFICATION_LEFT; 11618c2ecf20Sopenharmony_ci else if (!strcmp(str, "evenly")) 11628c2ecf20Sopenharmony_ci config->input_justification = 11638c2ecf20Sopenharmony_ci ADV7511_INPUT_JUSTIFICATION_EVENLY; 11648c2ecf20Sopenharmony_ci else if (!strcmp(str, "right")) 11658c2ecf20Sopenharmony_ci config->input_justification = 11668c2ecf20Sopenharmony_ci ADV7511_INPUT_JUSTIFICATION_RIGHT; 11678c2ecf20Sopenharmony_ci else 11688c2ecf20Sopenharmony_ci return -EINVAL; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci } else { 11718c2ecf20Sopenharmony_ci config->input_style = 1; 11728c2ecf20Sopenharmony_ci config->input_justification = ADV7511_INPUT_JUSTIFICATION_LEFT; 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci of_property_read_u32(np, "adi,clock-delay", &config->clock_delay); 11768c2ecf20Sopenharmony_ci if (config->clock_delay < -1200 || config->clock_delay > 1600) 11778c2ecf20Sopenharmony_ci return -EINVAL; 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci config->embedded_sync = of_property_read_bool(np, "adi,embedded-sync"); 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci /* Hardcode the sync pulse configurations for now. */ 11828c2ecf20Sopenharmony_ci config->sync_pulse = ADV7511_INPUT_SYNC_PULSE_NONE; 11838c2ecf20Sopenharmony_ci config->vsync_polarity = ADV7511_SYNC_POLARITY_PASSTHROUGH; 11848c2ecf20Sopenharmony_ci config->hsync_polarity = ADV7511_SYNC_POLARITY_PASSTHROUGH; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci return 0; 11878c2ecf20Sopenharmony_ci} 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_cistatic int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) 11908c2ecf20Sopenharmony_ci{ 11918c2ecf20Sopenharmony_ci struct adv7511_link_config link_config; 11928c2ecf20Sopenharmony_ci struct adv7511 *adv7511; 11938c2ecf20Sopenharmony_ci struct device *dev = &i2c->dev; 11948c2ecf20Sopenharmony_ci unsigned int val; 11958c2ecf20Sopenharmony_ci int ret; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci if (!dev->of_node) 11988c2ecf20Sopenharmony_ci return -EINVAL; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci adv7511 = devm_kzalloc(dev, sizeof(*adv7511), GFP_KERNEL); 12018c2ecf20Sopenharmony_ci if (!adv7511) 12028c2ecf20Sopenharmony_ci return -ENOMEM; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci adv7511->i2c_main = i2c; 12058c2ecf20Sopenharmony_ci adv7511->powered = false; 12068c2ecf20Sopenharmony_ci adv7511->status = connector_status_disconnected; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci if (dev->of_node) 12098c2ecf20Sopenharmony_ci adv7511->type = (enum adv7511_type)of_device_get_match_data(dev); 12108c2ecf20Sopenharmony_ci else 12118c2ecf20Sopenharmony_ci adv7511->type = id->driver_data; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci memset(&link_config, 0, sizeof(link_config)); 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci if (adv7511->type == ADV7511) 12168c2ecf20Sopenharmony_ci ret = adv7511_parse_dt(dev->of_node, &link_config); 12178c2ecf20Sopenharmony_ci else 12188c2ecf20Sopenharmony_ci ret = adv7533_parse_dt(dev->of_node, adv7511); 12198c2ecf20Sopenharmony_ci if (ret) 12208c2ecf20Sopenharmony_ci return ret; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci ret = adv7511_init_regulators(adv7511); 12238c2ecf20Sopenharmony_ci if (ret) { 12248c2ecf20Sopenharmony_ci dev_err(dev, "failed to init regulators\n"); 12258c2ecf20Sopenharmony_ci return ret; 12268c2ecf20Sopenharmony_ci } 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci /* 12298c2ecf20Sopenharmony_ci * The power down GPIO is optional. If present, toggle it from active to 12308c2ecf20Sopenharmony_ci * inactive to wake up the encoder. 12318c2ecf20Sopenharmony_ci */ 12328c2ecf20Sopenharmony_ci adv7511->gpio_pd = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH); 12338c2ecf20Sopenharmony_ci if (IS_ERR(adv7511->gpio_pd)) { 12348c2ecf20Sopenharmony_ci ret = PTR_ERR(adv7511->gpio_pd); 12358c2ecf20Sopenharmony_ci goto uninit_regulators; 12368c2ecf20Sopenharmony_ci } 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci if (adv7511->gpio_pd) { 12398c2ecf20Sopenharmony_ci usleep_range(5000, 6000); 12408c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(adv7511->gpio_pd, 0); 12418c2ecf20Sopenharmony_ci } 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci adv7511->regmap = devm_regmap_init_i2c(i2c, &adv7511_regmap_config); 12448c2ecf20Sopenharmony_ci if (IS_ERR(adv7511->regmap)) { 12458c2ecf20Sopenharmony_ci ret = PTR_ERR(adv7511->regmap); 12468c2ecf20Sopenharmony_ci goto uninit_regulators; 12478c2ecf20Sopenharmony_ci } 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci ret = regmap_read(adv7511->regmap, ADV7511_REG_CHIP_REVISION, &val); 12508c2ecf20Sopenharmony_ci if (ret) 12518c2ecf20Sopenharmony_ci goto uninit_regulators; 12528c2ecf20Sopenharmony_ci dev_dbg(dev, "Rev. %d\n", val); 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci if (adv7511->type == ADV7511) 12558c2ecf20Sopenharmony_ci ret = regmap_register_patch(adv7511->regmap, 12568c2ecf20Sopenharmony_ci adv7511_fixed_registers, 12578c2ecf20Sopenharmony_ci ARRAY_SIZE(adv7511_fixed_registers)); 12588c2ecf20Sopenharmony_ci else 12598c2ecf20Sopenharmony_ci ret = adv7533_patch_registers(adv7511); 12608c2ecf20Sopenharmony_ci if (ret) 12618c2ecf20Sopenharmony_ci goto uninit_regulators; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci adv7511_packet_disable(adv7511, 0xffff); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci adv7511->i2c_edid = i2c_new_ancillary_device(i2c, "edid", 12668c2ecf20Sopenharmony_ci ADV7511_EDID_I2C_ADDR_DEFAULT); 12678c2ecf20Sopenharmony_ci if (IS_ERR(adv7511->i2c_edid)) { 12688c2ecf20Sopenharmony_ci ret = PTR_ERR(adv7511->i2c_edid); 12698c2ecf20Sopenharmony_ci goto uninit_regulators; 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, 12738c2ecf20Sopenharmony_ci adv7511->i2c_edid->addr << 1); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci adv7511->i2c_packet = i2c_new_ancillary_device(i2c, "packet", 12768c2ecf20Sopenharmony_ci ADV7511_PACKET_I2C_ADDR_DEFAULT); 12778c2ecf20Sopenharmony_ci if (IS_ERR(adv7511->i2c_packet)) { 12788c2ecf20Sopenharmony_ci ret = PTR_ERR(adv7511->i2c_packet); 12798c2ecf20Sopenharmony_ci goto err_i2c_unregister_edid; 12808c2ecf20Sopenharmony_ci } 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR, 12838c2ecf20Sopenharmony_ci adv7511->i2c_packet->addr << 1); 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci ret = adv7511_init_cec_regmap(adv7511); 12868c2ecf20Sopenharmony_ci if (ret) 12878c2ecf20Sopenharmony_ci goto err_i2c_unregister_packet; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci INIT_WORK(&adv7511->hpd_work, adv7511_hpd_work); 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci if (i2c->irq) { 12928c2ecf20Sopenharmony_ci init_waitqueue_head(&adv7511->wq); 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(dev, i2c->irq, NULL, 12958c2ecf20Sopenharmony_ci adv7511_irq_handler, 12968c2ecf20Sopenharmony_ci IRQF_ONESHOT, dev_name(dev), 12978c2ecf20Sopenharmony_ci adv7511); 12988c2ecf20Sopenharmony_ci if (ret) 12998c2ecf20Sopenharmony_ci goto err_unregister_cec; 13008c2ecf20Sopenharmony_ci } 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci adv7511_power_off(adv7511); 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci i2c_set_clientdata(i2c, adv7511); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci if (adv7511->type == ADV7511) 13078c2ecf20Sopenharmony_ci adv7511_set_link_config(adv7511, &link_config); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci ret = adv7511_cec_init(dev, adv7511); 13108c2ecf20Sopenharmony_ci if (ret) 13118c2ecf20Sopenharmony_ci goto err_unregister_cec; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci adv7511->bridge.funcs = &adv7511_bridge_funcs; 13148c2ecf20Sopenharmony_ci adv7511->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID 13158c2ecf20Sopenharmony_ci | DRM_BRIDGE_OP_HPD; 13168c2ecf20Sopenharmony_ci adv7511->bridge.of_node = dev->of_node; 13178c2ecf20Sopenharmony_ci adv7511->bridge.type = DRM_MODE_CONNECTOR_HDMIA; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci drm_bridge_add(&adv7511->bridge); 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci adv7511_audio_init(dev, adv7511); 13228c2ecf20Sopenharmony_ci return 0; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_cierr_unregister_cec: 13258c2ecf20Sopenharmony_ci cec_unregister_adapter(adv7511->cec_adap); 13268c2ecf20Sopenharmony_ci i2c_unregister_device(adv7511->i2c_cec); 13278c2ecf20Sopenharmony_ci if (adv7511->cec_clk) 13288c2ecf20Sopenharmony_ci clk_disable_unprepare(adv7511->cec_clk); 13298c2ecf20Sopenharmony_cierr_i2c_unregister_packet: 13308c2ecf20Sopenharmony_ci i2c_unregister_device(adv7511->i2c_packet); 13318c2ecf20Sopenharmony_cierr_i2c_unregister_edid: 13328c2ecf20Sopenharmony_ci i2c_unregister_device(adv7511->i2c_edid); 13338c2ecf20Sopenharmony_ciuninit_regulators: 13348c2ecf20Sopenharmony_ci adv7511_uninit_regulators(adv7511); 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci return ret; 13378c2ecf20Sopenharmony_ci} 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_cistatic int adv7511_remove(struct i2c_client *i2c) 13408c2ecf20Sopenharmony_ci{ 13418c2ecf20Sopenharmony_ci struct adv7511 *adv7511 = i2c_get_clientdata(i2c); 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci if (adv7511->type == ADV7533 || adv7511->type == ADV7535) 13448c2ecf20Sopenharmony_ci adv7533_detach_dsi(adv7511); 13458c2ecf20Sopenharmony_ci i2c_unregister_device(adv7511->i2c_cec); 13468c2ecf20Sopenharmony_ci if (adv7511->cec_clk) 13478c2ecf20Sopenharmony_ci clk_disable_unprepare(adv7511->cec_clk); 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci adv7511_uninit_regulators(adv7511); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci drm_bridge_remove(&adv7511->bridge); 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci adv7511_audio_exit(adv7511); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci cec_unregister_adapter(adv7511->cec_adap); 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci i2c_unregister_device(adv7511->i2c_packet); 13588c2ecf20Sopenharmony_ci i2c_unregister_device(adv7511->i2c_edid); 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci return 0; 13618c2ecf20Sopenharmony_ci} 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_cistatic const struct i2c_device_id adv7511_i2c_ids[] = { 13648c2ecf20Sopenharmony_ci { "adv7511", ADV7511 }, 13658c2ecf20Sopenharmony_ci { "adv7511w", ADV7511 }, 13668c2ecf20Sopenharmony_ci { "adv7513", ADV7511 }, 13678c2ecf20Sopenharmony_ci { "adv7533", ADV7533 }, 13688c2ecf20Sopenharmony_ci { "adv7535", ADV7535 }, 13698c2ecf20Sopenharmony_ci { } 13708c2ecf20Sopenharmony_ci}; 13718c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, adv7511_i2c_ids); 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_cistatic const struct of_device_id adv7511_of_ids[] = { 13748c2ecf20Sopenharmony_ci { .compatible = "adi,adv7511", .data = (void *)ADV7511 }, 13758c2ecf20Sopenharmony_ci { .compatible = "adi,adv7511w", .data = (void *)ADV7511 }, 13768c2ecf20Sopenharmony_ci { .compatible = "adi,adv7513", .data = (void *)ADV7511 }, 13778c2ecf20Sopenharmony_ci { .compatible = "adi,adv7533", .data = (void *)ADV7533 }, 13788c2ecf20Sopenharmony_ci { .compatible = "adi,adv7535", .data = (void *)ADV7535 }, 13798c2ecf20Sopenharmony_ci { } 13808c2ecf20Sopenharmony_ci}; 13818c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, adv7511_of_ids); 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_cistatic struct mipi_dsi_driver adv7533_dsi_driver = { 13848c2ecf20Sopenharmony_ci .driver.name = "adv7533", 13858c2ecf20Sopenharmony_ci}; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_cistatic struct i2c_driver adv7511_driver = { 13888c2ecf20Sopenharmony_ci .driver = { 13898c2ecf20Sopenharmony_ci .name = "adv7511", 13908c2ecf20Sopenharmony_ci .of_match_table = adv7511_of_ids, 13918c2ecf20Sopenharmony_ci }, 13928c2ecf20Sopenharmony_ci .id_table = adv7511_i2c_ids, 13938c2ecf20Sopenharmony_ci .probe = adv7511_probe, 13948c2ecf20Sopenharmony_ci .remove = adv7511_remove, 13958c2ecf20Sopenharmony_ci}; 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_cistatic int __init adv7511_init(void) 13988c2ecf20Sopenharmony_ci{ 13998c2ecf20Sopenharmony_ci int ret; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) { 14028c2ecf20Sopenharmony_ci ret = mipi_dsi_driver_register(&adv7533_dsi_driver); 14038c2ecf20Sopenharmony_ci if (ret) 14048c2ecf20Sopenharmony_ci return ret; 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci ret = i2c_add_driver(&adv7511_driver); 14088c2ecf20Sopenharmony_ci if (ret) { 14098c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) 14108c2ecf20Sopenharmony_ci mipi_dsi_driver_unregister(&adv7533_dsi_driver); 14118c2ecf20Sopenharmony_ci } 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci return ret; 14148c2ecf20Sopenharmony_ci} 14158c2ecf20Sopenharmony_cimodule_init(adv7511_init); 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_cistatic void __exit adv7511_exit(void) 14188c2ecf20Sopenharmony_ci{ 14198c2ecf20Sopenharmony_ci i2c_del_driver(&adv7511_driver); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) 14228c2ecf20Sopenharmony_ci mipi_dsi_driver_unregister(&adv7533_dsi_driver); 14238c2ecf20Sopenharmony_ci} 14248c2ecf20Sopenharmony_cimodule_exit(adv7511_exit); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ciMODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 14278c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ADV7511 HDMI transmitter driver"); 14288c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1429