|
h3600 patch (lcd, micro, bl): msg#00036handhelds.linux.kernel
Small xmas gift for old h3600 device XMas give us a new patch for the iPAQ h3600 for kernel 2.6 - add support for LCD device, should be ok. - preliminary support micro communication, really early stage. - initial support for LCD backlight. There is also my h3600_defconfig, main differences from the one provided with kernel are : - correct setup for MTD mapping - remove all non internal devices support (pcmcia, CF, eth, ...) anso cause i cannot test them (sigh!) see u soon -- /-------------------------------------------------------------\ | Alessandro Gardich : gremlin-4KDpiRHFOM2onA0d6jMUrA@xxxxxxxxxxxxxxxx | >-------------------------------------------------------------< | I never saw a wild thing sorry for itself. | | A small bird will drop frozen dead from a bough | | without ever having felt sorry for itself. | \-------------------------------------------------------------/ diff -Nur --exclude=CVS kernel26-cvs/arch/arm/common/ipaq/Kconfig kernel26/arch/arm/common/ipaq/Kconfig --- kernel26-cvs/arch/arm/common/ipaq/Kconfig 2005-11-06 10:45:58.000000000 +0100 +++ kernel26/arch/arm/common/ipaq/Kconfig 2005-12-11 17:01:59.000000000 +0100 @@ -16,6 +16,10 @@ is required for the CF, PCMCIA, Bluetooth and GSM/GPRS extension packs. +config IPAQ_MICRO + tristate " micro Support" + depends on SA1100_H3600 + config IPAQ_ASIC2_TOUCHSCREEN tristate " ASIC2 touchscreen and keyboard drivers" depends on HTC_ASIC2 && INPUT diff -Nur --exclude=CVS kernel26-cvs/arch/arm/common/ipaq/Makefile kernel26/arch/arm/common/ipaq/Makefile --- kernel26-cvs/arch/arm/common/ipaq/Makefile 2005-11-06 10:45:58.000000000 +0100 +++ kernel26/arch/arm/common/ipaq/Makefile 2005-12-11 17:01:59.000000000 +0100 @@ -16,6 +16,8 @@ obj-$(CONFIG_IPAQ_MTD_ASSET) += ipaq-mtd-asset.o obj-$(CONFIG_IPAQ_SLEEVE) += ipaq-sleeve.o +obj-$(CONFIG_IPAQ_MICRO) += micro.o + obj-$(CONFIG_IPAQ_ASIC2_SLEEVE) += asic2_sleeve.o obj-$(CONFIG_IPAQ_ASIC2_TOUCHSCREEN) += asic2_adcts.o asic2_key.o obj-$(CONFIG_IPAQ_ASIC2_OWM) += asic2_owm.o diff -Nur --exclude=CVS kernel26-cvs/arch/arm/common/ipaq/micro.c kernel26/arch/arm/common/ipaq/micro.c --- kernel26-cvs/arch/arm/common/ipaq/micro.c 1970-01-01 01:00:00.000000000 +0100 +++ kernel26/arch/arm/common/ipaq/micro.c 2005-12-14 20:42:10.000000000 +0100 @@ -0,0 +1,407 @@ +/* + * 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. + * + * h3600 atmel micro companion support + * based on previous kernel 2.4 version + * Author : Alessandro Gardich <gremlin-4KDpiRHFOM2onA0d6jMUrA@xxxxxxxxxxxxxxxx> + * + */ + + +#include <linux/module.h> +#include <linux/version.h> + +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <linux/pm.h> +#include <linux/sysctl.h> +#include <linux/proc_fs.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/input.h> +#include <linux/soc-device.h> +#include <linux/backlight.h> /* backlight_device */ + +#include <asm/irq.h> +#include <asm/arch/hardware.h> + +#include <asm/arch/h3600.h> +#include <asm/arch/SA-1100.h> + +static void h3600_micro_rx_msg( int id, int len, unsigned char *data ); + + + +/*--- low lever serial interface ---*/ +/* event independent structure */ +enum rx_state { + STATE_SOF = 0, /* Next byte should be start of frame */ + STATE_ID, /* Next byte is ID & message length */ + STATE_DATA, /* Next byte is a data byte */ + STATE_CHKSUM /* Next byte should be checksum */ +}; + +#define RX_BUF_SIZE 16 +#define TX_BUF_SIZE 32 + +#define CHAR_SOF 0x02 + +unsigned char tx_buf[TX_BUF_SIZE]; +unsigned char *tx_index=tx_buf; +int tx_len=0; + +struct h3600_rxdev { + enum rx_state state; /* context of rx state machine */ + unsigned char chksum; /* calculated checksum */ + int id; /* message ID from packet */ + unsigned int len; /* rx buffer length */ + unsigned int index; /* rx buffer index */ + unsigned char buf[RX_BUF_SIZE]; /* rx buffer size */ +}; + +static struct h3600_rxdev rx; /* receive ISR state */ + +static void h3600_micro_process_char( unsigned char ch ) +{ + switch ( rx.state ) { + case STATE_SOF: /* Looking for SOF */ + if ( ch == CHAR_SOF ) + rx.state=STATE_ID; /* Next byte is the id and len */ + //else + // g_statistics.missing_sof++; + break; + case STATE_ID: /* Looking for id and len byte */ + rx.id = ( ch & 0xf0 ) >> 4 ; + rx.len = ( ch & 0x0f ); + rx.index = 0; + rx.chksum = ch; + rx.state = ( rx.len > 0 ) ? STATE_DATA : STATE_CHKSUM; + break; + case STATE_DATA: /* Looking for 'len' data bytes */ + rx.chksum += ch; + rx.buf[rx.index]= ch; + if ( ++rx.index == rx.len ) + rx.state = STATE_CHKSUM; + break; + case STATE_CHKSUM: /* Looking for the checksum */ + if ( ch == rx.chksum ) + h3600_micro_rx_msg( rx.id, rx.len, rx.buf ); + //else + // g_statistics.bad_checksum++; + rx.state = STATE_SOF; + break; + } +} + + +static void h3600_micro_rx_chars( void ) +{ + unsigned int status, ch; + + while ( (status = Ser1UTSR1) & UTSR1_RNE ) { + ch = Ser1UTDR; + /*g_statistics.rx++;*/ + + if ( status & UTSR1_PRE ) { /* Parity error */ + /*g_statistics.parity++;*/ + } else if ( status & UTSR1_FRE ) { /* Framing error */ + /*g_statistics.frame++;*/ + } else { + if ( status & UTSR1_ROR ) { /* Overrun error */ + /*g_statistics.overrun++;*/ + } + h3600_micro_process_char( ch ); + } + } + +} + +static void h3600_micro_tx_chars( void ) +{ + + tx_index = tx_buf; + + while ( (Ser1UTSR1 & UTSR1_TNF) ) { + Ser1UTDR = *tx_index; + tx_index++; + tx_len--; + if (tx_len==0) break; + } + + /*if ( g_txdev.tail == g_txdev.head )*/ /* Stop interrupts */ + /* Ser1UTCR3 &= ~UTCR3_TIE; */ +} + +static void h3600_micro_reset_comm( void ) +{ + if (1) printk("%s: initializing serial port\n", __FUNCTION__); + + /* Initialize Serial channel protocol frame */ + rx.state = STATE_SOF; /* Reset the state machine */ + + /* Set up interrupts */ + Ser1SDCR0 = 0x1; /* Select UART mode */ + + Ser1UTCR3 = 0; /* Clean up CR3 */ + Ser1UTCR0 = UTCR0_8BitData | UTCR0_1StpBit; /* 8 bits, no parity, 1 stop bit */ + Ser1UTCR1 = 0; /* Baud rate to 115K bits/sec */ + Ser1UTCR2 = 0x1; + + Ser1UTSR0 = 0xff; /* Clear SR0 */ + Ser1UTCR3 = UTCR3_TXE | UTCR3_RXE | UTCR3_RIE; /* Enable receive interrupt */ + Ser1UTCR3 &= ~UTCR3_TIE; /* disable send interrupt */ + +} + + +/*-----------------------------------*/ +/* ack messages from Atmel Micro */ + +static void h3600_micro_rx_msg( int id, int len, unsigned char *data ) +{ + int i; + + printk(KERN_ERR "h3600_micro : got a message from micro\n"); + + if ( len != 0 ) + printk(KERN_ERR "%s: invalid ack length = %d for message id %d\n", __FUNCTION__, len, id ); + + printk(KERN_ERR "h3600_micro : ack %d %d ", id, len); + + for (i=0;i<len;++i) + printk("0x%02x ", data[i]); + printk("\n"); + +} + +/*--- core interrupt core ---*/ +enum MessageHandleType { + HANDLE_NORMAL, + HANDLE_ACK, + HANDLE_ERROR +}; + +#define MICRO_MSG_WAITING 0 +#define MICRO_MSG_SUCCESS 1 +#define MICRO_MSG_ERROR -1 + +static irqreturn_t h3600_micro_serial_isr(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int status; /* UTSR0 */ + unsigned int pass_counter = 0; + + if (1) printk("%s: %s\n", __FILE__, __FUNCTION__); + + //g_statistics.isr++; + status = Ser1UTSR0; + do { + if ( status & (UTSR0_RID | UTSR0_RFS) ) { + if ( status & UTSR0_RID ) + Ser1UTSR0 = UTSR0_RID; /* Clear the Receiver IDLE bit */ + h3600_micro_rx_chars(); + } + + /* Clear break bits */ + if (status & (UTSR0_RBB | UTSR0_REB)) + Ser1UTSR0 = status & (UTSR0_RBB | UTSR0_REB); + + /* at now i send immediatelly, to be modified */ + //if ( status & UTSR0_TFS ) + // h3600_micro_tx_chars(); + + status = Ser1UTSR0; + } while ( ( /*( (g_txdev.head != g_txdev.tail) && (status & UTSR0_TFS) ) ||*/ + status & (UTSR0_RFS | UTSR0_RID ) ) + /*&& pass_counter++ < H3600_TS_PASS_LIMIT*/ ); + + //if ( pass_counter >= H3600_TS_PASS_LIMIT ) + // g_statistics.pass_limit++; + + return IRQ_HANDLED; +} + + +/*--- backlight ---*/ + +struct micro_data{ + struct device *micro; +}*micro_data; + +#define MAX_BRIGHTNESS 255 + +int micro_backlight_level = 0; +int micro_backlight_brightness = 90; + +static int micro_backlight_set_power (struct backlight_device *bl, int level) +{ + micro_backlight_level = level; + if (level < 1) { + micro_backlight_level = 0; + } else { + micro_backlight_level = 1; + } + + return 0; +} + +static int micro_backlight_get_power (struct backlight_device *bl) +{ + return micro_backlight_level; +} + +int micro_backlight_set_brightness (struct backlight_device *bl, int brightness) +{ + micro_backlight_brightness = brightness; + + if(brightness==0){ + tx_buf[0] = 0x02; + tx_buf[1] = 0xD3; + tx_buf[2] = 0x01; + tx_buf[3] = 0x00; + tx_buf[4] = 0x00; + tx_buf[5] = 0xD4; + tx_len=6; + } else { + if ( brightness > MAX_BRIGHTNESS ) + brightness = MAX_BRIGHTNESS; + tx_buf[0] = 0x02; + tx_buf[1] = 0xD3; + tx_buf[2] = 0x01; + tx_buf[3] = 0x01; + tx_buf[4] = 0x00+brightness; + tx_buf[5] = (0xD5+brightness) & 0xff; + tx_len=6; + } + + h3600_micro_tx_chars(); + + return 0; +} + +int micro_backlight_get_brightness (struct backlight_device *bl) +{ + return micro_backlight_brightness; +} + +static struct backlight_properties micro_backlight_properties = { + .owner = THIS_MODULE, + .get_power = micro_backlight_get_power, + .set_power = micro_backlight_set_power, + .get_brightness = micro_backlight_get_brightness, + .set_brightness = micro_backlight_set_brightness, + .max_brightness = 0xff, +}; + + +static struct backlight_device *micro_backlight_device; + +static int micro_suspend (struct device *dev, u32 state, u32 level) +{ + micro_backlight_set_power (micro_backlight_device, 0); + return 0; +} + +static int micro_resume (struct device *dev, u32 level) +{ + micro_backlight_set_power (micro_backlight_device, 4); + return 0; +} + +static int micro_probe (struct device *dev) +{ + int result=0; + struct platform_device *sdev; + struct micro_data *k; + + printk(KERN_ERR "micro probe : begin \n"); + + h3600_micro_reset_comm(); + + result = request_irq(IRQ_Ser1UART, h3600_micro_serial_isr, SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM, + "h3600_micro", h3600_micro_serial_isr); + if ( result ) { + printk(KERN_CRIT "%s: unable to grab serial port IRQ\n", __FUNCTION__); + return result; + } else { + printk(KERN_ERR "h3600_micro : grab serial port IRQ\n"); + } + + + + micro_data = k = kmalloc (sizeof (*k), GFP_KERNEL); + if (!k) { + printk(KERN_ERR "micro probe : memory allocation fail !\n"); + return -ENOMEM; + } + + memset (k, 0, sizeof (*k)); + + sdev = to_platform_device (dev); + k->micro = dev->parent; + dev->driver_data = k; + + + micro_backlight_device = backlight_device_register ("h3600-bl", NULL, + µ_backlight_properties); + if (IS_ERR (micro_backlight_device)) { + printk(KERN_ERR "micro probe : backlight register fail.\n"); + return PTR_ERR (micro_backlight_device); + } + + micro_backlight_set_power (micro_backlight_device, 0); + + printk(KERN_ERR "micro probe : end \n"); + + return result; +} + +static int micro_remove (struct device *dev) +{ + struct micro_data *k = dev->driver_data; + + free_irq(IRQ_Ser1UART, h3600_micro_serial_isr); + + micro_backlight_set_power (micro_backlight_device, 0); + + kfree (k); + + return 0; +} + +static struct device_driver micro_device_driver = { + .name = "h3600-micro", + .bus = &platform_bus_type, + .probe = micro_probe, + .remove = micro_remove, + .suspend = micro_suspend, + .resume = micro_resume, + .shutdown = micro_suspend +}; + + +static int micro_init (void) +{ + int ret; + ret = driver_register (µ_device_driver); + return ret; +} + +static void +micro_cleanup (void) +{ + driver_unregister (µ_device_driver); + + backlight_device_unregister (micro_backlight_device); +} + +module_init (micro_init); +module_exit (micro_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("gremlin.it"); +MODULE_DESCRIPTION("driver for iPAQ Atmel micro"); + diff -Nur --exclude=CVS kernel26-cvs/arch/arm/mach-sa1100/h3600.c kernel26/arch/arm/mach-sa1100/h3600.c --- kernel26-cvs/arch/arm/mach-sa1100/h3600.c 2005-11-16 20:21:06.000000000 +0100 +++ kernel26/arch/arm/mach-sa1100/h3600.c 2005-12-28 22:25:55.000000000 +0100 @@ -110,18 +110,6 @@ }; - -/* - * helper for sa1100fb - */ -static void h3xxx_lcd_power(int enable) -{ - assign_ipaqsa_egpio(IPAQ_EGPIO_LCD_POWER, enable); -} - - - - /************************* H3600 *************************/ #ifdef CONFIG_SA1100_H3600 @@ -210,7 +198,9 @@ static void __init h3600_map_io(void) { ipaqsa_map_io(); - sa1100fb_lcd_power = h3xxx_lcd_power; + /* gremlin : I suspect this is an old style driver, replace by lcd_device */ + /*sa1100fb_lcd_power = h3xxx_lcd_power;*/ + sa1100fb_lcd_power = NULL; /* Initialize h3600-specific values here */ @@ -225,10 +215,43 @@ ipaq_model_ops = h3600_model_ops; } + +/*--- list of devices ---*/ + +struct platform_device h3600micro_device = { + .name = "h3600-micro", + .id = -1, +}; + +static struct platform_device h3600bl_device = { + .name = "h3600-bl", +/* .dev = { */ +/* .parent = &sa11x0fb_device.dev, */ +/* }, */ + .id = -1, +}; + +static struct platform_device h3600lcd_device = { + .name = "h3600-lcd", +/* .dev = { */ +/* .parent = &sa11x0fb_device.dev, */ +/* }, */ + .id = -1, +}; + + +static struct platform_device *devices[] __initdata = { + &h3600micro_device, + &h3600bl_device, + &h3600lcd_device, +}; + + static void h3600_mach_init(void) { ipaqsa_mach_init(); sa11x0_set_flash_data(&h3xxx_flash_data, &h3xxx_flash_resource, 1); + platform_add_devices(devices, ARRAY_SIZE(devices)); } MACHINE_START(H3600, "Compaq iPAQ H3600") diff -Nur --exclude=CVS kernel26-cvs/arch/arm/mach-sa1100/h3600_lcd.c kernel26/arch/arm/mach-sa1100/h3600_lcd.c --- kernel26-cvs/arch/arm/mach-sa1100/h3600_lcd.c 1970-01-01 01:00:00.000000000 +0100 +++ kernel26/arch/arm/mach-sa1100/h3600_lcd.c 2005-12-28 10:44:29.000000000 +0100 @@ -0,0 +1,152 @@ +/* + * Hardware definitions for Compaq iPAQ H36xx Handheld Computers + * + * Use consistent with the GNU GPL is permitted, + * provided that this copyright notice is + * preserved in its entirety in all copies and derived works. + * + * Author: Alessandro Gardich. + * + * History : based on 2.4 drivers. + * + * 2005-11-xx Alessandro Gardich, let start. + * + */ + + +#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 <linux/err.h> + +#include <asm/mach-types.h> +#include <asm/hardware.h> +#include <asm/setup.h> + +#include <asm/mach/arch.h> +#include <asm/arch/h3600.h> +#include <asm/hardware/ipaq-ops.h> + +#include <../arch/arm/mach-sa1100/generic.h> + +static int h3600_lcd_power; + +/* + * helper for sa1100fb + */ +static void __h3600_lcd_set_power(int enable ) +{ + h3600_lcd_power = enable; + assign_ipaqsa_egpio(IPAQ_EGPIO_LCD_POWER, enable); + + return; +} + +static int __h3600_lcd_get_power(void) +{ + return h3600_lcd_power; +} +/*--- sa1100fb END ---*/ + + +static int h3600_lcd_set_power( struct lcd_device *lm, int enable ) +{ + __h3600_lcd_set_power( enable); + return 0; +} + +static int h3600_lcd_get_power( struct lcd_device *lm) +{ + return __h3600_lcd_get_power(); +} + + +static struct lcd_properties h3600_lcd_properties = { + .owner = THIS_MODULE, + .get_power = h3600_lcd_get_power, + .set_power = h3600_lcd_set_power, +}; + +static struct lcd_device *h3600_lcd_device; + +static int h3600_fp_probe (struct device *dev) +{ + if (! machine_is_h3600 ()) + return -ENODEV; + + h3600_lcd_device = lcd_device_register("sa1100fb", NULL, &h3600_lcd_properties); + if (IS_ERR (h3600_lcd_device)) + return PTR_ERR (h3600_lcd_device); + + h3600_lcd_set_power (h3600_lcd_device, 0); + + sa1100fb_lcd_power = __h3600_lcd_set_power; + + return 0; +} + +static int h3600_fp_remove (struct device *dev) +{ + lcd_device_unregister (h3600_lcd_device); + + sa1100fb_lcd_power = NULL; + + return 0; +} + +static int h3600_fp_suspend ( struct device *dev, u32 state, u32 level) +{ + if (level == SUSPEND_POWER_DOWN) { + h3600_lcd_set_power(h3600_lcd_device, 0); + } + return 0; +} + +static int h3600_fp_resume ( struct device *dev, u32 state, u32 level) +{ + if (level == RESUME_POWER_ON) { + h3600_lcd_set_power(h3600_lcd_device, 1); + } + return 0; +} + +struct device_driver h3600_fp_device_driver = { + .name = "h3600-lcd", + .bus = &platform_bus_type, + .probe = h3600_fp_probe, + .remove = h3600_fp_remove, + .suspend = h3600_fp_suspend, + .resume = h3600_fp_resume +}; + +static int __init h3600_fp_init(void) +{ + int rc; + + if (!machine_is_h3600()) + return -ENODEV; + + rc = driver_register(&h3600_fp_device_driver); + + return rc; +} + +static void __exit h3600_fp_exit(void) +{ + driver_unregister(&h3600_fp_device_driver); +} + +module_init (h3600_fp_init); +module_exit (h3600_fp_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Alessandro Gardich <gremlin-4KDpiRHFOM2onA0d6jMUrA@xxxxxxxxxxxxxxxx>"); +MODULE_DESCRIPTION("iPAQ h3600 LCD driver"); + diff -Nur --exclude=CVS kernel26-cvs/arch/arm/mach-sa1100/Kconfig kernel26/arch/arm/mach-sa1100/Kconfig --- kernel26-cvs/arch/arm/mach-sa1100/Kconfig 2005-11-06 10:47:28.000000000 +0100 +++ kernel26/arch/arm/mach-sa1100/Kconfig 2005-12-11 17:01:59.000000000 +0100 @@ -189,6 +189,10 @@ tristate "Support for SA11x0 USB character device emulation" depends on SA1100_USB +config IPAQ_H3600_LCD + tristate "HP iPAQ h3600 LCD" + depends on IPAQ_HANDHELD && SA1100_H3600 && LCD_DEVICE && FB_SA1100 + endmenu endif diff -Nur --exclude=CVS kernel26-cvs/arch/arm/mach-sa1100/Makefile kernel26/arch/arm/mach-sa1100/Makefile --- kernel26-cvs/arch/arm/mach-sa1100/Makefile 2005-03-30 17:04:33.000000000 +0200 +++ kernel26/arch/arm/mach-sa1100/Makefile 2005-12-11 17:01:59.000000000 +0100 @@ -57,3 +57,6 @@ # Miscelaneous functions obj-$(CONFIG_PM) += pm.o sleep.o obj-$(CONFIG_SA1100_SSP) += ssp.o + +obj-$(CONFIG_IPAQ_H3600_LCD) += h3600_lcd.o +
Kernel-discuss mailing list Kernel-discuss-CN5wO63fgwogsBAKwltoeQ@xxxxxxxxxxxxxxxx https://handhelds.org/mailman/listinfo/kernel-discuss |
|
| <Prev in Thread] | Current Thread | [Next in Thread> |
|---|---|---|
| Previous by Date: | RE: DiskOnChip in h6300 device: 00036, Torbjörn Jansson |
|---|---|
| Next by Date: | first attempt on transition to 2.6.15: 00036, Erik Hovland |
| Previous by Thread: | DiskOnChip in h6300 devicei: 00036, Husam Senussi |
| Next by Thread: | Re: h3600 patch (lcd, micro, bl): 00036, Erik Hovland |
| Indexes: | [Date] [Thread] [Top] [All Lists] |
| News | FAQ | advertise |