Linux Audio

Check our new training course

Buildroot integration, development and maintenance

Need a Buildroot system for your embedded project?
Loading...
Note: File does not exist in v6.8.
  1/*
  2 * Copyright © 2011 Intel Corporation
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a
  5 * copy of this software and associated documentation files (the "Software"),
  6 * to deal in the Software without restriction, including without limitation
  7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 * and/or sell copies of the Software, and to permit persons to whom the
  9 * Software is furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice (including the next
 12 * paragraph) shall be included in all copies or substantial portions of the
 13 * Software.
 14 *
 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 21 * DEALINGS IN THE SOFTWARE.
 22 *
 23 */
 24
 25#include <linux/delay.h>
 26#include <linux/kernel.h>
 27#include <linux/module.h>
 28#include <linux/platform_data/tc35876x.h>
 29
 30#include <asm/intel_scu_ipc.h>
 31
 32#include "mdfld_dsi_dpi.h"
 33#include "mdfld_dsi_pkg_sender.h"
 34#include "mdfld_output.h"
 35#include "tc35876x-dsi-lvds.h"
 36
 37static struct i2c_client *tc35876x_client;
 38static struct i2c_client *cmi_lcd_i2c_client;
 39
 40#define FLD_MASK(start, end)	(((1 << ((start) - (end) + 1)) - 1) << (end))
 41#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
 42
 43/* DSI D-PHY Layer Registers */
 44#define D0W_DPHYCONTTX		0x0004
 45#define CLW_DPHYCONTRX		0x0020
 46#define D0W_DPHYCONTRX		0x0024
 47#define D1W_DPHYCONTRX		0x0028
 48#define D2W_DPHYCONTRX		0x002C
 49#define D3W_DPHYCONTRX		0x0030
 50#define COM_DPHYCONTRX		0x0038
 51#define CLW_CNTRL		0x0040
 52#define D0W_CNTRL		0x0044
 53#define D1W_CNTRL		0x0048
 54#define D2W_CNTRL		0x004C
 55#define D3W_CNTRL		0x0050
 56#define DFTMODE_CNTRL		0x0054
 57
 58/* DSI PPI Layer Registers */
 59#define PPI_STARTPPI		0x0104
 60#define PPI_BUSYPPI		0x0108
 61#define PPI_LINEINITCNT		0x0110
 62#define PPI_LPTXTIMECNT		0x0114
 63#define PPI_LANEENABLE		0x0134
 64#define PPI_TX_RX_TA		0x013C
 65#define PPI_CLS_ATMR		0x0140
 66#define PPI_D0S_ATMR		0x0144
 67#define PPI_D1S_ATMR		0x0148
 68#define PPI_D2S_ATMR		0x014C
 69#define PPI_D3S_ATMR		0x0150
 70#define PPI_D0S_CLRSIPOCOUNT	0x0164
 71#define PPI_D1S_CLRSIPOCOUNT	0x0168
 72#define PPI_D2S_CLRSIPOCOUNT	0x016C
 73#define PPI_D3S_CLRSIPOCOUNT	0x0170
 74#define CLS_PRE			0x0180
 75#define D0S_PRE			0x0184
 76#define D1S_PRE			0x0188
 77#define D2S_PRE			0x018C
 78#define D3S_PRE			0x0190
 79#define CLS_PREP		0x01A0
 80#define D0S_PREP		0x01A4
 81#define D1S_PREP		0x01A8
 82#define D2S_PREP		0x01AC
 83#define D3S_PREP		0x01B0
 84#define CLS_ZERO		0x01C0
 85#define D0S_ZERO		0x01C4
 86#define D1S_ZERO		0x01C8
 87#define D2S_ZERO		0x01CC
 88#define D3S_ZERO		0x01D0
 89#define PPI_CLRFLG		0x01E0
 90#define PPI_CLRSIPO		0x01E4
 91#define HSTIMEOUT		0x01F0
 92#define HSTIMEOUTENABLE		0x01F4
 93
 94/* DSI Protocol Layer Registers */
 95#define DSI_STARTDSI		0x0204
 96#define DSI_BUSYDSI		0x0208
 97#define DSI_LANEENABLE		0x0210
 98#define DSI_LANESTATUS0		0x0214
 99#define DSI_LANESTATUS1		0x0218
