18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright © 2011 Intel Corporation 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the next 128c2ecf20Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 138c2ecf20Sopenharmony_ci * Software. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 168c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 188c2ecf20Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 198c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 208c2ecf20Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 218c2ecf20Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <linux/delay.h> 268c2ecf20Sopenharmony_ci#include <linux/kernel.h> 278c2ecf20Sopenharmony_ci#include <linux/module.h> 288c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <asm/intel_scu_ipc.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "mdfld_dsi_dpi.h" 338c2ecf20Sopenharmony_ci#include "mdfld_dsi_pkg_sender.h" 348c2ecf20Sopenharmony_ci#include "mdfld_output.h" 358c2ecf20Sopenharmony_ci#include "tc35876x-dsi-lvds.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic struct i2c_client *tc35876x_client; 388c2ecf20Sopenharmony_cistatic struct i2c_client *cmi_lcd_i2c_client; 398c2ecf20Sopenharmony_ci/* Panel GPIOs */ 408c2ecf20Sopenharmony_cistatic struct gpio_desc *bridge_reset; 418c2ecf20Sopenharmony_cistatic struct gpio_desc *bridge_bl_enable; 428c2ecf20Sopenharmony_cistatic struct gpio_desc *backlight_voltage; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end)) 468c2ecf20Sopenharmony_ci#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end)) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* DSI D-PHY Layer Registers */ 498c2ecf20Sopenharmony_ci#define D0W_DPHYCONTTX 0x0004 508c2ecf20Sopenharmony_ci#define CLW_DPHYCONTRX 0x0020 518c2ecf20Sopenharmony_ci#define D0W_DPHYCONTRX 0x0024 528c2ecf20Sopenharmony_ci#define D1W_DPHYCONTRX 0x0028 538c2ecf20Sopenharmony_ci#define D2W_DPHYCONTRX 0x002C 548c2ecf20Sopenharmony_ci#define D3W_DPHYCONTRX 0x0030 558c2ecf20Sopenharmony_ci#define COM_DPHYCONTRX 0x0038 568c2ecf20Sopenharmony_ci#define CLW_CNTRL 0x0040 578c2ecf20Sopenharmony_ci#define D0W_CNTRL 0x0044 588c2ecf20Sopenharmony_ci#define D1W_CNTRL 0x0048 598c2ecf20Sopenharmony_ci#define D2W_CNTRL 0x004C 608c2ecf20Sopenharmony_ci#define D3W_CNTRL 0x0050 618c2ecf20Sopenharmony_ci#define DFTMODE_CNTRL 0x0054 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* DSI PPI Layer Registers */ 648c2ecf20Sopenharmony_ci#define PPI_STARTPPI 0x0104 658c2ecf20Sopenharmony_ci#define PPI_BUSYPPI 0x0108 668c2ecf20Sopenharmony_ci#define PPI_LINEINITCNT 0x0110 678c2ecf20Sopenharmony_ci#define PPI_LPTXTIMECNT 0x0114 688c2ecf20Sopenharmony_ci#define PPI_LANEENABLE 0x0134 698c2ecf20Sopenharmony_ci#define PPI_TX_RX_TA 0x013C 708c2ecf20Sopenharmony_ci#define PPI_CLS_ATMR 0x0140 718c2ecf20Sopenharmony_ci#define PPI_D0S_ATMR 0x0144 728c2ecf20Sopenharmony_ci#define PPI_D1S_ATMR 0x0148 738c2ecf20Sopenharmony_ci#define PPI_D2S_ATMR 0x014C 748c2ecf20Sopenharmony_ci#define PPI_D3S_ATMR 0x0150 758c2ecf20Sopenharmony_ci#define PPI_D0S_CLRSIPOCOUNT 0x0164 768c2ecf20Sopenharmony_ci#define PPI_D1S_CLRSIPOCOUNT 0x0168 778c2ecf20Sopenharmony_ci#define PPI_D2S_CLRSIPOCOUNT 0x016C 788c2ecf20Sopenharmony_ci#define PPI_D3S_CLRSIPOCOUNT 0x0170 798c2ecf20Sopenharmony_ci#define CLS_PRE 0x0180 808c2ecf20Sopenharmony_ci#define D0S_PRE 0x0184 818c2ecf20Sopenharmony_ci#define D1S_PRE 0x0188 828c2ecf20Sopenharmony_ci#define D2S_PRE 0x018C 838c2ecf20Sopenharmony_ci#define D3S_PRE 0x0190 848c2ecf20Sopenharmony_ci#define CLS_PREP 0x01A0 858c2ecf20Sopenharmony_ci#define D0S_PREP 0x01A4 868c2ecf20Sopenharmony_ci#define D1S_PREP 0x01A8 878c2ecf20Sopenharmony_ci#define D2S_PREP 0x01AC 888c2ecf20Sopenharmony_ci#define D3S_PREP 0x01B0 898c2ecf20Sopenharmony_ci#define CLS_ZERO 0x01C0 908c2ecf20Sopenharmony_ci#define D0S_ZERO 0x01C4 918c2ecf20Sopenharmony_ci#define D1S_ZERO 0x01C8 928c2ecf20Sopenharmony_ci#define D2S_ZERO 0x01CC 938c2ecf20Sopenharmony_ci#define D3S_ZERO 0x01D0 948c2ecf20Sopenharmony_ci#define PPI_CLRFLG 0x01E0 958c2ecf20Sopenharmony_ci#define PPI_CLRSIPO 0x01E4 968c2ecf20Sopenharmony_ci#define HSTIMEOUT 0x01F0 978c2ecf20Sopenharmony_ci#define HSTIMEOUTENABLE 0x01F4 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* DSI Protocol Layer Registers */ 1008c2ecf20Sopenharmony_ci#define DSI_STARTDSI 0x0204 1018c2ecf20Sopenharmony_ci#define DSI_BUSYDSI 0x0208 1028c2ecf20Sopenharmony_ci#define DSI_LANEENABLE 0x0210 1038c2ecf20Sopenharmony_ci#define DSI_LANESTATUS0 0x0214 1048c2ecf20Sopenharmony_ci#define DSI_LANESTATUS1 0x0218 1058c2ecf20Sopenharmony_ci#define DSI_INTSTATUS 0x0220 1068c2ecf20Sopenharmony_ci#define DSI_INTMASK 0x0224 1078c2ecf20Sopenharmony_ci#define DSI_INTCLR 0x0228 1088c2ecf20Sopenharmony_ci#define DSI_LPTXTO 0x0230 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/* DSI General Registers */ 1118c2ecf20Sopenharmony_ci#define DSIERRCNT 0x0300 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* DSI Application Layer Registers */ 1148c2ecf20Sopenharmony_ci#define APLCTRL 0x0400 1158c2ecf20Sopenharmony_ci#define RDPKTLN 0x0404 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/* Video Path Registers */ 1188c2ecf20Sopenharmony_ci#define VPCTRL 0x0450 1198c2ecf20Sopenharmony_ci#define HTIM1 0x0454 1208c2ecf20Sopenharmony_ci#define HTIM2 0x0458 1218c2ecf20Sopenharmony_ci#define VTIM1 0x045C 1228c2ecf20Sopenharmony_ci#define VTIM2 0x0460 1238c2ecf20Sopenharmony_ci#define VFUEN 0x0464 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci/* LVDS Registers */ 1268c2ecf20Sopenharmony_ci#define LVMX0003 0x0480 1278c2ecf20Sopenharmony_ci#define LVMX0407 0x0484 1288c2ecf20Sopenharmony_ci#define LVMX0811 0x0488 1298c2ecf20Sopenharmony_ci#define LVMX1215 0x048C 1308c2ecf20Sopenharmony_ci#define LVMX1619 0x0490 1318c2ecf20Sopenharmony_ci#define LVMX2023 0x0494 1328c2ecf20Sopenharmony_ci#define LVMX2427 0x0498 1338c2ecf20Sopenharmony_ci#define LVCFG 0x049C 1348c2ecf20Sopenharmony_ci#define LVPHY0 0x04A0 1358c2ecf20Sopenharmony_ci#define LVPHY1 0x04A4 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci/* System Registers */ 1388c2ecf20Sopenharmony_ci#define SYSSTAT 0x0500 1398c2ecf20Sopenharmony_ci#define SYSRST 0x0504 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci/* GPIO Registers */ 1428c2ecf20Sopenharmony_ci/*#define GPIOC 0x0520*/ 1438c2ecf20Sopenharmony_ci#define GPIOO 0x0524 1448c2ecf20Sopenharmony_ci#define GPIOI 0x0528 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* I2C Registers */ 1478c2ecf20Sopenharmony_ci#define I2CTIMCTRL 0x0540 1488c2ecf20Sopenharmony_ci#define I2CMADDR 0x0544 1498c2ecf20Sopenharmony_ci#define WDATAQ 0x0548 1508c2ecf20Sopenharmony_ci#define RDATAQ 0x054C 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/* Chip/Rev Registers */ 1538c2ecf20Sopenharmony_ci#define IDREG 0x0580 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci/* Debug Registers */ 1568c2ecf20Sopenharmony_ci#define DEBUG00 0x05A0 1578c2ecf20Sopenharmony_ci#define DEBUG01 0x05A4 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/* Panel CABC registers */ 1608c2ecf20Sopenharmony_ci#define PANEL_PWM_CONTROL 0x90 1618c2ecf20Sopenharmony_ci#define PANEL_FREQ_DIVIDER_HI 0x91 1628c2ecf20Sopenharmony_ci#define PANEL_FREQ_DIVIDER_LO 0x92 1638c2ecf20Sopenharmony_ci#define PANEL_DUTY_CONTROL 0x93 1648c2ecf20Sopenharmony_ci#define PANEL_MODIFY_RGB 0x94 1658c2ecf20Sopenharmony_ci#define PANEL_FRAMERATE_CONTROL 0x96 1668c2ecf20Sopenharmony_ci#define PANEL_PWM_MIN 0x97 1678c2ecf20Sopenharmony_ci#define PANEL_PWM_REF 0x98 1688c2ecf20Sopenharmony_ci#define PANEL_PWM_MAX 0x99 1698c2ecf20Sopenharmony_ci#define PANEL_ALLOW_DISTORT 0x9A 1708c2ecf20Sopenharmony_ci#define PANEL_BYPASS_PWMI 0x9B 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/* Panel color management registers */ 1738c2ecf20Sopenharmony_ci#define PANEL_CM_ENABLE 0x700 1748c2ecf20Sopenharmony_ci#define PANEL_CM_HUE 0x701 1758c2ecf20Sopenharmony_ci#define PANEL_CM_SATURATION 0x702 1768c2ecf20Sopenharmony_ci#define PANEL_CM_INTENSITY 0x703 1778c2ecf20Sopenharmony_ci#define PANEL_CM_BRIGHTNESS 0x704 1788c2ecf20Sopenharmony_ci#define PANEL_CM_CE_ENABLE 0x705 1798c2ecf20Sopenharmony_ci#define PANEL_CM_PEAK_EN 0x710 1808c2ecf20Sopenharmony_ci#define PANEL_CM_GAIN 0x711 1818c2ecf20Sopenharmony_ci#define PANEL_CM_HUETABLE_START 0x730 1828c2ecf20Sopenharmony_ci#define PANEL_CM_HUETABLE_END 0x747 /* inclusive */ 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/* Input muxing for registers LVMX0003...LVMX2427 */ 1858c2ecf20Sopenharmony_cienum { 1868c2ecf20Sopenharmony_ci INPUT_R0, /* 0 */ 1878c2ecf20Sopenharmony_ci INPUT_R1, 1888c2ecf20Sopenharmony_ci INPUT_R2, 1898c2ecf20Sopenharmony_ci INPUT_R3, 1908c2ecf20Sopenharmony_ci INPUT_R4, 1918c2ecf20Sopenharmony_ci INPUT_R5, 1928c2ecf20Sopenharmony_ci INPUT_R6, 1938c2ecf20Sopenharmony_ci INPUT_R7, 1948c2ecf20Sopenharmony_ci INPUT_G0, /* 8 */ 1958c2ecf20Sopenharmony_ci INPUT_G1, 1968c2ecf20Sopenharmony_ci INPUT_G2, 1978c2ecf20Sopenharmony_ci INPUT_G3, 1988c2ecf20Sopenharmony_ci INPUT_G4, 1998c2ecf20Sopenharmony_ci INPUT_G5, 2008c2ecf20Sopenharmony_ci INPUT_G6, 2018c2ecf20Sopenharmony_ci INPUT_G7, 2028c2ecf20Sopenharmony_ci INPUT_B0, /* 16 */ 2038c2ecf20Sopenharmony_ci INPUT_B1, 2048c2ecf20Sopenharmony_ci INPUT_B2, 2058c2ecf20Sopenharmony_ci INPUT_B3, 2068c2ecf20Sopenharmony_ci INPUT_B4, 2078c2ecf20Sopenharmony_ci INPUT_B5, 2088c2ecf20Sopenharmony_ci INPUT_B6, 2098c2ecf20Sopenharmony_ci INPUT_B7, 2108c2ecf20Sopenharmony_ci INPUT_HSYNC, /* 24 */ 2118c2ecf20Sopenharmony_ci INPUT_VSYNC, 2128c2ecf20Sopenharmony_ci INPUT_DE, 2138c2ecf20Sopenharmony_ci LOGIC_0, 2148c2ecf20Sopenharmony_ci /* 28...31 undefined */ 2158c2ecf20Sopenharmony_ci}; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci#define INPUT_MUX(lvmx03, lvmx02, lvmx01, lvmx00) \ 2188c2ecf20Sopenharmony_ci (FLD_VAL(lvmx03, 29, 24) | FLD_VAL(lvmx02, 20, 16) | \ 2198c2ecf20Sopenharmony_ci FLD_VAL(lvmx01, 12, 8) | FLD_VAL(lvmx00, 4, 0)) 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci/** 2228c2ecf20Sopenharmony_ci * tc35876x_regw - Write DSI-LVDS bridge register using I2C 2238c2ecf20Sopenharmony_ci * @client: struct i2c_client to use 2248c2ecf20Sopenharmony_ci * @reg: register address 2258c2ecf20Sopenharmony_ci * @value: value to write 2268c2ecf20Sopenharmony_ci * 2278c2ecf20Sopenharmony_ci * Returns 0 on success, or a negative error value. 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_cistatic int tc35876x_regw(struct i2c_client *client, u16 reg, u32 value) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci int r; 2328c2ecf20Sopenharmony_ci u8 tx_data[] = { 2338c2ecf20Sopenharmony_ci /* NOTE: Register address big-endian, data little-endian. */ 2348c2ecf20Sopenharmony_ci (reg >> 8) & 0xff, 2358c2ecf20Sopenharmony_ci reg & 0xff, 2368c2ecf20Sopenharmony_ci value & 0xff, 2378c2ecf20Sopenharmony_ci (value >> 8) & 0xff, 2388c2ecf20Sopenharmony_ci (value >> 16) & 0xff, 2398c2ecf20Sopenharmony_ci (value >> 24) & 0xff, 2408c2ecf20Sopenharmony_ci }; 2418c2ecf20Sopenharmony_ci struct i2c_msg msgs[] = { 2428c2ecf20Sopenharmony_ci { 2438c2ecf20Sopenharmony_ci .addr = client->addr, 2448c2ecf20Sopenharmony_ci .flags = 0, 2458c2ecf20Sopenharmony_ci .buf = tx_data, 2468c2ecf20Sopenharmony_ci .len = ARRAY_SIZE(tx_data), 2478c2ecf20Sopenharmony_ci }, 2488c2ecf20Sopenharmony_ci }; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci r = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 2518c2ecf20Sopenharmony_ci if (r < 0) { 2528c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s: reg 0x%04x val 0x%08x error %d\n", 2538c2ecf20Sopenharmony_ci __func__, reg, value, r); 2548c2ecf20Sopenharmony_ci return r; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (r < ARRAY_SIZE(msgs)) { 2588c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s: reg 0x%04x val 0x%08x msgs %d\n", 2598c2ecf20Sopenharmony_ci __func__, reg, value, r); 2608c2ecf20Sopenharmony_ci return -EAGAIN; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "%s: reg 0x%04x val 0x%08x\n", 2648c2ecf20Sopenharmony_ci __func__, reg, value); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci return 0; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci/** 2708c2ecf20Sopenharmony_ci * tc35876x_regr - Read DSI-LVDS bridge register using I2C 2718c2ecf20Sopenharmony_ci * @client: struct i2c_client to use 2728c2ecf20Sopenharmony_ci * @reg: register address 2738c2ecf20Sopenharmony_ci * @value: pointer for storing the value 2748c2ecf20Sopenharmony_ci * 2758c2ecf20Sopenharmony_ci * Returns 0 on success, or a negative error value. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_cistatic int tc35876x_regr(struct i2c_client *client, u16 reg, u32 *value) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci int r; 2808c2ecf20Sopenharmony_ci u8 tx_data[] = { 2818c2ecf20Sopenharmony_ci (reg >> 8) & 0xff, 2828c2ecf20Sopenharmony_ci reg & 0xff, 2838c2ecf20Sopenharmony_ci }; 2848c2ecf20Sopenharmony_ci u8 rx_data[4]; 2858c2ecf20Sopenharmony_ci struct i2c_msg msgs[] = { 2868c2ecf20Sopenharmony_ci { 2878c2ecf20Sopenharmony_ci .addr = client->addr, 2888c2ecf20Sopenharmony_ci .flags = 0, 2898c2ecf20Sopenharmony_ci .buf = tx_data, 2908c2ecf20Sopenharmony_ci .len = ARRAY_SIZE(tx_data), 2918c2ecf20Sopenharmony_ci }, 2928c2ecf20Sopenharmony_ci { 2938c2ecf20Sopenharmony_ci .addr = client->addr, 2948c2ecf20Sopenharmony_ci .flags = I2C_M_RD, 2958c2ecf20Sopenharmony_ci .buf = rx_data, 2968c2ecf20Sopenharmony_ci .len = ARRAY_SIZE(rx_data), 2978c2ecf20Sopenharmony_ci }, 2988c2ecf20Sopenharmony_ci }; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci r = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 3018c2ecf20Sopenharmony_ci if (r < 0) { 3028c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s: reg 0x%04x error %d\n", __func__, 3038c2ecf20Sopenharmony_ci reg, r); 3048c2ecf20Sopenharmony_ci return r; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (r < ARRAY_SIZE(msgs)) { 3088c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s: reg 0x%04x msgs %d\n", __func__, 3098c2ecf20Sopenharmony_ci reg, r); 3108c2ecf20Sopenharmony_ci return -EAGAIN; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci *value = rx_data[0] << 24 | rx_data[1] << 16 | 3148c2ecf20Sopenharmony_ci rx_data[2] << 8 | rx_data[3]; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "%s: reg 0x%04x value 0x%08x\n", __func__, 3178c2ecf20Sopenharmony_ci reg, *value); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_civoid tc35876x_set_bridge_reset_state(struct drm_device *dev, int state) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci if (WARN(!tc35876x_client, "%s called before probe", __func__)) 3258c2ecf20Sopenharmony_ci return; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci dev_dbg(&tc35876x_client->dev, "%s: state %d\n", __func__, state); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (!bridge_reset) 3308c2ecf20Sopenharmony_ci return; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (state) { 3338c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(bridge_reset, 0); 3348c2ecf20Sopenharmony_ci mdelay(10); 3358c2ecf20Sopenharmony_ci } else { 3368c2ecf20Sopenharmony_ci /* Pull MIPI Bridge reset pin to Low */ 3378c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(bridge_reset, 0); 3388c2ecf20Sopenharmony_ci mdelay(20); 3398c2ecf20Sopenharmony_ci /* Pull MIPI Bridge reset pin to High */ 3408c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(bridge_reset, 1); 3418c2ecf20Sopenharmony_ci mdelay(40); 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_civoid tc35876x_configure_lvds_bridge(struct drm_device *dev) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci struct i2c_client *i2c = tc35876x_client; 3488c2ecf20Sopenharmony_ci u32 ppi_lptxtimecnt; 3498c2ecf20Sopenharmony_ci u32 txtagocnt; 3508c2ecf20Sopenharmony_ci u32 txtasurecnt; 3518c2ecf20Sopenharmony_ci u32 id; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (WARN(!tc35876x_client, "%s called before probe", __func__)) 3548c2ecf20Sopenharmony_ci return; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci dev_dbg(&tc35876x_client->dev, "%s\n", __func__); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (!tc35876x_regr(i2c, IDREG, &id)) 3598c2ecf20Sopenharmony_ci dev_info(&tc35876x_client->dev, "tc35876x ID 0x%08x\n", id); 3608c2ecf20Sopenharmony_ci else 3618c2ecf20Sopenharmony_ci dev_err(&tc35876x_client->dev, "Cannot read ID\n"); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci ppi_lptxtimecnt = 4; 3648c2ecf20Sopenharmony_ci txtagocnt = (5 * ppi_lptxtimecnt - 3) / 4; 3658c2ecf20Sopenharmony_ci txtasurecnt = 3 * ppi_lptxtimecnt / 2; 3668c2ecf20Sopenharmony_ci tc35876x_regw(i2c, PPI_TX_RX_TA, FLD_VAL(txtagocnt, 26, 16) | 3678c2ecf20Sopenharmony_ci FLD_VAL(txtasurecnt, 10, 0)); 3688c2ecf20Sopenharmony_ci tc35876x_regw(i2c, PPI_LPTXTIMECNT, FLD_VAL(ppi_lptxtimecnt, 10, 0)); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci tc35876x_regw(i2c, PPI_D0S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0)); 3718c2ecf20Sopenharmony_ci tc35876x_regw(i2c, PPI_D1S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0)); 3728c2ecf20Sopenharmony_ci tc35876x_regw(i2c, PPI_D2S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0)); 3738c2ecf20Sopenharmony_ci tc35876x_regw(i2c, PPI_D3S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0)); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* Enabling MIPI & PPI lanes, Enable 4 lanes */ 3768c2ecf20Sopenharmony_ci tc35876x_regw(i2c, PPI_LANEENABLE, 3778c2ecf20Sopenharmony_ci BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)); 3788c2ecf20Sopenharmony_ci tc35876x_regw(i2c, DSI_LANEENABLE, 3798c2ecf20Sopenharmony_ci BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)); 3808c2ecf20Sopenharmony_ci tc35876x_regw(i2c, PPI_STARTPPI, BIT(0)); 3818c2ecf20Sopenharmony_ci tc35876x_regw(i2c, DSI_STARTDSI, BIT(0)); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* Setting LVDS output frequency */ 3848c2ecf20Sopenharmony_ci tc35876x_regw(i2c, LVPHY0, FLD_VAL(1, 20, 16) | 3858c2ecf20Sopenharmony_ci FLD_VAL(2, 15, 14) | FLD_VAL(6, 4, 0)); /* 0x00048006 */ 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* Setting video panel control register,0x00000120 VTGen=ON ?!?!? */ 3888c2ecf20Sopenharmony_ci tc35876x_regw(i2c, VPCTRL, BIT(8) | BIT(5)); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* Horizontal back porch and horizontal pulse width. 0x00280028 */ 3918c2ecf20Sopenharmony_ci tc35876x_regw(i2c, HTIM1, FLD_VAL(40, 24, 16) | FLD_VAL(40, 8, 0)); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* Horizontal front porch and horizontal active video size. 0x00500500*/ 3948c2ecf20Sopenharmony_ci tc35876x_regw(i2c, HTIM2, FLD_VAL(80, 24, 16) | FLD_VAL(1280, 10, 0)); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci /* Vertical back porch and vertical sync pulse width. 0x000e000a */ 3978c2ecf20Sopenharmony_ci tc35876x_regw(i2c, VTIM1, FLD_VAL(14, 23, 16) | FLD_VAL(10, 7, 0)); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* Vertical front porch and vertical display size. 0x000e0320 */ 4008c2ecf20Sopenharmony_ci tc35876x_regw(i2c, VTIM2, FLD_VAL(14, 23, 16) | FLD_VAL(800, 10, 0)); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci /* Set above HTIM1, HTIM2, VTIM1, and VTIM2 at next VSYNC. */ 4038c2ecf20Sopenharmony_ci tc35876x_regw(i2c, VFUEN, BIT(0)); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci /* Soft reset LCD controller. */ 4068c2ecf20Sopenharmony_ci tc35876x_regw(i2c, SYSRST, BIT(2)); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci /* LVDS-TX input muxing */ 4098c2ecf20Sopenharmony_ci tc35876x_regw(i2c, LVMX0003, 4108c2ecf20Sopenharmony_ci INPUT_MUX(INPUT_R5, INPUT_R4, INPUT_R3, INPUT_R2)); 4118c2ecf20Sopenharmony_ci tc35876x_regw(i2c, LVMX0407, 4128c2ecf20Sopenharmony_ci INPUT_MUX(INPUT_G2, INPUT_R7, INPUT_R1, INPUT_R6)); 4138c2ecf20Sopenharmony_ci tc35876x_regw(i2c, LVMX0811, 4148c2ecf20Sopenharmony_ci INPUT_MUX(INPUT_G1, INPUT_G0, INPUT_G4, INPUT_G3)); 4158c2ecf20Sopenharmony_ci tc35876x_regw(i2c, LVMX1215, 4168c2ecf20Sopenharmony_ci INPUT_MUX(INPUT_B2, INPUT_G7, INPUT_G6, INPUT_G5)); 4178c2ecf20Sopenharmony_ci tc35876x_regw(i2c, LVMX1619, 4188c2ecf20Sopenharmony_ci INPUT_MUX(INPUT_B4, INPUT_B3, INPUT_B1, INPUT_B0)); 4198c2ecf20Sopenharmony_ci tc35876x_regw(i2c, LVMX2023, 4208c2ecf20Sopenharmony_ci INPUT_MUX(LOGIC_0, INPUT_B7, INPUT_B6, INPUT_B5)); 4218c2ecf20Sopenharmony_ci tc35876x_regw(i2c, LVMX2427, 4228c2ecf20Sopenharmony_ci INPUT_MUX(INPUT_R0, INPUT_DE, INPUT_VSYNC, INPUT_HSYNC)); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* Enable LVDS transmitter. */ 4258c2ecf20Sopenharmony_ci tc35876x_regw(i2c, LVCFG, BIT(0)); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* Clear notifications. Don't write reserved bits. Was write 0xffffffff 4288c2ecf20Sopenharmony_ci * to 0x0288, must be in error?! */ 4298c2ecf20Sopenharmony_ci tc35876x_regw(i2c, DSI_INTCLR, FLD_MASK(31, 30) | FLD_MASK(22, 0)); 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci#define GPIOPWMCTRL 0x38F 4338c2ecf20Sopenharmony_ci#define PWM0CLKDIV0 0x62 /* low byte */ 4348c2ecf20Sopenharmony_ci#define PWM0CLKDIV1 0x61 /* high byte */ 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci#define SYSTEMCLK 19200000UL /* 19.2 MHz */ 4378c2ecf20Sopenharmony_ci#define PWM_FREQUENCY 9600 /* Hz */ 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci/* f = baseclk / (clkdiv + 1) => clkdiv = (baseclk - f) / f */ 4408c2ecf20Sopenharmony_cistatic inline u16 calc_clkdiv(unsigned long baseclk, unsigned int f) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci return (baseclk - f) / f; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic void tc35876x_brightness_init(struct drm_device *dev) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci int ret; 4488c2ecf20Sopenharmony_ci u8 pwmctrl; 4498c2ecf20Sopenharmony_ci u16 clkdiv; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci /* Make sure the PWM reference is the 19.2 MHz system clock. Read first 4528c2ecf20Sopenharmony_ci * instead of setting directly to catch potential conflicts between PWM 4538c2ecf20Sopenharmony_ci * users. */ 4548c2ecf20Sopenharmony_ci ret = intel_scu_ipc_ioread8(GPIOPWMCTRL, &pwmctrl); 4558c2ecf20Sopenharmony_ci if (ret || pwmctrl != 0x01) { 4568c2ecf20Sopenharmony_ci if (ret) 4578c2ecf20Sopenharmony_ci dev_err(&dev->pdev->dev, "GPIOPWMCTRL read failed\n"); 4588c2ecf20Sopenharmony_ci else 4598c2ecf20Sopenharmony_ci dev_warn(&dev->pdev->dev, "GPIOPWMCTRL was not set to system clock (pwmctrl = 0x%02x)\n", pwmctrl); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci ret = intel_scu_ipc_iowrite8(GPIOPWMCTRL, 0x01); 4628c2ecf20Sopenharmony_ci if (ret) 4638c2ecf20Sopenharmony_ci dev_err(&dev->pdev->dev, "GPIOPWMCTRL set failed\n"); 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci clkdiv = calc_clkdiv(SYSTEMCLK, PWM_FREQUENCY); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci ret = intel_scu_ipc_iowrite8(PWM0CLKDIV1, (clkdiv >> 8) & 0xff); 4698c2ecf20Sopenharmony_ci if (!ret) 4708c2ecf20Sopenharmony_ci ret = intel_scu_ipc_iowrite8(PWM0CLKDIV0, clkdiv & 0xff); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (ret) 4738c2ecf20Sopenharmony_ci dev_err(&dev->pdev->dev, "PWM0CLKDIV set failed\n"); 4748c2ecf20Sopenharmony_ci else 4758c2ecf20Sopenharmony_ci dev_dbg(&dev->pdev->dev, "PWM0CLKDIV set to 0x%04x (%d Hz)\n", 4768c2ecf20Sopenharmony_ci clkdiv, PWM_FREQUENCY); 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci#define PWM0DUTYCYCLE 0x67 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_civoid tc35876x_brightness_control(struct drm_device *dev, int level) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci int ret; 4848c2ecf20Sopenharmony_ci u8 duty_val; 4858c2ecf20Sopenharmony_ci u8 panel_duty_val; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci level = clamp(level, 0, MDFLD_DSI_BRIGHTNESS_MAX_LEVEL); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /* PWM duty cycle 0x00...0x63 corresponds to 0...99% */ 4908c2ecf20Sopenharmony_ci duty_val = level * 0x63 / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* I won't pretend to understand this formula. The panel spec is quite 4938c2ecf20Sopenharmony_ci * bad engrish. 4948c2ecf20Sopenharmony_ci */ 4958c2ecf20Sopenharmony_ci panel_duty_val = (2 * level - 100) * 0xA9 / 4968c2ecf20Sopenharmony_ci MDFLD_DSI_BRIGHTNESS_MAX_LEVEL + 0x56; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci ret = intel_scu_ipc_iowrite8(PWM0DUTYCYCLE, duty_val); 4998c2ecf20Sopenharmony_ci if (ret) 5008c2ecf20Sopenharmony_ci dev_err(&tc35876x_client->dev, "%s: ipc write fail\n", 5018c2ecf20Sopenharmony_ci __func__); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci if (cmi_lcd_i2c_client) { 5048c2ecf20Sopenharmony_ci ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client, 5058c2ecf20Sopenharmony_ci PANEL_PWM_MAX, panel_duty_val); 5068c2ecf20Sopenharmony_ci if (ret < 0) 5078c2ecf20Sopenharmony_ci dev_err(&cmi_lcd_i2c_client->dev, "%s: i2c write failed\n", 5088c2ecf20Sopenharmony_ci __func__); 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_civoid tc35876x_toshiba_bridge_panel_off(struct drm_device *dev) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci if (WARN(!tc35876x_client, "%s called before probe", __func__)) 5158c2ecf20Sopenharmony_ci return; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci dev_dbg(&tc35876x_client->dev, "%s\n", __func__); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (bridge_bl_enable) 5208c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(bridge_bl_enable, 0); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci if (backlight_voltage) 5238c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(backlight_voltage, 0); 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_civoid tc35876x_toshiba_bridge_panel_on(struct drm_device *dev) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci struct drm_psb_private *dev_priv = dev->dev_private; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (WARN(!tc35876x_client, "%s called before probe", __func__)) 5318c2ecf20Sopenharmony_ci return; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci dev_dbg(&tc35876x_client->dev, "%s\n", __func__); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (backlight_voltage) { 5368c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(backlight_voltage, 1); 5378c2ecf20Sopenharmony_ci msleep(260); 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (cmi_lcd_i2c_client) { 5418c2ecf20Sopenharmony_ci int ret; 5428c2ecf20Sopenharmony_ci dev_dbg(&cmi_lcd_i2c_client->dev, "setting TCON\n"); 5438c2ecf20Sopenharmony_ci /* Bit 4 is average_saving. Setting it to 1, the brightness is 5448c2ecf20Sopenharmony_ci * referenced to the average of the frame content. 0 means 5458c2ecf20Sopenharmony_ci * reference to the maximum of frame contents. Bits 3:0 are 5468c2ecf20Sopenharmony_ci * allow_distort. When set to a nonzero value, all color values 5478c2ecf20Sopenharmony_ci * between 255-allow_distort*2 and 255 are mapped to the 5488c2ecf20Sopenharmony_ci * 255-allow_distort*2 value. 5498c2ecf20Sopenharmony_ci */ 5508c2ecf20Sopenharmony_ci ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client, 5518c2ecf20Sopenharmony_ci PANEL_ALLOW_DISTORT, 0x10); 5528c2ecf20Sopenharmony_ci if (ret < 0) 5538c2ecf20Sopenharmony_ci dev_err(&cmi_lcd_i2c_client->dev, 5548c2ecf20Sopenharmony_ci "i2c write failed (%d)\n", ret); 5558c2ecf20Sopenharmony_ci ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client, 5568c2ecf20Sopenharmony_ci PANEL_BYPASS_PWMI, 0); 5578c2ecf20Sopenharmony_ci if (ret < 0) 5588c2ecf20Sopenharmony_ci dev_err(&cmi_lcd_i2c_client->dev, 5598c2ecf20Sopenharmony_ci "i2c write failed (%d)\n", ret); 5608c2ecf20Sopenharmony_ci /* Set minimum brightness value - this is tunable */ 5618c2ecf20Sopenharmony_ci ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client, 5628c2ecf20Sopenharmony_ci PANEL_PWM_MIN, 0x35); 5638c2ecf20Sopenharmony_ci if (ret < 0) 5648c2ecf20Sopenharmony_ci dev_err(&cmi_lcd_i2c_client->dev, 5658c2ecf20Sopenharmony_ci "i2c write failed (%d)\n", ret); 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci if (bridge_bl_enable) 5698c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(bridge_bl_enable, 1); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci tc35876x_brightness_control(dev, dev_priv->brightness_adjusted); 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic struct drm_display_mode *tc35876x_get_config_mode(struct drm_device *dev) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci struct drm_display_mode *mode; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci dev_dbg(&dev->pdev->dev, "%s\n", __func__); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci mode = kzalloc(sizeof(*mode), GFP_KERNEL); 5818c2ecf20Sopenharmony_ci if (!mode) 5828c2ecf20Sopenharmony_ci return NULL; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci /* FIXME: do this properly. */ 5858c2ecf20Sopenharmony_ci mode->hdisplay = 1280; 5868c2ecf20Sopenharmony_ci mode->vdisplay = 800; 5878c2ecf20Sopenharmony_ci mode->hsync_start = 1360; 5888c2ecf20Sopenharmony_ci mode->hsync_end = 1400; 5898c2ecf20Sopenharmony_ci mode->htotal = 1440; 5908c2ecf20Sopenharmony_ci mode->vsync_start = 814; 5918c2ecf20Sopenharmony_ci mode->vsync_end = 824; 5928c2ecf20Sopenharmony_ci mode->vtotal = 838; 5938c2ecf20Sopenharmony_ci mode->clock = 33324 << 1; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, "hdisplay(w) = %d\n", mode->hdisplay); 5968c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, "vdisplay(h) = %d\n", mode->vdisplay); 5978c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, "HSS = %d\n", mode->hsync_start); 5988c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, "HSE = %d\n", mode->hsync_end); 5998c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, "htotal = %d\n", mode->htotal); 6008c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, "VSS = %d\n", mode->vsync_start); 6018c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, "VSE = %d\n", mode->vsync_end); 6028c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, "vtotal = %d\n", mode->vtotal); 6038c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, "clock = %d\n", mode->clock); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci drm_mode_set_name(mode); 6068c2ecf20Sopenharmony_ci drm_mode_set_crtcinfo(mode, 0); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci mode->type |= DRM_MODE_TYPE_PREFERRED; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci return mode; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci/* DV1 Active area 216.96 x 135.6 mm */ 6148c2ecf20Sopenharmony_ci#define DV1_PANEL_WIDTH 217 6158c2ecf20Sopenharmony_ci#define DV1_PANEL_HEIGHT 136 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cistatic int tc35876x_get_panel_info(struct drm_device *dev, int pipe, 6188c2ecf20Sopenharmony_ci struct panel_info *pi) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci if (!dev || !pi) 6218c2ecf20Sopenharmony_ci return -EINVAL; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci pi->width_mm = DV1_PANEL_WIDTH; 6248c2ecf20Sopenharmony_ci pi->height_mm = DV1_PANEL_HEIGHT; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci return 0; 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistatic int tc35876x_bridge_probe(struct i2c_client *client, 6308c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci dev_info(&client->dev, "%s\n", __func__); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 6358c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s: i2c_check_functionality() failed\n", 6368c2ecf20Sopenharmony_ci __func__); 6378c2ecf20Sopenharmony_ci return -ENODEV; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci bridge_reset = devm_gpiod_get_optional(&client->dev, "bridge-reset", GPIOD_OUT_LOW); 6418c2ecf20Sopenharmony_ci if (IS_ERR(bridge_reset)) 6428c2ecf20Sopenharmony_ci return PTR_ERR(bridge_reset); 6438c2ecf20Sopenharmony_ci if (bridge_reset) 6448c2ecf20Sopenharmony_ci gpiod_set_consumer_name(bridge_reset, "tc35876x bridge reset"); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci bridge_bl_enable = devm_gpiod_get_optional(&client->dev, "bl-en", GPIOD_OUT_LOW); 6478c2ecf20Sopenharmony_ci if (IS_ERR(bridge_bl_enable)) 6488c2ecf20Sopenharmony_ci return PTR_ERR(bridge_bl_enable); 6498c2ecf20Sopenharmony_ci if (bridge_bl_enable) 6508c2ecf20Sopenharmony_ci gpiod_set_consumer_name(bridge_bl_enable, "tc35876x panel bl en"); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci backlight_voltage = devm_gpiod_get_optional(&client->dev, "vadd", GPIOD_OUT_LOW); 6538c2ecf20Sopenharmony_ci if (IS_ERR(backlight_voltage)) 6548c2ecf20Sopenharmony_ci return PTR_ERR(backlight_voltage); 6558c2ecf20Sopenharmony_ci if (backlight_voltage) 6568c2ecf20Sopenharmony_ci gpiod_set_consumer_name(backlight_voltage, "tc35876x panel vadd"); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci tc35876x_client = client; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci return 0; 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic int tc35876x_bridge_remove(struct i2c_client *client) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "%s\n", __func__); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci tc35876x_client = NULL; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci return 0; 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic const struct i2c_device_id tc35876x_bridge_id[] = { 6738c2ecf20Sopenharmony_ci { "i2c_disp_brig", 0 }, 6748c2ecf20Sopenharmony_ci { } 6758c2ecf20Sopenharmony_ci}; 6768c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tc35876x_bridge_id); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_cistatic struct i2c_driver tc35876x_bridge_i2c_driver = { 6798c2ecf20Sopenharmony_ci .driver = { 6808c2ecf20Sopenharmony_ci .name = "i2c_disp_brig", 6818c2ecf20Sopenharmony_ci }, 6828c2ecf20Sopenharmony_ci .id_table = tc35876x_bridge_id, 6838c2ecf20Sopenharmony_ci .probe = tc35876x_bridge_probe, 6848c2ecf20Sopenharmony_ci .remove = tc35876x_bridge_remove, 6858c2ecf20Sopenharmony_ci}; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci/* LCD panel I2C */ 6888c2ecf20Sopenharmony_cistatic int cmi_lcd_i2c_probe(struct i2c_client *client, 6898c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci dev_info(&client->dev, "%s\n", __func__); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 6948c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s: i2c_check_functionality() failed\n", 6958c2ecf20Sopenharmony_ci __func__); 6968c2ecf20Sopenharmony_ci return -ENODEV; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci cmi_lcd_i2c_client = client; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci return 0; 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistatic int cmi_lcd_i2c_remove(struct i2c_client *client) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "%s\n", __func__); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci cmi_lcd_i2c_client = NULL; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci return 0; 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_cistatic const struct i2c_device_id cmi_lcd_i2c_id[] = { 7148c2ecf20Sopenharmony_ci { "cmi-lcd", 0 }, 7158c2ecf20Sopenharmony_ci { } 7168c2ecf20Sopenharmony_ci}; 7178c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, cmi_lcd_i2c_id); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_cistatic struct i2c_driver cmi_lcd_i2c_driver = { 7208c2ecf20Sopenharmony_ci .driver = { 7218c2ecf20Sopenharmony_ci .name = "cmi-lcd", 7228c2ecf20Sopenharmony_ci }, 7238c2ecf20Sopenharmony_ci .id_table = cmi_lcd_i2c_id, 7248c2ecf20Sopenharmony_ci .probe = cmi_lcd_i2c_probe, 7258c2ecf20Sopenharmony_ci .remove = cmi_lcd_i2c_remove, 7268c2ecf20Sopenharmony_ci}; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci/* HACK to create I2C device while it's not created by platform code */ 7298c2ecf20Sopenharmony_ci#define CMI_LCD_I2C_ADAPTER 2 7308c2ecf20Sopenharmony_ci#define CMI_LCD_I2C_ADDR 0x60 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cistatic int cmi_lcd_hack_create_device(void) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci struct i2c_adapter *adapter; 7358c2ecf20Sopenharmony_ci struct i2c_client *client; 7368c2ecf20Sopenharmony_ci struct i2c_board_info info = { 7378c2ecf20Sopenharmony_ci .type = "cmi-lcd", 7388c2ecf20Sopenharmony_ci .addr = CMI_LCD_I2C_ADDR, 7398c2ecf20Sopenharmony_ci }; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci pr_debug("%s\n", __func__); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci adapter = i2c_get_adapter(CMI_LCD_I2C_ADAPTER); 7448c2ecf20Sopenharmony_ci if (!adapter) { 7458c2ecf20Sopenharmony_ci pr_err("%s: i2c_get_adapter(%d) failed\n", __func__, 7468c2ecf20Sopenharmony_ci CMI_LCD_I2C_ADAPTER); 7478c2ecf20Sopenharmony_ci return -EINVAL; 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci client = i2c_new_client_device(adapter, &info); 7518c2ecf20Sopenharmony_ci if (IS_ERR(client)) { 7528c2ecf20Sopenharmony_ci pr_err("%s: creating I2C device failed\n", __func__); 7538c2ecf20Sopenharmony_ci i2c_put_adapter(adapter); 7548c2ecf20Sopenharmony_ci return PTR_ERR(client); 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci return 0; 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic const struct drm_encoder_helper_funcs tc35876x_encoder_helper_funcs = { 7618c2ecf20Sopenharmony_ci .dpms = mdfld_dsi_dpi_dpms, 7628c2ecf20Sopenharmony_ci .mode_fixup = mdfld_dsi_dpi_mode_fixup, 7638c2ecf20Sopenharmony_ci .prepare = mdfld_dsi_dpi_prepare, 7648c2ecf20Sopenharmony_ci .mode_set = mdfld_dsi_dpi_mode_set, 7658c2ecf20Sopenharmony_ci .commit = mdfld_dsi_dpi_commit, 7668c2ecf20Sopenharmony_ci}; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ciconst struct panel_funcs mdfld_tc35876x_funcs = { 7698c2ecf20Sopenharmony_ci .encoder_helper_funcs = &tc35876x_encoder_helper_funcs, 7708c2ecf20Sopenharmony_ci .get_config_mode = tc35876x_get_config_mode, 7718c2ecf20Sopenharmony_ci .get_panel_info = tc35876x_get_panel_info, 7728c2ecf20Sopenharmony_ci}; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_civoid tc35876x_init(struct drm_device *dev) 7758c2ecf20Sopenharmony_ci{ 7768c2ecf20Sopenharmony_ci int r; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci dev_dbg(&dev->pdev->dev, "%s\n", __func__); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci cmi_lcd_hack_create_device(); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci r = i2c_add_driver(&cmi_lcd_i2c_driver); 7838c2ecf20Sopenharmony_ci if (r < 0) 7848c2ecf20Sopenharmony_ci dev_err(&dev->pdev->dev, 7858c2ecf20Sopenharmony_ci "%s: i2c_add_driver() for %s failed (%d)\n", 7868c2ecf20Sopenharmony_ci __func__, cmi_lcd_i2c_driver.driver.name, r); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci r = i2c_add_driver(&tc35876x_bridge_i2c_driver); 7898c2ecf20Sopenharmony_ci if (r < 0) 7908c2ecf20Sopenharmony_ci dev_err(&dev->pdev->dev, 7918c2ecf20Sopenharmony_ci "%s: i2c_add_driver() for %s failed (%d)\n", 7928c2ecf20Sopenharmony_ci __func__, tc35876x_bridge_i2c_driver.driver.name, r); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci tc35876x_brightness_init(dev); 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_civoid tc35876x_exit(void) 7988c2ecf20Sopenharmony_ci{ 7998c2ecf20Sopenharmony_ci pr_debug("%s\n", __func__); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci i2c_del_driver(&tc35876x_bridge_i2c_driver); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci if (cmi_lcd_i2c_client) 8048c2ecf20Sopenharmony_ci i2c_del_driver(&cmi_lcd_i2c_driver); 8058c2ecf20Sopenharmony_ci} 806