Linux Audio

Check our new training course

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