100#define DSI_INTSTATUS		0x0220
101#define DSI_INTMASK		0x0224
102#define DSI_INTCLR		0x0228
103#define DSI_LPTXTO		0x0230
104
105/* DSI General Registers */
106#define DSIERRCNT		0x0300
107
108/* DSI Application Layer Registers */
109#define APLCTRL			0x0400
110#define RDPKTLN			0x0404
111
112/* Video Path Registers */
113#define VPCTRL			0x0450
114#define HTIM1			0x0454
115#define HTIM2			0x0458
116#define VTIM1			0x045C
117#define VTIM2			0x0460
118#define VFUEN			0x0464
119
120/* LVDS Registers */
121#define LVMX0003		0x0480
122#define LVMX0407		0x0484
123#define LVMX0811		0x0488
124#define LVMX1215		0x048C
125#define LVMX1619		0x0490
126#define LVMX2023		0x0494
127#define LVMX2427		0x0498
128#define LVCFG			0x049C
129#define LVPHY0			0x04A0
130#define LVPHY1			0x04A4
131
132/* System Registers */
133#define SYSSTAT			0x0500
134#define SYSRST			0x0504
135
136/* GPIO Registers */
137/*#define GPIOC			0x0520*/
138#define GPIOO			0x0524
139#define GPIOI			0x0528
140
141/* I2C Registers */
142#define I2CTIMCTRL		0x0540
143#define I2CMADDR		0x0544
144#define WDATAQ			0x0548
145#define RDATAQ			0x054C
146
147/* Chip/Rev Registers */
148#define IDREG			0x0580
149
150/* Debug Registers */
151#define DEBUG00			0x05A0
152#define DEBUG01			0x05A4
153
154/* Panel CABC registers */
155#define PANEL_PWM_CONTROL	0x90
156#define PANEL_FREQ_DIVIDER_HI	0x91
157#define PANEL_FREQ_DIVIDER_LO	0x92
158#define PANEL_DUTY_CONTROL	0x93
159#define PANEL_MODIFY_RGB	0x94
160#define PANEL_FRAMERATE_CONTROL	0x96
161#define PANEL_PWM_MIN		0x97
162#define PANEL_PWM_REF		0x98
163#define PANEL_PWM_MAX		0x99
164#define PANEL_ALLOW_DISTORT	0x9A
165#define PANEL_BYPASS_PWMI	0x9B
166
167/* Panel color management registers */
168#define PANEL_CM_ENABLE		0x700
169#define PANEL_CM_HUE		0x701
170#define PANEL_CM_SATURATION	0x702
171#define PANEL_CM_INTENSITY	0x703
172#define PANEL_CM_BRIGHTNESS	0x704
173#define PANEL_CM_CE_ENABLE	0x705
174#define PANEL_CM_PEAK_EN	0x710
175#define PANEL_CM_GAIN		0x711
176#define PANEL_CM_HUETABLE_START	0x730
177#define PANEL_CM_HUETABLE_END	0x747 /* inclusive */
178
179/* Input muxing for registers LVMX0003...LVMX2427 */
180enum {
181	INPUT_R0,	/* 0 */
182	INPUT_R1,
183	INPUT_R2,
184	INPUT_R3,
185	INPUT_R4,
186	INPUT_R5,
187	INPUT_R6,
188	INPUT_R7,
189	INPUT_G0,	/* 8 */
190	INPUT_G1,
191	INPUT_G2,
192	INPUT_G3,
193	INPUT_G4,
194	INPUT_G5,
195	INPUT_G6,
196	INPUT_G7,
197	INPUT_B0,	/* 16 */
198	INPUT_B1,
199	INPUT_B2,
200	INPUT_B3,
201	INPUT_B4,
202	INPUT_B5,
203	INPUT_B6,
204	INPUT_B7,
205	INPUT_HSYNC,	/* 24 */
206	INPUT_VSYNC,
207	INPUT_DE,
208	LOGIC_0,
209	/* 28...31 undefined */
210};
211
212#define INPUT_MUX(lvmx03, lvmx02, lvmx01, lvmx00)		\
213	(FLD_VAL(lvmx03, 29, 24) | FLD_VAL(lvmx02, 20, 16) |	\
214	FLD_VAL(lvmx01, 12, 8) | FLD_VAL(lvmx00, 4, 0))
215
216/**
217 * tc35876x_regw - Write DSI-LVDS bridge register using I2C
218 * @client: struct i2c_client to use
219 * @reg: register address
220 * @value: value to write
221 *
222 * Returns 0 on success, or a negative error value.
223 */
224static int tc35876x_regw(struct i2c_client *client, u16 reg, u32 value)
225{
226	int r;
227	u8 tx_data[] = {
228		/* NOTE: Register address big-endian, data little-endian. */
229		(reg >> 8) & 0xff,
230		reg & 0xff,
231		value & 0xff,
232		(value >> 8) & 0xff,
233		(value >> 16) & 0xff,
234		(value >> 24) & 0xff,
235	};
236	struct i2c_msg msgs[] = {
237		{
238			.addr = client->addr,
239			.flags = 0,
240			.buf = tx_data,
241			.len = ARRAY_SIZE(tx_data),
242		},
243	};
244
245	r = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
246	if (r < 0) {
247		dev_err(&client->dev, "%s: reg 0x%04x val 0x%08x error %d\n",
248			__func__, reg, value, r);
249		return r;
250	}
251
252	if (r < ARRAY_SIZE(msgs)) {
253		dev_err(&client->dev, "%s: reg 0x%04x val 0x%08x msgs %d\n",
254			__func__, reg, value, r);
255		return -EAGAIN;
256	}
257
258	dev_dbg(&client->dev, "%s: reg 0x%04x val 0x%08x\n",
259			__func__, reg, value);
260
261	return 0;
262}
263
264/**
265 * tc35876x_regr - Read DSI-LVDS bridge register using I2C
266 * @client: struct i2c_client to use
267 * @reg: register address
268 * @value: pointer for storing the value
269 *
270 * Returns 0 on success, or a negative error value.
271 */
272static int tc35876x_regr(struct i2c_client *client, u16 reg, u32 *value)
273{
274	int r;
275	u8 tx_data[] = {
276		(reg >> 8) & 0xff,
277		reg & 0xff,
278	};
279	u8 rx_data[4];
280	struct i2c_msg msgs[] = {
281		{
282			.addr = client->addr,
283			.flags = 0,
284			.buf = tx_data,
285			.len = ARRAY_SIZE(tx_data),
286		},
287		{
288			.addr = client->addr,
289			.flags = I2C_M_RD,
290			.buf = rx_data,
291			.len = ARRAY_SIZE(rx_data),
292		 },
293	};
294
295	r = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
296	if (r < 0) {
297		dev_err(&client->dev, "%s: reg 0x%04x error %d\n", __func__,
298			reg, r);
299		return r;
300	}
301
302	if (r < ARRAY_SIZE(msgs)) {
303		dev_err(&client->dev, "%s: reg 0x%04x msgs %d\n", __func__,
304			reg, r);
305		return -EAGAIN;
306	}
307
308	*value = rx_data[0] << 24 | rx_data[1] << 16 |
309		rx_data[2] << 8 | rx_data[3];
310
311	dev_dbg(&client->dev, "%s: reg 0x%04x value 0x%08x\n", __func__,
312		reg, *value);
313
314	return 0;
315}
316
317void tc35876x_set_bridge_reset_state(struct drm_device *dev, int state)
318{
319	struct tc35876x_platform_data *pdata;
320
321	if (WARN(!tc35876x_client, "%s called before probe", __func__))
322		return;
323
324	dev_dbg(&tc35876x_client->dev, "%s: state %d\n", __func__, state);
325
326	pdata = dev_get_platdata(&tc35876x_client->dev);
327
328	if (pdata->gpio_bridge_reset == -1)
329		return;
330
331	if (state) {
332		gpio_set_value_cansleep(pdata->gpio_bridge_reset, 0);
333		mdelay(10);
334	} else {
335		/* Pull MIPI Bridge reset pin to Low */
336		gpio_set_value_cansleep(pdata->gpio_bridge_reset, 0);
337		mdelay(20);
338		/* Pull MIPI Bridge reset pin to High */
339		gpio_set_value_cansleep(pdata->gpio_bridge_reset, 1);
340		mdelay(40);
341	}
342}
343
344void tc35876x_configure_lvds_bridge(struct drm_device *dev)
345{
346	struct i2c_client *i2c = tc35876x_client;
347	u32 ppi_lptxtimecnt;
348	u32 txtagocnt;
349	u32 txtasurecnt;
350	u32 id;
351
352	if (WARN(!tc35876x_client, "%s called before probe", __func__))
353		return;
354
355	dev_dbg(&tc35876x_client->dev, "%s\n", __func__);
356
357	if (!tc35876x_regr(i2c, IDREG, &id))
358		dev_info(&tc35876x_client->dev, "tc35876x ID 0x%08x\n", id);
359	else
360		dev_err(&tc35876x_client->dev, "Cannot read ID\n");
361
362	ppi_lptxtimecnt = 4;
363	txtagocnt = (5 * ppi_lptxtimecnt - 3) / 4;
364	txtasurecnt = 3 * ppi_lptxtimecnt / 2;
365	tc35876x_regw(i2c, PPI_TX_RX_TA, FLD_VAL(txtagocnt, 26, 16) |
366		FLD_VAL(txtasurecnt, 10, 0));
367	tc35876x_regw(i2c, PPI_LPTXTIMECNT, FLD_VAL(ppi_lptxtimecnt, 10, 0));
368
369	tc35876x_regw(i2c, PPI_D0S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0));
370	tc35876x_regw(i2c, PPI_D1S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0));
371	tc35876x_regw(i2c, PPI_D2S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0));
372	tc35876x_regw(i2c, PPI_D3S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0));
373
374	/* Enabling MIPI & PPI lanes, Enable 4 lanes */
375	tc35876x_regw(i2c, PPI_LANEENABLE,
376		BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0));
377	tc35876x_regw(i2c, DSI_LANEENABLE,
378		BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0));
379	tc35876x_regw(i2c, PPI_STARTPPI, BIT(0));
380	tc35876x_regw(i2c, DSI_STARTDSI, BIT(0));
381
382	/* Setting LVDS output frequency */
383	tc35876x_regw(i2c, LVPHY0, FLD_VAL(1, 20, 16) |
384		FLD_VAL(2, 15, 14) | FLD_VAL(6, 4, 0)); /* 0x00048006 */
385
386	/* Setting video panel control register,0x00000120 VTGen=ON ?!?!? */
387	tc35876x_regw(i2c, VPCTRL, BIT(8) | BIT(5));
388
389	/* Horizontal back porch and horizontal pulse width. 0x00280028 */
390	tc35876x_regw(i2c, HTIM1, FLD_VAL(40, 24, 16) | FLD_VAL(40, 8, 0));
391
392	/* Horizontal front porch and horizontal active video size. 0x00500500*/
393	tc35876x_regw(i2c, HTIM2, FLD_VAL(80, 24, 16) | FLD_VAL(1280, 10, 0));
394
395	/* Vertical back porch and vertical sync pulse width. 0x000e000a */
396	tc35876x_regw(i2c, VTIM1, FLD_VAL(14, 23, 16) | FLD_VAL(10, 7, 0));
397
398	/* Vertical front porch and vertical display size. 0x000e0320 */
399	tc35876x_regw(i2c, VTIM2, FLD_VAL(14, 23, 16) | FLD_VAL(800, 10, 0));
400
401	/* Set above HTIM1, HTIM2, VTIM1, and VTIM2 at next VSYNC. */
402	tc35876x_regw(i2c, VFUEN, BIT(0));
403
404	/* Soft reset LCD controller. */
405	tc35876x_regw(i2c, SYSRST, BIT(2));
406
407	/* LVDS-TX input muxing */
408	tc35876x_regw(i2c, LVMX0003,
409		INPUT_MUX(INPUT_R5, INPUT_R4, INPUT_R3, INPUT_R2));
410	tc35876x_regw(i2c, LVMX0407,
411		INPUT_MUX(INPUT_G2, INPUT_R7, INPUT_R1, INPUT_R6));
412	tc35876x_regw(i2c, LVMX0811,
413		INPUT_MUX(INPUT_G1, INPUT_G0, INPUT_G4, INPUT_G3));
414	tc35876x_regw(i2c, LVMX1215,
415		INPUT_MUX(INPUT_B2, INPUT_G7, INPUT_G6, INPUT_G5));
416	tc35876x_regw(i2c, LVMX1619,
417		INPUT_MUX(INPUT_B4, INPUT_B3, INPUT_B1, INPUT_B0));
418	tc35876x_regw(i2c, LVMX2023,
419		INPUT_MUX(LOGIC_0,  INPUT_B7, INPUT_B6, INPUT_B5));
420	tc35876x_regw(i2c, LVMX2427,
421		INPUT_MUX(INPUT_R0, INPUT_DE, INPUT_VSYNC, INPUT_HSYNC));
422
423	/* Enable LVDS transmitter. */
424	tc35876x_regw(i2c, LVCFG, BIT(0));
425
426	/* Clear notifications. Don't write reserved bits. Was write 0xffffffff
427	 * to 0x0288, must be in error?! */
428	tc35876x_regw(i2c, DSI_INTCLR, FLD_MASK(31, 30) | FLD_MASK(22, 0));
429}
430
431#define GPIOPWMCTRL	0x38F
432#define PWM0CLKDIV0	0x62 /* low byte */
433#define PWM0CLKDIV1	0x61 /* high byte */
434
435#define SYSTEMCLK	19200000UL /* 19.2 MHz */
436#define PWM_FREQUENCY	9600 /* Hz */
437
438/* f = baseclk / (clkdiv + 1) => clkdiv = (baseclk - f) / f */
439static inline u16 calc_clkdiv(unsigned long baseclk, unsigned int f)
440{
441	return (baseclk - f) / f;
442}
443
444static void tc35876x_brightness_init(struct drm_device *dev)
445{
446	int ret;
447	u8 pwmctrl;
448	u16 clkdiv;
449
450	/* Make sure the PWM reference is the 19.2 MHz system clock. Read first
451	 * instead of setting directly to catch potential conflicts between PWM
452	 * users. */
453	ret = intel_scu_ipc_ioread8(GPIOPWMCTRL, &pwmctrl);
454	if (ret || pwmctrl != 0x01) {
455		if (ret)
456			dev_err(&dev->pdev->dev, "GPIOPWMCTRL read failed\n");
457		else
458			dev_warn(&dev->pdev->dev, "GPIOPWMCTRL was not set to system clock (pwmctrl = 0x%02x)\n", pwmctrl);
459
460		ret = intel_scu_ipc_iowrite8(GPIOPWMCTRL, 0x01);
461		if (ret)
462			dev_err(&dev->pdev->dev, "GPIOPWMCTRL set failed\n");
463	}
464
465	clkdiv = calc_clkdiv(SYSTEMCLK, PWM_FREQUENCY);
466
467	ret = intel_scu_ipc_iowrite8(PWM0CLKDIV1, (clkdiv >> 8) & 0xff);
468	if (!ret)
469		ret = intel_scu_ipc_iowrite8(PWM0CLKDIV0, clkdiv & 0xff);
470
471	if (ret)
472		dev_err(&dev->pdev->dev, "PWM0CLKDIV set failed\n");
473	else
474		dev_dbg(&dev->pdev->dev, "PWM0CLKDIV set to 0x%04x (%d Hz)\n",
475			clkdiv, PWM_FREQUENCY);
476}
477
478#define PWM0DUTYCYCLE			0x67
479
480void tc35876x_brightness_control(struct drm_device *dev, int level)
481{
482	int ret;
483	u8 duty_val;
484	u8 panel_duty_val;
485
486	level = clamp(level, 0, MDFLD_DSI_BRIGHTNESS_MAX_LEVEL);
487
488	/* PWM duty cycle 0x00...0x63 corresponds to 0...99% */
489	duty_val = level * 0x63 / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL;
490
491	/* I won't pretend to understand this formula. The panel spec is quite
492	 * bad engrish.
493	 */
494	panel_duty_val = (2 * level - 100) * 0xA9 /
495			 MDFLD_DSI_BRIGHTNESS_MAX_LEVEL + 0x56;
496
497	ret = intel_scu_ipc_iowrite8(PWM0DUTYCYCLE, duty_val);
498	if (ret)
499		dev_err(&tc35876x_client->dev, "%s: ipc write fail\n",
500			__func__);
501
502	if (cmi_lcd_i2c_client) {
503		ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client,
504						PANEL_PWM_MAX, panel_duty_val);
505		if (ret < 0)
506			dev_err(&cmi_lcd_i2c_client->dev, "%s: i2c write failed\n",
507				__func__);
508	}
509}
510
511void tc35876x_toshiba_bridge_panel_off(struct drm_device *dev)
512{
513	struct tc35876x_platform_data *pdata;
514
515	if (WARN(!tc35876x_client, "%s called before probe", __func__))
516		return;
517
518	dev_dbg(&tc35876x_client->dev, "%s\n", __func__);
519
520	pdata = dev_get_platdata(&tc35876x_client->dev);
521
522	if (pdata->gpio_panel_bl_en != -1)
523		gpio_set_value_cansleep(pdata->gpio_panel_bl_en, 0);
524
525	if (pdata->gpio_panel_vadd != -1)
526		gpio_set_value_cansleep(pdata->gpio_panel_vadd, 0);
527}
528
529void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev)
530{
531	struct tc35876x_platform_data *pdata;
532	struct drm_psb_private *dev_priv = dev->dev_private;
533
534	if (WARN(!tc35876x_client, "%s called before probe", __func__))
535		return;
536
537	dev_dbg(&tc35876x_client->dev, "%s\n", __func__);
538
539	pdata = dev_get_platdata(&tc35876x_client->dev);
540
541	if (pdata->gpio_panel_vadd != -1) {
542		gpio_set_value_cansleep(pdata->gpio_panel_vadd, 1);
543		msleep(260);
544	}
545
546	if (cmi_lcd_i2c_client) {
547		int ret;
548		dev_dbg(&cmi_lcd_i2c_client->dev, "setting TCON\n");
549		/* Bit 4 is average_saving. Setting it to 1, the brightness is
550		 * referenced to the average of the frame content. 0 means
551		 * reference to the maximum of frame contents. Bits 3:0 are
552		 * allow_distort. When set to a nonzero value, all color values
553		 * between 255-allow_distort*2 and 255 are mapped to the
554		 * 255-allow_distort*2 value.
555		 */
556		ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client,
557						PANEL_ALLOW_DISTORT, 0x10);
558		if (ret < 0)
559			dev_err(&cmi_lcd_i2c_client->dev,
560				"i2c write failed (%d)\n", ret);
561		ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client,
562						PANEL_BYPASS_PWMI, 0);
563		if (ret < 0)
564			dev_err(&cmi_lcd_i2c_client->dev,
565				"i2c write failed (%d)\n", ret);
566		/* Set minimum brightness value - this is tunable */
567		ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client,
568						PANEL_PWM_MIN, 0x35);
569		if (ret < 0)
570			dev_err(&cmi_lcd_i2c_client->dev,
571				"i2c write failed (%d)\n", ret);
572	}
573
574	if (pdata->gpio_panel_bl_en != -1)
575		gpio_set_value_cansleep(pdata->gpio_panel_bl_en, 1);
576
577	tc35876x_brightness_control(dev, dev_priv->brightness_adjusted);
578}
579
580static struct drm_display_mode *tc35876x_get_config_mode(struct drm_device *dev)
581{
582	struct drm_display_mode *mode;
583
584	dev_dbg(&dev->pdev->dev, "%s\n", __func__);
585
586	mode = kzalloc(sizeof(*mode), GFP_KERNEL);
587	if (!mode)
588		return NULL;
589
590	/* FIXME: do this properly. */
591	mode->hdisplay = 1280;
592	mode->vdisplay = 800;
593	mode->hsync_start = 1360;
594	mode->hsync_end = 1400;
595	mode->htotal = 1440;
596	mode->vsync_start = 814;
597	mode->vsync_end = 824;
598	mode->vtotal = 838;
599	mode->clock = 33324 << 1;
600
601	dev_info(&dev->pdev->dev, "hdisplay(w) = %d\n", mode->hdisplay);
602	dev_info(&dev->pdev->dev, "vdisplay(h) = %d\n", mode->vdisplay);
603	dev_info(&dev->pdev->dev, "HSS = %d\n", mode->hsync_start);
604	dev_info(&dev->pdev->dev, "HSE = %d\n", mode->hsync_end);
605	dev_info(&dev->pdev->dev, "htotal = %d\n", mode->htotal);
606	dev_info(&dev->pdev->dev, "VSS = %d\n", mode->vsync_start);
607	dev_info(&dev->pdev->dev, "VSE = %d\n", mode->vsync_end);
608	dev_info(&dev->pdev->dev, "vtotal = %d\n", mode->vtotal);
609	dev_info(&dev->pdev->dev, "clock = %d\n", mode->clock);
610
611	drm_mode_set_name(mode);
612	drm_mode_set_crtcinfo(mode, 0);
613
614	mode->type |= DRM_MODE_TYPE_PREFERRED;
615
616	return mode;
617}
618
619/* DV1 Active area 216.96 x 135.6 mm */
620#define DV1_PANEL_WIDTH 217
621#define DV1_PANEL_HEIGHT 136
622
623static int tc35876x_get_panel_info(struct drm_device *dev, int pipe,
624				struct panel_info *pi)
625{
626	if (!dev || !pi)
627		return -EINVAL;
628
629	pi->width_mm = DV1_PANEL_WIDTH;
630	pi->height_mm = DV1_PANEL_HEIGHT;
631
632	return 0;
633}
634
635static int tc35876x_bridge_probe(struct i2c_client *client,
636				const struct i2c_device_id *id)
637{
638	struct tc35876x_platform_data *pdata;
639
640	dev_info(&client->dev, "%s\n", __func__);
641
642	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
643		dev_err(&client->dev, "%s: i2c_check_functionality() failed\n",
644			__func__);
645		return -ENODEV;
646	}
647
648	pdata = dev_get_platdata(&client->dev);
649	if (!pdata) {
650		dev_err(&client->dev, "%s: no platform data\n", __func__);
651		return -ENODEV;
652	}
653
654	if (pdata->gpio_bridge_reset != -1) {
655		gpio_request(pdata->gpio_bridge_reset, "tc35876x bridge reset");
656		gpio_direction_output(pdata->gpio_bridge_reset, 0);
657	}
658
659	if (pdata->gpio_panel_bl_en != -1) {
660		gpio_request(pdata->gpio_panel_bl_en, "tc35876x panel bl en");
661		gpio_direction_output(pdata->gpio_panel_bl_en, 0);
662	}
663
664	if (pdata->gpio_panel_vadd != -1) {
665		gpio_request(pdata->gpio_panel_vadd, "tc35876x panel vadd");
666		gpio_direction_output(pdata->gpio_panel_vadd, 0);
667	}
668
669	tc35876x_client = client;
670
671	return 0;
672}
673
674static int tc35876x_bridge_remove(struct i2c_client *client)
675{
676	struct tc35876x_platform_data *pdata = dev_get_platdata(&client->dev);
677
678	dev_dbg(&client->dev, "%s\n", __func__);
679
680	if (pdata->gpio_bridge_reset != -1)
681		gpio_free(pdata->gpio_bridge_reset);
682
683	if (pdata->gpio_panel_bl_en != -1)
684		gpio_free(pdata->gpio_panel_bl_en);
685
686	if (pdata->gpio_panel_vadd != -1)
687		gpio_free(pdata->gpio_panel_vadd);
688
689	tc35876x_client = NULL;
690
691	return 0;
692}
693
694static const struct i2c_device_id tc35876x_bridge_id[] = {
695	{ "i2c_disp_brig", 0 },
696	{ }
697};
698MODULE_DEVICE_TABLE(i2c, tc35876x_bridge_id);
699
700static struct i2c_driver tc35876x_bridge_i2c_driver = {
701	.driver = {
702		.name = "i2c_disp_brig",
703	},
704	.id_table = tc35876x_bridge_id,
705	.probe = tc35876x_bridge_probe,
706	.remove = tc35876x_bridge_remove,
707};
708
709/* LCD panel I2C */
710static int cmi_lcd_i2c_probe(struct i2c_client *client,
711			     const struct i2c_device_id *id)
712{
713	dev_info(&client->dev, "%s\n", __func__);
714
715	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
716		dev_err(&client->dev, "%s: i2c_check_functionality() failed\n",
717			__func__);
718		return -ENODEV;
719	}
720
721	cmi_lcd_i2c_client = client;
722
723	return 0;
724}
725
726static int cmi_lcd_i2c_remove(struct i2c_client *client)
727{
728	dev_dbg(&client->dev, "%s\n", __func__);
729
730	cmi_lcd_i2c_client = NULL;
731
732	return 0;
733}
734
735static const struct i2c_device_id cmi_lcd_i2c_id[] = {
736	{ "cmi-lcd", 0 },
737	{ }
738};
739MODULE_DEVICE_TABLE(i2c, cmi_lcd_i2c_id);
740
741static struct i2c_driver cmi_lcd_i2c_driver = {
742	.driver = {
743		.name = "cmi-lcd",
744	},
745	.id_table = cmi_lcd_i2c_id,
746	.probe = cmi_lcd_i2c_probe,
747	.remove = cmi_lcd_i2c_remove,
748};
749
750/* HACK to create I2C device while it's not created by platform code */
751#define CMI_LCD_I2C_ADAPTER	2
752#define CMI_LCD_I2C_ADDR	0x60
753
754static int cmi_lcd_hack_create_device(void)
755{
756	struct i2c_adapter *adapter;
757	struct i2c_client *client;
758	struct i2c_board_info info = {
759		.type = "cmi-lcd",
760		.addr = CMI_LCD_I2C_ADDR,
761	};
762
763	pr_debug("%s\n", __func__);
764
765	adapter = i2c_get_adapter(CMI_LCD_I2C_ADAPTER);
766	if (!adapter) {
767		pr_err("%s: i2c_get_adapter(%d) failed\n", __func__,
768			CMI_LCD_I2C_ADAPTER);
769		return -EINVAL;
770	}
771
772	client = i2c_new_device(adapter, &info);
773	if (!client) {
774		pr_err("%s: i2c_new_device() failed\n", __func__);
775		i2c_put_adapter(adapter);
776		return -EINVAL;
777	}
778
779	return 0;
780}
781
782static const struct drm_encoder_helper_funcs tc35876x_encoder_helper_funcs = {
783	.dpms = mdfld_dsi_dpi_dpms,
784	.mode_fixup = mdfld_dsi_dpi_mode_fixup,
785	.prepare = mdfld_dsi_dpi_prepare,
786	.mode_set = mdfld_dsi_dpi_mode_set,
787	.commit = mdfld_dsi_dpi_commit,
788};
789
790static const struct drm_encoder_funcs tc35876x_encoder_funcs = {
791	.destroy = drm_encoder_cleanup,
792};
793
794const struct panel_funcs mdfld_tc35876x_funcs = {
795	.encoder_funcs = &tc35876x_encoder_funcs,
796	.encoder_helper_funcs = &tc35876x_encoder_helper_funcs,
797	.get_config_mode = tc35876x_get_config_mode,
798	.get_panel_info = tc35876x_get_panel_info,
799};
800
801void tc35876x_init(struct drm_device *dev)
802{
803	int r;
804
805	dev_dbg(&dev->pdev->dev, "%s\n", __func__);
806
807	cmi_lcd_hack_create_device();
808
809	r = i2c_add_driver(&cmi_lcd_i2c_driver);
810	if (r < 0)
811		dev_err(&dev->pdev->dev,
812			"%s: i2c_add_driver() for %s failed (%d)\n",
813			__func__, cmi_lcd_i2c_driver.driver.name, r);
814
815	r = i2c_add_driver(&tc35876x_bridge_i2c_driver);
816	if (r < 0)
817		dev_err(&dev->pdev->dev,
818			"%s: i2c_add_driver() for %s failed (%d)\n",
819			__func__, tc35876x_bridge_i2c_driver.driver.name, r);
820
821	tc35876x_brightness_init(dev);
822}
823
824void tc35876x_exit(void)
825{
826	pr_debug("%s\n", __func__);
827
828	i2c_del_driver(&tc35876x_bridge_i2c_driver);
829
830	if (cmi_lcd_i2c_client)
831		i2c_del_driver(&cmi_lcd_i2c_driver);
832}