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