/*
* ld9040 AMOLED LCD panel driver.
*
* Copyright (c) 2011 Samsung Electronics
* Author: Donghwa Lee <dh09.lee@samsung.com>
* Derived from drivers/video/backlight/s6e63m0.c
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/backlight.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/lcd.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <linux/wait.h>
#include "ld9040_gamma.h"
#define SLEEPMSEC 0x1000
#define ENDDEF 0x2000
#define DEFMASK 0xFF00
#define COMMAND_ONLY 0xFE
#define DATA_ONLY 0xFF
#define MIN_BRIGHTNESS 0
#define MAX_BRIGHTNESS 24
struct ld9040 {
struct device *dev;
struct spi_device *spi;
unsigned int power;
unsigned int current_brightness;
struct lcd_device *ld;
struct backlight_device *bd;
struct lcd_platform_data *lcd_pd;
struct mutex lock;
bool enabled;
};
static struct regulator_bulk_data supplies[] = {
{ .supply = "vdd3", },
{ .supply = "vci", },
};
static void ld9040_regulator_enable(struct ld9040 *lcd)
{
int ret = 0;
struct lcd_platform_data *pd = NULL;
pd = lcd->lcd_pd;
mutex_lock(&lcd->lock);
if (!lcd->enabled) {
ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
if (ret)
goto out;
lcd->enabled = true;
}
msleep(pd->power_on_delay);
out:
mutex_unlock(&lcd->lock);
}
static void ld9040_regulator_disable(struct ld9040 *lcd)
{
int ret = 0;
mutex_lock(&lcd->lock);
if (lcd->enabled) {
ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
if (ret)
goto out;
lcd->enabled = false;
}
out:
mutex_unlock(&lcd->lock);
}
static const unsigned short seq_swreset[] = {
0x01, COMMAND_ONLY,
ENDDEF, 0x00
};
static const unsigned short seq_user_setting[] = {
0xF0, 0x5A,
DATA_ONLY, 0x5A,
ENDDEF, 0x00
};
static const unsigned short seq_elvss_on[] = {
0xB1, 0x0D,
DATA_ONLY, 0x00,
DATA_ONLY, 0x16,
ENDDEF, 0x00
};
static const unsigned short seq_gtcon[] = {
0xF7, 0x09,
DATA_ONLY, 0x00,
DATA_ONLY, 0x00,
ENDDEF, 0x00
};
static const unsigned short seq_panel_condition[] = {
0xF8, 0x05,
DATA_ONLY, 0x65,
DATA_ONLY, 0x96,
DATA_ONLY, 0x71,
DATA_ONLY, 0x7D,
DATA_ONLY, 0x19,
DATA_ONLY, 0x3B,
DATA_ONLY, 0x0D,
DATA_ONLY, 0x19,
DATA_ONLY, 0x7E,
DATA_ONLY, 0x0D,
DATA_ONLY, 0xE2,
DATA_ONLY, 0x00,
DATA_ONLY, 0x00,
DATA_ONLY, 0x7E,
DATA_ONLY, 0x7D,
DATA_ONLY, 0x07,
DATA_ONLY, 0x07,
DATA_ONLY, 0x20,
DATA_ONLY, 0x20,
DATA_ONLY, 0x20,
DATA_ONLY, 0x02,
DATA_ONLY, 0x02,
ENDDEF, 0x00
};
static const unsigned short seq_gamma_set1[] = {
0xF9, 0x00,
DATA_ONLY, 0xA7,
DATA_ONLY, 0xB4,
DATA_ONLY, 0xAE,
DATA_ONLY, 0xBF,
DATA_ONLY, 0x00,
DATA_ONLY, 0x91,
DATA_ONLY, 0x00,
DATA_ONLY, 0xB2,
DATA_ONLY, 0xB4,
DATA_ONLY, 0xAA,
DATA_ONLY, 0xBB,
DATA_ONLY, 0x00,
DATA_ONLY, 0xAC,
DATA_ONLY, 0x00,
DATA_ONLY, 0xB3,
DATA_ONLY, 0xB1,
DATA_ONLY, 0xAA,
DATA_ONLY, 0xBC,
DATA_ONLY, 0x00,
DATA_ONLY, 0xB3,
ENDDEF, 0x00
};
static const unsigned short seq_gamma_ctrl[] = {
0xFB, 0x02,
DATA_ONLY, 0x5A,
ENDDEF, 0x00
};
static const unsigned short seq_gamma_start[] = {
0xF9, COMMAND_ONLY,
ENDDEF, 0x00
};
static const unsigned short seq_apon[] = {
0xF3, 0x00,
DATA_ONLY, 0x00,
DATA_ONLY, 0x00,
DATA_ONLY, 0x0A,
DATA_ONLY, 0x02,
ENDDEF, 0x00
};
static const unsigned short seq_display_ctrl[] = {
0xF2, 0x02,
DATA_ONLY, 0x08,
DATA_ONLY, 0x08,
DATA_ONLY, 0x10,
DATA_ONLY, 0x10,
ENDDEF, 0x00
};
static const unsigned short seq_manual_pwr[] = {
0xB0, 0x04,
ENDDEF, 0x00
};
static const unsigned short seq_pwr_ctrl[] = {
0xF4, 0x0A,
DATA_ONLY, 0x87,
DATA_ONLY, 0x25,
DATA_ONLY, 0x6A,
DATA_ONLY, 0x44,
DATA_ONLY, 0x02,
DATA_ONLY, 0x88,
ENDDEF, 0x00
};
static const unsigned