1/*
2 * picodlp panel driver
3 * picodlp_i2c_driver: i2c_client driver
4 *
5 * Copyright (C) 2009-2011 Texas Instruments
6 * Author: Mythri P K <mythripk@ti.com>
7 * Mayuresh Janorkar <mayur@ti.com>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as published by
11 * the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <linux/module.h>
23#include <linux/input.h>
24#include <linux/platform_device.h>
25#include <linux/interrupt.h>
26#include <linux/firmware.h>
27#include <linux/slab.h>
28#include <linux/mutex.h>
29#include <linux/i2c.h>
30#include <linux/delay.h>
31#include <linux/gpio.h>
32
33#include <video/omapdss.h>
34#include <video/omap-panel-picodlp.h>
35
36#include "panel-picodlp.h"
37
38struct picodlp_data {
39	struct mutex lock;
40	struct i2c_client *picodlp_i2c_client;
41};
42
43static struct i2c_board_info picodlp_i2c_board_info = {
44	I2C_BOARD_INFO("picodlp_i2c_driver", 0x1b),
45};
46
47struct picodlp_i2c_data {
48	struct mutex xfer_lock;
49};
50
51static struct i2c_device_id picodlp_i2c_id[] = {
52	{ "picodlp_i2c_driver", 0 },
53};
54
55struct picodlp_i2c_command {
56	u8 reg;
57	u32 value;
58};
59
60static struct omap_video_timings pico_ls_timings = {
61	.x_res		= 864,
62	.y_res		= 480,
63	.hsw		= 7,
64	.hfp		= 11,
65	.hbp		= 7,
66
67	.pixel_clock	= 19200,
68
69	.vsw		= 2,
70	.vfp		= 3,
71	.vbp		= 14,
72};
73
74static inline struct picodlp_panel_data
75		*get_panel_data(const struct omap_dss_device *dssdev)
76{
77	return (struct picodlp_panel_data *) dssdev->data;
78}
79
80static u32 picodlp_i2c_read(struct i2c_client *client, u8 reg)
81{
82	u8 read_cmd[] = {READ_REG_SELECT, reg}, data[4];
83	struct picodlp_i2c_data *picodlp_i2c_data = i2c_get_clientdata(client);
84	struct i2c_msg msg[2];
85
86	mutex_lock(&picodlp_i2c_data->xfer_lock);
87
88	msg[0].addr = client->addr;
89	msg[0].flags = 0;
90	msg[0].len = 2;
91	msg[0].buf = read_cmd;
92
93	msg[1].addr = client->addr;
94	msg[1].flags = I2C_M_RD;
95	msg[1].len = 4;
96	msg[1].buf = data;
97
98	i2c_transfer(client->adapter, msg, 2);
99	mutex_unlock(&picodlp_i2c_data->xfer_lock);
100	return (data[3] | (data[2] << 8) | (data[1] << 16) | (data[0] << 24));
101}
102
103static int picodlp_i2c_write_block(struct i2c_client *client,
104					u8 *data, int len)
105{
106	struct i2c_msg msg;
107	int i, r, msg_count = 1;
108
109	struct picodlp_i2c_data *picodlp_i2c_data = i2c_get_clientdata(client);
110
111	if (len < 1 || len > 32) {
112		dev_err(&client->dev,
113			"too long syn_write_block len %d\n", len);
114		return -EIO;
115	}
116	mutex_lock(&picodlp_i2c_data->xfer_lock);
117
118	msg.addr = client->addr;
119	msg.flags = 0;
120	msg.len = len;
121	msg.buf = data;
122	r = i2c_transfer(client->adapter, &msg, msg_count);
123	mutex_unlock(&picodlp_i2c_data->xfer_lock);
124
125	/*
126	 * i2c_transfer returns:
127	 * number of messages sent in case of success
128	 * a negative error number in case of failure
129	 */
130	if (r != msg_count)
131		goto err;
132
133	/* In case of success */
134	for (i = 0; i < len; i++)
135		dev_dbg(&client->dev,
136			"addr %x bw 0x%02x[%d]: 0x%02x\n",
137			client->addr, data[0] + i, i, data[i]);
138
139	return 0;
140err:
141	dev_err(&client->dev, "picodlp_i2c_write error\n");
142	return r;
143}
144
145static int picodlp_i2c_write(struct i2c_client *client, u8 reg, u32 value)
146{
147	u8 data[5];
148	int i;
149
150	data[0] = reg;
151	for (i = 1; i < 5; i++)
152		data[i] = (value >> (32 - (i) * 8)) & 0xFF;
153
154	return picodlp_i2c_write_block(client, data, 5);
155}
156
157static int picodlp_i2c_write_array(struct i2c_client *client,
158			const struct picodlp_i2c_command commands[],
159			int count)
160{
161	int i, r = 0;
162	for (i = 0; i < count; i++) {
163		r = picodlp_i2c_write(client, commands[i].reg,
164						commands[i].value);
165		if (r)
166			return r;
167	}
168	return r;
169}
170
171static int picodlp_wait_for_dma_done(struct i2c_client *client)
172{
173	u8 trial = 100;
174
175	do {
176		msleep(1);
177		if (!trial--)
178			return -ETIMEDOUT;
179	} while (picodlp_i2c_read(client, MAIN_STATUS) & DMA_STATUS);
180
181	return 0;
182}
183
184/**
185 * picodlp_i2c_init:	i2c_initialization routine
186 * client:	i2c_client for communication
187 *
188 * return
189 *		0	: Success, no error
190 *	error code	: Failure
191 */
192static int picodlp_i2c_init(struct i2c_client *client)
193{
194	int r;
195	static const struct picodlp_i2c_command init_cmd_set1[] = {
196		{SOFT_RESET, 1},
197		{DMD_PARK_TRIGGER, 1},
198		{MISC_REG, 5},
199		{SEQ_CONTROL, 0},
200		{SEQ_VECTOR, 0x100},
201		{DMD_BLOCK_COUNT, 7},
202		{DMD_VCC_CONTROL, 0x109},
203		{DMD_PARK_PULSE_COUNT, 0xA},
204		{DMD_PARK_PULSE_WIDTH, 0xB},
205		{DMD_PARK_DELAY, 0x2ED},
206		{DMD_SHADOW_ENABLE, 0},
207		{FLASH_OPCODE, 0xB},
208		{FLASH_DUMMY_BYTES, 1},
209		{FLASH_ADDR_BYTES, 3},
210		{PBC_CONTROL, 0},
211		{FLASH_START_ADDR, CMT_LUT_0_START_ADDR},
212		{FLASH_READ_BYTES, CMT_LUT_0_SIZE},
213		{CMT_SPLASH_LUT_START_ADDR, 0},
214		{CMT_SPLASH_LUT_DEST_SELECT, CMT_LUT_ALL},
215		{PBC_CONTROL, 1},
216	};
217
218	static const struct picodlp_i2c_command init_cmd_set2[] = {
219		{PBC_CONTROL, 0},
220		{CMT_SPLASH_LUT_DEST_SELECT, 0},
221		{PBC_CONTROL, 0},
222		{FLASH_START_ADDR, SEQUENCE_0_START_ADDR},
223		{FLASH_READ_BYTES, SEQUENCE_0_SIZE},
224		{SEQ_RESET_LUT_START_ADDR, 0},
225		{SEQ_RESET_LUT_DEST_SELECT, SEQ_SEQ_LUT},
226		{PBC_CONTROL, 1},
227	};
228
229	static const struct picodlp_i2c_command init_cmd_set3[] = {
230		{PBC_CONTROL, 0},
231		{SEQ_RESET_LUT_DEST_SELECT, 0},
232		{PBC_CONTROL, 0},
233		{FLASH_START_ADDR, DRC_TABLE_0_START_ADDR},
234		{FLASH_READ_BYTES, DRC_TABLE_0_SIZE},
235		{SEQ_RESET_LUT_START_ADDR, 0},
236		{SEQ_RESET_LUT_DEST_SELECT, SEQ_DRC_LUT_ALL},
237		{PBC_CONTROL, 1},
238	};
239
240	static const struct picodlp_i2c_command init_cmd_set4[] = {
241		{PBC_CONTROL, 0},
242		{SEQ_RESET_LUT_DEST_SELECT, 0},
243		{SDC_ENABLE, 1},
244		{AGC_CTRL, 7},
245		{CCA_C1A, 0x100},
246		{CCA_C1B, 0x0},
247		{CCA_C1C, 0x0},
248		{CCA_C2A, 0x0},
249		{CCA_C2B, 0x100},
250		{CCA_C2C, 0x0},
251		{CCA_C3A, 0x0},
252		{CCA_C3B, 0x0},
253		{CCA_C3C, 0x100},
254		{CCA_C7A, 0x100},
255		{CCA_C7B, 0x100},
256		{CCA_C7C, 0x100},
257		{CCA_ENABLE, 1},
258		{CPU_IF_MODE, 1},
259		{SHORT_FLIP, 1},
260		{CURTAIN_CONTROL, 0},
261		{DMD_PARK_TRIGGER, 0},
262		{R_DRIVE_CURRENT, 0x298},
263		{G_DRIVE_CURRENT, 0x298},
264		{B_DRIVE_CURRENT, 0x298},
265		{RGB_DRIVER_ENABLE, 7},
266		{SEQ_CONTROL, 0},
267		{ACTGEN_CONTROL, 0x10},
268		{SEQUENCE_MODE, SEQ_LOCK},
269		{DATA_FORMAT, RGB888},
270		{INPUT_RESOLUTION, WVGA_864_LANDSCAPE},
271		{INPUT_SOURCE, PARALLEL_RGB},
272		{CPU_IF_SYNC_METHOD, 1},
273		{SEQ_CONTROL, 1}
274	};
275
276	r = picodlp_i2c_write_array(client, init_cmd_set1,
277						ARRAY_SIZE(init_cmd_set1));
278	if (r)
279		return r;
280
281	r = picodlp_wait_for_dma_done(client);
282	if (r)
283		return r;
284
285	r = picodlp_i2c_write_array(client, init_cmd_set2,
286					ARRAY_SIZE(init_cmd_set2));
287	if (r)
288		return r;
289
290	r = picodlp_wait_for_dma_done(client);
291	if (r)
292		return r;
293
294	r = picodlp_i2c_write_array(client, init_cmd_set3,
295					ARRAY_SIZE(init_cmd_set3));
296	if (r)
297		return r;
298
299	r = picodlp_wait_for_dma_done(client);
300	if (r)
301		return r;
302
303	r = picodlp_i2c_write_array(client, init_cmd_set4,
304					ARRAY_SIZE(init_cmd_set4));
305	if (r)
306		return r;
307
308	return 0;
309}
310
311static int picodlp_i2c_probe(struct i2c_client *client,
312		const struct i2c_device_id *id)
313{
314	struct picodlp_i2c_data *picodlp_i2c_data;
315
316	picodlp_i2c_data = kzalloc(sizeof(struct picodlp_i2c_data), GFP_KERNEL);
317
318	if (!picodlp_i2c_data)
319		return -ENOMEM;
320
321	mutex_init(&picodlp_i2c_data->xfer_lock);
322	i2c_set_clientdata(client, picodlp_i2c_data);
323
324	return 0;
325}
326
327static int picodlp_i2c_remove(struct i2c_client *client)
328{
329	struct picodlp_i2c_data *picodlp_i2c_data =
330					i2c_get_clientdata(client);
331	kfree(picodlp_i2c_data);
332	return 0;
333}
334
335static struct i2c_driver picodlp_i2c_driver = {
336	.driver = {
337		.name	= "picodlp_i2c_driver",
338	},
339	.probe		= picodlp_i2c_probe,
340	.remove		= picodlp_i2c_remove,
341	.id_table	= picodlp_i2c_id,
342};
343
344static int picodlp_panel_power_on(struct omap_dss_device *dssdev)
345{
346	int r, trial = 100;
347	struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
348	struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev);
349
350	if (dssdev->platform_enable) {
351		r = dssdev->platform_enable(dssdev);
352		if (r)
353			return r;
354	}
355
356	gpio_set_value(picodlp_pdata->pwrgood_gpio, 0);
357	msleep(1);
358	gpio_set_value(picodlp_pdata->pwrgood_gpio, 1);
359
360	while (!gpio_get_value(picodlp_pdata->emu_done_gpio)) {
361		if (!trial--) {
362			dev_err(&dssdev->dev, "emu_done signal not"
363						" going high\n");
364			return -ETIMEDOUT;
365		}
366		msleep(5);
367	}
368	/*
369	 * As per dpp2600 programming guide,
370	 * it is required to sleep for 1000ms after emu_done signal goes high
371	 * then only i2c commands can be successfully sent to dpp2600
372	 */
373	msleep(1000);
374	r = omapdss_dpi_display_enable(dssdev);
375	if (r) {
376		dev_err(&dssdev->dev, "failed to enable DPI\n");
377		goto err1;
378	}
379
380	r = picodlp_i2c_init(picod->picodlp_i2c_client);
381	if (r)
382		goto err;
383
384	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
385
386	return r;
387err:
388	omapdss_dpi_display_disable(dssdev);
389err1:
390	if (dssdev->platform_disable)
391		dssdev->platform_disable(dssdev);
392
393	return r;
394}
395
396static void picodlp_panel_power_off(struct omap_dss_device *dssdev)
397{
398	struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev);
399
400	omapdss_dpi_display_disable(dssdev);
401
402	gpio_set_value(picodlp_pdata->emu_done_gpio, 0);
403	gpio_set_value(picodlp_pdata->pwrgood_gpio, 0);
404
405	if (dssdev->platform_disable)
406		dssdev->platform_disable(dssdev);
407}
408
409static int picodlp_panel_probe(struct omap_dss_device *dssdev)
410{
411	struct picodlp_data *picod;
412	struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev);
413	struct i2c_adapter *adapter;
414	struct i2c_client *picodlp_i2c_client;
415	int r = 0, picodlp_adapter_id;
416
417	dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_ONOFF |
418				OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IVS;
419	dssdev->panel.acb = 0x0;
420	dssdev->panel.timings = pico_ls_timings;
421
422	picod =  kzalloc(sizeof(struct picodlp_data), GFP_KERNEL);
423	if (!picod)
424		return -ENOMEM;
425
426	mutex_init(&picod->lock);
427
428	picodlp_adapter_id = picodlp_pdata->picodlp_adapter_id;
429
430	adapter = i2c_get_adapter(picodlp_adapter_id);
431	if (!adapter) {
432		dev_err(&dssdev->dev, "can't get i2c adapter\n");
433		r = -ENODEV;
434		goto err;
435	}
436
437	picodlp_i2c_client = i2c_new_device(adapter, &picodlp_i2c_board_info);
438	if (!picodlp_i2c_client) {
439		dev_err(&dssdev->dev, "can't add i2c device::"
440					 " picodlp_i2c_client is NULL\n");
441		r = -ENODEV;
442		goto err;
443	}
444
445	picod->picodlp_i2c_client = picodlp_i2c_client;
446
447	dev_set_drvdata(&dssdev->dev, picod);
448	return r;
449err:
450	kfree(picod);
451	return r;
452}
453
454static void picodlp_panel_remove(struct omap_dss_device *dssdev)
455{
456	struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
457
458	i2c_unregister_device(picod->picodlp_i2c_client);
459	dev_set_drvdata(&dssdev->dev, NULL);
460	dev_dbg(&dssdev->dev, "removing picodlp panel\n");
461
462	kfree(picod);
463}
464
465static int picodlp_panel_enable(struct omap_dss_device *dssdev)
466{
467	struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
468	int r;
469
470	dev_dbg(&dssdev->dev, "enabling picodlp panel\n");
471
472	mutex_lock(&picod->lock);
473	if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
474		mutex_unlock(&picod->lock);
475		return -EINVAL;
476	}
477
478	r = picodlp_panel_power_on(dssdev);
479	mutex_unlock(&picod->lock);
480
481	return r;
482}
483
484static void picodlp_panel_disable(struct omap_dss_device *dssdev)
485{
486	struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
487
488	mutex_lock(&picod->lock);
489	/* Turn off DLP Power */
490	if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
491		picodlp_panel_power_off(dssdev);
492
493	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
494	mutex_unlock(&picod->lock);
495
496	dev_dbg(&dssdev->dev, "disabling picodlp panel\n");
497}
498
499static int picodlp_panel_suspend(struct omap_dss_device *dssdev)
500{
501	struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
502
503	mutex_lock(&picod->lock);
504	/* Turn off DLP Power */
505	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
506		mutex_unlock(&picod->lock);
507		dev_err(&dssdev->dev, "unable to suspend picodlp panel,"
508					" panel is not ACTIVE\n");
509		return -EINVAL;
510	}
511
512	picodlp_panel_power_off(dssdev);
513
514	dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
515	mutex_unlock(&picod->lock);
516
517	dev_dbg(&dssdev->dev, "suspending picodlp panel\n");
518	return 0;
519}
520
521static int picodlp_panel_resume(struct omap_dss_device *dssdev)
522{
523	struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
524	int r;
525
526	mutex_lock(&picod->lock);
527	if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
528		mutex_unlock(&picod->lock);
529		dev_err(&dssdev->dev, "unable to resume picodlp panel,"
530			" panel is not ACTIVE\n");
531		return -EINVAL;
532	}
533
534	r = picodlp_panel_power_on(dssdev);
535	mutex_unlock(&picod->lock);
536	dev_dbg(&dssdev->dev, "resuming picodlp panel\n");
537	return r;
538}
539
540static void picodlp_get_resolution(struct omap_dss_device *dssdev,
541					u16 *xres, u16 *yres)
542{
543	*xres = dssdev->panel.timings.x_res;
544	*yres = dssdev->panel.timings.y_res;
545}
546
547static struct omap_dss_driver picodlp_driver = {
548	.probe		= picodlp_panel_probe,
549	.remove		= picodlp_panel_remove,
550
551	.enable		= picodlp_panel_enable,
552	.disable	= picodlp_panel_disable,
553
554	.get_resolution	= picodlp_get_resolution,
555
556	.suspend	= picodlp_panel_suspend,
557	.resume		= picodlp_panel_resume,
558
559	.driver		= {
560		.name	= "picodlp_panel",
561		.owner	= THIS_MODULE,
562	},
563};
564
565static int __init picodlp_init(void)
566{
567	int r = 0;
568
569	r = i2c_add_driver(&picodlp_i2c_driver);
570	if (r) {
571		printk(KERN_WARNING "picodlp_i2c_driver" \
572			" registration failed\n");
573		return r;
574	}
575
576	r = omap_dss_register_driver(&picodlp_driver);
577	if (r)
578		i2c_del_driver(&picodlp_i2c_driver);
579
580	return r;
581}
582
583static void __exit picodlp_exit(void)
584{
585	i2c_del_driver(&picodlp_i2c_driver);
586	omap_dss_unregister_driver(&picodlp_driver);
587}
588
589module_init(picodlp_init);
590module_exit(picodlp_exit);
591
592MODULE_AUTHOR("Mythri P K <mythripk@ti.com>");
593MODULE_DESCRIPTION("picodlp driver");
594MODULE_LICENSE("GPL");
595