blob: 31ec742293ebbe7ecafcb05a58d831f11e532ebf [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* linux/arch/arm/mach-msm/board-mahimahi-panel.c
2 *
3 * Copyright (c) 2009 Google Inc.
4 * Author: Dima Zavin <dima@android.com>
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/clk.h>
18#include <linux/delay.h>
19#include <linux/err.h>
20#include <linux/gpio.h>
21#include <linux/init.h>
22#include <linux/kernel.h>
23#include <linux/leds.h>
24#include <linux/platform_device.h>
25#include <linux/workqueue.h>
26
27#include <asm/io.h>
28#include <asm/mach-types.h>
29
30#include <mach/msm_fb.h>
31#include <mach/msm_iomap.h>
32#include <mach/vreg.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070033#include <mach/proc_comm.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070034
35#include "board-mahimahi.h"
36#include "devices.h"
37
38
39#define SPI_CONFIG (0x00000000)
40#define SPI_IO_CONTROL (0x00000004)
41#define SPI_OPERATIONAL (0x00000030)
42#define SPI_ERROR_FLAGS_EN (0x00000038)
43#define SPI_ERROR_FLAGS (0x00000038)
44#define SPI_OUTPUT_FIFO (0x00000100)
45
46static void __iomem *spi_base;
47static struct clk *spi_clk ;
48static struct vreg *vreg_lcm_rftx_2v6;
49static struct vreg *vreg_lcm_aux_2v6;
50
51static int qspi_send(uint32_t id, uint8_t data)
52{
53 uint32_t err;
54
55 /* bit-5: OUTPUT_FIFO_NOT_EMPTY */
56 while (readl(spi_base + SPI_OPERATIONAL) & (1<<5)) {
57 if ((err = readl(spi_base + SPI_ERROR_FLAGS))) {
58 pr_err("%s: ERROR: SPI_ERROR_FLAGS=0x%08x\n", __func__,
59 err);
60 return -EIO;
61 }
62 }
63 writel((0x7000 | (id << 9) | data) << 16, spi_base + SPI_OUTPUT_FIFO);
64 udelay(100);
65
66 return 0;
67}
68
69static int qspi_send_9bit(uint32_t id, uint8_t data)
70{
71 uint32_t err;
72
73 while (readl(spi_base + SPI_OPERATIONAL) & (1<<5)) {
74 err = readl(spi_base + SPI_ERROR_FLAGS);
75 if (err) {
76 pr_err("%s: ERROR: SPI_ERROR_FLAGS=0x%08x\n", __func__,
77 err);
78 return -EIO;
79 }
80 }
81 writel(((id << 8) | data) << 23, spi_base + SPI_OUTPUT_FIFO);
82 udelay(100);
83
84 return 0;
85}
86
87static int lcm_writeb(uint8_t reg, uint8_t val)
88{
89 qspi_send(0x0, reg);
90 qspi_send(0x1, val);
91 return 0;
92}
93
94static int lcm_writew(uint8_t reg, uint16_t val)
95{
96 qspi_send(0x0, reg);
97 qspi_send(0x1, val >> 8);
98 qspi_send(0x1, val & 0xff);
99 return 0;
100}
101
102static struct resource resources_msm_fb[] = {
103 {
104 .start = MSM_FB_BASE,
105 .end = MSM_FB_BASE + MSM_FB_SIZE - 1,
106 .flags = IORESOURCE_MEM,
107 },
108};
109
110struct lcm_tbl {
111 uint8_t reg;
112 uint8_t val;
113};
114
115static struct lcm_tbl samsung_oled_rgb565_init_table[] = {
116 { 0x31, 0x08 },
117 { 0x32, 0x14 },
118 { 0x30, 0x2 },
119 { 0x27, 0x1 },
120 { 0x12, 0x8 },
121 { 0x13, 0x8 },
122 { 0x15, 0x0 },
123 { 0x16, 0x02 },
124 { 0x39, 0x24 },
125 { 0x17, 0x22 },
126 { 0x18, 0x33 },
127 { 0x19, 0x3 },
128 { 0x1A, 0x1 },
129 { 0x22, 0xA4 },
130 { 0x23, 0x0 },
131 { 0x26, 0xA0 },
132};
133
134static struct lcm_tbl samsung_oled_rgb666_init_table[] = {
135 { 0x31, 0x08 },
136 { 0x32, 0x14 },
137 { 0x30, 0x2 },
138 { 0x27, 0x1 },
139 { 0x12, 0x8 },
140 { 0x13, 0x8 },
141 { 0x15, 0x0 },
142 { 0x16, 0x01 },
143 { 0x39, 0x24 },
144 { 0x17, 0x22 },
145 { 0x18, 0x33 },
146 { 0x19, 0x3 },
147 { 0x1A, 0x1 },
148 { 0x22, 0xA4 },
149 { 0x23, 0x0 },
150 { 0x26, 0xA0 },
151};
152
153static struct lcm_tbl *init_tablep = samsung_oled_rgb565_init_table;
154static size_t init_table_sz = ARRAY_SIZE(samsung_oled_rgb565_init_table);
155
156#define OLED_GAMMA_TABLE_SIZE (7 * 3)
157static struct lcm_tbl samsung_oled_gamma_table[][OLED_GAMMA_TABLE_SIZE] = {
158 /* level 10 */
159 {
160 /* Gamma-R */
161 { 0x40, 0x0 },
162 { 0x41, 0x3f },
163 { 0x42, 0x3f },
164 { 0x43, 0x35 },
165 { 0x44, 0x30 },
166 { 0x45, 0x2c },
167 { 0x46, 0x13 },
168 /* Gamma -G */
169 { 0x50, 0x0 },
170 { 0x51, 0x0 },
171 { 0x52, 0x0 },
172 { 0x53, 0x0 },
173 { 0x54, 0x27 },
174 { 0x55, 0x2b },
175 { 0x56, 0x12 },
176 /* Gamma -B */
177 { 0x60, 0x0 },
178 { 0x61, 0x3f },
179 { 0x62, 0x3f },
180 { 0x63, 0x34 },
181 { 0x64, 0x2f },
182 { 0x65, 0x2b },
183 { 0x66, 0x1b },
184 },
185
186 /* level 40 */
187 {
188 /* Gamma -R */
189 { 0x40, 0x0 },
190 { 0x41, 0x3f },
191 { 0x42, 0x3e },
192 { 0x43, 0x2e },
193 { 0x44, 0x2d },
194 { 0x45, 0x28 },
195 { 0x46, 0x21 },
196 /* Gamma -G */
197 { 0x50, 0x0 },
198 { 0x51, 0x0 },
199 { 0x52, 0x0 },
200 { 0x53, 0x21 },
201 { 0x54, 0x2a },
202 { 0x55, 0x28 },
203 { 0x56, 0x20 },
204 /* Gamma -B */
205 { 0x60, 0x0 },
206 { 0x61, 0x3f },
207 { 0x62, 0x3e },
208 { 0x63, 0x2d },
209 { 0x64, 0x2b },
210 { 0x65, 0x26 },
211 { 0x66, 0x2d },
212 },
213
214 /* level 70 */
215 {
216 /* Gamma -R */
217 { 0x40, 0x0 },
218 { 0x41, 0x3f },
219 { 0x42, 0x35 },
220 { 0x43, 0x2c },
221 { 0x44, 0x2b },
222 { 0x45, 0x26 },
223 { 0x46, 0x29 },
224 /* Gamma -G */
225 { 0x50, 0x0 },
226 { 0x51, 0x0 },
227 { 0x52, 0x0 },
228 { 0x53, 0x25 },
229 { 0x54, 0x29 },
230 { 0x55, 0x26 },
231 { 0x56, 0x28 },
232 /* Gamma -B */
233 { 0x60, 0x0 },
234 { 0x61, 0x3f },
235 { 0x62, 0x34 },
236 { 0x63, 0x2b },
237 { 0x64, 0x2a },
238 { 0x65, 0x23 },
239 { 0x66, 0x37 },
240 },
241
242 /* level 100 */
243 {
244 /* Gamma -R */
245 { 0x40, 0x0 },
246 { 0x41, 0x3f },
247 { 0x42, 0x30 },
248 { 0x43, 0x2a },
249 { 0x44, 0x2b },
250 { 0x45, 0x24 },
251 { 0x46, 0x2f },
252 /* Gamma -G */
253 { 0x50, 0x0 },
254 { 0x51, 0x0 },
255 { 0x52, 0x0 },
256 { 0x53, 0x25 },
257 { 0x54, 0x29 },
258 { 0x55, 0x24 },
259 { 0x56, 0x2e },
260 /* Gamma -B */
261 { 0x60, 0x0 },
262 { 0x61, 0x3f },
263 { 0x62, 0x2f },
264 { 0x63, 0x29 },
265 { 0x64, 0x29 },
266 { 0x65, 0x21 },
267 { 0x66, 0x3f },
268 },
269
270 /* level 130 */
271 {
272 /* Gamma -R */
273 { 0x40, 0x0 },
274 { 0x41, 0x3f },
275 { 0x42, 0x2e },
276 { 0x43, 0x29 },
277 { 0x44, 0x2a },
278 { 0x45, 0x23 },
279 { 0x46, 0x34 },
280 /* Gamma -G */
281 { 0x50, 0x0 },
282 { 0x51, 0x0 },
283 { 0x52, 0xa },
284 { 0x53, 0x25 },
285 { 0x54, 0x28 },
286 { 0x55, 0x23 },
287 { 0x56, 0x33 },
288 /* Gamma -B */
289 { 0x60, 0x0 },
290 { 0x61, 0x3f },
291 { 0x62, 0x2d },
292 { 0x63, 0x28 },
293 { 0x64, 0x27 },
294 { 0x65, 0x20 },
295 { 0x66, 0x46 },
296 },
297
298 /* level 160 */
299 {
300 /* Gamma -R */
301 { 0x40, 0x0 },
302 { 0x41, 0x3f },
303 { 0x42, 0x2b },
304 { 0x43, 0x29 },
305 { 0x44, 0x28 },
306 { 0x45, 0x23 },
307 { 0x46, 0x38 },
308 /* Gamma -G */
309 { 0x50, 0x0 },
310 { 0x51, 0x0 },
311 { 0x52, 0xb },
312 { 0x53, 0x25 },
313 { 0x54, 0x27 },
314 { 0x55, 0x23 },
315 { 0x56, 0x37 },
316 /* Gamma -B */
317 { 0x60, 0x0 },
318 { 0x61, 0x3f },
319 { 0x62, 0x29 },
320 { 0x63, 0x28 },
321 { 0x64, 0x25 },
322 { 0x65, 0x20 },
323 { 0x66, 0x4b },
324 },
325
326 /* level 190 */
327 {
328 /* Gamma -R */
329 { 0x40, 0x0 },
330 { 0x41, 0x3f },
331 { 0x42, 0x29 },
332 { 0x43, 0x29 },
333 { 0x44, 0x27 },
334 { 0x45, 0x22 },
335 { 0x46, 0x3c },
336 /* Gamma -G */
337 { 0x50, 0x0 },
338 { 0x51, 0x0 },
339 { 0x52, 0x10 },
340 { 0x53, 0x26 },
341 { 0x54, 0x26 },
342 { 0x55, 0x22 },
343 { 0x56, 0x3b },
344 /* Gamma -B */
345 { 0x60, 0x0 },
346 { 0x61, 0x3f },
347 { 0x62, 0x28 },
348 { 0x63, 0x28 },
349 { 0x64, 0x24 },
350 { 0x65, 0x1f },
351 { 0x66, 0x50 },
352 },
353
354 /* level 220 */
355 {
356 /* Gamma -R */
357 { 0x40, 0x0 },
358 { 0x41, 0x3f },
359 { 0x42, 0x28 },
360 { 0x43, 0x28 },
361 { 0x44, 0x28 },
362 { 0x45, 0x20 },
363 { 0x46, 0x40 },
364 /* Gamma -G */
365 { 0x50, 0x0 },
366 { 0x51, 0x0 },
367 { 0x52, 0x11 },
368 { 0x53, 0x25 },
369 { 0x54, 0x27 },
370 { 0x55, 0x20 },
371 { 0x56, 0x3f },
372 /* Gamma -B */
373 { 0x60, 0x0 },
374 { 0x61, 0x3f },
375 { 0x62, 0x27 },
376 { 0x63, 0x26 },
377 { 0x64, 0x26 },
378 { 0x65, 0x1c },
379 { 0x66, 0x56 },
380 },
381
382 /* level 250 */
383 {
384 /* Gamma -R */
385 { 0x40, 0x0 },
386 { 0x41, 0x3f },
387 { 0x42, 0x2a },
388 { 0x43, 0x27 },
389 { 0x44, 0x27 },
390 { 0x45, 0x1f },
391 { 0x46, 0x44 },
392 /* Gamma -G */
393 { 0x50, 0x0 },
394 { 0x51, 0x0 },
395 { 0x52, 0x17 },
396 { 0x53, 0x24 },
397 { 0x54, 0x26 },
398 { 0x55, 0x1f },
399 { 0x56, 0x43 },
400 /* Gamma -B */
401 { 0x60, 0x0 },
402 { 0x61, 0x3f },
403 { 0x62, 0x2a },
404 { 0x63, 0x25 },
405 { 0x64, 0x24 },
406 { 0x65, 0x1b },
407 { 0x66, 0x5c },
408 },
409};
410#define SAMSUNG_OLED_NUM_LEVELS ARRAY_SIZE(samsung_oled_gamma_table)
411
412#define SAMSUNG_OLED_MIN_VAL 10
413#define SAMSUNG_OLED_MAX_VAL 250
414#define SAMSUNG_OLED_DEFAULT_VAL (SAMSUNG_OLED_MIN_VAL + \
415 (SAMSUNG_OLED_MAX_VAL - \
416 SAMSUNG_OLED_MIN_VAL) / 2)
417
418#define SAMSUNG_OLED_LEVEL_STEP ((SAMSUNG_OLED_MAX_VAL - \
419 SAMSUNG_OLED_MIN_VAL) / \
420 (SAMSUNG_OLED_NUM_LEVELS - 1))
421
422
423#define SONY_TFT_DEF_USER_VAL 102
424#define SONY_TFT_MIN_USER_VAL 30
425#define SONY_TFT_MAX_USER_VAL 255
426#define SONY_TFT_DEF_PANEL_VAL 155
427#define SONY_TFT_MIN_PANEL_VAL 26
428#define SONY_TFT_MAX_PANEL_VAL 255
429
430
431static DEFINE_MUTEX(panel_lock);
432static struct work_struct brightness_delayed_work;
433static DEFINE_SPINLOCK(brightness_lock);
434static uint8_t new_val = SAMSUNG_OLED_DEFAULT_VAL;
435static uint8_t last_val = SAMSUNG_OLED_DEFAULT_VAL;
436static uint8_t table_sel_vals[] = { 0x43, 0x34 };
437static int table_sel_idx = 0;
438static uint8_t tft_panel_on;
439
440static void gamma_table_bank_select(void)
441{
442 lcm_writeb(0x39, table_sel_vals[table_sel_idx]);
443 table_sel_idx ^= 1;
444}
445
446static void samsung_oled_set_gamma_val(int val)
447{
448 int i;
449 int level;
450 int frac;
451
452 val = clamp(val, SAMSUNG_OLED_MIN_VAL, SAMSUNG_OLED_MAX_VAL);
453 val = (val / 2) * 2;
454
455 level = (val - SAMSUNG_OLED_MIN_VAL) / SAMSUNG_OLED_LEVEL_STEP;
456 frac = (val - SAMSUNG_OLED_MIN_VAL) % SAMSUNG_OLED_LEVEL_STEP;
457
458 clk_enable(spi_clk);
459
460 for (i = 0; i < OLED_GAMMA_TABLE_SIZE; ++i) {
461 unsigned int v1;
462 unsigned int v2 = 0;
463 u8 v;
464 if (frac == 0) {
465 v = samsung_oled_gamma_table[level][i].val;
466 } else {
467
468 v1 = samsung_oled_gamma_table[level][i].val;
469 v2 = samsung_oled_gamma_table[level+1][i].val;
470 v = (v1 * (SAMSUNG_OLED_LEVEL_STEP - frac) +
471 v2 * frac) / SAMSUNG_OLED_LEVEL_STEP;
472 }
473 lcm_writeb(samsung_oled_gamma_table[level][i].reg, v);
474 }
475
476 gamma_table_bank_select();
477 clk_disable(spi_clk);
478 last_val = val;
479}
480
481static int samsung_oled_panel_init(struct msm_lcdc_panel_ops *ops)
482{
483 pr_info("%s: +()\n", __func__);
484 mutex_lock(&panel_lock);
485
486 clk_enable(spi_clk);
487 /* Set the gamma write target to 4, leave the current gamma set at 2 */
488 lcm_writeb(0x39, 0x24);
489 clk_disable(spi_clk);
490
491 mutex_unlock(&panel_lock);
492 pr_info("%s: -()\n", __func__);
493 return 0;
494}
495
496static int samsung_oled_panel_unblank(struct msm_lcdc_panel_ops *ops)
497{
498 int i;
499
500 pr_info("%s: +()\n", __func__);
501
502 mutex_lock(&panel_lock);
503
504 gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 1);
505 udelay(50);
506 gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 0);
507 udelay(20);
508 gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 1);
509 msleep(20);
510
511 clk_enable(spi_clk);
512
513 for (i = 0; i < init_table_sz; i++)
514 lcm_writeb(init_tablep[i].reg, init_tablep[i].val);
515
516 lcm_writew(0xef, 0xd0e8);
517 lcm_writeb(0x1d, 0xa0);
518 table_sel_idx = 0;
519 gamma_table_bank_select();
520 samsung_oled_set_gamma_val(last_val);
521 msleep(250);
522 lcm_writeb(0x14, 0x03);
523 clk_disable(spi_clk);
524
525 mutex_unlock(&panel_lock);
526
527 pr_info("%s: -()\n", __func__);
528 return 0;
529}
530
531static int samsung_oled_panel_blank(struct msm_lcdc_panel_ops *ops)
532{
533 pr_info("%s: +()\n", __func__);
534 mutex_lock(&panel_lock);
535
536 clk_enable(spi_clk);
537 lcm_writeb(0x14, 0x0);
538 mdelay(1);
539 lcm_writeb(0x1d, 0xa1);
540 clk_disable(spi_clk);
541 msleep(200);
542
543 gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 0);
544
545 mutex_unlock(&panel_lock);
546 pr_info("%s: -()\n", __func__);
547 return 0;
548}
549
550struct lcm_cmd {
551 int reg;
552 uint32_t val;
553 unsigned delay;
554};
555
556#define LCM_GPIO_CFG(gpio, func, str) \
557 PCOM_GPIO_CFG(gpio, func, GPIO_OUTPUT, GPIO_NO_PULL, str)
558
559static uint32_t sony_tft_display_on_gpio_table[] = {
560 LCM_GPIO_CFG(MAHIMAHI_LCD_R1, 1, GPIO_8MA),
561 LCM_GPIO_CFG(MAHIMAHI_LCD_R2, 1, GPIO_8MA),
562 LCM_GPIO_CFG(MAHIMAHI_LCD_R3, 1, GPIO_8MA),
563 LCM_GPIO_CFG(MAHIMAHI_LCD_R4, 1, GPIO_8MA),
564 LCM_GPIO_CFG(MAHIMAHI_LCD_R5, 1, GPIO_8MA),
565 LCM_GPIO_CFG(MAHIMAHI_LCD_G0, 1, GPIO_8MA),
566 LCM_GPIO_CFG(MAHIMAHI_LCD_G1, 1, GPIO_8MA),
567 LCM_GPIO_CFG(MAHIMAHI_LCD_G2, 1, GPIO_8MA),
568 LCM_GPIO_CFG(MAHIMAHI_LCD_G3, 1, GPIO_8MA),
569 LCM_GPIO_CFG(MAHIMAHI_LCD_G4, 1, GPIO_8MA),
570 LCM_GPIO_CFG(MAHIMAHI_LCD_G5, 1, GPIO_8MA),
571 LCM_GPIO_CFG(MAHIMAHI_LCD_B1, 1, GPIO_8MA),
572 LCM_GPIO_CFG(MAHIMAHI_LCD_B2, 1, GPIO_8MA),
573 LCM_GPIO_CFG(MAHIMAHI_LCD_B3, 1, GPIO_8MA),
574 LCM_GPIO_CFG(MAHIMAHI_LCD_B4, 1, GPIO_8MA),
575 LCM_GPIO_CFG(MAHIMAHI_LCD_B5, 1, GPIO_8MA),
576 LCM_GPIO_CFG(MAHIMAHI_LCD_PCLK, 1, GPIO_4MA),
577 LCM_GPIO_CFG(MAHIMAHI_LCD_VSYNC, 1, GPIO_8MA),
578 LCM_GPIO_CFG(MAHIMAHI_LCD_HSYNC, 1, GPIO_8MA),
579 LCM_GPIO_CFG(MAHIMAHI_LCD_DE, 1, GPIO_8MA),
580 LCM_GPIO_CFG(MAHIMAHI_LCD_SPI_CLK, 1, GPIO_4MA),
581 LCM_GPIO_CFG(MAHIMAHI_LCD_SPI_DO, 1, GPIO_4MA),
582 LCM_GPIO_CFG(MAHIMAHI_LCD_SPI_CSz, 1, GPIO_4MA),
583};
584
585static uint32_t sony_tft_display_off_gpio_table[] = {
586 LCM_GPIO_CFG(MAHIMAHI_LCD_R1, 0, GPIO_8MA),
587 LCM_GPIO_CFG(MAHIMAHI_LCD_R2, 0, GPIO_8MA),
588 LCM_GPIO_CFG(MAHIMAHI_LCD_R3, 0, GPIO_8MA),
589 LCM_GPIO_CFG(MAHIMAHI_LCD_R4, 0, GPIO_8MA),
590 LCM_GPIO_CFG(MAHIMAHI_LCD_R5, 0, GPIO_8MA),
591 LCM_GPIO_CFG(MAHIMAHI_LCD_G0, 0, GPIO_8MA),
592 LCM_GPIO_CFG(MAHIMAHI_LCD_G1, 0, GPIO_8MA),
593 LCM_GPIO_CFG(MAHIMAHI_LCD_G2, 0, GPIO_8MA),
594 LCM_GPIO_CFG(MAHIMAHI_LCD_G3, 0, GPIO_8MA),
595 LCM_GPIO_CFG(MAHIMAHI_LCD_G4, 0, GPIO_8MA),
596 LCM_GPIO_CFG(MAHIMAHI_LCD_G5, 0, GPIO_8MA),
597 LCM_GPIO_CFG(MAHIMAHI_LCD_B1, 0, GPIO_8MA),
598 LCM_GPIO_CFG(MAHIMAHI_LCD_B2, 0, GPIO_8MA),
599 LCM_GPIO_CFG(MAHIMAHI_LCD_B3, 0, GPIO_8MA),
600 LCM_GPIO_CFG(MAHIMAHI_LCD_B4, 0, GPIO_8MA),
601 LCM_GPIO_CFG(MAHIMAHI_LCD_B5, 0, GPIO_8MA),
602 LCM_GPIO_CFG(MAHIMAHI_LCD_PCLK, 0, GPIO_4MA),
603 LCM_GPIO_CFG(MAHIMAHI_LCD_VSYNC, 0, GPIO_8MA),
604 LCM_GPIO_CFG(MAHIMAHI_LCD_HSYNC, 0, GPIO_8MA),
605 LCM_GPIO_CFG(MAHIMAHI_LCD_DE, 0, GPIO_8MA),
606 LCM_GPIO_CFG(MAHIMAHI_LCD_SPI_CLK, 0, GPIO_4MA),
607 LCM_GPIO_CFG(MAHIMAHI_LCD_SPI_DO, 0, GPIO_4MA),
608 LCM_GPIO_CFG(MAHIMAHI_LCD_SPI_CSz, 0, GPIO_4MA),
609};
610
611#undef LCM_GPIO_CFG
612
613#define SONY_TFT_DEF_PANEL_DELTA \
614 (SONY_TFT_DEF_PANEL_VAL - SONY_TFT_MIN_PANEL_VAL)
615#define SONY_TFT_DEF_USER_DELTA \
616 (SONY_TFT_DEF_USER_VAL - SONY_TFT_MIN_USER_VAL)
617
618static void sony_tft_set_pwm_val(int val)
619{
620 pr_info("%s: %d\n", __func__, val);
621
622 last_val = val;
623
624 if (!tft_panel_on)
625 return;
626
627 if (val <= SONY_TFT_DEF_USER_VAL) {
628 if (val <= SONY_TFT_MIN_USER_VAL)
629 val = SONY_TFT_MIN_PANEL_VAL;
630 else
631 val = SONY_TFT_DEF_PANEL_DELTA *
632 (val - SONY_TFT_MIN_USER_VAL) /
633 SONY_TFT_DEF_USER_DELTA +
634 SONY_TFT_MIN_PANEL_VAL;
635 } else
636 val = (SONY_TFT_MAX_PANEL_VAL - SONY_TFT_DEF_PANEL_VAL) *
637 (val - SONY_TFT_DEF_USER_VAL) /
638 (SONY_TFT_MAX_USER_VAL - SONY_TFT_DEF_USER_VAL) +
639 SONY_TFT_DEF_PANEL_VAL;
640
641 clk_enable(spi_clk);
642 qspi_send_9bit(0x0, 0x51);
643 qspi_send_9bit(0x1, val);
644 qspi_send_9bit(0x0, 0x53);
645 qspi_send_9bit(0x1, 0x24);
646 clk_disable(spi_clk);
647}
648
649#undef SONY_TFT_DEF_PANEL_DELTA
650#undef SONY_TFT_DEF_USER_DELTA
651
652static void sony_tft_panel_config_gpio_table(uint32_t *table, int len)
653{
654 int n;
655 unsigned id;
656 for (n = 0; n < len; n++) {
657 id = table[n];
658 msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
659 }
660}
661
662
663static int sony_tft_panel_power(int on)
664{
665 unsigned id, on_off;
666
667 if (on) {
668 on_off = 0;
669
670 vreg_enable(vreg_lcm_aux_2v6);
671 vreg_enable(vreg_lcm_rftx_2v6);
672
673 id = PM_VREG_PDOWN_AUX_ID;
674 msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
675
676 id = PM_VREG_PDOWN_RFTX_ID;
677 msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
678 mdelay(10);
679 gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 1);
680 mdelay(10);
681 gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 0);
682 udelay(500);
683 gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 1);
684 mdelay(10);
685 sony_tft_panel_config_gpio_table(
686 sony_tft_display_on_gpio_table,
687 ARRAY_SIZE(sony_tft_display_on_gpio_table));
688 } else {
689 on_off = 1;
690
691 gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 0);
692
693 mdelay(120);
694
695 vreg_disable(vreg_lcm_rftx_2v6);
696 vreg_disable(vreg_lcm_aux_2v6);
697
698 id = PM_VREG_PDOWN_RFTX_ID;
699 msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
700
701 id = PM_VREG_PDOWN_AUX_ID;
702 msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
703 sony_tft_panel_config_gpio_table(
704 sony_tft_display_off_gpio_table,
705 ARRAY_SIZE(sony_tft_display_off_gpio_table));
706 }
707 return 0;
708}
709
710static int sony_tft_panel_init(struct msm_lcdc_panel_ops *ops)
711{
712 return 0;
713}
714
715static int sony_tft_panel_unblank(struct msm_lcdc_panel_ops *ops)
716{
717 pr_info("%s: +()\n", __func__);
718
719 mutex_lock(&panel_lock);
720
721 if (tft_panel_on) {
722 pr_info("%s: -() already unblanked\n", __func__);
723 goto done;
724 }
725
726 sony_tft_panel_power(1);
727 msleep(45);
728
729 clk_enable(spi_clk);
730 qspi_send_9bit(0x0, 0x11);
731 msleep(5);
732 qspi_send_9bit(0x0, 0x3a);
733 qspi_send_9bit(0x1, 0x05);
734 msleep(100);
735 qspi_send_9bit(0x0, 0x29);
736 /* unlock register page for pwm setting */
737 qspi_send_9bit(0x0, 0xf0);
738 qspi_send_9bit(0x1, 0x5a);
739 qspi_send_9bit(0x1, 0x5a);
740 qspi_send_9bit(0x0, 0xf1);
741 qspi_send_9bit(0x1, 0x5a);
742 qspi_send_9bit(0x1, 0x5a);
743 qspi_send_9bit(0x0, 0xd0);
744 qspi_send_9bit(0x1, 0x5a);
745 qspi_send_9bit(0x1, 0x5a);
746
747 qspi_send_9bit(0x0, 0xc2);
748 qspi_send_9bit(0x1, 0x53);
749 qspi_send_9bit(0x1, 0x12);
750 clk_disable(spi_clk);
751 msleep(100);
752 tft_panel_on = 1;
753 sony_tft_set_pwm_val(last_val);
754
755 pr_info("%s: -()\n", __func__);
756done:
757 mutex_unlock(&panel_lock);
758 return 0;
759}
760
761static int sony_tft_panel_blank(struct msm_lcdc_panel_ops *ops)
762{
763 pr_info("%s: +()\n", __func__);
764
765 mutex_lock(&panel_lock);
766
767 clk_enable(spi_clk);
768 qspi_send_9bit(0x0, 0x28);
769 qspi_send_9bit(0x0, 0x10);
770 clk_disable(spi_clk);
771
772 msleep(40);
773 sony_tft_panel_power(0);
774 tft_panel_on = 0;
775
776 mutex_unlock(&panel_lock);
777
778 pr_info("%s: -()\n", __func__);
779 return 0;
780}
781
782static struct msm_lcdc_panel_ops mahimahi_lcdc_amoled_panel_ops = {
783 .init = samsung_oled_panel_init,
784 .blank = samsung_oled_panel_blank,
785 .unblank = samsung_oled_panel_unblank,
786};
787
788static struct msm_lcdc_panel_ops mahimahi_lcdc_tft_panel_ops = {
789 .init = sony_tft_panel_init,
790 .blank = sony_tft_panel_blank,
791 .unblank = sony_tft_panel_unblank,
792};
793
794
795static struct msm_lcdc_timing mahimahi_lcdc_amoled_timing = {
796 .clk_rate = 24576000,
797 .hsync_pulse_width = 4,
798 .hsync_back_porch = 8,
799 .hsync_front_porch = 8,
800 .hsync_skew = 0,
801 .vsync_pulse_width = 2,
802 .vsync_back_porch = 8,
803 .vsync_front_porch = 8,
804 .vsync_act_low = 1,
805 .hsync_act_low = 1,
806 .den_act_low = 1,
807};
808
809static struct msm_lcdc_timing mahimahi_lcdc_tft_timing = {
810 .clk_rate = 24576000,
811 .hsync_pulse_width = 2,
812 .hsync_back_porch = 20,
813 .hsync_front_porch = 20,
814 .hsync_skew = 0,
815 .vsync_pulse_width = 2,
816 .vsync_back_porch = 6,
817 .vsync_front_porch = 4,
818 .vsync_act_low = 1,
819 .hsync_act_low = 1,
820 .den_act_low = 0,
821};
822
823static struct msm_fb_data mahimahi_lcdc_fb_data = {
824 .xres = 480,
825 .yres = 800,
826 .width = 48,
827 .height = 80,
828 .output_format = MSM_MDP_OUT_IF_FMT_RGB565,
829};
830
831static struct msm_lcdc_platform_data mahimahi_lcdc_amoled_platform_data = {
832 .panel_ops = &mahimahi_lcdc_amoled_panel_ops,
833 .timing = &mahimahi_lcdc_amoled_timing,
834 .fb_id = 0,
835 .fb_data = &mahimahi_lcdc_fb_data,
836 .fb_resource = &resources_msm_fb[0],
837};
838
839static struct msm_lcdc_platform_data mahimahi_lcdc_tft_platform_data = {
840 .panel_ops = &mahimahi_lcdc_tft_panel_ops,
841 .timing = &mahimahi_lcdc_tft_timing,
842 .fb_id = 0,
843 .fb_data = &mahimahi_lcdc_fb_data,
844 .fb_resource = &resources_msm_fb[0],
845};
846
847static struct platform_device mahimahi_lcdc_amoled_device = {
848 .name = "msm_mdp_lcdc",
849 .id = -1,
850 .dev = {
851 .platform_data = &mahimahi_lcdc_amoled_platform_data,
852 },
853};
854
855static struct platform_device mahimahi_lcdc_tft_device = {
856 .name = "msm_mdp_lcdc",
857 .id = -1,
858 .dev = {
859 .platform_data = &mahimahi_lcdc_tft_platform_data,
860 },
861};
862
863static int mahimahi_init_spi_hack(void)
864{
865 int ret;
866
867 spi_base = ioremap(MSM_SPI_PHYS, MSM_SPI_SIZE);
868 if (!spi_base)
869 return -1;
870
871 spi_clk = clk_get(&msm_device_spi.dev, "spi_clk");
872 if (IS_ERR(spi_clk)) {
873 pr_err("%s: unable to get spi_clk\n", __func__);
874 ret = PTR_ERR(spi_clk);
875 goto err_clk_get;
876 }
877
878 clk_enable(spi_clk);
879
880 printk("spi: SPI_CONFIG=%x\n", readl(spi_base + SPI_CONFIG));
881 printk("spi: SPI_IO_CONTROL=%x\n", readl(spi_base + SPI_IO_CONTROL));
882 printk("spi: SPI_OPERATIONAL=%x\n", readl(spi_base + SPI_OPERATIONAL));
883 printk("spi: SPI_ERROR_FLAGS_EN=%x\n",
884 readl(spi_base + SPI_ERROR_FLAGS_EN));
885 printk("spi: SPI_ERROR_FLAGS=%x\n", readl(spi_base + SPI_ERROR_FLAGS));
886 printk("-%s()\n", __FUNCTION__);
887 clk_disable(spi_clk);
888
889 return 0;
890
891err_clk_get:
892 iounmap(spi_base);
893 return ret;
894}
895
896static void mahimahi_brightness_set(struct led_classdev *led_cdev,
897 enum led_brightness val)
898{
899 unsigned long flags;
900 led_cdev->brightness = val;
901
902 spin_lock_irqsave(&brightness_lock, flags);
903 new_val = val;
904 spin_unlock_irqrestore(&brightness_lock, flags);
905
906 schedule_work(&brightness_delayed_work);
907}
908
909static void mahimahi_brightness_amoled_set_work(struct work_struct *work_ptr)
910{
911 unsigned long flags;
912 uint8_t val;
913
914 spin_lock_irqsave(&brightness_lock, flags);
915 val = new_val;
916 spin_unlock_irqrestore(&brightness_lock, flags);
917
918 mutex_lock(&panel_lock);
919 samsung_oled_set_gamma_val(val);
920 mutex_unlock(&panel_lock);
921}
922
923static void mahimahi_brightness_tft_set_work(struct work_struct *work_ptr)
924{
925 unsigned long flags;
926 uint8_t val;
927
928 spin_lock_irqsave(&brightness_lock, flags);
929 val = new_val;
930 spin_unlock_irqrestore(&brightness_lock, flags);
931
932 mutex_lock(&panel_lock);
933 sony_tft_set_pwm_val(val);
934 mutex_unlock(&panel_lock);
935}
936
937static struct led_classdev mahimahi_brightness_led = {
938 .name = "lcd-backlight",
939 .brightness = LED_FULL,
940 .brightness_set = mahimahi_brightness_set,
941};
942
943int __init mahimahi_init_panel(void)
944{
945 int ret;
946
947 if (!machine_is_mahimahi())
948 return 0;
949
950 if (system_rev > 0xC0) {
951 /* CDMA version (except for EVT1) supports RGB666 */
952 init_tablep = samsung_oled_rgb666_init_table;
953 init_table_sz = ARRAY_SIZE(samsung_oled_rgb666_init_table);
954 mahimahi_lcdc_fb_data.output_format = MSM_MDP_OUT_IF_FMT_RGB666;
955 }
956
957 ret = platform_device_register(&msm_device_mdp);
958 if (ret != 0)
959 return ret;
960
961 ret = mahimahi_init_spi_hack();
962 if (ret != 0)
963 return ret;
964
965 if (gpio_get_value(MAHIMAHI_GPIO_LCD_ID0)) {
966 pr_info("%s: tft panel\n", __func__);
967 vreg_lcm_rftx_2v6 = vreg_get(0, "rftx");
968 if (IS_ERR(vreg_lcm_rftx_2v6))
969 return PTR_ERR(vreg_lcm_rftx_2v6);
970 vreg_set_level(vreg_lcm_rftx_2v6, 2600);
971
972 vreg_lcm_aux_2v6 = vreg_get(0, "gp4");
973 if (IS_ERR(vreg_lcm_aux_2v6))
974 return PTR_ERR(vreg_lcm_aux_2v6);
975
976 if (gpio_get_value(MAHIMAHI_GPIO_LCD_RST_N))
977 tft_panel_on = 1;
978 ret = platform_device_register(&mahimahi_lcdc_tft_device);
979 INIT_WORK(&brightness_delayed_work, mahimahi_brightness_tft_set_work);
980 } else {
981 pr_info("%s: amoled panel\n", __func__);
982 ret = platform_device_register(&mahimahi_lcdc_amoled_device);
983 INIT_WORK(&brightness_delayed_work, mahimahi_brightness_amoled_set_work);
984 }
985
986 if (ret != 0)
987 return ret;
988
989 ret = led_classdev_register(NULL, &mahimahi_brightness_led);
990 if (ret != 0) {
991 pr_err("%s: Cannot register brightness led\n", __func__);
992 return ret;
993 }
994
995 return 0;
996}
997
998device_initcall(mahimahi_init_panel);