/*
 * Hardware definitions for HP iPAQ Handheld Computers
 *
 * Copyright 2000-2003 Hewlett-Packard Company.
 *
 * Use consistent with the GNU GPL is permitted,
 * provided that this copyright notice is
 * preserved in its entirety in all copies and derived works.
 *
 * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
 * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
 * FITNESS FOR ANY PARTICULAR PURPOSE.
 *
 * Author: Jamey Hicks.
 *
 * History:
 *
 * 2004-03-01	Eddi De Pieri      Adapted for h4000 using h3900_lcd.c and 
 *                                 Shawn's functions
 * 2004-??-??	Shawn Anderson     Lcd hacking on h4000
 * 2003-05-14	Joshua Wise        Adapted for the HP iPAQ H1900
 * 2002-08-23   Jamey Hicks        Adapted for use with PXA250-based iPAQs
 * 2001-10-??   Andrew Christian   Added support for iPAQ H3800
 *                                 and abstracted EGPIO interface.
 *
 */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/lcd.h>
#include <linux/backlight.h>
#include <linux/fb.h>
#include <../drivers/video/pxafb.h>

#include <asm/hardware.h>
#include <asm/setup.h>

#include <asm/mach/arch.h>
#include <asm/arch/h3900_asic.h>
#include <asm/arch/ipaq.h>

#include "asic2_base.h"
#include "asic3_base.h"

extern struct platform_device h3900_asic2, h3900_asic3;

/*
  On screen enable, we get 
  
     h3800_lcd_power_on(1)
     LCD controller starts
     h3800_lcd_enable(1)

  On screen disable, we get
  
     h3800_lcd_enable(0)
     LCD controller stops
     h3800_lcd_power_on(0)
*/

static int h4000_lcd_set_power( struct lcd_device *lm, int setp )
{
        printk("%s: \n", __FUNCTION__);
	return 0;
}

static int h4000_lcd_get_power( struct lcd_device *lm )
{
        printk("%s: \n", __FUNCTION__);
	return 0;
}

static int h4000_lcd_set_enable( struct lcd_device *lm, int setp )
{
        printk("%s: \n", __FUNCTION__);
	return -EINVAL;	
}

static int h4000_lcd_get_enable( struct lcd_device *lm )
{
        printk("%s: \n", __FUNCTION__);
	return -EINVAL;		
}

static int h4000_backlight_set_power (struct backlight_device *bl, int on)
{
        printk("%s: backlight o%s\n", __FUNCTION__,
                                                on ? "n" : "ff",GAFR0_U);
	if (on) {
            // also CKEN[0] = 1 turns on PWM clock, mabey do that here too.
	    GAFR0_U |= 0x2;
    	    printk("%s: GAFR0_U |= 0x2, GAFR0_U=0x%x\n", __FUNCTION__, GAFR0_U);
            printk("%s: CKEN=0x%x\n", __FUNCTION__, CKEN);
	}
        else
	    GAFR0_U &= ~(0x2);

        return 0;
}

static int h4000_backlight_get_power (struct backlight_device *bl)
{
	printk("%s: \n", __FUNCTION__);
	if (GAFR0_U & 0x2)
    	    return 1;
	else
    	    return 0;
}

/*
 * LCCR0: 0x003008f9 -- ENB=0x1,  CMS=0x0, SDS=0x0, LDM=0x1,
 *                      SFM=0x1,  IUM=0x1, EFM=0x1, PAS=0x1,
 *                      res=0x0,  DPD=0x0, DIS=0x0, QDM=0x1,
 *                      PDD=0x0,  BM=0x1,  OUM=0x1, res=0x0
 * LCCR1: 0x13070cef -- BLW=0x13, ELW=0x7, HSW=0x3, PPL=0xef
 * LCCR2: 0x0708013f -- BFW=0x7,  EFW=0x8, VSW=0x0, LPP=0x13f
 * LCCR3: 0x04700008 -- res=0x0,  DPC=0x0, BPP=0x4, OEP=0x0, PCP=0x1
 *                      HSP=0x1,  VSP=0x1, API=0x0, ACD=0x0, PCD=0x8
 */

static struct pxafb_mach_info h4000_fb_info = {
        .pixclock     = 0,
        .bpp          = 16,         // BPP (0x4 == 16bits)
        .xres         = 240,        // PPL + 1
        .yres         = 320,        // LPP + 1
        .hsync_len    = 4,          // HSW + 1
        .vsync_len    = 1,          // VSW + 1
        .left_margin  = 20,         // BLW + 1
	.upper_margin = 8,          // BFW + 1
        .right_margin = 8,          // ELW + 1
        .lower_margin = 9,          // EFW + 1
	.sync         = 0,
        .lccr0 = (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM |
                  LCCR0_PAS | LCCR0_QDM | LCCR0_BM | LCCR0_OUM),
        .lccr3 = (LCCR3_HorSnchL | LCCR3_VrtSnchL | LCCR3_16BPP |
		  LCCR3_PCP | /*PCD */ 0x8)
};

static void *h4000_get_mach_info(struct lcd_device *lm)
{
	return (void *)&h4000_fb_info;
}

static struct lcd_device h4000_lcd_device = {
	.name          = "pxafb",
	.get_mach_info = h4000_get_mach_info,
	.set_power     = h4000_lcd_set_power,
	.get_power     = h4000_lcd_get_power,
	.set_enable    = h4000_lcd_set_enable,
	.get_enable    = h4000_lcd_get_enable,
};

static struct backlight_device h4000_backlight_device = {
	.name          = "pxafb",
	.set_power     = h4000_backlight_set_power,
	.get_power     = h4000_backlight_get_power,
};

static int
h4000_lcd_init (void)
{
	int rc = 0;
	
	if (! machine_is_h4000 ())
		return -ENODEV;

	rc = lcd_device_register(&h4000_lcd_device);
	if (rc)
		return rc;
	rc = backlight_device_register(&h4000_backlight_device);

	return rc;
}

static void
h4000_lcd_exit (void)
{
	lcd_device_unregister (&h4000_lcd_device);
	backlight_device_unregister (&h4000_backlight_device);
}

module_init (h4000_lcd_init);
module_exit (h4000_lcd_exit);

MODULE_AUTHOR(" ");
MODULE_DESCRIPTION("Framebuffer driver for iPAQ H4000");
MODULE_LICENSE("GPL");
