From a5ad3f8a7223c7f8dd17ddc57c1a018ba4d62835 Mon Sep 17 00:00:00 2001 From: Michael Sparmann Date: Sun, 14 Nov 2010 15:29:05 +0000 Subject: iPod Nano 2G: Implement LCD sleep (FS#11604 by Franz-Josef Haider), adds up to 5 hours of battery life git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28591 a1c6a512-1295-4272-9138-f99709370657 --- firmware/export/config/ipodnano2g.h | 13 +- .../arm/s5l8700/ipodnano2g/backlight-nano2g.c | 11 + .../target/arm/s5l8700/ipodnano2g/lcd-nano2g.c | 490 +++++++++++++++++++-- 3 files changed, 479 insertions(+), 35 deletions(-) diff --git a/firmware/export/config/ipodnano2g.h b/firmware/export/config/ipodnano2g.h index 6797187023..2cc3cecc6c 100644 --- a/firmware/export/config/ipodnano2g.h +++ b/firmware/export/config/ipodnano2g.h @@ -45,9 +45,6 @@ /* define this to enable JPEG decoding */ #define HAVE_JPEG -/* define this if the LCD can shut down */ -#define HAVE_LCD_SHUTDOWN - /* define this if you can invert the colours on your LCD */ //#define HAVE_LCD_INVERT @@ -92,12 +89,18 @@ #define LCD_DEPTH 16 /* pseudo 262.144 colors */ #define LCD_PIXELFORMAT RGB565 /* rgb565 */ +/* Define this if the LCD can shut down */ +#define HAVE_LCD_SHUTDOWN + /* Define this if your LCD can be enabled/disabled */ -//#define HAVE_LCD_ENABLE +#define HAVE_LCD_ENABLE /* Define this if your LCD can be put to sleep. HAVE_LCD_ENABLE should be defined as well. */ -//#define HAVE_LCD_SLEEP +#ifndef BOOTLOADER +#define HAVE_LCD_SLEEP +#define HAVE_LCD_SLEEP_SETTING +#endif #define CONFIG_KEYPAD IPOD_4G_PAD diff --git a/firmware/target/arm/s5l8700/ipodnano2g/backlight-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/backlight-nano2g.c index 705b5858bf..060dcccae4 100644 --- a/firmware/target/arm/s5l8700/ipodnano2g/backlight-nano2g.c +++ b/firmware/target/arm/s5l8700/ipodnano2g/backlight-nano2g.c @@ -21,10 +21,15 @@ #include #include "config.h" +#include "kernel.h" #include "backlight.h" #include "backlight-target.h" #include "pmu-target.h" +#ifdef HAVE_LCD_SLEEP +void lcd_awake(void); +void lcd_update(void); +#endif void _backlight_set_brightness(int brightness) { @@ -33,6 +38,12 @@ void _backlight_set_brightness(int brightness) void _backlight_on(void) { + if(pmu_read(0x29) == 1) return; +#ifdef HAVE_LCD_SLEEP + lcd_awake(); + lcd_update(); + sleep(HZ/10); +#endif pmu_write(0x29, 1); } diff --git a/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c index 0600c77b62..f2d0c3458f 100644 --- a/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c +++ b/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c @@ -57,13 +57,341 @@ #define R_ROW_ADDR_SET 0x2b #define R_MEMORY_WRITE 0x2c - /** globals **/ int lcd_type; /* also needed in debug-s5l8700.c */ static int xoffset; /* needed for flip */ - -/** hardware access functions */ +static bool lcd_ispowered; + +#ifdef HAVE_LCD_SLEEP + +#define SLEEP 0 +#define CMD8 1 +#define CMD16 2 +#define DATA8 3 +#define DATA16 4 + +unsigned short lcd_init_sequence_0[] = { + CMD16, 0x00a4, + DATA16, 0x0001, + SLEEP, 0x0000, + CMD16, 0x0001, + DATA16, 0x0100, + CMD16, 0x0002, + DATA16, 0x0300, + CMD16, 0x0003, + DATA16, 0x1230, + CMD16, 0x0008, + DATA16, 0x0404, + CMD16, 0x0008, + DATA16, 0x0404, + CMD16, 0x000e, + DATA16, 0x0010, + CMD16, 0x0070, + DATA16, 0x1000, + CMD16, 0x0071, + DATA16, 0x0001, + CMD16, 0x0030, + DATA16, 0x0002, + CMD16, 0x0031, + DATA16, 0x0400, + CMD16, 0x0032, + DATA16, 0x0007, + CMD16, 0x0033, + DATA16, 0x0500, + CMD16, 0x0034, + DATA16, 0x0007, + CMD16, 0x0035, + DATA16, 0x0703, + CMD16, 0x0036, + DATA16, 0x0507, + CMD16, 0x0037, + DATA16, 0x0005, + CMD16, 0x0038, + DATA16, 0x0407, + CMD16, 0x0039, + DATA16, 0x000e, + CMD16, 0x0040, + DATA16, 0x0202, + CMD16, 0x0041, + DATA16, 0x0003, + CMD16, 0x0042, + DATA16, 0x0000, + CMD16, 0x0043, + DATA16, 0x0200, + CMD16, 0x0044, + DATA16, 0x0707, + CMD16, 0x0045, + DATA16, 0x0407, + CMD16, 0x0046, + DATA16, 0x0505, + CMD16, 0x0047, + DATA16, 0x0002, + CMD16, 0x0048, + DATA16, 0x0004, + CMD16, 0x0049, + DATA16, 0x0004, + CMD16, 0x0060, + DATA16, 0x0202, + CMD16, 0x0061, + DATA16, 0x0003, + CMD16, 0x0062, + DATA16, 0x0000, + CMD16, 0x0063, + DATA16, 0x0200, + CMD16, 0x0064, + DATA16, 0x0707, + CMD16, 0x0065, + DATA16, 0x0407, + CMD16, 0x0066, + DATA16, 0x0505, + CMD16, 0x0068, + DATA16, 0x0004, + CMD16, 0x0069, + DATA16, 0x0004, + CMD16, 0x0007, + DATA16, 0x0001, + CMD16, 0x0018, + DATA16, 0x0001, + CMD16, 0x0010, + DATA16, 0x1690, + CMD16, 0x0011, + DATA16, 0x0100, + CMD16, 0x0012, + DATA16, 0x0117, + CMD16, 0x0013, + DATA16, 0x0f80, + CMD16, 0x0012, + DATA16, 0x0137, + CMD16, 0x0020, + DATA16, 0x0000, + CMD16, 0x0021, + DATA16, 0x0000, + CMD16, 0x0050, + DATA16, 0x0000, + CMD16, 0x0051, + DATA16, 0x00af, + CMD16, 0x0052, + DATA16, 0x0000, + CMD16, 0x0053, + DATA16, 0x0083, + CMD16, 0x0090, + DATA16, 0x0003, + CMD16, 0x0091, + DATA16, 0x0000, + CMD16, 0x0092, + DATA16, 0x0101, + CMD16, 0x0098, + DATA16, 0x0400, + CMD16, 0x0099, + DATA16, 0x1302, + CMD16, 0x009a, + DATA16, 0x0202, + CMD16, 0x009b, + DATA16, 0x0200, + SLEEP, 0x0000, + CMD16, 0x0007, + DATA16, 0x0021, + CMD16, 0x0012, + DATA16, 0x0137, + SLEEP, 0x0000, + CMD16, 0x0007, + DATA16, 0x0021, + CMD16, 0x0012, + DATA16, 0x1137, + SLEEP, 0x0000, + CMD16, 0x0007, + DATA16, 0x0233, +}; + +unsigned short lcd_init_sequence_1[] = { + CMD8, 0x01, + DATA8, 0x00, + SLEEP, 0, + CMD8, 0xB1, + DATA8, 0x16, + DATA8, 0x03, + CMD8, 0xB2, + DATA8, 0x17, + DATA8, 0x03, + CMD8, 0xB4, + DATA8, 0x00, + CMD8, 0xB6, + DATA8, 0x01, + CMD8, 0xB7, + DATA8, 0x00, + DATA8, 0x00, + DATA8, 0x02, + DATA8, 0x00, + DATA8, 0x06, + DATA8, 0x26, + DATA8, 0x2D, + DATA8, 0x27, + DATA8, 0x55, + DATA8, 0x27, + CMD8, 0xB8, + DATA8, 0x10, + CMD8, 0xB9, + DATA8, 0x52, + DATA8, 0x12, + DATA8, 0x03, + CMD8, 0xC0, + DATA8, 0x0A, + DATA8, 0x10, + DATA8, 0x10, + CMD8, 0xC2, + DATA8, 0x14, + DATA8, 0x23, + CMD8, 0xC3, + DATA8, 0x12, + DATA8, 0x23, + CMD8, 0xC6, + DATA8, 0x48, + CMD8, 0xE0, + DATA8, 0x20, + DATA8, 0x71, + DATA8, 0x17, + DATA8, 0x09, + DATA8, 0x70, + DATA8, 0x0C, + DATA8, 0x13, + DATA8, 0x25, + CMD8, 0xE1, + DATA8, 0x37, + DATA8, 0x00, + DATA8, 0x63, + DATA8, 0x11, + DATA8, 0xD9, + DATA8, 0x00, + DATA8, 0x12, + DATA8, 0x01, + CMD8, 0xE2, + DATA8, 0x42, + DATA8, 0x42, + DATA8, 0x60, + DATA8, 0x08, + DATA8, 0xB4, + DATA8, 0x07, + DATA8, 0x0E, + DATA8, 0x90, + CMD8, 0xE3, + DATA8, 0x47, + DATA8, 0x60, + DATA8, 0x66, + DATA8, 0x09, + DATA8, 0x6A, + DATA8, 0x02, + DATA8, 0x0E, + DATA8, 0x09, + CMD8, 0xE4, + DATA8, 0x11, + DATA8, 0x40, + DATA8, 0x03, + DATA8, 0x0A, + DATA8, 0xC1, + DATA8, 0x0D, + DATA8, 0x17, + DATA8, 0x30, + CMD8, 0xE5, + DATA8, 0x00, + DATA8, 0x30, + DATA8, 0x77, + DATA8, 0x1C, + DATA8, 0xFB, + DATA8, 0x00, + DATA8, 0x13, + DATA8, 0x07, + CMD8, 0xE6, + DATA8, 0x01, + CMD8, 0x35, + DATA8, 0x00, + CMD8, 0x36, + DATA8, 0x00, + CMD8, 0xF2, + DATA8, 0x40, + CMD8, 0xF3, + DATA8, 0x50, + CMD8, 0xFB, + DATA8, 0x01, + CMD8, 0x11, + DATA8, 0x00, + SLEEP, 0, + CMD8, 0x3A, + DATA8, 0x65, + CMD8, 0x29, + DATA8, 0x00, +}; + +unsigned short lcd_init_sequence_2[] = { + CMD8, 0x01, + SLEEP, 0, + CMD8, 0x11, + SLEEP, 0, + CMD8, 0x3a, + DATA8, 0x65, + CMD8, 0xab, + CMD8, 0x35, + DATA8, 0x00, + CMD8, 0xf2, + DATA8, 0x01, + CMD8, 0xe0, + DATA8, 0x71, + DATA8, 0x76, + DATA8, 0x25, + DATA8, 0x01, + DATA8, 0xa5, + DATA8, 0x09, + DATA8, 0x15, + DATA8, 0x11, + CMD8, 0xe1, + DATA8, 0x40, + DATA8, 0x21, + DATA8, 0x64, + DATA8, 0x13, + DATA8, 0xf3, + DATA8, 0x0b, + DATA8, 0x00, + DATA8, 0x00, + CMD8, 0xe2, + DATA8, 0x71, + DATA8, 0x65, + DATA8, 0x24, + DATA8, 0x08, + DATA8, 0x97, + DATA8, 0x01, + DATA8, 0x15, + DATA8, 0x11, + CMD8, 0xe3, + DATA8, 0x51, + DATA8, 0x01, + DATA8, 0x62, + DATA8, 0x13, + DATA8, 0xf3, + DATA8, 0x0b, + DATA8, 0x00, + DATA8, 0x00, + CMD8, 0xe4, + DATA8, 0x71, + DATA8, 0x57, + DATA8, 0x31, + DATA8, 0x01, + DATA8, 0x82, + DATA8, 0x04, + DATA8, 0x1f, + DATA8, 0x11, + CMD8, 0xe5, + DATA8, 0x64, + DATA8, 0x41, + DATA8, 0x64, + DATA8, 0x19, + DATA8, 0xb3, + DATA8, 0x09, + DATA8, 0x00, + DATA8, 0x00, + CMD8, 0x29, +}; + +#endif /* HAVE_LCD_SLEEP */ static inline void s5l_lcd_write_cmd_data(int cmd, int data) { @@ -84,7 +412,21 @@ static inline void s5l_lcd_write_cmd(unsigned short cmd) LCD_WCMD = cmd; } -static inline void s5l_lcd_write_data(int data) +static inline void s5l_lcd_write_wcmd(unsigned short cmd) +{ + while (LCD_STATUS & 0x10); + LCD_WCMD = cmd >> 8; + while (LCD_STATUS & 0x10); + LCD_WCMD = cmd & 0xff; +} + +static inline void s5l_lcd_write_data(unsigned short data) +{ + while (LCD_STATUS & 0x10); + LCD_WDATA = data & 0xff; +} + +static inline void s5l_lcd_write_wdata(unsigned short data) { while (LCD_STATUS & 0x10); LCD_WDATA = data >> 8; @@ -125,6 +467,89 @@ void lcd_set_flip(bool yesno) } } +bool lcd_active(void) +{ + return lcd_ispowered; +} + +#ifdef HAVE_LCD_SLEEP + +void lcd_wakeup(void) +{ + unsigned short *lcd_init_sequence; + unsigned int lcd_init_sequence_length; + int type = lcd_type; + + pmu_ldo_set_voltage(2, 17); + PWRCONEXT &= ~0x80; + PCON2 = 0x33333333; + PCON3 = 0x11113333; + PCON4 = 0x33333333; + PCON13 &= ~0xf; /* Set pin 0 to input */ + PCON14 &= ~0xf0; /* Set pin 1 to input */ + + if((((PDAT13 & 1) == 1) && ((PDAT14 & 2) == 2))|| + (((PDAT13 & 1) == 0) && ((PDAT14 & 2) == 0))) + { + type = 2; /* there is a third lcd type which behaves like type 7 (LDS176) but needs to be initialized differently */ + } + + if(type == 0) + { + lcd_init_sequence = lcd_init_sequence_0; + lcd_init_sequence_length = (sizeof(lcd_init_sequence_0) - 1)/sizeof(unsigned short); + } + else if(type == 1) + { + lcd_init_sequence = lcd_init_sequence_1; + lcd_init_sequence_length = (sizeof(lcd_init_sequence_1) - 1)/sizeof(unsigned short); + } + else + { + lcd_init_sequence = lcd_init_sequence_2; + lcd_init_sequence_length = (sizeof(lcd_init_sequence_2) - 1)/sizeof(unsigned short); + } + + /* reset the lcd chip */ + + LCD_RST_TIME = 0x7FFF; + LCD_DRV_RST = 0; + sleep(0); + LCD_DRV_RST = 1; + sleep(HZ / 100); + + for(unsigned int i=0;i