blob: f8244dcd1bca071d833a7427fc422e8e4be15d71 [file] [log] [blame]
/*
* Copyright (C) 2015 Marvell International Ltd.
* Fenghang Yin <yinfh@marvell.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <errno.h>
#include <common.h>
#include <command.h>
#include <asm/io.h>
#include <asm/gpio.h>
#include <linux/types.h>
#include <i2c.h>
#include <asm/gpio.h>
#include <power/oled_ssd1306.h>
/* extern const u8 char611v_I2COLED[96][7][2]; */
/* extern const u8 USB_Status[1][48][3]; */
/* extern const u8 External_Power_Status[1][16][4]; */
/* extern const u8 download_Status[2][32][4]; */
extern const u8 BatteryState[6][64][4];
extern const u8 logo[1][64][4];
extern const u8 Battery_Status[1][32][4];
/* static u8 ssd1306_DataBuf[DATABUF_SIZE_I2COLED] = {0}; */
static u8 ssd1306_battery_base_percent = 0xff;
static u8 ssd1306_battery_display_stage = 0;
static u8 is_ssd1306_present = 0;
static u8 get_display_percent(u8 percent);
static void battery_charging_display(u8 battery_stage);
/*
*
* Control byte
* Bit7 6 5 4 3 2 1 0
* Co D/C 0 0 0 0 0 0
*
* Co - Continuation bit
* If the Co is set as logic "0", the transmission of the following information
* will contain data bytes only.
*
* D/C - Data / Command selection bit
* The D/C# bit determines the next data byte is acted as a command or a data.
* If the D/C# bit is set to logic "0", it defines the following data byte as a command.
* If the D/C# bit is set to logic "1", it defines the following data byte as a data
* which will be stored at the GDDRAM. The GDDRAM column address pointer will be increased
* by one automatically after each data write.
*
*/
#define Control_Byte_Command 0x00 // Co - 0, D/C - 0
#define Control_Byte_Data 0x40 // Co - 0, D/C - 1
int ssd1306_i2c_write_cmd(u8 value)
{
int ret;
if (!is_ssd1306_present)
return 0;
i2c_set_bus_num(1);
ret = i2c_write(SSD1306_SLAVE_ADDR, Control_Byte_Command, 1, &value, 1);
if (ret) {
printf("[%s]: i2c write error\n", __func__);
}
return 0;
}
int ssd1306_i2c_write_data(u8 value)
{
int ret;
if (!is_ssd1306_present)
return 0;
i2c_set_bus_num(1);
ret = i2c_write(SSD1306_SLAVE_ADDR, Control_Byte_Data, 1, &value, 1);
if (ret) {
printf("[%s]: i2c write error\n", __func__);
}
return 0;
}
static void oled_detect(void)
{
u8 data;
int ret;
i2c_set_bus_num(1);
ret = i2c_read(SSD1306_SLAVE_ADDR, 0x0, 1, &data, 1);
if (!ret)
is_ssd1306_present = 1;
else
is_ssd1306_present = 0;
}
void ssd1306_set_column_addr(u8 addr_start, u8 addr_end)
{
if (is_ssd1306_present == 0)
return;
ssd1306_i2c_write_cmd(0x21);
ssd1306_i2c_write_cmd(addr_start);
ssd1306_i2c_write_cmd(addr_end);
}
void clear_screen(void)
{
u32 i, bytes_number = 128 * 8;
if (is_ssd1306_present == 0)
return;
ssd1306_set_column_addr(0x00, 0x7f);
for (i = 0; i < bytes_number; i++)
{
ssd1306_i2c_write_data(0x00);
}
ssd1306_i2c_write_cmd(I2COLED_Display_ON); /* set display on */
}
#if 0
void ssd1306_dis_defaultline(u32 page_start, u32 page_num, u32 p_coloum, u8 *str)
{
u32 i;
u32 index,size;
u32 char_index;
const u8 * char_buf;
if (is_ssd1306_present == 0)
return;
/**** (2)Map lib to Color Data ****/
index = 0;
while((index < DATABUF_SIZE_I2COLED) && (*str != 0))
{
char_index = *str -' ';
char_buf = (const u8 *)&char611v_I2COLED[char_index];
for (i = 0; i < char611v_CharSize; i++)
{
ssd1306_DataBuf[index++] = (*char_buf++);
}
//ssd1306_DataBuf[index++] =0x00; //add space
//ssd1306_DataBuf[index++] =0x00; //add space
str++;
}
/**** (3) write Data ****/
size = index;
//(1)set page limit
ssd1306_i2c_write_cmd(0x22);
ssd1306_i2c_write_cmd(page_start);
ssd1306_i2c_write_cmd((page_start + page_num-1));
//(2)set column limit
ssd1306_i2c_write_cmd(0x21);
ssd1306_i2c_write_cmd(p_coloum);
ssd1306_i2c_write_cmd((p_coloum + (size>>1)-1));
//(3)send data
for (i = 0; i < size; i++)
{
ssd1306_i2c_write_data(ssd1306_DataBuf[i]);
}
}
#endif
void ssd1306_fill_area(u32 page_start,
u32 page_num,
u32 p_coloum,
u32 p_width,
u8 fill_data,
u32 byte_num)
{
int i;
if (is_ssd1306_present == 0)
return;
/* set page limit */
ssd1306_i2c_write_cmd(0x22);
ssd1306_i2c_write_cmd(page_start);
ssd1306_i2c_write_cmd((page_start+page_num-1));
/* set column limit */
ssd1306_i2c_write_cmd(0x21);
ssd1306_i2c_write_cmd(p_coloum);
ssd1306_i2c_write_cmd((p_coloum+p_width-1));
/* send data */
for (i = 0; i < byte_num; i++)
{
ssd1306_i2c_write_data(fill_data);
}
}
void ssd1306_pic_display(u32 page_start,
u32 page_num,
u32 p_coloum,
u32 p_width,
const u8 *buf,
u32 byte_num)
{
u32 i;
if (is_ssd1306_present == 0)
return;
/* (1)set page limit */
ssd1306_i2c_write_cmd(0x22);
ssd1306_i2c_write_cmd(page_start);
ssd1306_i2c_write_cmd((page_start+page_num-1));
/* (2)set column limit */
ssd1306_i2c_write_cmd(0x21);
ssd1306_i2c_write_cmd(p_coloum);
ssd1306_i2c_write_cmd((p_coloum+p_width-1));
/* (3)send data */
for (i = 0; i < byte_num; i++)
{
ssd1306_i2c_write_data((*buf++));
}
}
static void battery_charging_display(u8 battery_stage)
{
if (is_ssd1306_present == 0)
return;
ssd1306_pic_display( ssd136_Battery_Charging_Page_Start,
ssd136_Battery_Charging_Page_Num,
ssd136_Battery_Charging_Coloum,
ssd136_Battery_Charging_Width,
(const u8 *)&BatteryState[battery_stage],
ssd136_Battery_Charging_Bytes_Num
);
}
static void show_battery_status(u8 choice)
{
if (is_ssd1306_present == 0)
return;
ssd1306_fill_area(0x2, 0x4, 0x20, 0x40, 0x00, (0x4*0x40));
ssd1306_pic_display( ssd136_Battery_status0_Page_Start,
ssd136_Battery_status0_Page_Num,
ssd136_Battery_status0_Coloum,
ssd136_Battery_status0_Width,
(const u8 *)&Battery_Status[choice],
ssd136_Battery_status0_Bytes_Num);
}
static u8 get_display_percent(u8 percent)
{
u8 stage;
#if 0
if (percent < 5) {
stage = 0;
} else if (percent < 26) {
stage = 1;
} else if (percent < 46) {
stage = 2;
} else if (percent < 66) {
stage = 3;
} else if (percent < 95) {
stage = 4;
} else {
stage = 5;
}
#else
if (percent < 20) {
stage = 0;
} else if (percent < 40) {
stage = 1;
} else if (percent < 60) {
stage = 2;
} else if (percent < 80) {
stage = 3;
} else if (percent < 100) {
stage = 4;
} else {
stage = 5;
}
#endif
if (ssd1306_battery_base_percent == 0xff)
{
ssd1306_battery_base_percent = stage;
ssd1306_battery_display_stage = ssd1306_battery_base_percent;
}
return stage;
}
void oled_show_bat_soc(u8 percent)
{
if (is_ssd1306_present == 0)
return;
get_display_percent(percent);
printf("percent: %d/100\n", percent);
battery_charging_display(ssd1306_battery_base_percent);
}
void oled_show_no_battery(void)
{
if (is_ssd1306_present == 0)
return;
show_battery_status(0);
}
void oled_show_mrvl_logo(u8 choice)
{
if (is_ssd1306_present == 0)
return;
ssd1306_pic_display( ssd136_LOGO0_Page_Start,
ssd136_LOGO0_Page_Num,
ssd136_LOGO0_Coloum,
ssd136_LOGO0_Width,
(const u8 *)&logo[choice],
ssd136_LOGO0_Bytes_Num);
}
#if 0
void display_bat_stat(u8 batpercent, u32 vbat_mv)
{
if (is_ssd1306_present == 0)
return;
get_display_percent(batpercent);
battery_charging_display(ssd1306_battery_base_percent);
}
void external_power_display(u8 choice)
{
if (is_ssd1306_present == 0)
return;
ssd1306_pic_display( ssd136_External_Power_status0_Page_Start,
ssd136_External_Power_status0_Page_Num,
ssd136_External_Power_status0_Coloum,
ssd136_External_Power_status0_Width,
(const u8 *)&External_Power_Status[choice],
ssd136_External_Power_status0_Bytes_Num);
}
void show_usb_status(u8 choice)
{
if (is_ssd1306_present == 0)
return;
ssd1306_pic_display( ssd136_USB_status0_Page_Start,
ssd136_USB_status0_Page_Num,
ssd136_USB_status0_Coloum,
ssd136_USB_status0_Width,
(const u8 *)&USB_Status[choice],
ssd136_USB_status0_Bytes_Num);
}
void show_external_power(void)
{
if (is_ssd1306_present == 0)
return;
external_power_display(0);
}
void show_onkey_bootup(void)
{
if (is_ssd1306_present == 0)
return;
ssd1306_pic_display(ssd136_LOGO0_Page_Start,
ssd136_LOGO0_Page_Num,
ssd136_LOGO0_Coloum,
ssd136_LOGO0_Width,
(const u8 *)&logo[0],
ssd136_LOGO0_Bytes_Num);
}
void show_battery_full(void)
{
if (is_ssd1306_present == 0)
return;
battery_charging_display(5);
}
#endif
void oled_show_bat_charging(u16 percent)
{
u8 update_stage;
if (is_ssd1306_present == 0)
return;
if (percent >= 100) {
battery_charging_display(5);
return;
}
update_stage = get_display_percent(percent);
if (ssd1306_battery_display_stage == 5)
ssd1306_battery_display_stage = ssd1306_battery_base_percent;
else
ssd1306_battery_display_stage++;
battery_charging_display(ssd1306_battery_display_stage);
if (update_stage > ssd1306_battery_base_percent)
ssd1306_battery_base_percent = update_stage;
}
int oled_i2c_init(void)
{
oled_detect();
if (!is_ssd1306_present) {
printf("SSD1306 OLED doesn't exsit\n");
return -ENODEV;
}
ssd1306_i2c_write_cmd(I2COLED_Display_OFF);
ssd1306_i2c_write_cmd(0x00);/* set lower column start address */
ssd1306_i2c_write_cmd(0x10);/* set higher column start address */
ssd1306_i2c_write_cmd(0x40);/* set display start line : 0x40+x_line*/
ssd1306_i2c_write_cmd(0x81);/* set contrast control register */
ssd1306_i2c_write_cmd(0x7f);
ssd1306_i2c_write_cmd(0xa1);/* set column remap */
ssd1306_i2c_write_cmd(0xa6);/* set normal control */
ssd1306_i2c_write_cmd(0xa8);/* set multiplex ratio */
ssd1306_i2c_write_cmd(63);
ssd1306_i2c_write_cmd(0xd3);/* set display offset */
ssd1306_i2c_write_cmd(0x00);
ssd1306_i2c_write_cmd(0xd5);/* set display clock divide ratio/oscillator frequancy */
ssd1306_i2c_write_cmd(0x80);
ssd1306_i2c_write_cmd(0xda);/* set com configuration */
ssd1306_i2c_write_cmd(0x12);//0x12 is nomarl
ssd1306_i2c_write_cmd(0x8d);/* interal dc-dc */
ssd1306_i2c_write_cmd(0x14);
SSD1306_Cmd_1Para(ScanModeSet, SCAN_In_vertical);
return 0;
}
void oled_display_off(void)
{
ssd1306_i2c_write_cmd(I2COLED_Display_OFF);
}
void oled_power_up(void)
{
gpio_direction_output(OLED_RST, 1);
udelay(3);
gpio_direction_output(OLED_RST, 0);
udelay(3);
gpio_direction_output(OLED_RST, 1);
mdelay(100);
}
void oled_power_off(void)
{
//step1. turn off vcc and delay 100ms
//step2. turn off vdd
}
void oled_init(void)
{
int ret;
oled_power_up();
ret = oled_i2c_init();
if (ret != 0)
return;
clear_screen();
}
void test_i2c_oled(void)
{
oled_power_up();
oled_i2c_init();
clear_screen();
ssd1306_i2c_write_cmd(I2COLED_Display_ON);/* set display on */
#if 0
ssd1306_dis_defaultline(0, 2, 0, (u8 *)"ABCDEFGHIJKLMNO");
ssd1306_dis_defaultline(2, 2, 0, (u8 *)"abcdefghijklmnopq");
ssd1306_dis_defaultline(4, 2, 0, (u8 *)"BCDEFGHIJKLMNO");
ssd1306_dis_defaultline(6, 2, 0, (u8 *)"UVWXYZxyz!%");
printf("show logo\n");
oled_show_logo(0);
mdelay(1000);
printf("show no battery\n");
show_no_battery();
mdelay(1000);
printf("external_power_display\n");
show_external_power();
mdelay(1000);
printf("onkey_bootup\n");
show_onkey_bootup();
mdelay(1000);
printf("onkey_bootup\n");
show_onkey_bootup();
mdelay(1000);
printf("oled_show_bat_charging 5\n");
oled_show_bat_charging(5);
mdelay(1000);
printf("oled_show_bat_charging 5\n");
oled_show_bat_charging(5);
mdelay(1000);
printf("oled_show_bat_charging 5\n");
oled_show_bat_charging(5);
mdelay(1000);
printf("oled_show_bat_charging 5\n");
oled_show_bat_charging(5);
mdelay(1000);
printf("oled_show_bat_charging 5\n");
oled_show_bat_charging(5);
mdelay(1000);
printf("oled_show_bat_charging 15\n");
oled_show_bat_charging(15);
mdelay(1000);
printf("oled_show_bat_charging 25\n");
oled_show_bat_charging(25);
mdelay(1000);
printf("oled_show_bat_charging 35\n");
oled_show_bat_charging(35);
mdelay(1000);
printf("oled_show_bat_charging 45\n");
oled_show_bat_charging(45);
mdelay(1000);
printf("oled_show_bat_charging 55\n");
oled_show_bat_charging(55);
mdelay(1000);
printf("oled_show_bat_charging 65\n");
oled_show_bat_charging(65);
mdelay(1000);
printf("oled_show_bat_charging 75\n");
oled_show_bat_charging(75);
mdelay(1000);
printf("oled_show_bat_charging 85\n");
oled_show_bat_charging(85);
mdelay(1000);
printf("oled_show_bat_charging 95\n");
oled_show_bat_charging(95);
mdelay(1000);
printf("oled_show_bat_charging 99\n");
oled_show_bat_charging(99);
mdelay(1000);
printf("oled_show_bat_charging 5\n");
oled_show_bat_charging(5);
mdelay(1000);
printf("oled_show_bat_charging 5\n");
oled_show_bat_charging(5);
mdelay(1000);
printf("oled_show_bat_charging 5\n");
oled_show_bat_charging(5);
mdelay(1000);
printf("oled_show_bat_charging 5\n");
oled_show_bat_charging(5);
mdelay(1000);
printf("oled_show_bat_charging 5\n");
oled_show_bat_charging(5);
mdelay(1000);
printf("oled_show_bat_charging 15\n");
oled_show_bat_charging(15);
mdelay(1000);
printf("oled_show_bat_charging 25\n");
oled_show_bat_charging(25);
mdelay(1000);
printf("oled_show_bat_charging 35\n");
oled_show_bat_charging(35);
mdelay(1000);
#endif
}
static int do_oled_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
test_i2c_oled();
return 0;
}
U_BOOT_CMD(
ioled, 1, 1, do_oled_test,
"turn on oled and test oled\n",
""
);