arch/arm/mach-pxa/Kconfig | 5 arch/arm/mach-pxa/Makefile | 2 arch/arm/mach-pxa/tosa.c | 49 +++++- arch/arm/mach-pxa/tosa_lcd.c | 344 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 396 insertions(+), 4 deletions(-) Index: git/arch/arm/mach-pxa/Makefile =================================================================== --- git.orig/arch/arm/mach-pxa/Makefile 2006-11-07 22:13:10.000000000 +0000 +++ git/arch/arm/mach-pxa/Makefile 2006-11-07 23:29:38.000000000 +0000 @@ -17,7 +17,7 @@ obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o spitz_pm.o obj-$(CONFIG_MACH_AKITA) += akita-ioexp.o obj-$(CONFIG_MACH_POODLE) += poodle.o corgi_ssp.o sharpsl_pm.o poodle_pm.o -obj-$(CONFIG_MACH_TOSA) += tosa.o sharpsl_pm.o tosa_pm.o +obj-$(CONFIG_MACH_TOSA) += tosa.o sharpsl_pm.o tosa_pm.o tosa_lcd.o obj-$(CONFIG_MACH_HX2750) += hx2750.o hx2750_test.o # Support for blinky lights Index: git/arch/arm/mach-pxa/tosa_lcd.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ git/arch/arm/mach-pxa/tosa_lcd.c 2006-11-07 23:29:25.000000000 +0000 @@ -0,0 +1,344 @@ +/* + * LCD / Backlight control code for Sharp SL-6000x (tosa) + * + * Copyright (c) 2005 Dirk Opfer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/fb.h> + +#include <asm/mach/sharpsl_param.h> +#include <asm/hardware.h> +#include <asm/hardware/scoop.h> +#include <asm/hardware/tmio.h> +#include <asm/arch/ssp.h> +#include <asm/arch/sharpsl.h> +#include <asm/arch/tosa.h> +#include <asm/arch/pxa-regs.h> + +#define DAC_BASE 0x4e +#define DAC_CH1 0 +#define DAC_CH2 1 + +#define TG_REG0_VQV 0x0001 +#define TG_REG0_COLOR 0x0002 +#define TG_REG0_UD 0x0004 +#define TG_REG0_LR 0x0008 +#define COMADJ_DEFAULT 97 +#define TOSA_LCD_I2C_DEVICEID 0x4711 // Fixme: new value + +static void tosa_lcd_tg_init(struct device *dev); +static void tosa_lcd_tg_on(struct device *dev, const struct fb_videomode *mode); +static void tosa_lcd_tg_off(struct device *dev); +static void tosa_set_backlight(int intensity); + +const static struct tmio_lcd_ops tosa_tc6393_lcd_ops = { + .init = tosa_lcd_tg_init, + .tg_on = tosa_lcd_tg_on, + .tg_off = tosa_lcd_tg_off, +}; + +static struct platform_device *tosabl_device; +static struct i2c_driver tosa_driver; +static struct i2c_client* tosa_i2c_dac; +static int initialised; +static int comadj; +static int bl_intensity; +static struct ssp_dev tosa_nssp_dev; +static struct ssp_state tosa_nssp_state; +static spinlock_t tosa_nssp_lock; + +static unsigned short normal_i2c[] = { + DAC_BASE, + I2C_CLIENT_END +}; +I2C_CLIENT_INSMOD; + +static struct corgibl_machinfo tosa_bl_machinfo = { + .max_intensity = 255, + .default_intensity = 68, + .limit_mask = 0x0b, + .set_bl_intensity = tosa_set_backlight, +}; + +int tosa_bl_intensity(void) +{ + return bl_intensity; +} + +static void pxa_nssp_output(unsigned char reg, unsigned char data) +{ + unsigned long flag, dummy; + u32 dat = ( ((reg << 5) & 0xe0) | (data & 0x1f) ); + spin_lock_irqsave(&tosa_nssp_lock, flag); + + ssp_config(&tosa_nssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), 0, 0, SSCR0_SerClkDiv(128)); + ssp_enable(&tosa_nssp_dev); + + ssp_write_word(&tosa_nssp_dev,dat); + + /* Read null data back from device to prevent SSP overflow */ + ssp_read_word(&tosa_nssp_dev, &dummy); + ssp_disable(&tosa_nssp_dev); + spin_unlock_irqrestore(&tosa_nssp_lock, flag); + +} + +static void tosa_set_backlight(int intensity) +{ + if (!tosa_i2c_dac) + return; + + bl_intensity = intensity; + /* SetBacklightDuty */ + i2c_smbus_write_byte_data(tosa_i2c_dac, DAC_CH2, (unsigned char)intensity); + + /* SetBacklightVR */ + if (intensity) + set_tc6393_gpio(&tc6393_device.dev,TOSA_TC6393_BL_C20MA); + else + reset_tc6393_gpio(&tc6393_device.dev,TOSA_TC6393_BL_C20MA); + + /* bl_enable GP04=1 otherwise GP04=0*/ + pxa_nssp_output(TG_GPODR2, intensity ? 0x01 : 0x00); +} + +static void tosa_lcd_tg_init(struct device *dev) +{ + /* L3V On */ + set_scoop_gpio( &tosascoop_jc_device.dev,TOSA_SCOOP_JC_TC3693_L3V_ON); + mdelay(60); + + /* TG On */ + reset_tc6393_gpio(&tc6393_device.dev,TOSA_TC6393_TG_ON); + mdelay(60); + + pxa_nssp_output(TG_TPOSCTL,0x00); /* delayed 0clk TCTL signal for VGA */ + pxa_nssp_output(TG_GPOSR,0x02); /* GPOS0=powercontrol, GPOS1=GPIO, GPOS2=TCTL */ +} + +static void tosa_lcd_tg_on(struct device *dev, const struct fb_videomode *mode) +{ + const int value = TG_REG0_COLOR | TG_REG0_UD | TG_REG0_LR; + pxa_nssp_output(TG_PNLCTL, value | (mode->yres == 320 ? 0 : TG_REG0_VQV)); + + /* TG LCD pannel power up */ + pxa_nssp_output(TG_PINICTL,0x4); + mdelay(50); + + /* TG LCD GVSS */ + pxa_nssp_output(TG_PINICTL,0x0); + + if (!initialised) + { + /* after the pannel is powered up the first time, we can access the i2c bus */ + /* so probe for the DAC */ + i2c_add_driver(&tosa_driver); + initialised = 1; + mdelay(50); + } + if (tosa_i2c_dac) + /* set common voltage */ + i2c_smbus_write_byte_data(tosa_i2c_dac, DAC_CH1, comadj); + +} + +static void tosa_lcd_tg_off(struct device *dev) +{ + /* TG LCD VHSA off */ + pxa_nssp_output(TG_PINICTL,0x4); + mdelay(50); + + /* TG LCD signal off */ + pxa_nssp_output(TG_PINICTL,0x6); + mdelay(50); + + /* TG Off */ + set_tc6393_gpio(&tc6393_device.dev, TOSA_TC6393_TG_ON); + mdelay(100); + + /* L3V Off */ + reset_scoop_gpio( &tosascoop_jc_device.dev,TOSA_SCOOP_JC_TC3693_L3V_ON); +} + +static int tosa_detect_client(struct i2c_adapter* adapter, int address, int kind) { + int err = 0; + + printk("Tosa-LCD: DAC detected address:0x%2.2x\n",address); + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA )) + goto ERROR0; + + if (!(tosa_i2c_dac = (struct i2c_client*)kzalloc(sizeof(*tosa_i2c_dac), GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR0; + } + + //i2c_set_clientdata(tosa_i2c_dac, data); + tosa_i2c_dac->addr = address; + tosa_i2c_dac->adapter = adapter; + tosa_i2c_dac->driver = &tosa_driver; + tosa_i2c_dac->dev.parent = &tc6393_device.dev; + strcpy(tosa_i2c_dac->name, "tosa lcd"); + if ((err = i2c_attach_client(tosa_i2c_dac))) + goto ERROR3; + + /* Now i2c is ready, allocate the backlight device*/ + tosabl_device = platform_device_alloc("corgi-bl", -1); + if (!tosabl_device) { + err = -ENOMEM; + goto ERROR4; + } + + /* set parent device */ + tosabl_device->dev.parent = &tosa_i2c_dac->dev; + tosabl_device->dev.platform_data = &tosa_bl_machinfo; + + err = platform_device_add(tosabl_device); + + if (err) + platform_device_put(tosabl_device); + + /* set common voltage */ + i2c_smbus_write_byte_data(tosa_i2c_dac, DAC_CH1, comadj); + + return 0; +ERROR4: + i2c_detach_client(tosa_i2c_dac); +ERROR3: + kfree(tosa_i2c_dac); +ERROR0: + return err; +} + +static int tosa_attach_adapter(struct i2c_adapter* adapter) { + return i2c_probe(adapter, &addr_data, &tosa_detect_client); +} + +static int tosa_detach_client(struct i2c_client* client) { + int err; + + if ((err = i2c_detach_client(client))) { + printk(KERN_ERR "tosa: Cannot deregister client\n"); + return err; + } + kfree(client); + return 0; +} + +static struct i2c_driver tosa_driver={ + .id = TOSA_LCD_I2C_DEVICEID, + .attach_adapter = tosa_attach_adapter, + .detach_client = tosa_detach_client, +}; + +static int __init tosa_lcd_probe(struct platform_device *pdev) +{ + int ret; + spin_lock_init(&tosa_nssp_lock); + + if (!pdev->dev.platform_data) + return -EINVAL; + + /* Set Common Voltage */ + comadj = sharpsl_param.comadj == -1 ? COMADJ_DEFAULT : sharpsl_param.comadj; + + ret=ssp_init(&tosa_nssp_dev,2,0); + + /* initialize SSP */ + pxa_gpio_mode(GPIO83_NSSP_TX); + pxa_gpio_mode(GPIO81_NSSP_CLK_OUT); + pxa_gpio_mode(GPIO82_NSSP_FRM_OUT); + + if (ret) + printk(KERN_ERR "Unable to register NSSP handler!\n"); + else { + struct tmio_lcd_ops* *tmio_ops = pdev->dev.platform_data; + ssp_disable(&tosa_nssp_dev); + initialised = 0; + + /* Set the lcd functions */ + *tmio_ops = (struct tmio_lcd_ops*) &tosa_tc6393_lcd_ops; + } + + return ret; +} + +static int tosa_lcd_remove(struct platform_device *pdev) +{ + /* delete the lcd functions */ + struct tmio_lcd_ops* *tmio_ops = pdev->dev.platform_data; + *tmio_ops = NULL; + + ssp_exit(&tosa_nssp_dev); + + if (tosa_i2c_dac) { + i2c_detach_client(tosa_i2c_dac); + kfree(tosa_i2c_dac); + } + + return 0; +} + +#ifdef CONFIG_PM + +static int tosa_lcd_suspend(struct platform_device *pdev, pm_message_t state) +{ + ssp_flush(&tosa_nssp_dev); + ssp_save_state(&tosa_nssp_dev,&tosa_nssp_state); + return 0; +} + +static int tosa_lcd_resume(struct platform_device *pdev) +{ + printk("tosa_lcd_resume\n"); + ssp_restore_state(&tosa_nssp_dev,&tosa_nssp_state); + ssp_enable(&tosa_nssp_dev); + printk("tosa_lcd_resume ok\n"); + return 0; +} +#else + +#define tosa_lcd_suspend NULL +#define tosa_lcd_resume NULL + +#endif + + +static struct platform_driver tosalcd_driver = { + .probe = tosa_lcd_probe, + .remove = tosa_lcd_remove, + .suspend = tosa_lcd_suspend, + .resume = tosa_lcd_resume, + .driver = { + .name = "tosa-lcd", + }, +}; + +static int __init tosa_lcd_init(void) +{ + return platform_driver_register(&tosalcd_driver); +} + +static void __exit tosa_lcd_cleanup (void) +{ + platform_driver_unregister (&tosalcd_driver); +} + +device_initcall(tosa_lcd_init); +module_exit (tosa_lcd_cleanup); + +MODULE_DESCRIPTION ("Tosa LCD device"); +MODULE_AUTHOR ("Dirk Opfer"); +MODULE_LICENSE ("GPL v2"); Index: git/arch/arm/mach-pxa/tosa.c =================================================================== --- git.orig/arch/arm/mach-pxa/tosa.c 2006-11-07 22:13:10.000000000 +0000 +++ git/arch/arm/mach-pxa/tosa.c 2006-11-07 23:29:38.000000000 +0000 @@ -24,6 +24,7 @@ #include <linux/mtd/partitions.h> #include <linux/pm.h> #include <linux/delay.h> +#include <linux/fb.h> #include <asm/setup.h> #include <asm/memory.h> @@ -48,7 +49,6 @@ #include "generic.h" - /* * SCOOP Device */ @@ -345,7 +345,38 @@ static struct tmio_nand_platform_data to .badblock_pattern = &tosa_tc6393_nand_bbt, }; -extern struct tmio_lcd_platform_data tosa_tc6393_lcd_platform_data; +static struct fb_videomode tosa_tc6393_lcd_mode[] = { + { + .xres = 480, + .yres = 640, + .pixclock = 0x002cdf00,/* PLL divisor */ + .left_margin = 0x004c, + .right_margin = 0x005b, + .upper_margin = 0x0001, + .lower_margin = 0x000d, + .hsync_len = 0x0002, + .vsync_len = 0x0001, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED, + },{ + .xres = 240, + .yres = 320, + .pixclock = 0x00e7f203,/* PLL divisor */ + .left_margin = 0x0024, + .right_margin = 0x002f, + .upper_margin = 0x0001, + .lower_margin = 0x000d, + .hsync_len = 0x0002, + .vsync_len = 0x0001, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED, +}}; + +struct tmio_lcd_platform_data tosa_tc6393_lcd_platform_data = { + .ops = NULL, + .modelist = tosa_tc6393_lcd_mode, + .num_modes = ARRAY_SIZE(tosa_tc6393_lcd_mode), +}; static struct tmio_cell tosa_tc6393_cells[] = { { @@ -384,6 +415,19 @@ struct platform_device tc6393_device = { .num_resources = ARRAY_SIZE(tc6393_resources), .resource = tc6393_resources, }; +EXPORT_SYMBOL (tc6393_device); + +/* + * Tosa LCD / Backlight stuff + */ +static struct platform_device tosalcd_device = { + .name = "tosa-lcd", + .id = -1, + .dev = { + .parent = &tc6393_device.dev, + .platform_data = &tosa_tc6393_lcd_platform_data.ops, + }, +}; static struct platform_device *devices[] __initdata = { &tosascoop_device, @@ -391,6 +435,7 @@ static struct platform_device *devices[] &tosakbd_device, &tosaled_device, &tc6393_device, + &tosalcd_device, }; static void tosa_poweroff(void) Index: git/arch/arm/mach-pxa/Kconfig =================================================================== --- git.orig/arch/arm/mach-pxa/Kconfig 2006-11-07 22:13:10.000000000 +0000 +++ git/arch/arm/mach-pxa/Kconfig 2006-11-07 22:13:10.000000000 +0000 @@ -129,7 +129,10 @@ config MACH_TOSA bool "Enable Sharp SL-6000x (Tosa) Support" depends PXA_SHARPSL_25x select TOSHIBA_TC6393XB - select SHARPSL_PM + select I2C + select I2C_PXA + select SHARPSL_PM + select PXA_SSP config PXA25x bool