diff options
Diffstat (limited to 'recipes/linux/linux-h6300-omap1-2.6.16.16/linux-h6300-omap2-2.6.16.16.patch')
-rw-r--r-- | recipes/linux/linux-h6300-omap1-2.6.16.16/linux-h6300-omap2-2.6.16.16.patch | 3736 |
1 files changed, 3736 insertions, 0 deletions
diff --git a/recipes/linux/linux-h6300-omap1-2.6.16.16/linux-h6300-omap2-2.6.16.16.patch b/recipes/linux/linux-h6300-omap1-2.6.16.16/linux-h6300-omap2-2.6.16.16.patch new file mode 100644 index 0000000000..98b4365f98 --- /dev/null +++ b/recipes/linux/linux-h6300-omap1-2.6.16.16/linux-h6300-omap2-2.6.16.16.patch @@ -0,0 +1,3736 @@ +diff -Naur linux-2.6.16.16/arch/arm/Kconfig h6300_dev/arch/arm/Kconfig +--- linux-2.6.16.16/arch/arm/Kconfig 2006-05-17 21:41:27.000000000 +0300 ++++ h6300_dev/arch/arm/Kconfig 2006-04-02 00:23:01.000000000 +0300 +@@ -811,6 +811,8 @@ + + source "drivers/video/Kconfig" + ++source "drivers/telephony/Kconfig" ++ + source "sound/Kconfig" + + source "drivers/usb/Kconfig" +diff -Naur linux-2.6.16.16/arch/arm/mach-omap1/board-h6300.c h6300_dev/arch/arm/mach-omap1/board-h6300.c +--- linux-2.6.16.16/arch/arm/mach-omap1/board-h6300.c 1970-01-01 02:00:00.000000000 +0200 ++++ h6300_dev/arch/arm/mach-omap1/board-h6300.c 2006-04-24 20:53:29.000000000 +0300 +@@ -0,0 +1,424 @@ ++/* ++ * Modified from board-h6300.c ++ * ++ * Code for generic OMAP board. Should work on many OMAP systems where ++ * the device drivers take care of all the necessary hardware initialization. ++ * Do not put any board specific code to this file; create a new machine ++ * type if you need custom low-level initializations. ++ * ++ * 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/kernel.h> ++#include <linux/init.h> ++#include <linux/platform_device.h> ++#include <linux/delay.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/partitions.h> ++#include <linux/input.h> ++ ++#include <asm/hardware.h> ++#include <asm/mach-types.h> ++#include <asm/mach/arch.h> ++#include <asm/mach/flash.h> ++#include <asm/mach/map.h> ++ ++#include <asm/arch/gpio.h> ++ ++#include <asm/arch/tc.h> ++#include <asm/arch/usb.h> ++#include <asm/arch/keypad.h> ++#include <asm/arch/common.h> ++#include <asm/arch/mcbsp.h> ++#include <asm/arch/omap-alsa.h> ++#include <asm/arch/h6300_uart_info.h> ++ ++#define _h6300_KEY_CALENDAR 67 // xmodmap 75 aka F9 ++#define _H6300_KEY_TELEPHONE 68 // xmodmap 76 aka F10 ++#define _H6300_KEY_HOMEPAGE 87 // xmodmap 87 aka Num_Lock ++#define _H6300_KEY_MAIL 88 // xmodmap 88 aka Scroll_Lock ++ ++/* ++ * Following 5 keypad events are not really sent to userspace. ++ * Instead if the good combination of them is sent, then that is send. ++ * (up, right, down, left, enter) ++ */ ++#define _H6300_JOYPAD_UP_RIGHT 1 // 00001 ++#define _H6300_JOYPAD_DOWN_RIGHT 2 // 00010 ++#define _h6300_JOYPAD_DOWN_LEFT 4 // 00100 ++#define _h6300_JOYPAD_UP_LEFT 8 // 01000 ++#define _H6300_JOYPAD_KEY_OK 16 // 10000 ++ ++static int h6300_keymap[] = { ++ KEY(2, 0, _h6300_KEY_CALENDAR), // address button in the bottom left ++ KEY(2, 3, _H6300_KEY_TELEPHONE), // start call button in the bottom ++ KEY(3, 1, _H6300_KEY_HOMEPAGE), // stop call button in the bottom ++ KEY(3, 4, _H6300_KEY_MAIL), // messaging button in the bottom right ++ ++ KEY(0, 0, KEY_VOLUMEUP), // volume up button in the right side ++ KEY(0, 1, KEY_VOLUMEDOWN), // volume down button in the right side ++ KEY(3, 2, KEY_RECORD), // record button in the left side ++ ++ KEY(1, 0, _h6300_JOYPAD_UP_LEFT), ++ KEY(1, 1, _h6300_JOYPAD_DOWN_LEFT), ++ KEY(1, 2, _H6300_JOYPAD_KEY_OK), ++ KEY(1, 3, _H6300_JOYPAD_DOWN_RIGHT), ++ KEY(1, 4, _H6300_JOYPAD_UP_RIGHT), ++ ++ KEY(4, 0, KEY_RIGHT), ++ KEY(4, 1, KEY_DOWN), ++ KEY(4, 2, KEY_LEFT), ++ KEY(4, 3, KEY_UP), ++ KEY(4, 4, KEY_ENTER), ++ ++ 0 ++}; ++ ++/* ++ * Bluetooth - Relies on h6300_bt module, ++ * so make the calls indirectly through pointers. Requires that the ++ * h6300_bt bluetooth module be loaded before any attempt to use ++ * bluetooth (obviously). ++ */ ++ ++static struct h6300_uart_funcs bt_funcs; ++static struct h6300_uart_funcs gsm_funcs; ++ ++static void h6300_bt_configure(struct uart_omap_port *up, int enable) ++{ ++ printk(KERN_NOTICE "board-h6300.c, h6300_bt_configure() started\n"); ++ if (bt_funcs.configure != NULL) ++ bt_funcs.configure(up, enable); ++ printk(KERN_NOTICE "board-h6300.c, h6300_bt_configure() done\n"); ++} ++ ++static void h6300_bt_set_txrx(struct uart_omap_port *up, int txrx) ++{ ++ printk(KERN_NOTICE "board-h6300.c, h6300_bt_set_txrx() started\n"); ++ if (bt_funcs.set_txrx != NULL) ++ { ++ printk(KERN_NOTICE "board-h6300.c, h6300_bt_set_txrx(), bt_funcs.set_txrx != NULL\n"); ++ bt_funcs.set_txrx(up, txrx); ++ } ++ printk(KERN_NOTICE "board-h6300.c, h6300_bt_set_txrx() done\n"); ++} ++ ++static int h6300_bt_get_txrx(struct uart_omap_port *up) ++{ ++ int retVal; ++ ++ printk(KERN_NOTICE "board-h6300.c, h6300_bt_get_txrx() started\n"); ++ if (bt_funcs.get_txrx != NULL) ++ { ++ retVal = bt_funcs.get_txrx(up); ++ printk(KERN_NOTICE "board-h6300.c, h6300_bt_get_txrx(), bt_funcs.get_trx != null, done, retVal %d\n", retVal); ++ return retVal; ++ } ++ else ++ { ++ printk(KERN_NOTICE "board-h6300.c, h6300_bt_get_txrx() done, returning 0\n"); ++ return 0; ++ } ++} ++ ++static struct platform_omap_serial_funcs h6300_omap_bt_funcs = { ++ .configure = h6300_bt_configure, ++ .set_txrx = h6300_bt_set_txrx, ++ .get_txrx = h6300_bt_get_txrx, ++}; ++ ++struct platform_device btuart_device = { ++ .name = "h6300_bt", ++ .id = 1, ++}; ++EXPORT_SYMBOL(btuart_device); ++ ++static void h6300_gsm_configure(struct uart_omap_port *up, int enable) ++{ ++ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_configure() started\n"); ++ if (gsm_funcs.configure != NULL) ++ gsm_funcs.configure(up, enable); ++ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_configure() done\n"); ++} ++ ++static void h6300_gsm_set_txrx(struct uart_omap_port *up, int txrx) ++{ ++ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_set_txrx() started\n"); ++ if (bt_funcs.set_txrx != NULL) ++ { ++ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_set_txrx(), bt_funcs.set_txrx != NULL\n"); ++ gsm_funcs.set_txrx(up, txrx); ++ } ++ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_set_txrx() done\n"); ++} ++ ++static int h6300_gsm_get_txrx(struct uart_omap_port *up) ++{ ++ int retVal; ++ ++ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_get_txrx() started\n"); ++ if (bt_funcs.get_txrx != NULL) ++ { ++ retVal = gsm_funcs.get_txrx(up); ++ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_get_txrx(), bt_funcs.get_trx != null, done, retVal %d\n", retVal); ++ return retVal; ++ } ++ else ++ { ++ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_get_txrx() done, returning 0\n"); ++ return 0; ++ } ++} ++ ++static struct platform_omap_serial_funcs h6300_omap_gsm_funcs = { ++ .configure = h6300_gsm_configure, ++ .set_txrx = h6300_gsm_set_txrx, ++ .get_txrx = h6300_gsm_get_txrx, ++}; ++ ++struct platform_device gsmuart_device = { ++ .name = "h6300_gsm", ++ .id = 1, ++}; ++EXPORT_SYMBOL(gsmuart_device); ++ ++#if 0 ++static struct mtd_partition h6300_partitions[] = { ++ /* bootloader (U-Boot, etc) in first sector */ ++ { ++ .name = "bootloader", ++ .offset = 0, ++ .size = SZ_128K, ++ .mask_flags = MTD_WRITEABLE, /* force read-only */ ++ }, ++ /* bootloader params in the next sector */ ++ { ++ .name = "params", ++ .offset = MTDPART_OFS_APPEND, ++ .size = SZ_128K, ++ .mask_flags = 0, ++ }, ++ /* kernel */ ++ { ++ .name = "kernel", ++ .offset = MTDPART_OFS_APPEND, ++ .size = SZ_2M, ++ .mask_flags = 0 ++ }, ++ /* rest of flash1 is a file system */ ++ { ++ .name = "rootfs", ++ .offset = MTDPART_OFS_APPEND, ++ .size = SZ_16M - SZ_2M - 2 * SZ_128K, ++ .mask_flags = 0 ++ }, ++ /* file system */ ++ { ++ .name = "filesystem", ++ .offset = MTDPART_OFS_APPEND, ++ .size = MTDPART_SIZ_FULL, ++ .mask_flags = 0 ++ } ++}; ++ ++static struct flash_platform_data h6300_flash_data = { ++ .map_name = "cfi_probe", ++ .width = 2, ++ .parts = h6300_partitions, ++ .nr_parts = ARRAY_SIZE(h6300_partitions), ++}; ++ ++static struct resource h6300_flash_resource = { ++ .start = OMAP_CS0_PHYS, ++ .end = OMAP_CS0_PHYS + SZ_32M - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++static struct platform_device h6300_flash_device = { ++ .name = "omapflash", ++ .id = 0, ++ .dev = { ++ .platform_data = &h6300_flash_data, ++ }, ++static struct platform_device h6300_flash_device = { ++ .name = "omapflash", ++ .id = 0, ++ .dev = { ++ .platform_data = &h6300_flash_data, ++ }, ++ .num_resources = 1, ++ .resource = &h6300_flash_resource, ++}; ++#endif ++ ++static struct resource h6300_kp_resources[] = { ++ [0] = { ++ .start = INT_KEYBOARD, ++ .end = INT_KEYBOARD, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct omap_kp_platform_data h6300_kp_data = { ++ .rows = 8, ++ .cols = 8, ++ .keymap = h6300_keymap, ++ .rep = 1, // turns repeat bit on ++}; ++ ++static struct platform_device h6300_kp_device = { ++ .name = "omap-keypad", ++ .id = -1, ++ .dev = { ++ .platform_data = &h6300_kp_data, ++ }, ++ .num_resources = ARRAY_SIZE(h6300_kp_resources), ++ .resource = h6300_kp_resources, ++}; ++ ++static struct resource h6300_wlan_resource[] = { ++ [0] = { ++ .start = OMAP_CS1_PHYS, ++ .end = OMAP_CS1_PHYS + SZ_32M -1, ++ .flags = IORESOURCE_MEM, ++ }, ++ ++ [1] = { ++ .start = OMAP_GPIO_IRQ(11), ++ .end = OMAP_GPIO_IRQ(11), ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device h6300_wlan_device = { ++ .name = "tnetw1100b", ++ .id = 0, ++ .num_resources = 2, ++ .resource = h6300_wlan_resource, ++}; ++ ++static struct omap_mcbsp_reg_cfg mcbsp_regs = { ++ .spcr2 = 0x0000, ++ .spcr1 = 0x0000, ++ .rcr2 = 0x8041, ++ .rcr1 = 0x0040, ++ .xcr2 = 0x00a1, ++ .xcr1 = 0x00a0, ++ .srgr2 = 0xb000, ++ .srgr1 = 0x0000, ++ .pcr0 = 0x0081, ++}; ++ ++static struct omap_alsa_codec_config alsa_config = { ++ .name = "iPAQ h6300 TSC2101", ++ .mcbsp_regs_alsa = &mcbsp_regs, ++ .codec_configure_dev = NULL, //tsc2101_configure, ++ .codec_set_samplerate = NULL, //tsc2101_set_samplerate, ++ .codec_clock_setup = NULL, //tsc2101_clock_setup, ++ .codec_clock_on = NULL, //tsc2101_clock_on, ++ .codec_clock_off = NULL, //tsc2101_clock_off, ++ .get_default_samplerate = NULL, //tsc2101_get_default_samplerate, ++}; ++ ++static struct platform_device h6300_mcbsp1_device = { ++ .name = "omap_alsa_mcbsp", ++ .id = 1, ++ .dev = { ++ .platform_data = &alsa_config, ++ }, ++}; ++ ++static struct platform_device h6300_lcd_device = { ++ .name = "lcd_h6300", ++ .id = -1, ++}; ++ ++static struct platform_device *h6300_devices[] __initdata = { ++ &h6300_lcd_device, ++ &btuart_device, ++ &gsmuart_device, ++ &h6300_kp_device, ++ &h6300_mcbsp1_device, ++ &h6300_wlan_device, ++ //&h6300_flash_device, ++}; ++ ++static void __init h6300_init_irq(void) ++{ ++ omap1_init_common_hw(); ++ omap_init_irq(); ++ omap_gpio_init(); ++ ++ /* this is now done in the drivers/input/touschreen/omap/ts_hx.c*/ ++ //omap_request_gpio(2); ++ //omap_set_gpio_direction(2, 0); ++ //omap_set_gpio_dataout(2, 1); ++} ++ ++/* assume no Mini-AB port */ ++ ++static struct omap_usb_config h6300_usb_config __initdata = { ++ .hmc_mode = 0, ++ .register_dev = 1, ++ .pins[0] = 0, ++}; ++ ++static struct omap_lcd_config h6300_lcd_config __initdata = { ++ .ctrl_name = "internal", ++}; ++ ++static struct omap_mmc_config h6300_mmc_config __initdata = { ++ .mmc [0] = { ++ .enabled = 1, ++ .wire4 = 1, ++ .wp_pin = OMAP_GPIO_IRQ(13), ++ .power_pin = -1, // tps65010 ? ++ .switch_pin = -1, // OMAP_MPUIO(1), // = -1, // ARMIO2? ++ }, ++}; ++ ++static struct omap_uart_config h6300_uart_config __initdata = { ++ .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), ++}; ++ ++static struct omap_board_config_kernel h6300_config[] = { ++ { OMAP_TAG_USB, &h6300_usb_config }, ++ { OMAP_TAG_MMC, &h6300_mmc_config }, ++ { OMAP_TAG_UART, &h6300_uart_config }, ++ { OMAP_TAG_LCD, &h6300_lcd_config }, ++}; ++ ++static void __init h6300_init(void) ++{ ++ int ret; ++ ++ ret = platform_add_devices(h6300_devices, ARRAY_SIZE(h6300_devices)); ++ if (ret) ++ { ++ printk(KERN_WARNING "Unable to add h6300 platform devices like bluetooth"); ++ } ++ omap_board_config = h6300_config; ++ omap_board_config_size = ARRAY_SIZE(h6300_config); ++ omap_serial_init(); ++} ++ ++static void __init h6300_map_io(void) ++{ ++ omap1_map_common_io(); ++ ++ btuart_device.dev.platform_data = &h6300_omap_bt_funcs; ++ gsmuart_device.dev.platform_data = &h6300_omap_gsm_funcs; ++} ++ ++MACHINE_START(OMAP_H6300, "HP iPAQ h6300") ++ /* MAINTAINER("Everett Coleman II <gcc80x86@fuzzyneural.net>") */ ++ .phys_io = 0xfff00000, ++ .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc, ++ .boot_params = 0x10000100, ++ .map_io = h6300_map_io, ++ .init_irq = h6300_init_irq, ++ .init_machine = h6300_init, ++ .timer = &omap_timer, ++MACHINE_END +diff -Naur linux-2.6.16.16/arch/arm/mach-omap1/Kconfig h6300_dev/arch/arm/mach-omap1/Kconfig +--- linux-2.6.16.16/arch/arm/mach-omap1/Kconfig 2006-05-17 21:41:27.000000000 +0300 ++++ h6300_dev/arch/arm/mach-omap1/Kconfig 2006-04-02 20:47:24.000000000 +0300 +@@ -26,6 +26,15 @@ + TI OMAP 1510 or 1610 Innovator board support. Say Y here if you + have such a board. + ++config MACH_OMAP_H6300 ++ bool "HP iPAQ h6300 series" ++ depends on ARCH_OMAP1 && ARCH_OMAP15XX ++ select I2C ++ select PCA9535 ++ help ++ HP iPAQ h6315, h6340 and h6365 devices that are based ++ on the OMAP 1510. Say Y here if you have such a device. ++ + config MACH_OMAP_H2 + bool "TI H2 Support" + depends on ARCH_OMAP1 && ARCH_OMAP16XX +diff -Naur linux-2.6.16.16/arch/arm/mach-omap1/Makefile h6300_dev/arch/arm/mach-omap1/Makefile +--- linux-2.6.16.16/arch/arm/mach-omap1/Makefile 2006-05-17 21:41:28.000000000 +0300 ++++ h6300_dev/arch/arm/mach-omap1/Makefile 2006-04-02 00:23:01.000000000 +0300 +@@ -23,6 +23,7 @@ + obj-$(CONFIG_MACH_OMAP_PALMTE) += board-palmte.o + obj-$(CONFIG_MACH_NOKIA770) += board-nokia770.o + obj-$(CONFIG_MACH_AMS_DELTA) += board-ams-delta.o ++obj-$(CONFIG_MACH_OMAP_H6300) += board-h6300.o + + ifeq ($(CONFIG_ARCH_OMAP15XX),y) + # Innovator-1510 FPGA +@@ -36,4 +37,3 @@ + led-$(CONFIG_MACH_OMAP_PERSEUS2) += leds-h2p2-debug.o + led-$(CONFIG_MACH_OMAP_OSK) += leds-osk.o + obj-$(CONFIG_LEDS) += $(led-y) +- +diff -Naur linux-2.6.16.16/arch/arm/mach-omap1/mux.c h6300_dev/arch/arm/mach-omap1/mux.c +--- linux-2.6.16.16/arch/arm/mach-omap1/mux.c 2006-05-17 21:41:28.000000000 +0300 ++++ h6300_dev/arch/arm/mach-omap1/mux.c 2006-02-21 23:54:33.000000000 +0200 +@@ -200,6 +200,13 @@ + MUX_CFG("P15_1610_UWIRE_CS3", 8, 12, 1, 1, 22, 0, 1, 1, 1) + MUX_CFG("N15_1610_UWIRE_CS1", 7, 18, 2, 1, 14, 0, NA, 0, 1) + ++/* OMAP-1510 uWire */ ++MUX_CFG("P15_1510_UWIRE_CS3", 8, 12, 1, NA, 0, 0, NA, 0, 1) ++MUX_CFG("N14_1510_UWIRE_CS0", 8, 9, 1, NA, 0, 0, NA, 0, 1) ++MUX_CFG("V19_1510_UWIRE_SCLK", 8, 6, 0, NA, 0, 0, NA, 0, 1) ++MUX_CFG("W21_1510_UWIRE_SDO", 8, 3, 0, NA, 0, 0, NA, 0, 1) ++MUX_CFG("U18_1510_UWIRE_SDI", 8, 0, 0, 1, 18, 0, NA, 0, 1) ++ + /* OMAP-1610 Flash */ + MUX_CFG("L3_1610_FLASH_CS2B_OE",10, 6, 1, NA, 0, 0, NA, 0, 1) + MUX_CFG("M8_1610_FLASH_CS2B_WE",10, 3, 1, NA, 0, 0, NA, 0, 1) +@@ -262,6 +269,7 @@ + MUX_CFG("T20_1610_LOW_PWR", 7, 12, 1, NA, 0, 0, NA, 0, 0) + + /* MCLK Settings */ ++MUX_CFG("R10_1510_MCLK_ON", B, 18, 0, 2, 22, 1, NA, 1, 1) + MUX_CFG("V5_1710_MCLK_ON", B, 15, 0, NA, 0, 0, NA, 0, 0) + MUX_CFG("V5_1710_MCLK_OFF", B, 15, 6, NA, 0, 0, NA, 0, 0) + MUX_CFG("R10_1610_MCLK_ON", B, 18, 0, NA, 22, 0, NA, 1, 0) +diff -Naur linux-2.6.16.16/arch/arm/plat-omap/devices.c h6300_dev/arch/arm/plat-omap/devices.c +--- linux-2.6.16.16/arch/arm/plat-omap/devices.c 2006-05-17 21:41:28.000000000 +0300 ++++ h6300_dev/arch/arm/plat-omap/devices.c 2006-05-18 00:59:02.000000000 +0300 +@@ -92,7 +92,7 @@ + + static void omap_init_kp(void) + { +- if (machine_is_omap_h2() || machine_is_omap_h3()) { ++ if (machine_is_omap_h2() || machine_is_omap_h3() || machine_is_omap_h6300()) { + omap_cfg_reg(F18_1610_KBC0); + omap_cfg_reg(D20_1610_KBC1); + omap_cfg_reg(D19_1610_KBC2); +diff -Naur linux-2.6.16.16/arch/arm/plat-omap/dma.c h6300_dev/arch/arm/plat-omap/dma.c +--- linux-2.6.16.16/arch/arm/plat-omap/dma.c 2006-05-17 21:41:28.000000000 +0300 ++++ h6300_dev/arch/arm/plat-omap/dma.c 2006-02-06 15:36:21.000000000 +0200 +@@ -30,6 +30,7 @@ + #include <asm/hardware.h> + #include <asm/dma.h> + #include <asm/io.h> ++#include <asm/mach-types.h> + + #include <asm/arch/tc.h> + +@@ -1086,6 +1087,10 @@ + } + + if (omap_dma_in_1510_mode()) { ++ u16 l = omap_readw(OMAP1510_DMA_LCD_CTRL); ++ l &= ~(1 << 6); ++ omap_writew (l, OMAP1510_DMA_LCD_CTRL); ++ + omap_writew(top >> 16, OMAP1510_DMA_LCD_TOP_F1_U); + omap_writew(top, OMAP1510_DMA_LCD_TOP_F1_L); + omap_writew(bottom >> 16, OMAP1510_DMA_LCD_BOT_F1_U); +diff -Naur linux-2.6.16.16/arch/arm/tools/mach-types h6300_dev/arch/arm/tools/mach-types +--- linux-2.6.16.16/arch/arm/tools/mach-types 2006-05-11 04:56:24.000000000 +0300 ++++ h6300_dev/arch/arm/tools/mach-types 2006-04-24 20:53:29.000000000 +0300 +@@ -576,7 +576,7 @@ + s3c2460 MACH_S3C2460 S3C2460 560 + pdm MACH_PDM PDM 561 + h4700 MACH_H4700 H4700 562 +-h6300 MACH_H6300 H6300 563 ++omap_h6300 MACH_OMAP_H6300 OMAP_H6300 563 + rz1700 MACH_RZ1700 RZ1700 564 + a716 MACH_A716 A716 565 + estk2440a MACH_ESTK2440A ESTK2440A 566 +diff -Naur linux-2.6.16.16/drivers/bluetooth/Kconfig h6300_dev/drivers/bluetooth/Kconfig +--- linux-2.6.16.16/drivers/bluetooth/Kconfig 2006-05-17 21:41:29.000000000 +0300 ++++ h6300_dev/drivers/bluetooth/Kconfig 2006-02-21 23:54:33.000000000 +0200 +@@ -166,6 +166,16 @@ + + Say Y here to compile support for virtual HCI devices into the + kernel or say M to compile it as module (hci_vhci). ++ ++config BT_H6300 ++ tristate "H6300 BRF6100 BT DRIVER" ++ help ++ Bluetooth H6300 BRF6100 driver. ++ This driver provides the firmware loading mechanism for the BRF6100 ++ bt hardware in iPAQ h6300. ++ ++ Say Y here to compile support for BRF6100 BT devices into the ++ kernel or say M to compile it as module (h6300_BT). + + endmenu + +diff -Naur linux-2.6.16.16/drivers/bluetooth/Makefile h6300_dev/drivers/bluetooth/Makefile +--- linux-2.6.16.16/drivers/bluetooth/Makefile 2006-05-17 21:41:29.000000000 +0300 ++++ h6300_dev/drivers/bluetooth/Makefile 2006-02-21 23:54:33.000000000 +0200 +@@ -13,6 +13,7 @@ + obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o + obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o + obj-$(CONFIG_BT_HCIBRF6150) += brf6150.o ++obj-$(CONFIG_BT_H6300) += omap/ + + hci_uart-y := hci_ldisc.o + hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o +diff -Naur linux-2.6.16.16/drivers/bluetooth/omap/h6300_bt_brf6100.c h6300_dev/drivers/bluetooth/omap/h6300_bt_brf6100.c +--- linux-2.6.16.16/drivers/bluetooth/omap/h6300_bt_brf6100.c 1970-01-01 02:00:00.000000000 +0200 ++++ h6300_dev/drivers/bluetooth/omap/h6300_bt_brf6100.c 2006-01-23 00:09:23.000000000 +0200 +@@ -0,0 +1,154 @@ ++/* ++ * Bluetooth interface driver for TI BRF6100 on h6300 ++ * ++ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> ++ * Ideas taken from the brf6150 bt driver made by Todd Blumer for the pxa hx4700. ++ * ++ * 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/kernel.h> ++#include <linux/delay.h> ++#include <linux/platform_device.h> ++ ++#include <asm/hardware.h> ++#include <asm/arch/gpio.h> ++ ++#include <asm/arch/h6300_uart_info.h> ++#include "h6300_bt_led.h" ++ ++static void ++h6300_bt_configure(struct uart_omap_port *up, int enable) ++{ ++ printk(KERN_NOTICE "h6300_bt_brf6100.c h6300_bt_configure() started, enable = %d\n", enable); ++ ++ // printk( KERN_NOTICE "h6300 configure bluetooth: %d\n", enable ); ++ if (enable == 0) { ++ omap_set_gpio_dataout(GPIO_N_BT_RST, 1); // turn off gpio, note 1 == off for negative gpios ++ mdelay(5); ++ h6300_clear_led(INDEX_BT_LED); ++ } ++ else if (enable == 1) { ++ omap_set_gpio_dataout(GPIO_N_BT_RST, 1); // turn on gpio, note 0 == on for negative gpios ++ mdelay(5); ++ } ++ else if (enable == 2) { ++ /* ++ * BRF6150's RTS goes low when firmware is ready ++ * so check for CTS=1 (nCTS=0 -> CTS=1). Typical 150ms ++ */ ++/* ++ int tries = 0; ++ do ++ { ++ mdelay(10); ++ } ++ while ((BTMSR & MSR_CTS) == 0 && tries++ < 50); ++*/ ++ h6300_set_led(INDEX_BT_LED, 16, 16); ++ } ++ printk(KERN_NOTICE "h6300_bt_brf6100.c h6300_bt_configure() done\n"); ++} ++ ++static void ++h6300_bt_set_txrx(struct uart_omap_port *up, int txrx) ++{ ++ printk(KERN_NOTICE "h6300_bt_brf6100.c h6300_bt_set_txrx(), txrx = %d done\n", txrx); ++ /* do nothing */ ++} ++ ++static int ++h6300_bt_get_txrx(struct uart_omap_port *up) ++{ ++ printk(KERN_NOTICE "h6300_bt_brf6100.c h6300_bt_get_txrx() done\n"); ++ /* do nothing */ ++ return 0; ++} ++ ++static int ++h6300_bt_probe(struct platform_device *pdev) ++{ ++ struct h6300_uart_funcs *funcs = (struct h6300_uart_funcs *)pdev->dev.platform_data; ++ ++ omap_request_gpio(GPIO_BT_PWR_EN); // ask bt_power_en gpio, remember to release in remove_function ++ omap_set_gpio_direction(GPIO_BT_PWR_EN, 1); // set gpio direction to be output ++ omap_set_gpio_dataout(GPIO_BT_PWR_EN, 1); // turn on gpio ++ ++ mdelay(200); ++ ++ omap_request_gpio(GPIO_N_BT_RST); // ask bt_reset gpio, remember to release in remove_function ++ omap_set_gpio_direction(GPIO_N_BT_RST, 1); // set gpio direction to be output ++ omap_set_gpio_dataout(GPIO_N_BT_RST, 0); // turn on gpio, note 0 == on for negative gpios ++ ++ /* configure bluetooth UART */ ++ //h6300_gpio_mode(GPIO_NR_H6300_BT_RXD_MD); ++ //h6300_gpio_mode(GPIO_NR_H6300_BT_TXD_MD); ++ //h6300_gpio_mode(GPIO_NR_H6300_BT_UART_CTS_MD); ++ //h6300_gpio_mode(GPIO_NR_H6300_BT_UART_RTS_MD); ++ ++ funcs->configure = h6300_bt_configure; ++ funcs->set_txrx = h6300_bt_set_txrx; ++ funcs->get_txrx = h6300_bt_get_txrx; ++ ++ /* Make sure the LED is off */ ++ h6300_clear_led(INDEX_BT_LED); ++ ++ printk(KERN_NOTICE "h6300_bt_brf6100.c h6300_bt_probe() done\n"); ++ ++ return 0; ++} ++ ++static int ++h6300_bt_remove(struct platform_device *pdev) ++{ ++ struct h6300_uart_funcs *funcs = (struct h6300_uart_funcs *)pdev->dev.platform_data; ++ ++ printk(KERN_NOTICE "h6300_bt_brf6100.c h6300_bt_remove() started\n"); ++ ++ omap_free_gpio(GPIO_BT_PWR_EN); ++ omap_free_gpio(GPIO_N_BT_RST); ++ ++ funcs->configure = NULL; ++ funcs->set_txrx = NULL; ++ funcs->get_txrx = NULL; ++ ++ /* Make sure the LED is off */ ++ h6300_clear_led(INDEX_BT_LED); ++ ++ printk(KERN_NOTICE "h6300_bt_brf6100.c, h6300_bt_remove() done\n"); ++ ++ return 0; ++} ++ ++static struct platform_driver bt_driver = { ++ .probe = h6300_bt_probe, ++ .remove = h6300_bt_remove, ++ .driver = { ++ .name = "h6300_bt", ++ }, ++}; ++ ++static int __init ++h6300_bt_init(void) ++{ ++ printk(KERN_NOTICE "h6300 Bluetooth Driver init()\n"); ++ return platform_driver_register(&bt_driver); ++} ++ ++static void __exit ++h6300_bt_exit(void) ++{ ++ printk(KERN_NOTICE "h6300 Bluetooth Driver exit()\n"); ++ platform_driver_unregister(&bt_driver); ++} ++ ++module_init(h6300_bt_init); ++module_exit(h6300_bt_exit); ++ ++MODULE_AUTHOR("Mika Laitio, <lamikr@cc.jyu.fi>"); ++MODULE_DESCRIPTION("iPAQ h6300 BRF6100 Bluetooth driver."); ++MODULE_LICENSE("GPL"); ++ +diff -Naur linux-2.6.16.16/drivers/bluetooth/omap/h6300_bt_led.c h6300_dev/drivers/bluetooth/omap/h6300_bt_led.c +--- linux-2.6.16.16/drivers/bluetooth/omap/h6300_bt_led.c 1970-01-01 02:00:00.000000000 +0200 ++++ h6300_dev/drivers/bluetooth/omap/h6300_bt_led.c 2005-10-06 02:34:39.000000000 +0300 +@@ -0,0 +1,41 @@ ++/* ++ * Bluetooth interface driver helper for controlling bluetooth leds available in iPAQ h6300. ++ * ++ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> ++ * Ideas from the brf6150 bt driver made by Todd Blumer for the pxa hx4700. ++ * ++ * 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/kernel.h> ++#include <linux/delay.h> ++#include <linux/device.h> ++ ++#include <asm/hardware.h> ++#include <asm/arch/gpio.h> ++ ++/* ++ * Low level access for disabling h6300 bt led. ++ * ++ * TODO: implement for h6300 ++ */ ++void h6300_clear_led(int led_num) ++{ ++ printk(KERN_NOTICE "h6300_bt_led.c h6300_clear_led() done\n"); ++ //hx4700_set_led(led_num, 0, 16); ++} ++EXPORT_SYMBOL(h6300_clear_led); ++ ++/* ++ * Low level access for setting up the bt led. ++ * ++ * TODO: implement for h6300 ++ */ ++void h6300_set_led(int led_num, int duty_time, int cycle_time) ++{ ++ printk(KERN_NOTICE "h6300_bt_led.c h6300_set_led() done\n"); ++} ++EXPORT_SYMBOL(h6300_set_led); +diff -Naur linux-2.6.16.16/drivers/bluetooth/omap/h6300_bt_led.h h6300_dev/drivers/bluetooth/omap/h6300_bt_led.h +--- linux-2.6.16.16/drivers/bluetooth/omap/h6300_bt_led.h 1970-01-01 02:00:00.000000000 +0200 ++++ h6300_dev/drivers/bluetooth/omap/h6300_bt_led.h 2005-10-06 02:34:39.000000000 +0300 +@@ -0,0 +1,9 @@ ++#ifndef H6300_BT_LED_H_ ++#define H6300_BT_LED_H_ ++ ++#define INDEX_BT_LED 2 ++ ++void h6300_clear_led(int led_num); ++void h6300_set_led(int led_num, int duty_time, int cycle_time); ++ ++#endif /*H6300_BT_LED_H_*/ +diff -Naur linux-2.6.16.16/drivers/bluetooth/omap/Makefile h6300_dev/drivers/bluetooth/omap/Makefile +--- linux-2.6.16.16/drivers/bluetooth/omap/Makefile 1970-01-01 02:00:00.000000000 +0200 ++++ h6300_dev/drivers/bluetooth/omap/Makefile 2005-10-06 02:34:39.000000000 +0300 +@@ -0,0 +1,6 @@ ++# ++# Makefile for the Linux iPAQ H6300 BRF6100 Bluetooth device drivers. ++# ++ ++h6300_bt-objs := h6300_bt_led.o h6300_bt_brf6100.o ++obj-$(CONFIG_BT_H6300) += h6300_bt.o +diff -Naur linux-2.6.16.16/drivers/i2c/busses/i2c-omap.c h6300_dev/drivers/i2c/busses/i2c-omap.c +--- linux-2.6.16.16/drivers/i2c/busses/i2c-omap.c 2006-05-17 21:41:29.000000000 +0300 ++++ h6300_dev/drivers/i2c/busses/i2c-omap.c 2006-04-02 00:23:01.000000000 +0300 +@@ -163,17 +163,22 @@ + + static int omap_i2c_get_clocks(struct omap_i2c_dev *dev) + { +- if (cpu_is_omap16xx() || cpu_is_omap24xx()) { ++ if (cpu_is_omap24xx()) { + dev->iclk = clk_get(dev->dev, "i2c_ick"); +- if (IS_ERR(dev->iclk)) ++ if (IS_ERR(dev->iclk)) { + return -ENODEV; ++ } ++ dev->fclk = clk_get(dev->dev, "i2c_fck"); ++ if (IS_ERR(dev->fclk)) { ++ clk_put(dev->fclk); ++ return -ENODEV; ++ } + } + +- dev->fclk = clk_get(dev->dev, "i2c_fck"); +- if (IS_ERR(dev->fclk)) { +- if (dev->iclk != NULL) +- clk_put(dev->iclk); +- return -ENODEV; ++ if (cpu_class_is_omap1()) { ++ dev->fclk = clk_get(dev->dev, "i2c_fck"); ++ if (IS_ERR(dev->fclk)) ++ return -ENODEV; + } + + return 0; +diff -Naur linux-2.6.16.16/drivers/i2c/chips/Kconfig h6300_dev/drivers/i2c/chips/Kconfig +--- linux-2.6.16.16/drivers/i2c/chips/Kconfig 2006-05-17 21:41:29.000000000 +0300 ++++ h6300_dev/drivers/i2c/chips/Kconfig 2006-04-24 20:53:29.000000000 +0300 +@@ -46,6 +46,16 @@ + This driver can also be built as a module. If so, the module + will be called pcf8574. + ++config PCA9535 ++ tristate "Philips PCA9535 16-bit I/O port" ++ depends on I2C ++ help ++ If you say yes here you get support for the Philips PCA9535 ++ 16-bit I/O port. ++ ++ This driver can also be built as a module. If so, the module ++ will be called pca9535. ++ + config SENSORS_PCA9539 + tristate "Philips PCA9539 16-bit I/O port" + depends on I2C && EXPERIMENTAL +diff -Naur linux-2.6.16.16/drivers/i2c/chips/Makefile h6300_dev/drivers/i2c/chips/Makefile +--- linux-2.6.16.16/drivers/i2c/chips/Makefile 2006-05-17 21:41:29.000000000 +0300 ++++ h6300_dev/drivers/i2c/chips/Makefile 2006-04-24 20:53:29.000000000 +0300 +@@ -7,6 +7,7 @@ + obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o + obj-$(CONFIG_SENSORS_MAX6875) += max6875.o + obj-$(CONFIG_SENSORS_M41T00) += m41t00.o ++obj-$(CONFIG_PCA9535) += pca9535.o + obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o + obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o + obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o +diff -Naur linux-2.6.16.16/drivers/i2c/chips/pca9535.c h6300_dev/drivers/i2c/chips/pca9535.c +--- linux-2.6.16.16/drivers/i2c/chips/pca9535.c 1970-01-01 02:00:00.000000000 +0200 ++++ h6300_dev/drivers/i2c/chips/pca9535.c 2006-04-24 20:53:29.000000000 +0300 +@@ -0,0 +1,412 @@ ++/* ++ Driver for Philips PCA9535 16-bit low power I/O port with interrupt ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ ++ Copyright (C) 2005 Husam Senussi ++ Framework based on Pawel Kolodziejski's pca9535 driver in ++ handheld.org's 2.6.13 kernel. Driver updated by Mika Laitio. ++*/ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/i2c.h> ++#include <linux/hwmon-sysfs.h> ++#include <linux/hwmon.h> ++#include <linux/err.h> ++ ++#include <asm/arch/pca9535.h> ++#include <linux/delay.h> ++ ++#include <linux/interrupt.h> ++#include <asm/mach-types.h> ++#include <asm/irq.h> ++#include <asm/mach/arch.h> ++#include <asm/hardware.h> ++ ++EXPORT_SYMBOL(pca9535_gpio_read); ++EXPORT_SYMBOL(pca9535_gpio_write); ++EXPORT_SYMBOL(pca9535_gpio_direction); ++ ++static int pca9535_attach_adapter(struct i2c_adapter *adapter); ++static int pca9535_detach_client(struct i2c_client *client); ++static int pca9535_attach(struct i2c_adapter *adapter, int address, int zero_or_minus_one); ++static u32 pca9535_read_reg(struct i2c_client *client, u8 regaddr); ++static void pca9535_write_reg(struct i2c_client *client, u8 regaddr, u16 param); ++ ++enum pca9535_cmd ++{ ++ PCA9535_INPUT_0 = 0, ++ PCA9535_INPUT_1 = 1, ++ PCA9535_OUTPUT_0 = 2, ++ PCA9535_OUTPUT_1 = 3, ++ PCA9535_INVERT_0 = 4, ++ PCA9535_INVERT_1 = 5, ++ PCA9535_DIRECTION_0 = 6, ++ PCA9535_DIRECTION_1 = 7, ++}; ++ ++struct pca9535_data { ++ struct semaphore lock; ++ struct i2c_client client; ++}; ++ ++static struct i2c_driver pca9535_driver = { ++ .driver = { ++ .name = "pca9535", ++ }, ++ .attach_adapter = pca9535_attach_adapter, ++ .detach_client = pca9535_detach_client, ++}; ++ ++static struct i2c_client *pca9535_i2c_client = NULL; ++static struct pca9535_data pca9535_inited; ++ ++static unsigned short normal_i2c[] = { 0x20, I2C_CLIENT_END }; ++ ++#define DRIVER_VERSION "20 OCT 2005" ++#define DRIVER_NAME "PCA9535" ++ ++/* ++ * sysfs callback function. ++ */ ++static ssize_t pca9535_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct sensor_device_attribute *psa = to_sensor_dev_attr(attr); ++ struct i2c_client *client = to_i2c_client(dev); ++ return sprintf(buf, "%02X\n", (pca9535_read_reg(client, psa->index) >> 8)); ++} ++ ++/* ++ * sysfs callback function. ++ */ ++static ssize_t pca9535_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct sensor_device_attribute *psa = to_sensor_dev_attr(attr); ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned long val = simple_strtoul(buf, NULL, 0); ++ unsigned long old = pca9535_read_reg(client, psa->index); ++ ++ if (val > 0xff) ++ return -EINVAL; ++ ++ val = (old & 0xff) | (val << 8); ++ pca9535_write_reg(client, psa->index, val); ++ return count; ++} ++ ++#define PCA9535_ENTRY_RO(name, cmd_idx) \ ++ static SENSOR_DEVICE_ATTR(name, S_IRUGO, pca9535_show, NULL, cmd_idx) ++ ++#define PCA9535_ENTRY_RW(name, cmd_idx) \ ++ static SENSOR_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, pca9535_show, \ ++ pca9535_store, cmd_idx) ++ ++PCA9535_ENTRY_RO(input0, PCA9535_INPUT_0); ++PCA9535_ENTRY_RO(input1, PCA9535_INPUT_1); ++PCA9535_ENTRY_RW(output0, PCA9535_OUTPUT_0); ++PCA9535_ENTRY_RW(output1, PCA9535_OUTPUT_1); ++PCA9535_ENTRY_RW(invert0, PCA9535_INVERT_0); ++PCA9535_ENTRY_RW(invert1, PCA9535_INVERT_1); ++PCA9535_ENTRY_RW(direction0, PCA9535_DIRECTION_0); ++PCA9535_ENTRY_RW(direction1, PCA9535_DIRECTION_1); ++ ++static struct attribute *pca9535_attributes[] = { ++ &sensor_dev_attr_input0.dev_attr.attr, ++ &sensor_dev_attr_input1.dev_attr.attr, ++ &sensor_dev_attr_output0.dev_attr.attr, ++ &sensor_dev_attr_output1.dev_attr.attr, ++ &sensor_dev_attr_invert0.dev_attr.attr, ++ &sensor_dev_attr_invert1.dev_attr.attr, ++ &sensor_dev_attr_direction0.dev_attr.attr, ++ &sensor_dev_attr_direction1.dev_attr.attr, ++ NULL ++}; ++ ++static struct attribute_group pca9535_defattr_group = { ++ .attrs = pca9535_attributes, ++}; ++//End of sysfs management code. ++ ++I2C_CLIENT_INSMOD; ++ ++u32 pca9535_read_input(void) ++{ ++ return pca9535_read_reg(pca9535_i2c_client, 0); ++} ++EXPORT_SYMBOL(pca9535_read_input); ++ ++void pca9535_write_output(u16 param) ++{ ++ pca9535_write_reg(pca9535_i2c_client, 2, param); ++} ++EXPORT_SYMBOL(pca9535_write_output); ++ ++void pca9535_set_dir(u16 param) ++{ ++ pca9535_write_reg(pca9535_i2c_client, 6, param); ++} ++EXPORT_SYMBOL(pca9535_set_dir); ++ ++static int pca9535_attach_adapter(struct i2c_adapter *adapter) ++{ ++ return i2c_probe(adapter, &addr_data, pca9535_attach); ++} ++ ++static int pca9535_attach(struct i2c_adapter *adapter, int address, int zero_or_minus_one) ++{ ++ struct i2c_client *new_client; ++ int err = 0; ++ ++ new_client = &(pca9535_inited.client); ++ i2c_set_clientdata(new_client, 0); ++ new_client->addr = address; ++ new_client->adapter = adapter; ++ new_client->driver = &pca9535_driver; ++ strcpy(new_client->name, DRIVER_NAME); ++ ++ if ((err = i2c_attach_client(new_client))) ++ goto exit_free; ++ ++ pca9535_i2c_client = new_client; ++ ++ init_MUTEX(&pca9535_inited.lock); ++ i2c_set_clientdata(pca9535_i2c_client, &pca9535_inited); ++ ++ sysfs_create_group(&pca9535_i2c_client->dev.kobj, &pca9535_defattr_group); ++ ++ printk("pca9535_attach() ok, address = %d, zero_or_minus_one = %d\n", address, zero_or_minus_one); ++ return 0; ++ ++exit_free: ++ printk("pca9535_attach() failed, error code = %d\n", err); ++ return err; ++} ++ ++static int pca9535_detach_client(struct i2c_client *client) ++{ ++ int err; ++ ++ if ((err = i2c_detach_client(client))) { ++ dev_err(&client->dev, "Client deregistration failed, client not detached.\n"); ++ return err; ++ } ++ pca9535_i2c_client = NULL; ++ ++ return 0; ++} ++ ++static int __init pca9535_init(void) ++{ ++ return i2c_add_driver(&pca9535_driver); ++} ++ ++static void __exit pca9535_exit(void) ++{ ++ i2c_del_driver(&pca9535_driver); ++} ++ ++/* ++ * Reads the value of GPIO available via I2C. ++ */ ++int pca9535_gpio_read(int gpio){ ++ unsigned char reg = 0; ++ unsigned long val = 0; ++ ++ printk("9535_gpio_read() called\n"); ++ if(!pca9535_i2c_client) ++ return -ENODEV; ++ ++ if(gpio < GPIO0 || gpio > GPIO17) ++ return -EINVAL; ++ ++ if(gpio >= GPIO0 && gpio <= GPIO7){ ++ reg = PCA9535_INPUT_0; ++ gpio -= GPIO0; ++ }else if(gpio >= GPIO8 && gpio <= GPIO17){ ++ reg = PCA9535_INPUT_1; ++ gpio -= GPIO8; ++ } ++ ++ down(&pca9535_inited.lock); ++ ++ // Read the existing values first ++ val = pca9535_read_reg(pca9535_i2c_client, reg) >> 8; ++ val = (val >> gpio) & 0x01; ++ ++ up(&pca9535_inited.lock); ++ ++ return val; ++} ++ ++/* ++ * Set the value of I2C GPIO. ++ */ ++int pca9535_gpio_write(int gpio, unsigned char value){ ++ unsigned char in_reg = 0; ++ unsigned char out_reg = 0; ++ unsigned long val = 0; ++ unsigned long old = 0; ++ int ret = 0; ++ ++ if(!pca9535_i2c_client) ++ return -ENODEV; ++ ++ if(gpio < GPIO0 || gpio > GPIO17) ++ return -EINVAL; ++ ++ if(gpio >= GPIO0 && gpio <= GPIO7){ ++ in_reg = PCA9535_INPUT_0; ++ out_reg = PCA9535_OUTPUT_0; ++ gpio -= GPIO0; ++ }else if(gpio >= GPIO8 && gpio <= GPIO17){ ++ in_reg = PCA9535_INPUT_1; ++ out_reg = PCA9535_OUTPUT_1; ++ gpio -= GPIO8; ++ } ++ ++ down(&pca9535_inited.lock); ++ ++ // Read the existing values first ++ val = pca9535_read_reg(pca9535_i2c_client, in_reg); ++ old = val >> 8; ++ ++ switch(value){ ++ case LOW: ++ old |= (1 << gpio); ++ break; ++ case HI: ++ old &= ~(1 << gpio); ++ break; ++ default: ++ ret = -EINVAL; ++ goto error; ++ } ++ ++ val = (val & 0xff) | (old << 8); ++ ++ // write the values back to the register ++ pca9535_write_reg(pca9535_i2c_client, out_reg, val); ++error: ++ ++ up(&pca9535_inited.lock); ++ return ret; ++} ++ ++/* ++ * Set the direction of I2C GPIO. ++ */ ++int pca9535_gpio_direction(int gpio, unsigned char direction){ ++ unsigned char reg = 0; ++ unsigned long val = 0; ++ unsigned long old = 0; ++ int ret = 0; ++ ++ if(!pca9535_i2c_client) ++ return -ENODEV; ++ ++ if(gpio < GPIO0 || gpio > GPIO17) ++ return -EINVAL; ++ ++ if(gpio >= GPIO0 && gpio <= GPIO7){ ++ reg = PCA9535_DIRECTION_0; ++ gpio -= GPIO0; ++ }else if(gpio >= GPIO8 && gpio <= GPIO17){ ++ reg = PCA9535_DIRECTION_1; ++ gpio -= GPIO8; ++ } ++ ++ down(&pca9535_inited.lock); ++ ++ // Read the existing values first ++ old = pca9535_read_reg(pca9535_i2c_client, reg); ++ val = old >> 8; ++ ++ switch(direction){ ++ case GPIO_INPUT: ++ val |= (1 << gpio); ++ break; ++ case GPIO_OUTPUT: ++ val &= ~(1 << gpio); ++ break; ++ default: ++ ret = -EINVAL; ++ goto error; ++ } ++ ++ val = (old & 0xff) | (val << 8); ++ ++ // write the values back to the register ++ pca9535_write_reg(pca9535_i2c_client, reg, val); ++error: ++ ++ up(&pca9535_inited.lock); ++ return ret; ++} ++ ++static u32 pca9535_read_reg(struct i2c_client *client, u8 regaddr) ++{ ++ char buffer[3]; ++ int r; ++ u32 data; ++ ++ buffer[0] = regaddr; ++ buffer[1] = 0; ++ buffer[2] = 0; ++ ++ r = i2c_master_send(client, buffer, 1); ++ if (r != 1) { ++ printk(KERN_ERR "pca9535: read failed, status %d\n", r); ++ return 0xffffffff; ++ } ++ ++ r = i2c_master_recv(client, buffer, 3); ++ if (r != 3) { ++ printk(KERN_ERR "pca9535: read failed, status %d\n", r); ++ return 0xffffffff; ++ } ++ ++ data = buffer[1]; ++ data |= buffer[2] << 8; ++ //printk(KERN_ERR "%s: reading %x in %x\n", __FUNCTION__, data, regaddr); ++ ++ return data; ++} ++ ++static void pca9535_write_reg(struct i2c_client *client, u8 regaddr, u16 data) ++{ ++ char buffer[3]; ++ int r; ++ ++ //printk(KERN_ERR "%s: writing %x in %x\n", __FUNCTION__, data, regaddr); ++ buffer[0] = regaddr; ++ buffer[1] = data >> 8; ++ buffer[2] = data & 0xff; ++ ++ r = i2c_master_send(client, buffer, 3); ++ if (r != 3) { ++ printk(KERN_ERR "pca9535: write failed, status %d\n", r); ++ } ++} ++ ++MODULE_AUTHOR("Husam Senussi <husamsenussi@gmail.com>"); ++MODULE_DESCRIPTION("PCA9535 driver"); ++MODULE_LICENSE("GPL"); ++ ++module_init(pca9535_init); ++module_exit(pca9535_exit); +diff -Naur linux-2.6.16.16/drivers/input/keyboard/omap-keypad.c h6300_dev/drivers/input/keyboard/omap-keypad.c +--- linux-2.6.16.16/drivers/input/keyboard/omap-keypad.c 2006-05-17 21:41:29.000000000 +0300 ++++ h6300_dev/drivers/input/keyboard/omap-keypad.c 2006-04-24 20:53:29.000000000 +0300 +@@ -4,11 +4,12 @@ + * OMAP Keypad Driver + * + * Copyright (C) 2003 Nokia Corporation +- * Written by Timo Teräs <ext-timo.teras@nokia.com> ++ * Written by Timo Ter�s <ext-timo.teras@nokia.com> ++ * iPAQ h6300 key and joypad support added by Mika Laitio. (2005) + * + * Added support for H2 & H3 Keypad + * Copyright (C) 2004 Texas Instruments +- * ++ * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or +@@ -44,6 +45,19 @@ + #include <asm/arch/mux.h> + + #undef NEW_BOARD_LEARNING_MODE ++//#define NEW_BOARD_LEARNING_MODE 1 ++ ++/* ++ * Following 5 keypad events are not really sent to userspace. ++ * Instead if the good combination of them is sent, then that is send. ++ * (up, right, down, left, enter) ++ */ ++#define _H6300_JOYPAD_UP_RIGHT 1 // 00001 ++#define _H6300_JOYPAD_DOWN_RIGHT 2 // 00010 ++#define _h6300_JOYPAD_DOWN_LEFT 4 // 00100 ++#define _h6300_JOYPAD_UP_LEFT 8 // 01000 ++#define _H6300_JOYPAD_KEY_OK 16 // 10000 ++#define _H6300_JOYPAD_REPORT_COLUMN 4 + + static void omap_kp_tasklet(unsigned long); + static void omap_kp_timer(unsigned long); +@@ -53,6 +67,8 @@ + static int kp_enable = 1; + static int kp_cur_group = -1; + ++static int prevJoypadKeycodePressEmulated; ++ + struct omap_kp { + struct input_dev *input; + struct timer_list timer; +@@ -139,7 +155,7 @@ + for (col = 0; col < omap_kp->cols; col++) { + omap_writew(~(1 << col) & 0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC); + +- if (machine_is_omap_osk() || machine_is_omap_h2() || machine_is_omap_h3()) { ++ if (machine_is_omap_osk() || machine_is_omap_h2() || machine_is_omap_h3() || machine_is_omap_h6300()) { + udelay(9); + } else { + udelay(4); +@@ -169,17 +185,26 @@ + return -1; + } + ++int is_key_down(unsigned char new_state[], ++ int col, ++ int row) ++{ ++ return (new_state[col] & (1 << row)) ? 1 : 0; ++} ++ + static void omap_kp_tasklet(unsigned long data) + { + struct omap_kp *omap_kp_data = (struct omap_kp *) data; + unsigned char new_state[8], changed, key_down = 0; + int col, row; + int spurious = 0; ++ int report_key, report_col, report_row, joypad_checked; // h6300-joypad specific variables + + /* check for any changes */ + omap_kp_scan_keypad(omap_kp_data, new_state); + + /* check for changes and print those */ ++ joypad_checked = 0; + for (col = 0; col < omap_kp_data->cols; col++) { + changed = new_state[col] ^ keypad_state[col]; + key_down |= new_state[col]; +@@ -201,14 +226,177 @@ + spurious = 1; + continue; + } +- +- if (!(kp_cur_group == (key & GROUP_MASK) || +- kp_cur_group == -1)) +- continue; +- +- kp_cur_group = key & GROUP_MASK; +- input_report_key(omap_kp_data->input, key & ~GROUP_MASK, +- !!(new_state[col] & (1 << row))); ++ if (machine_is_omap_h6300() && ++ ((col == 1) || (col == _H6300_JOYPAD_REPORT_COLUMN))) ++ { ++ if (col == _H6300_JOYPAD_REPORT_COLUMN) ++ { ++ continue; ++ } ++ if ((joypad_checked == 0) && ++ ((key == _H6300_JOYPAD_KEY_OK) || ++ (key == _h6300_JOYPAD_UP_LEFT) || ++ (key == _H6300_JOYPAD_UP_RIGHT) || ++ (key == _H6300_JOYPAD_DOWN_RIGHT) || ++ (key == _h6300_JOYPAD_DOWN_LEFT))) ++ { ++ if (is_key_down(new_state, col, row)) ++ { ++ /* ++ * only enter pressed ++ * 1 0 0 _H6300_JOYPAD_KEY_OK 0 0 ++ * --> 100100 == 36 ++ */ ++ if (new_state[1] == 36) ++ { ++ joypad_checked = 1; ++ prevJoypadKeycodePressEmulated = KEY_ENTER; ++ new_state[_H6300_JOYPAD_REPORT_COLUMN] = 48; //110000 ++ report_key = prevJoypadKeycodePressEmulated; ++ report_col = _H6300_JOYPAD_REPORT_COLUMN; ++ report_row = 4; ++ input_report_key(omap_kp_data->input, ++ report_key, ++ new_state[report_col] & (1 << report_row)); ++ } ++ /* ++ * enter, up_left and up_right sensors pressed. ++ * 1 _H6300_JOYPAD_UP_RIGHT 0 _H6300_JOYPAD_KEY_OK 0 _h6300_JOYPAD_UP_LEFT ++ * --> 110101 == 53 ++ * OR ++ * 1 KEY_UP_RIGHT 0 0 0 _h6300_JOYPAD_UP_LEFT ++ * --> 110001 == 42 ++ * --> move to up ++ */ ++ else if ((new_state[1] == 53) || ++ (new_state[1] == 49)) ++ { ++ joypad_checked = 1; ++ prevJoypadKeycodePressEmulated = KEY_UP; ++ new_state[_H6300_JOYPAD_REPORT_COLUMN] = 40; //101000 ++ report_key = prevJoypadKeycodePressEmulated; ++ report_col = _H6300_JOYPAD_REPORT_COLUMN; ++ report_row = 3; ++ input_report_key(omap_kp_data->input, ++ report_key, ++ new_state[report_col] & (1 << report_row)); ++ } ++ /* ++ * enter, down_left and down_right sensors pressed ++ * --> 101110 == 46 ++ * OR ++ * down_left and down_right ++ * -->101010 == 42 ++ * --> move to down ++ */ ++ else if ((new_state[1] == 46) || ++ (new_state[1] == 42)) ++ { ++ joypad_checked = 1; ++ prevJoypadKeycodePressEmulated = KEY_DOWN; ++ new_state[_H6300_JOYPAD_REPORT_COLUMN] = 34; //100010 ++ report_key = prevJoypadKeycodePressEmulated; ++ report_col = _H6300_JOYPAD_REPORT_COLUMN; ++ report_row = 1; ++ input_report_key(omap_kp_data->input, ++ report_key, ++ new_state[report_col] & (1 << report_row)); ++ } ++ /* ++ * enter, up_right and down_right sensors pressed ++ * --> 111100 == 60 ++ * or ++ * down_right and up_right ++ * --> 111000 == 56 ++ * --> move to right ++ */ ++ else if ((new_state[1] == 60) || ++ (new_state[1] == 56)) ++ { ++ joypad_checked = 1; ++ prevJoypadKeycodePressEmulated = KEY_RIGHT; ++ new_state[_H6300_JOYPAD_REPORT_COLUMN] = 33; //100001 ++ report_key = prevJoypadKeycodePressEmulated; ++ report_col = _H6300_JOYPAD_REPORT_COLUMN; ++ report_row = 0; ++ input_report_key(omap_kp_data->input, ++ report_key, ++ new_state[report_col] & (1 << report_row)); ++ } ++ /* ++ * enter, up_left and down_left sensors pressed ++ * --> 100111 == 39 ++ * or up_left and down_left ++ * --> 100011 == 35 ++ * --> move to left ++ */ ++ else if ((new_state[1] == 39) || ++ (new_state[1] == 35)) ++ { ++ joypad_checked = 1; ++ prevJoypadKeycodePressEmulated = KEY_LEFT; ++ new_state[_H6300_JOYPAD_REPORT_COLUMN] = 36; //100100 ++ report_key = prevJoypadKeycodePressEmulated; ++ report_col = _H6300_JOYPAD_REPORT_COLUMN; ++ report_row = 2; ++ input_report_key(omap_kp_data->input, ++ report_key, ++ new_state[report_col] & (1 << report_row)); ++ } ++ else ++ { ++ //printk("missed new_state = %d\n", new_state[1]); ++ } ++ } ++ else ++ { ++ if (prevJoypadKeycodePressEmulated != 0) ++ { ++ // report key up event ++ joypad_checked = 1; ++ new_state[_H6300_JOYPAD_REPORT_COLUMN] = 32; //100000 ++ report_key = prevJoypadKeycodePressEmulated; ++ report_col = _H6300_JOYPAD_REPORT_COLUMN; ++ switch(prevJoypadKeycodePressEmulated) ++ { ++ case KEY_RIGHT: ++ report_row = 0; ++ break; ++ case KEY_DOWN: ++ report_row = 1; ++ break; ++ case KEY_LEFT: ++ report_row = 2; ++ break; ++ case KEY_UP: ++ report_row = 3; ++ break; ++ case KEY_ENTER: ++ report_row = 4; ++ break; ++ default: ++ printk(KERN_WARNING "Unknown iPAQ h6300 column 1 key = %d released. This should newer happen!\n", ++ key); ++ report_row = 0; ++ } ++ input_report_key(omap_kp_data->input, ++ report_key, ++ new_state[report_col] & (1 << report_row)); ++ prevJoypadKeycodePressEmulated = 0; ++ } ++ } ++ } ++ } ++ else ++ { ++ if (!(kp_cur_group == (key & GROUP_MASK) || ++ kp_cur_group == -1)) ++ continue; ++ ++ kp_cur_group = key & GROUP_MASK; ++ input_report_key(omap_kp_data->input, key & ~GROUP_MASK, ++ !!(new_state[col] & (1 << row))); ++ } + #endif + } + } +@@ -348,10 +536,11 @@ + omap_set_gpio_direction(row_gpios[i], 1); + } + } ++ prevJoypadKeycodePressEmulated = 0; + + init_timer(&omap_kp->timer); + omap_kp->timer.function = omap_kp_timer; +- omap_kp->timer.data = (unsigned long) omap_kp; ++ omap_kp->timer.data = (unsigned long)omap_kp; + + /* get the irq and init timer*/ + tasklet_enable(&kp_tasklet); +@@ -376,7 +565,7 @@ + input_register_device(omap_kp->input); + + if (machine_is_omap_h2() || machine_is_omap_h3() || +- machine_is_omap_perseus2()) { ++ machine_is_omap_perseus2() || machine_is_omap_h6300()) { + omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_DEBOUNCING); + } + /* scan current status and enable interrupt */ +@@ -447,6 +636,6 @@ + module_init(omap_kp_init); + module_exit(omap_kp_exit); + +-MODULE_AUTHOR("Timo Teräs"); ++MODULE_AUTHOR("Timo Ter�s"); + MODULE_DESCRIPTION("OMAP Keypad Driver"); + MODULE_LICENSE("GPL"); +diff -Naur linux-2.6.16.16/drivers/input/touchscreen/omap/Makefile h6300_dev/drivers/input/touchscreen/omap/Makefile +--- linux-2.6.16.16/drivers/input/touchscreen/omap/Makefile 2006-05-17 21:41:30.000000000 +0300 ++++ h6300_dev/drivers/input/touchscreen/omap/Makefile 2005-10-22 03:52:45.000000000 +0300 +@@ -8,5 +8,6 @@ + objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_H3) += ts_hx.o + objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += ts_inn1510.o + objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_OSK) += ts_osk.o ++objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_H6300) += ts_hx.o + + omapts-objs := omap_ts.o $(objs-yy) +diff -Naur linux-2.6.16.16/drivers/input/touchscreen/omap/omap_ts.c h6300_dev/drivers/input/touchscreen/omap/omap_ts.c +--- linux-2.6.16.16/drivers/input/touchscreen/omap/omap_ts.c 2006-05-17 21:41:30.000000000 +0300 ++++ h6300_dev/drivers/input/touchscreen/omap/omap_ts.c 2006-02-21 23:54:33.000000000 +0200 +@@ -46,7 +46,7 @@ + #define OMAP_TS_NAME "omap_ts" + + static struct ts_device *__initdata ts_devs[] = { +-#if defined(CONFIG_MACH_OMAP_H2) || defined(CONFIG_MACH_OMAP_H3) ++#if defined(CONFIG_MACH_OMAP_H2) || defined(CONFIG_MACH_OMAP_H3) || defined(CONFIG_MACH_OMAP_H6300) + &hx_ts, + #endif + #ifdef CONFIG_MACH_OMAP_OSK +diff -Naur linux-2.6.16.16/drivers/input/touchscreen/omap/ts_hx.c h6300_dev/drivers/input/touchscreen/omap/ts_hx.c +--- linux-2.6.16.16/drivers/input/touchscreen/omap/ts_hx.c 2006-05-17 21:41:30.000000000 +0300 ++++ h6300_dev/drivers/input/touchscreen/omap/ts_hx.c 2006-04-24 20:53:29.000000000 +0300 +@@ -39,6 +39,7 @@ + + #define H2_GPIO_NUM 4 + #define H3_GPIO_NUM 48 ++#define H6300_GPIO_NUM 2 + + #define OMAP_TSC2101_XRES 500 + #define TOUCHSCREEN_DATA_REGISTERS_PAGE 0x0 +@@ -88,6 +89,9 @@ + } else if (machine_is_omap_h3()) { + gpio = H3_GPIO_NUM; + omap_cfg_reg(W19_1610_GPIO48); ++ } else if (machine_is_omap_h6300 ()) { ++ gpio = H6300_GPIO_NUM; ++ omap_cfg_reg(M14_1510_GPIO2); + } else + return -ENODEV; + +@@ -180,5 +184,7 @@ + omap_free_gpio(H2_GPIO_NUM); + else if (machine_is_omap_h3()) + omap_free_gpio(H3_GPIO_NUM); ++ else if (machine_is_omap_h6300()) ++ omap_free_gpio(H6300_GPIO_NUM); + } + #endif +diff -Naur linux-2.6.16.16/drivers/mmc/mmc.c h6300_dev/drivers/mmc/mmc.c +--- linux-2.6.16.16/drivers/mmc/mmc.c 2006-05-17 21:41:30.000000000 +0300 ++++ h6300_dev/drivers/mmc/mmc.c 2006-03-28 10:34:39.000000000 +0300 +@@ -964,7 +964,7 @@ + mmc_decode_scr(card); + } + +- mmc_deselect_cards(host); ++ //mmc_deselect_cards(host); + } + + static unsigned int mmc_calculate_clock(struct mmc_host *host) +diff -Naur linux-2.6.16.16/drivers/ssi/omap-tsc2101.c h6300_dev/drivers/ssi/omap-tsc2101.c +--- linux-2.6.16.16/drivers/ssi/omap-tsc2101.c 2006-05-17 21:41:30.000000000 +0300 ++++ h6300_dev/drivers/ssi/omap-tsc2101.c 2006-04-24 20:53:29.000000000 +0300 +@@ -36,10 +36,11 @@ + #include <asm/arch/hardware.h> + #include <asm/hardware/tsc2101.h> + #include <asm/arch/gpioexpander.h> ++#include <asm/arch/gpio.h> + + #include "omap-tsc2101.h" + +-#if CONFIG_ARCH_OMAP16XX ++#if CONFIG_ARCH_OMAP1 + #include <../drivers/ssi/omap-uwire.h> + #else + #error "Unsupported configuration" +@@ -66,27 +67,28 @@ + if (count++ == 0) { + int ret = 0; + /* set the Mux to provide MCLK to TSC2101 */ +- if (machine_is_omap_h3()) { ++ if (machine_is_omap_h3()) + ret = omap_cfg_reg(V5_1710_MCLK_ON); +- } else { +- if (machine_is_omap_h2()) { +- ret = omap_cfg_reg(R10_1610_MCLK_ON); ++ else if (machine_is_omap_h2()) ++ ret = omap_cfg_reg(R10_1610_MCLK_ON); ++ else if (machine_is_omap_h6300()) ++ ret = omap_cfg_reg(R10_1510_MCLK_ON); ++ ++ if (!cpu_is_omap1510 ()) { ++ /* Get the MCLK */ ++ tsc2101_mclk_ck = clk_get(NULL, "mclk"); ++ if (NULL == tsc2101_mclk_ck) { ++ printk(KERN_ERR "Unable to get the clock MCLK!!!\n");; ++ ret = -EPERM; ++ goto done; + } +- } +- +- /* Get the MCLK */ +- tsc2101_mclk_ck = clk_get(NULL, "mclk"); +- if (NULL == tsc2101_mclk_ck) { +- printk(KERN_ERR "Unable to get the clock MCLK!!!\n");; +- ret = -EPERM; +- goto done; +- } +- if (clk_set_rate(tsc2101_mclk_ck, 12000000)) { +- printk(KERN_ERR "Unable to set rate to the MCLK!!!\n");; +- ret = -EPERM; +- goto done; +- } +- clk_enable(tsc2101_mclk_ck); ++ if (clk_set_rate(tsc2101_mclk_ck, 12000000)) { ++ printk(KERN_ERR "Unable to set rate to the MCLK!!!\n");; ++ ret = -EPERM; ++ goto done; ++ } ++ clk_enable(tsc2101_mclk_ck); ++ } /* if (!cpu_is_omap1510 ()) */ + + ret = omap_tsc2101_configure(); + +@@ -116,10 +118,16 @@ + } + } + +- /* Release the MCLK */ +- clk_disable(tsc2101_mclk_ck); +- clk_put(tsc2101_mclk_ck); +- tsc2101_mclk_ck = NULL; ++ if (!cpu_is_omap1510 ()) { ++ /* Release the MCLK */ ++ clk_disable(tsc2101_mclk_ck); ++ clk_put(tsc2101_mclk_ck); ++ tsc2101_mclk_ck = NULL; ++ } ++ ++#if defined(CONFIG_MACH_OMAP_H6300) ++ omap_free_gpio(8); ++#endif + + module_put(THIS_MODULE); + } +@@ -150,7 +158,10 @@ + return; + } + } +- if (machine_is_omap_h3()) { ++ if (machine_is_omap_h3() || machine_is_omap_h6300()) { ++ ++ if (machine_is_omap_h6300()) ++ omap_set_gpio_dataout (8, 0); + + ret = + omap_uwire_data_transfer(0, ((page << 11) | (address << 5)), +@@ -159,6 +170,8 @@ + printk(KERN_ERR + "uwire-write returned error for address %x\n", + address); ++ if (machine_is_omap_h6300()) ++ omap_set_gpio_dataout (8, 1); + return; + } + ret = omap_uwire_data_transfer(0, data, 16, 0, NULL, 0); +@@ -166,10 +179,14 @@ + printk(KERN_ERR + "uwire-write returned error for address %x\n", + address); ++ if (machine_is_omap_h6300()) ++ omap_set_gpio_dataout (8, 1); + return; + } +- } + ++ if (machine_is_omap_h6300()) ++ omap_set_gpio_dataout (8, 1); ++ } + } + + void omap_tsc2101_reads(int page, u8 startaddress, u16 * data, int numregs) +@@ -178,9 +195,13 @@ + if (machine_is_omap_h2()) { + cs = 1; + } +- if (machine_is_omap_h3()) { ++ if (machine_is_omap_h3() || machine_is_omap_h6300()) { + cs = 0; + } ++ ++ if (machine_is_omap_h6300()) ++ omap_set_gpio_dataout(8, 0); ++ + (void)omap_uwire_data_transfer(cs, (0x8000 | (page << 11) + | (startaddress << 5)), + 16, 0, NULL, 1); +@@ -188,6 +209,9 @@ + omap_uwire_data_transfer(cs, 0, 0, 16, data, 1); + } + omap_uwire_data_transfer(cs, 0, 0, 16, data, 0); ++ ++ if (machine_is_omap_h6300()) ++ omap_set_gpio_dataout(8, 1); + } + + u16 omap_tsc2101_read(int page, u8 address) +@@ -228,9 +252,24 @@ + omap_cfg_reg(N14_1610_UWIRE_CS0); + omap_uwire_configure_mode(0, uwire_flags); + } ++ if (machine_is_omap_h6300()) { ++ uwire_flags = UWIRE_READ_RISING_EDGE | UWIRE_WRITE_RISING_EDGE; ++ omap_cfg_reg(N14_1510_UWIRE_CS0); ++ omap_uwire_configure_mode(0, uwire_flags); ++ ++ omap_request_gpio(8); ++ omap_set_gpio_dataout(8, 0); ++ omap_set_gpio_direction (8, 0); ++ } + + /* Configure MCLK enable */ +- omap_writel(omap_readl(PU_PD_SEL_2) | (1 << 22), PU_PD_SEL_2); ++ if (cpu_is_omap16xx() || cpu_is_omap1710()) ++ omap_writel(omap_readl(PU_PD_SEL_2) | (1 << 22), PU_PD_SEL_2); ++ if (machine_is_omap_h6300()) { ++ omap_cfg_reg(V19_1510_UWIRE_SCLK); ++ omap_cfg_reg(W21_1510_UWIRE_SDO); ++ omap_cfg_reg(U18_1510_UWIRE_SDI); ++ } + + return 0; + } +@@ -243,5 +282,5 @@ + + MODULE_AUTHOR("Texas Instruments"); + MODULE_DESCRIPTION +- ("Glue audio driver for the TI OMAP1610/OMAP1710 TSC2101 codec."); ++ ("Glue audio driver for the TI OMAP1510/1610/OMAP1710 TSC2101 codec."); + MODULE_LICENSE("GPL"); +diff -Naur linux-2.6.16.16/drivers/ssi/omap-uwire.c h6300_dev/drivers/ssi/omap-uwire.c +--- linux-2.6.16.16/drivers/ssi/omap-uwire.c 2006-05-17 21:41:30.000000000 +0300 ++++ h6300_dev/drivers/ssi/omap-uwire.c 2006-04-24 20:53:29.000000000 +0300 +@@ -10,7 +10,7 @@ + * Ported to 2.6 uwire interface. + * Copyright (C) 2004 Texas Instruments. + * +- * Generalization patches by Juha Yrjölä <juha.yrjola@nokia.com> ++ * Generalization patches by Juha Yrj�l� <juha.yrjola@nokia.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the +@@ -212,6 +212,10 @@ + omap_cfg_reg(N14_1610_UWIRE_CS0); + omap_cfg_reg(P15_1610_UWIRE_CS3); + } ++ if (machine_is_omap_h6300()) { ++ omap_cfg_reg(N14_1510_UWIRE_CS0); ++ omap_cfg_reg(P15_1510_UWIRE_CS3); ++ } + if (machine_is_omap_perseus2()) { + /* configure pins: MPU_UW_nSCS1, MPU_UW_SDO, MPU_UW_SCLK */ + int val = omap_readl(OMAP730_IO_CONF_9) & ~0x00EEE000; +diff -Naur linux-2.6.16.16/drivers/telephony/Kconfig h6300_dev/drivers/telephony/Kconfig +--- linux-2.6.16.16/drivers/telephony/Kconfig 2006-05-11 04:56:24.000000000 +0300 ++++ h6300_dev/drivers/telephony/Kconfig 2005-10-06 02:34:39.000000000 +0300 +@@ -41,7 +41,18 @@ + help + Say Y here to configure in PCMCIA service support for the Quicknet + cards manufactured by Quicknet Technologies, Inc. This changes the +- card initialization code to work with the card manager daemon. ++ card initialization code to work with the card manager daemon. ++ ++config GSM_H6300 ++ tristate "H6300 P5186 GSM/GPRS DRIVER" ++ depends on PHONE && I2C && PCA9535 ++ help ++ Bluetooth H6300 P5186 gsm/gprs driver. ++ This driver provides the firmware loading mechanism for the P5185 ++ gsm/gprs hardware in iPAQ h6300. ++ ++ Say Y here to compile support for P5186 gsm/gprs devices into the ++ kernel or say M to compile it as module (h6300_gsm). + + endmenu + +diff -Naur linux-2.6.16.16/drivers/telephony/Makefile h6300_dev/drivers/telephony/Makefile +--- linux-2.6.16.16/drivers/telephony/Makefile 2006-05-11 04:56:24.000000000 +0300 ++++ h6300_dev/drivers/telephony/Makefile 2005-10-06 02:34:39.000000000 +0300 +@@ -2,6 +2,7 @@ + # Makefile for drivers/telephony + # + +-obj-$(CONFIG_PHONE) += phonedev.o +-obj-$(CONFIG_PHONE_IXJ) += ixj.o +-obj-$(CONFIG_PHONE_IXJ_PCMCIA) += ixj_pcmcia.o ++obj-$(CONFIG_PHONE) += phonedev.o ++obj-$(CONFIG_PHONE_IXJ) += ixj.o ++obj-$(CONFIG_PHONE_IXJ_PCMCIA) += ixj_pcmcia.o ++obj-$(CONFIG_GSM_H6300) += omap/ +diff -Naur linux-2.6.16.16/drivers/telephony/omap/h6300_gsm_led.c h6300_dev/drivers/telephony/omap/h6300_gsm_led.c +--- linux-2.6.16.16/drivers/telephony/omap/h6300_gsm_led.c 1970-01-01 02:00:00.000000000 +0200 ++++ h6300_dev/drivers/telephony/omap/h6300_gsm_led.c 2005-10-06 02:34:39.000000000 +0300 +@@ -0,0 +1,40 @@ ++/* ++ * GSM interface driver helper for controlling bluetooth leds available in iPAQ h6300. ++ * ++ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> ++ * ++ * 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/kernel.h> ++#include <linux/delay.h> ++#include <linux/device.h> ++ ++#include <asm/hardware.h> ++#include <asm/arch/gpio.h> ++ ++/* ++ * Low level access for disabling h6300 gsm led. ++ * ++ * TODO: implement for h6300 ++ */ ++void h6300_clear_gsm_led(int led_num) ++{ ++ printk(KERN_NOTICE "h6300_gsm_led.c h6300_clear_gsm_led() done\n"); ++ //hx4700_set_led(led_num, 0, 16); ++} ++EXPORT_SYMBOL(h6300_clear_gsm_led); ++ ++/* ++ * Low level access for setting up the gsm led. ++ * ++ * TODO: implement for h6300 ++ */ ++void h6300_set_gsm_led(int led_num, int duty_time, int cycle_time) ++{ ++ printk(KERN_NOTICE "h6300_gsm_led.c h6300_set_gsm_led() done\n"); ++} ++EXPORT_SYMBOL(h6300_set_gsm_led); +diff -Naur linux-2.6.16.16/drivers/telephony/omap/h6300_gsm_led.h h6300_dev/drivers/telephony/omap/h6300_gsm_led.h +--- linux-2.6.16.16/drivers/telephony/omap/h6300_gsm_led.h 1970-01-01 02:00:00.000000000 +0200 ++++ h6300_dev/drivers/telephony/omap/h6300_gsm_led.h 2005-10-06 02:34:39.000000000 +0300 +@@ -0,0 +1,10 @@ ++#ifndef H6300_GSM_LED_H_ ++#define H6300_GSM_LED_H_ ++ ++#define INDEX_GSM_LED 1 ++ ++void h6300_clear_gsm_led(int led_num); ++void h6300_set_gsm_led(int led_num, int duty_time, int cycle_time); ++ ++ ++#endif /*H6300_GSM_LED_H_*/ +diff -Naur linux-2.6.16.16/drivers/telephony/omap/h6300_gsm_p5186.c h6300_dev/drivers/telephony/omap/h6300_gsm_p5186.c +--- linux-2.6.16.16/drivers/telephony/omap/h6300_gsm_p5186.c 1970-01-01 02:00:00.000000000 +0200 ++++ h6300_dev/drivers/telephony/omap/h6300_gsm_p5186.c 2006-01-23 00:09:23.000000000 +0200 +@@ -0,0 +1,172 @@ ++/* ++ * Wavecom P5186 GPRS and GSM module driver for iPAQ h6300. ++ * ++ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> ++ * ++ * 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/kernel.h> ++#include <linux/delay.h> ++#include <linux/platform_device.h> ++ ++#include <asm/hardware.h> ++#include <asm/arch/gpio.h> ++ ++#include <asm/arch/pca9535.h> ++#include <asm/arch/h6300_uart_info.h> ++#include "h6300_gsm_led.h" ++ ++static void ++h6300_gsm_configure(struct uart_omap_port *up, int enable) ++{ ++ printk(KERN_NOTICE "h6300_gsm_p5186.c h6300_gsm_configure() started, enable = %d\n", enable); ++ ++ // printk( KERN_NOTICE "h6300 configure bluetooth: %d\n", enable ); ++ if (enable == 0) { ++ pca9535_gpio_write(GPIO_I2C_GPRS_RESET, GPIO_VALUE_OFF); // turn off gpio ++ mdelay(5); ++ h6300_clear_gsm_led(INDEX_GSM_LED); ++ } ++ else if (enable == 1) { ++ pca9535_gpio_write(GPIO_I2C_GPRS_RESET, GPIO_VALUE_ON); // turn on gpio ++ mdelay(5); ++ } ++ else if (enable == 2) { ++ h6300_set_gsm_led(INDEX_GSM_LED, 16, 16); ++ } ++ printk(KERN_NOTICE "h6300_gsm_p5186.c h6300_gsm_configure() done\n"); ++} ++ ++static void ++h6300_gsm_set_txrx(struct uart_omap_port *up, int txrx) ++{ ++ printk(KERN_NOTICE "h6300_gsm_p5186.c h6300_gsm_set_txrx(), txrx = %d done\n", txrx); ++ /* do nothing */ ++} ++ ++static int ++h6300_gsm_get_txrx(struct uart_omap_port *up) ++{ ++ printk(KERN_NOTICE "h6300_gsm_p5186.c h6300_gsm_get_txrx() done\n"); ++ /* do nothing */ ++ return 0; ++} ++ ++static int ++h6300_gsm_probe(struct platform_device *pdev) ++{ ++ int ii; ++ int curVal; ++ ++ struct h6300_uart_funcs *funcs = (struct h6300_uart_funcs *)pdev->dev.platform_data; ++/* ++ printk(KERN_NOTICE "h6300_gsm_p5186.c h6300_gsm_probe() started\n"); ++ for (ii = 0; ii < 8; ii++) ++ { ++ curVal = pca9535_gpio_read(ii); ++ printk(KERN_NOTICE "I2C[%d] = %d ", ii, curVal); ++ } ++ for (ii = 10; ii < 18; ii++) ++ { ++ curVal = pca9535_gpio_read(ii); ++ printk(KERN_NOTICE "I2C[%d] = %d ", ii, curVal); ++ } ++ printk(KERN_NOTICE "\nfirst check done\n"); ++*/ ++ pca9535_gpio_direction(GPIO_I2C_GPRS_RESET, GPIO_DIR_OUTPUT); // set gpio direction to be output ++ pca9535_gpio_write(GPIO_I2C_GPRS_RESET, GPIO_VALUE_ON); // turn on gpio ++ mdelay(200); ++ ++ pca9535_gpio_direction(GPIO_I2C_MIC_OP_EN, GPIO_DIR_OUTPUT); // set gpio direction to be output ++ pca9535_gpio_write(GPIO_I2C_MIC_OP_EN, GPIO_VALUE_ON); // turn on gpio ++ mdelay(200); ++ ++ pca9535_gpio_direction(GPIO_I2C_SPK_OP_PD, GPIO_DIR_OUTPUT); // set gpio direction to be output ++ pca9535_gpio_write(GPIO_I2C_SPK_OP_PD, GPIO_VALUE_ON); // pd = pulldown?, normal off = on ++ ++ mdelay(200); ++ ++ //pca9535_gpio_direction( ++ /* configure bluetooth UART */ ++ //h6300_gpio_mode(GPIO_NR_H6300_BT_RXD_MD); ++ //h6300_gpio_mode(GPIO_NR_H6300_BT_TXD_MD); ++ //h6300_gpio_mode(GPIO_NR_H6300_BT_UART_CTS_MD); ++ //h6300_gpio_mode(GPIO_NR_H6300_BT_UART_RTS_MD); ++ ++ funcs->configure = h6300_gsm_configure; ++ funcs->set_txrx = h6300_gsm_set_txrx; ++ funcs->get_txrx = h6300_gsm_get_txrx; ++ ++ /* Make sure the LED is off */ ++ h6300_clear_gsm_led(INDEX_GSM_LED); ++/* ++ for (ii = 0; ii < 8; ii++) ++ { ++ curVal = pca9535_gpio_read(ii); ++ printk(KERN_NOTICE "I2C[%d] = %d ", ii, curVal); ++ } ++ for (ii = 10; ii < 18; ii++) ++ { ++ curVal = pca9535_gpio_read(ii); ++ printk(KERN_NOTICE "I2C[%d] = %d ", ii, curVal); ++ } ++*/ ++ printk(KERN_NOTICE "\nh6300_gsm_p5186.c h6300_gsm_probe() done\n"); ++ ++ return 0; ++} ++ ++static int ++h6300_gsm_remove(struct platform_device *pdev) ++{ ++ struct h6300_uart_funcs *funcs = (struct h6300_uart_funcs *)pdev->dev.platform_data; ++ ++ printk(KERN_NOTICE "h6300_gsm_p5186.c h6300_gsm_remove() started\n"); ++ ++ pca9535_gpio_write(GPIO_I2C_GPRS_RESET, 0); // turn off gpio ++ ++ funcs->configure = NULL; ++ funcs->set_txrx = NULL; ++ funcs->get_txrx = NULL; ++ ++ /* Make sure the LED is off */ ++ h6300_clear_gsm_led(INDEX_GSM_LED); ++ ++ printk(KERN_NOTICE "h6300_gsm_p5186.c, h6300_gsm_remove() done\n"); ++ ++ return 0; ++} ++ ++static struct platform_driver gsm_driver = { ++ .probe = h6300_gsm_probe, ++ .remove = h6300_gsm_remove, ++ .driver = { ++ .name = "h6300_gsm", ++ }, ++}; ++ ++static int __init ++h6300_gsm_init(void) ++{ ++ printk(KERN_NOTICE "h6300 GSM Driver init()\n"); ++ return platform_driver_register(&gsm_driver); ++} ++ ++static void __exit ++h6300_gsm_exit(void) ++{ ++ printk(KERN_NOTICE "h6300 GSM Driver exit()\n"); ++ platform_driver_unregister(&gsm_driver); ++} ++ ++module_init(h6300_gsm_init); ++module_exit(h6300_gsm_exit); ++ ++MODULE_AUTHOR("Mika Laitio, <lamikr@cc.jyu.fi>"); ++MODULE_DESCRIPTION("iPAQ h6300 Wavecom P5186 GPRS and GSM module driver."); ++MODULE_LICENSE("GPL"); ++ +diff -Naur linux-2.6.16.16/drivers/telephony/omap/Makefile h6300_dev/drivers/telephony/omap/Makefile +--- linux-2.6.16.16/drivers/telephony/omap/Makefile 1970-01-01 02:00:00.000000000 +0200 ++++ h6300_dev/drivers/telephony/omap/Makefile 2005-10-06 02:34:39.000000000 +0300 +@@ -0,0 +1,6 @@ ++# ++# Makefile for the Linux iPAQ H6300 BRF6100 Bluetooth device drivers. ++# ++ ++h6300_gsm-objs := h6300_gsm_led.o h6300_gsm_p5186.o ++obj-$(CONFIG_GSM_H6300) += h6300_gsm.o +diff -Naur linux-2.6.16.16/drivers/usb/gadget/omap_udc.c h6300_dev/drivers/usb/gadget/omap_udc.c +--- linux-2.6.16.16/drivers/usb/gadget/omap_udc.c 2006-05-17 21:41:30.000000000 +0300 ++++ h6300_dev/drivers/usb/gadget/omap_udc.c 2006-04-24 20:53:29.000000000 +0300 +@@ -60,7 +60,8 @@ + #undef USB_TRACE + + /* bulk DMA seems to be behaving for both IN and OUT */ +-#define USE_DMA ++//#define USE_DMA ++#undef USE_DMA + + /* ISO too */ + #define USE_ISO +@@ -2147,7 +2148,7 @@ + /* boards that don't have VBUS sensing can't autogate 48MHz; + * can't enter deep sleep while a gadget driver is active. + */ +- if (machine_is_omap_innovator() || machine_is_omap_osk()) ++ if (machine_is_omap_innovator() || machine_is_omap_osk() || machine_is_omap_h6300()) + omap_vbus_session(&udc->gadget, 1); + + done: +@@ -2170,7 +2171,7 @@ + if (udc->dc_clk != NULL) + omap_udc_enable_clock(1); + +- if (machine_is_omap_innovator() || machine_is_omap_osk()) ++ if (machine_is_omap_innovator() || machine_is_omap_osk() || machine_is_omap_h6300()) + omap_vbus_session(&udc->gadget, 0); + + if (udc->transceiver) +@@ -2791,7 +2792,7 @@ + hmc = HMC_1510; + type = "(unknown)"; + +- if (machine_is_omap_innovator()) { ++ if (machine_is_omap_innovator() || machine_is_omap_h6300()) { + /* just set up software VBUS detect, and then + * later rig it so we always report VBUS. + * FIXME without really sensing VBUS, we can't +diff -Naur linux-2.6.16.16/drivers/usb/host/ohci-omap.c h6300_dev/drivers/usb/host/ohci-omap.c +--- linux-2.6.16.16/drivers/usb/host/ohci-omap.c 2006-05-17 21:41:30.000000000 +0300 ++++ h6300_dev/drivers/usb/host/ohci-omap.c 2006-02-06 15:36:21.000000000 +0200 +@@ -353,11 +353,7 @@ + if (IS_ERR(usb_host_ck)) + return PTR_ERR(usb_host_ck); + +- if (!cpu_is_omap1510()) +- usb_dc_ck = clk_get(0, "usb_dc_ck"); +- else +- usb_dc_ck = clk_get(0, "lb_ck"); +- ++ usb_dc_ck = clk_get(0, "usb_dc_ck"); + if (IS_ERR(usb_dc_ck)) { + clk_put(usb_host_ck); + return PTR_ERR(usb_dc_ck); +diff -Naur linux-2.6.16.16/drivers/video/omap/lcd_h6300.c h6300_dev/drivers/video/omap/lcd_h6300.c +--- linux-2.6.16.16/drivers/video/omap/lcd_h6300.c 1970-01-01 02:00:00.000000000 +0200 ++++ h6300_dev/drivers/video/omap/lcd_h6300.c 2006-04-24 20:53:29.000000000 +0300 +@@ -0,0 +1,159 @@ ++/* ++ * File: drivers/video/omap_new/lcd-h6300.c ++ * ++ * LCD panel support for the TI OMAP1510 Innovator board ++ * ++ * Copyright (C) 2004 Nokia Corporation ++ * Author: Imre Deak <imre.deak@nokia.com> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <asm/io.h> ++ ++#include <asm/arch/pca9535.h> ++#include <asm/arch/omapfb.h> ++ ++/* #define OMAPFB_DBG 1 */ ++ ++#include "debug.h" ++ ++//static struct clk *h6300_lcd_ck; ++ ++static int h6300_panel_init(struct omapfb_device *fbdev) ++{ ++ DBGENTER(1); ++/* ++ if ((h6300_lcd_ck = clk_get (NULL, "lcd_ck")) == NULL) { ++ printk(KERN_ERR "Unable to get the clock LCD_CK!!!\n"); ++ return -EPERM; ++ } clk_enable(h6300_lcd_ck); ++*/ ++ DBGLEAVE(1); ++ printk(KERN_INFO "lcd_h6300.c: h6300_panel_init() done\n"); ++ return 0; ++} ++ ++static void h6300_panel_cleanup(void) ++{ ++ DBGENTER(1); ++/* ++ if (h6300_lcd_ck) { ++ clk_disable(h6300_lcd_ck); ++ clk_put(h6300_lcd_ck); ++ h6300_lcd_ck = NULL; ++ } ++*/ ++ DBGLEAVE(1); ++ printk(KERN_INFO "lcd_h6300.c: h6300_panel_cleanup() done\n"); ++} ++ ++static int h6300_panel_enable(void) ++{ ++ DBGENTER(1); ++ DBGLEAVE(1); ++ printk(KERN_INFO "lcd_h6300.c: h6300_panel_enable() done\n"); ++ return 0; ++} ++ ++static void h6300_panel_disable(void) ++{ ++ DBGENTER(1); ++ DBGLEAVE(1); ++ printk(KERN_INFO "lcd_h6300.c: h6300_panel_disable() done\n"); ++} ++ ++static unsigned long h6300_panel_get_caps(void) ++{ ++ printk(KERN_INFO "lcd_h6300.c: h6300_panel_get_caps() called\n"); ++ return 0; ++} ++ ++struct lcd_panel h6300_panel = { ++ .name = "h6300", ++ .config = OMAP_LCDC_PANEL_TFT, ++ ++ .bpp = 16, ++ .data_lines = 16, ++ .x_res = 240, ++ .y_res = 320, ++ .pixel_clock = 21000, ++ .hsw = 12, ++ .hfp = 10, ++ .hbp = 10, ++ .vsw = 3, ++ .vfp = 10, ++ .vbp = 3, ++ .pcd = 0, ++ ++ .init = h6300_panel_init, ++ .cleanup = h6300_panel_cleanup, ++ .enable = h6300_panel_enable, ++ .disable = h6300_panel_disable, ++ .get_caps = h6300_panel_get_caps, ++}; ++ ++static int h6300_panel_probe(struct platform_device *pdev) ++{ ++ DBGENTER(1); ++ omapfb_register_panel(&h6300_panel); ++ return 0; ++} ++ ++static int h6300_panel_remove(struct platform_device *pdev) ++{ ++ DBGENTER(1); ++ return 0; ++} ++ ++static int h6300_panel_suspend(struct platform_device *pdev, pm_message_t mesg) ++{ ++ DBGENTER(1); ++ pca9535_gpio_write(GPIO3, HI); ++ return 0; ++} ++ ++static int h6300_panel_resume(struct platform_device *pdev) ++{ ++ DBGENTER(1); ++ pca9535_gpio_write(GPIO3, LOW); ++ return 0; ++} ++ ++struct platform_driver h6300_panel_driver = { ++ .probe = h6300_panel_probe, ++ .remove = h6300_panel_remove, ++ .suspend = h6300_panel_suspend, ++ .resume = h6300_panel_resume, ++ .driver = { ++ .name = "lcd_h6300", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int h6300_panel_drv_init(void) ++{ ++ return platform_driver_register(&h6300_panel_driver); ++} ++ ++static void h6300_panel_drv_cleanup(void) ++{ ++ platform_driver_unregister(&h6300_panel_driver); ++} ++ ++module_init(h6300_panel_drv_init); ++module_exit(h6300_panel_drv_cleanup); +diff -Naur linux-2.6.16.16/drivers/video/omap/Makefile h6300_dev/drivers/video/omap/Makefile +--- linux-2.6.16.16/drivers/video/omap/Makefile 2006-05-17 21:41:30.000000000 +0300 ++++ h6300_dev/drivers/video/omap/Makefile 2006-02-21 23:54:33.000000000 +0200 +@@ -23,6 +23,7 @@ + objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o + objs-y$(CONFIG_MACH_OMAP_PERSEUS2) += lcd_p2.o + objs-y$(CONFIG_MACH_OMAP_APOLLON) += lcd_apollon.o ++objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_H6300) += lcd_h6300.o + + objs-y$(CONFIG_FB_OMAP_LCD_LPH8923) += lcd_lph8923.o + +diff -Naur linux-2.6.16.16/include/asm-arm/arch-omap/board-h6300.h h6300_dev/include/asm-arm/arch-omap/board-h6300.h +--- linux-2.6.16.16/include/asm-arm/arch-omap/board-h6300.h 1970-01-01 02:00:00.000000000 +0200 ++++ h6300_dev/include/asm-arm/arch-omap/board-h6300.h 2006-04-24 20:53:29.000000000 +0300 +@@ -0,0 +1,40 @@ ++/* ++ * linux/include/asm-arm/arch-omap/board-innovator.h ++ * ++ * Copyright (C) 2001 RidgeRun, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN ++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++#ifndef __ASM_ARCH_OMAP_H6300_H ++#define __ASM_ARCH_OMAP_H6300_H ++ ++#ifndef OMAP_SDRAM_DEVICE ++#define OMAP_SDRAM_DEVICE D256M_1X16_4B ++#endif ++ ++#define OMAP1510P1_IMIF_PRI_VALUE 0x00 ++#define OMAP1510P1_EMIFS_PRI_VALUE 0x00 ++#define OMAP1510P1_EMIFF_PRI_VALUE 0x00 ++ ++#define NR_FPGA_IRQS 24 ++#define NR_IRQS IH_BOARD_BASE + NR_FPGA_IRQS ++ ++#endif /* __ASM_ARCH_OMAP_H6300_H */ +diff -Naur linux-2.6.16.16/include/asm-arm/arch-omap/h6300_uart_info.h h6300_dev/include/asm-arm/arch-omap/h6300_uart_info.h +--- linux-2.6.16.16/include/asm-arm/arch-omap/h6300_uart_info.h 1970-01-01 02:00:00.000000000 +0200 ++++ h6300_dev/include/asm-arm/arch-omap/h6300_uart_info.h 2005-10-14 18:55:31.000000000 +0300 +@@ -0,0 +1,33 @@ ++/* ++ * Support file for calling h6300 uart configuration functions. ++ * Used at least by h6300_bt driver. ++ * ++ * Copyright (c) 2005 SDG Systems, LLC ++ * 2005-03-29 Todd Blumer Converted basic structure to support hx4700 ++ * 2005-10-03 Mika Laitio (lamikr@cc.jyu.fi) Reorganized for the iPAQ h6300 bt driver. ++ */ ++ ++#ifndef _H6300_UART_INFO_H ++#define _H6300_UART_INFO_H ++ ++#include "omap_serial.h" ++ ++#define GPIO_BT_PWR_EN 3 ++#define GPIO_N_BT_RST 9 ++ ++#define GPIO_I2C_GPRS_RESET 16 ++#define GPIO_I2C_MIC_OP_EN 10 ++#define GPIO_I2C_SPK_OP_PD 11 ++ ++#define GPIO_VALUE_OFF 0 ++#define GPIO_VALUE_ON 1 ++ ++#define GPIO_DIR_OUTPUT 1 ++ ++struct h6300_uart_funcs { ++ void (*configure)( struct uart_omap_port *up, int state); ++ void (*set_txrx)( struct uart_omap_port *up, int txrx); ++ int (*get_txrx)( struct uart_omap_port *up); ++}; ++ ++#endif +diff -Naur linux-2.6.16.16/include/asm-arm/arch-omap/hardware.h h6300_dev/include/asm-arm/arch-omap/hardware.h +--- linux-2.6.16.16/include/asm-arm/arch-omap/hardware.h 2006-05-17 21:41:31.000000000 +0300 ++++ h6300_dev/include/asm-arm/arch-omap/hardware.h 2006-02-06 15:36:21.000000000 +0200 +@@ -290,6 +290,10 @@ + #include "board-innovator.h" + #endif + ++#ifdef CONFIG_MACH_OMAP_H6300 ++#include "board-h6300.h" ++#endif ++ + #ifdef CONFIG_MACH_OMAP_H2 + #include "board-h2.h" + #endif +diff -Naur linux-2.6.16.16/include/asm-arm/arch-omap/mux.h h6300_dev/include/asm-arm/arch-omap/mux.h +--- linux-2.6.16.16/include/asm-arm/arch-omap/mux.h 2006-05-17 21:41:31.000000000 +0300 ++++ h6300_dev/include/asm-arm/arch-omap/mux.h 2006-05-18 00:38:24.000000000 +0300 +@@ -320,6 +320,13 @@ + P15_1610_UWIRE_CS3, + N15_1610_UWIRE_CS1, + ++ /* OMAP-1510 uWire */ ++ P15_1510_UWIRE_CS3, ++ N14_1510_UWIRE_CS0, ++ V19_1510_UWIRE_SCLK, ++ W21_1510_UWIRE_SDO, ++ U18_1510_UWIRE_SDI, ++ + /* OMAP-1610 Flash */ + L3_1610_FLASH_CS2B_OE, + M8_1610_FLASH_CS2B_WE, +@@ -384,6 +391,7 @@ + T20_1610_LOW_PWR, + + /* MCLK Settings */ ++ R10_1510_MCLK_ON, + V5_1710_MCLK_ON, + V5_1710_MCLK_OFF, + R10_1610_MCLK_ON, +diff -Naur linux-2.6.16.16/include/asm-arm/arch-omap/omap-alsa.h h6300_dev/include/asm-arm/arch-omap/omap-alsa.h +--- linux-2.6.16.16/include/asm-arm/arch-omap/omap-alsa.h 2006-05-17 21:41:31.000000000 +0300 ++++ h6300_dev/include/asm-arm/arch-omap/omap-alsa.h 2006-03-08 13:28:16.000000000 +0200 +@@ -1,6 +1,6 @@ + /* + * linux/include/asm-arm/arch-omap/omap-alsa.h +- * ++ * + * Alsa Driver for AIC23 and TSC2101 codecs on OMAP platform boards. + * + * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi> +diff -Naur linux-2.6.16.16/include/asm-arm/arch-omap/omap_serial.h h6300_dev/include/asm-arm/arch-omap/omap_serial.h +--- linux-2.6.16.16/include/asm-arm/arch-omap/omap_serial.h 1970-01-01 02:00:00.000000000 +0200 ++++ h6300_dev/include/asm-arm/arch-omap/omap_serial.h 2005-10-04 00:58:34.000000000 +0300 +@@ -0,0 +1,62 @@ ++/* ++ * Omap/h6300 serial driver private interface. ++ * Code originates from the pxa-serial.h available in the handheld org drivers ++ * for iPAQ PXA4700. ++ * ++ * Copyright (c) 2005 SDG Systems, LLC ++ * 2005-03-29 Todd Blumer Converted basic structure to support hx4700 ++ * 2005-10-03 Mika Laitio (lamikr@cc.jyu.fi) Reorganized for the iPAQ h6300 bt driver. ++ */ ++ ++#ifndef _OMAP_SERIAL_H ++#define _OMAP_SERIAL_H ++ ++#define OMAP_SERIAL_TX 1 ++#define OMAP_SERIAL_RX 2 ++ ++#include <linux/tty.h> ++#include <linux/serial_core.h> ++ ++struct platform_omap_serial_funcs; ++ ++struct uart_omap_port { ++ struct uart_port port; ++ unsigned char ier; ++ unsigned char lcr; ++ unsigned char mcr; ++ unsigned int lsr_break_flag; ++ unsigned int cken; ++ char *name; ++ struct platform_omap_serial_funcs *pf; ++}; ++ ++/* A pointer to such a structure can be contained in the platform_data ++ * field of every PXA UART platform_device. If the field is NULL, the ++ * serial port works as usual. ++ * ++ * For the sake of simplicity/performance no one of the function pointers ++ * in the structure below can be NULL. ++ */ ++struct platform_omap_serial_funcs { ++ /* Platform-specific function to initialize whatever is connected ++ to this serial port... enable=1 -> enable transceiver, ++ 0 -> disable transceiver. */ ++ void (*configure) (struct uart_omap_port *up, int enable); ++ /* Platform-specific function to enable or disable the individual ++ transmitter/receiver submodules. On transceivers without echo ++ cancellation (e.g. SIR) transmitter always has priority, e.g. ++ if both bits are set, only the transmitter is enabled. */ ++ void (*set_txrx) (struct uart_omap_port *up, int txrx); ++ /* Get the current state of tx/rx (see bitflags above) */ ++ int (*get_txrx) (struct uart_omap_port *up); ++}; ++ ++/* ++ * The variables below are located in arch/arm/mach-omap/board_h6300.c ++ * Machine-specific code may want to put a pointer to a static ++ * platform_pxa_serial_funcs structure in the dev.platform_data ++ * field of the respective port device. ++ */ ++extern struct platform_device btuart_device; ++ ++#endif +diff -Naur linux-2.6.16.16/include/asm-arm/arch-omap/pca9535.h h6300_dev/include/asm-arm/arch-omap/pca9535.h +--- linux-2.6.16.16/include/asm-arm/arch-omap/pca9535.h 1970-01-01 02:00:00.000000000 +0200 ++++ h6300_dev/include/asm-arm/arch-omap/pca9535.h 2005-10-25 03:24:45.000000000 +0300 +@@ -0,0 +1,39 @@ ++#ifndef _PCA9535_H ++#define _PCA9535_H ++ ++enum pca9535_gpios { ++ GPIO0 = 0, ++ GPIO1 = 1, ++ GPIO2 = 2, ++ GPIO3 = 3, ++ GPIO4 = 4, ++ GPIO5 = 5, ++ GPIO6 = 6, ++ GPIO7 = 7, ++ GPIO8 = 8, ++ GPIO9 = 9, ++ GPIO10 = 10, ++ GPIO11 = 11, ++ GPIO12 = 12, ++ GPIO13 = 13, ++ GPIO14 = 14, ++ GPIO15 = 15, ++ GPIO16 = 16, ++ GPIO17 = 17 ++}; ++ ++enum gpio_values { ++ HI = 0, ++ LOW = 1 ++}; ++ ++enum gpio_direction { ++ GPIO_INPUT = 0, ++ GPIO_OUTPUT = 1 ++}; ++ ++extern int pca9535_gpio_read(int gpio); ++extern int pca9535_gpio_write(int gpio, unsigned char val); ++extern int pca9535_gpio_direction(int gpio, unsigned char direction); ++ ++#endif +diff -Naur linux-2.6.16.16/Makefile h6300_dev/Makefile +--- linux-2.6.16.16/Makefile 2006-05-17 21:41:27.000000000 +0300 ++++ h6300_dev/Makefile 2006-05-18 01:45:17.000000000 +0300 +@@ -11,7 +11,7 @@ + # expect to learn how to build the kernel reading this file. + + # Add custom flags here to avoid conflict with updates +-EXTRAVERSION := $(EXTRAVERSION)-omap2 ++EXTRAVERSION := $(EXTRAVERSION)-omap1-h6300 + + # Do not print "Entering directory ..." + MAKEFLAGS += --no-print-directory +diff -Naur linux-2.6.16.16/sound/arm/omap/omap-alsa-tsc2101.c h6300_dev/sound/arm/omap/omap-alsa-tsc2101.c +--- linux-2.6.16.16/sound/arm/omap/omap-alsa-tsc2101.c 2006-05-17 21:41:31.000000000 +0300 ++++ h6300_dev/sound/arm/omap/omap-alsa-tsc2101.c 2006-03-30 23:15:31.000000000 +0300 +@@ -96,7 +96,11 @@ + static snd_pcm_hardware_t tsc2101_snd_omap_alsa_playback = { + .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), +- .formats = (SNDRV_PCM_FMTBIT_S16_LE), ++#ifdef CONFIG_MACH_OMAP_H6300 ++ .formats = (SNDRV_PCM_FMTBIT_S8), ++#else ++ .formats = (SNDRV_PCM_FMTBIT_S16_LE), ++#endif + .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | +@@ -136,7 +140,7 @@ + }; + + /* +- * Simplified write for tsc Audio ++ * Simplified write for tsc2101 audio registers. + */ + inline void tsc2101_audio_write(u8 address, u16 data) + { +@@ -144,7 +148,7 @@ + } + + /* +- * Simplified read for tsc Audio ++ * Simplified read for tsc2101 audio registers. + */ + inline u16 tsc2101_audio_read(u8 address) + { +@@ -246,14 +250,17 @@ + #endif /* #ifdef TSC_MASTER */ + tsc2101_audio_write(TSC2101_AUDIO_CTRL_3, data); + +- /* program the PLLs */ ++ /* Program the PLLs. This code assumes that the 12 Mhz MCLK is in use. ++ * If MCLK rate is something else, these values must be changed. ++ * See the tsc2101 specification for the details. ++ */ + if (rate_reg_info[count].fs_44kHz) { +- /* 44.1 khz - 12 MHz Mclk */ ++ /* samplerate = (44.1kHZ / x), where x is int. */ + tsc2101_audio_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | + PLL1_PVAL(1) | PLL1_I_VAL(7)); /* PVAL 1; I_VAL 7 */ + tsc2101_audio_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x1490)); /* D_VAL 5264 */ + } else { +- /* 48 khz - 12 Mhz Mclk */ ++ /* samplerate = (48.kHZ / x), where x is int. */ + tsc2101_audio_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | + PLL1_PVAL(1) | PLL1_I_VAL(8)); /* PVAL 1; I_VAL 8 */ + tsc2101_audio_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x780)); /* D_VAL 1920 */ +@@ -317,21 +324,14 @@ + CODEC_CLOCK); + } + curRate = (uint)clk_get_rate(tsc2101_mclk); +- DPRINTK("old clock rate = %d\n", curRate); + if (curRate != CODEC_CLOCK) { + err = clk_set_rate(tsc2101_mclk, CODEC_CLOCK); + if (err) { + printk(KERN_WARNING + "Cannot set MCLK clock rate for TSC2101 CODEC, error code = %d\n", err); +- //return -ECANCELED; ++ return -ECANCELED; + } + } +- else +- { +- printk(KERN_INFO +- "omap_alsa_tsc2101_clock_on(), no need to change rate, no need to change clock rate, rate already %d Hz.\n", +- CODEC_CLOCK); +- } + err = clk_enable(tsc2101_mclk); + curRate = (uint)clk_get_rate(tsc2101_mclk); + curUseCount = clk_get_usecount(tsc2101_mclk); +@@ -349,8 +349,7 @@ + } + + /* +- * Do some sanity check, turn clock off and then turn +- * codec audio off ++ * Do some sanity check, turn clock off and then turn codec audio off + */ + int tsc2101_clock_off(void) + { +@@ -374,10 +373,6 @@ + tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL, + ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC)); + DPRINTK("audio codec off\n"); +-#ifdef DUMP_TSC2101_AUDIO_REGISTERS +- printk("tsc2101_clock_off()\n"); +- dump_tsc2101_audio_reg(); +-#endif + return 0; + } + +@@ -420,18 +415,22 @@ + }; + + static int __init omap_alsa_tsc2101_init(void) +-{ +- int err; +- ++{ + ADEBUG(); +- err = platform_driver_register(&omap_alsa_driver); +- +- return err; ++#ifdef DUMP_TSC2101_AUDIO_REGISTERS ++ printk("omap_alsa_tsc2101_init()\n"); ++ dump_tsc2101_audio_reg(); ++#endif ++ return platform_driver_register(&omap_alsa_driver); + } + + static void __exit omap_alsa_tsc2101_exit(void) + { + ADEBUG(); ++#ifdef DUMP_TSC2101_AUDIO_REGISTERS ++ printk("omap_alsa_tsc2101_exit()\n"); ++ dump_tsc2101_audio_reg(); ++#endif + platform_driver_unregister(&omap_alsa_driver); + } + +diff -Naur linux-2.6.16.16/sound/arm/omap/omap-alsa-tsc2101-mixer.c h6300_dev/sound/arm/omap/omap-alsa-tsc2101-mixer.c +--- linux-2.6.16.16/sound/arm/omap/omap-alsa-tsc2101-mixer.c 2006-05-17 21:41:31.000000000 +0300 ++++ h6300_dev/sound/arm/omap/omap-alsa-tsc2101-mixer.c 2006-05-10 02:42:13.000000000 +0300 +@@ -50,47 +50,53 @@ + //#define M_DPRINTK(ARGS...) printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS) + #define M_DPRINTK(ARGS...) /* nop */ + ++#define CHECK_BIT(INDX, ARG) (((ARG) & TSC2101_BIT(INDX)) >> INDX) ++#define IS_UNMUTED(INDX, ARG) (((CHECK_BIT(INDX, ARG)) == 0)) ++ + #define DGC_DALVL_EXTRACT(ARG) ((ARG & 0x7f00) >> 8) + #define DGC_DARVL_EXTRACT(ARG) ((ARG & 0x007f)) +-#define GET_DGC_DALMU_BIT_VALUE(ARG) (((ARG) & TSC2101_BIT(15)) >> 15) +-#define GET_DGC_DARMU_BIT_VALUE(ARG) (((ARG) & TSC2101_BIT(7)) >> 7) +-#define IS_DGC_DALMU_UNMUTED(ARG) (((GET_DGC_DALMU_BIT_VALUE(ARG)) == 0)) +-#define IS_DGC_DARMU_UNMUTED(ARG) (((GET_DGC_DARMU_BIT_VALUE(ARG)) == 0)) + + #define HGC_ADPGA_HED_EXTRACT(ARG) ((ARG & 0x7f00) >> 8) +-#define GET_DGC_HGCMU_BIT_VALUE(ARG) (((ARG) & TSC2101_BIT(15)) >> 15) +-#define IS_DGC_HGCMU_UNMUTED(ARG) (((GET_DGC_HGCMU_BIT_VALUE(ARG)) == 0)) +- + #define HNGC_ADPGA_HND_EXTRACT(ARG) ((ARG & 0x7f00) >> 8) +-#define GET_DGC_HNGCMU_BIT_VALUE(ARG) (((ARG) & TSC2101_BIT(15)) >> 15) +-#define IS_DGC_HNGCMU_UNMUTED(ARG) (((GET_DGC_HNGCMU_BIT_VALUE(ARG)) == 0)) ++#define BGC_ADPGA_BGC_EXTRACT(ARG) ((ARG & 0x7f00) >> 8) + + static int current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER; + static int current_rec_src = REC_SRC_SINGLE_ENDED_MICIN_HED; + ++/* ++ * Simplified write for the tsc2101 audio registers. ++ */ ++inline void omap_tsc2101_audio_write(u8 address, u16 data) ++{ ++ omap_tsc2101_write(PAGE2_AUDIO_CODEC_REGISTERS, address, data); ++} ++ ++/* ++ * Simplified read for the tsc2101 audio registers. ++ */ ++inline u16 omap_tsc2101_audio_read(u8 address) ++{ ++ return (omap_tsc2101_read(PAGE2_AUDIO_CODEC_REGISTERS, address)); ++} ++ + /* +- * Used for switching between TSC2101 recourd sources. +- * Logic is adjusted from the TSC2101 OSS code. ++ * For selecting tsc2101 recourd source. + */ +-static int set_record_source(int val) ++static void set_record_source(int val) + { + u16 data; +- int maskedVal; + +- FN_IN; +- maskedVal = 0xe0 & val; +- +- data = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_MIXER_PGA_CTRL); ++ /* Mute Analog Sidetone ++ * Analog sidetone gain db? ++ * Input selected by MICSEL connected to ADC ++ */ ++ data = MPC_ASTMU | MPC_ASTG(0x45); + data &= ~MPC_MICSEL(7); /* clear all MICSEL bits */ +- data |= maskedVal; +- omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_MIXER_PGA_CTRL, +- data); ++ data |= MPC_MICSEL(val); ++ data |= MPC_MICADC; ++ omap_tsc2101_audio_write(TSC2101_MIXER_PGA_CTRL, data); ++ + current_rec_src = val; +- +- FN_OUT(0); +- return 0; + } + + /* +@@ -147,32 +153,34 @@ + volL = get_mixer_volume_as_dac_gain_control_volume(mixerVolL); + volR = get_mixer_volume_as_dac_gain_control_volume(mixerVolR); + +- val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_DAC_GAIN_CTRL); ++ val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL); + /* keep the old mute bit settings */ + val &= ~(DGC_DALVL(OUTPUT_VOLUME_MIN) | DGC_DARVL(OUTPUT_VOLUME_MIN)); + val |= DGC_DALVL(volL) | DGC_DARVL(volR); + retVal = 2; + if (retVal) { +- omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_DAC_GAIN_CTRL, +- val); ++ omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val); + } + M_DPRINTK("to registry: left = %d, right = %d, total = %d\n", DGC_DALVL_EXTRACT(val), DGC_DARVL_EXTRACT(val), val); + return retVal; + } + +-int dac_gain_control_unmute_control(int muteLeft, int muteRight) ++/** ++ * If unmuteLeft/unmuteRight == 0 --> mute ++ * If unmuteLeft/unmuteRight == 1 --> unmute ++ */ ++int dac_gain_control_unmute(int unmuteLeft, int unmuteRight) + { + u16 val; + int count; + + count = 0; +- val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_DAC_GAIN_CTRL); ++ val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL); + /* in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on + * so if values are same, it's time to change the registry value. + */ +- if (muteLeft == GET_DGC_DALMU_BIT_VALUE(val)) { +- if (muteLeft == 0) { ++ if (unmuteLeft != IS_UNMUTED(15, val)) { ++ if (unmuteLeft == 0) { + /* mute --> turn bit on */ + val = val | DGC_DALMU; + } +@@ -182,8 +190,8 @@ + } + count++; + } /* L */ +- if (muteRight == GET_DGC_DARMU_BIT_VALUE(val)) { +- if (muteRight == 0) { ++ if (unmuteRight != IS_UNMUTED(7, val)) { ++ if (unmuteRight == 0) { + /* mute --> turn bit on */ + val = val | DGC_DARMU; + } +@@ -194,14 +202,47 @@ + count++; + } /* R */ + if (count) { +- omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_DAC_GAIN_CTRL, val); ++ omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val); + M_DPRINTK("changed value, is_unmuted left = %d, right = %d\n", +- IS_DGC_DALMU_UNMUTED(val), +- IS_DGC_DARMU_UNMUTED(val)); ++ IS_UNMUTED(15, val), ++ IS_UNMUTED(7, val)); + } + return count; + } + ++/** ++ * unmute: 0 --> mute, 1 --> unmute ++ * page2RegIndx: Registry index in tsc2101 page2. ++ * muteBitIndx: Index number for the bit in registry that indicates whether muted or unmuted. ++ */ ++int adc_pga_unmute_control(int unmute, int page2regIndx, int muteBitIndx) ++{ ++ int count; ++ u16 val; ++ ++ count = 0; ++ val = omap_tsc2101_audio_read(page2regIndx); ++ /* in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on ++ * so if the values are same, it's time to change the registry value... ++ */ ++ if (unmute != IS_UNMUTED(muteBitIndx, val)) { ++ if (unmute == 0) { ++ /* mute --> turn bit on */ ++ val = val | TSC2101_BIT(muteBitIndx); ++ } ++ else { ++ /* unmute --> turn bit off */ ++ val = val & ~TSC2101_BIT(muteBitIndx); ++ } ++ M_DPRINTK("changed value, is_unmuted = %d\n", IS_UNMUTED(muteBitIndx, val)); ++ count++; ++ } ++ if (count) { ++ omap_tsc2101_audio_write(page2regIndx, val); ++ } ++ return count; ++} ++ + /* + * Converts the DGC registry value read from the TSC2101 registry to + * Alsa mixer volume format (0 - 100). +@@ -271,14 +312,11 @@ + /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */ + /* NOTE: 0 is minimum volume and not mute */ + volume = get_mixer_volume_as_headset_gain_control_volume(mixerVol); +- val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_HEADSET_GAIN_CTRL); ++ val = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL); + /* preserve the old mute settings */ + val &= ~(HGC_ADPGA_HED(INPUT_VOLUME_MAX)); + val |= HGC_ADPGA_HED(volume); +- omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_HEADSET_GAIN_CTRL, +- val); ++ omap_tsc2101_audio_write(TSC2101_HEADSET_GAIN_CTRL, val); + retVal = 1; + + M_DPRINTK("to registry = %d\n", val); +@@ -305,71 +343,37 @@ + * NOTE: 0 is minimum volume and not mute + */ + volume = get_mixer_volume_as_headset_gain_control_volume(mixerVol); +- val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_HANDSET_GAIN_CTRL); ++ val = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL); + /* preserve the old mute settigns */ + val &= ~(HNGC_ADPGA_HND(INPUT_VOLUME_MAX)); + val |= HNGC_ADPGA_HND(volume); +- omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_HANDSET_GAIN_CTRL, +- val); ++ omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val); + retVal = 1; + + M_DPRINTK("to registry = %d\n", val); + return retVal; + } + +-void init_record_sources(void) +-{ +- /* Mute Analog Sidetone +- * analog sidetone gain db? +- * Cell Phone In not connected to ADC +- * Input selected by MICSEL connected to ADC +- */ +- omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_MIXER_PGA_CTRL, +- MPC_ASTMU | MPC_ASTG(0x40) | ~MPC_CPADC | MPC_MICADC); +- /* Set record source, Select MIC_INHED input for headset */ +- set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED); +-} +- + void set_loudspeaker_to_playback_target(void) + { +- u16 val; +- +- /* power down sp1, sp2 and loudspeaker */ +- omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_CODEC_POWER_CTRL, ++ /* power down SPK1, SPK2 and loudspeaker */ ++ omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL, + CPC_SP1PWDN | CPC_SP2PWDN | CPC_LDAPWDF); + /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled + * 1dB AGC hysteresis + * MICes bias 2V + */ +- omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_AUDIO_CTRL_4, +- AC4_MB_HED(0)); ++ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0)); + + /* DAC left and right routed to SPK1/SPK2 + * SPK1/SPK2 unmuted +- * keyclicks routed to SPK1/SPK2 +- */ +- val = AC5_DIFFIN | ++ * Keyclicks routed to SPK1/SPK2 */ ++ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5, ++ AC5_DIFFIN | + AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 | +- AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 | +- AC5_HDSCPTC; +- val = val & ~AC5_HDSCPTC; +- omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_AUDIO_CTRL_5, +- val); +- +- /* powerdown spk1/out32n and spk2 */ +- val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_POWERDOWN_STS); +- val = val & ~(~PS_SPK1FL | ~PS_HNDFL | PS_LSPKFL); +- omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_POWERDOWN_STS, +- val); +- +- /* routing selected to SPK1 goes to OUT8P/OUT84 alsa. (loudspeaker) ++ AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2); ++ ++ /* routing selected to SPK1 goes also to OUT8P/OUT8N. (loudspeaker) + * analog sidetone routed to loudspeaker + * buzzer pga routed to loudspeaker + * keyclick routing to loudspeaker +@@ -381,43 +385,242 @@ + * Enable loudspeaker short protection control (0 = enable protection) + * VGND short protection control (0 = enable protection) + */ +- omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_AUDIO_CTRL_6, ++ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6, + AC6_SPL2LSK | AC6_AST2LSK | AC6_BUZ2LSK | AC6_KCL2LSK | +- AC6_CPI2LSK | AC6_MIC2CPO | AC6_SPL2CPO | +- ~AC6_MUTLSPK | ~AC6_MUTSPK2 | ~AC6_LDSCPTC | ~AC6_VGNDSCPTC); ++ AC6_CPI2LSK | AC6_MIC2CPO | AC6_SPL2CPO); + current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER; + } + + void set_headphone_to_playback_target(void) + { +- /* power down sp1, sp2 and loudspeaker */ +- omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_CODEC_POWER_CTRL, ++ /* power down SPK1, SPK2 and loudspeaker */ ++ omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL, + CPC_SP1PWDN | CPC_SP2PWDN | CPC_LDAPWDF); + /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */ + /* 1dB AGC hysteresis */ + /* MICes bias 2V */ +- omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_AUDIO_CTRL_4, +- AC4_MB_HED(0)); +- +- /* DAC left and right routed to SPK2 */ +- /* SPK1/2 unmuted */ +- omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_AUDIO_CTRL_5, ++ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0)); ++ ++ /* DAC left and right routed to SPK1/SPK2 ++ * SPK1/SPK2 unmuted ++ * Keyclicks routed to SPK1/SPK2 */ ++ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5, + AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 | + AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 | + AC5_HDSCPTC); +- +- /* OUT8P/N muted, CPOUT muted */ +- omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_AUDIO_CTRL_6, ++ ++ /* OUT8P/OUT8N muted, CPOUT muted */ ++ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6, + AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC | + AC6_VGNDSCPTC); + current_playback_target = PLAYBACK_TARGET_HEADPHONE; + } + ++void set_telephone_to_playback_target(void) ++{ ++ /* ++ * 0110 1101 0101 1100 ++ * power down MICBIAS_HED, Analog sidetone, SPK2, DAC, ++ * Driver virtual ground, loudspeaker. Values D2-d5 are flags. ++ */ ++ omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL, ++ CPC_MBIAS_HED | CPC_ASTPWD | CPC_SP2PWDN | CPC_DAPWDN | ++ CPC_VGPWDN | CPC_LSPWDN); ++ ++ /* ++ * 0010 1010 0100 0000 ++ * ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled ++ * 1dB AGC hysteresis ++ * MICes bias 2V ++ */ ++ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, ++ AC4_MB_HND | AC4_MB_HED(0) | AC4_AGCHYS(1) | ++ AC4_BISTPD | AC4_ASSTPD | AC4_DASTPD); ++ printk("set_telephone_to_playback_target(), TSC2101_AUDIO_CTRL_4 = %d\n", omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4)); ++ ++ /* ++ * 1110 0010 0000 0010 ++ * DAC left and right routed to SPK1/SPK2 ++ * SPK1/SPK2 unmuted ++ * keyclicks routed to SPK1/SPK2 ++ */ ++ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5, ++ AC5_DIFFIN | AC5_DAC2SPK1(3) | ++ AC5_CPI2SPK1 | AC5_MUTSPK2); ++ ++ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6, ++ AC6_MIC2CPO | AC6_MUTLSPK | ++ AC6_LDSCPTC | AC6_VGNDSCPTC | AC6_CAPINTF); ++ current_playback_target = PLAYBACK_TARGET_CELLPHONE; ++} ++ ++/* ++ * 1100 0101 1101 0000 ++ * ++ * #define MPC_ASTMU TSC2101_BIT(15) ++ * #define MPC_ASTG(ARG) (((ARG) & 0x7F) << 8) ++ * #define MPC_MICSEL(ARG) (((ARG) & 0x07) << 5) ++ * #define MPC_MICADC TSC2101_BIT(4) ++ * #define MPC_CPADC TSC2101_BIT(3) ++ * #define MPC_ASTGF (0x01) ++ */ ++static void set_telephone_to_record_source(void) ++{ ++ u16 val; ++ ++ /* ++ * D0 = 0: ++ * --> AGC is off for handset input. ++ * --> ADC PGA is controlled by the ADMUT_HDN + ADPGA_HND ++ * (D15, D14-D8) ++ * D4 - D1 = 0000 ++ * --> AGC time constant for handset input, ++ * attack time = 8 mc, decay time = 100 ms ++ * D7 - D5 = 000 ++ * --> AGC Target gain for handset input = -5.5 db ++ * D14 - D8 = 011 1100 ++ * --> ADC handset PGA settings = 60 = 30 db ++ * D15 = 0 ++ * --> Handset input ON (unmuted) ++ */ ++ val = 0x3c00; // 0011 1100 0000 0000 = 60 = 30 ++ omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val); ++ ++ /* ++ * D0 = 0 ++ * --> AGC is off for headset/Aux input ++ * --> ADC headset/Aux PGA is contoller by ADMUT_HED + ADPGA_HED ++ * (D15, D14-D8) ++ * D4 - D1 = 0000 ++ * --> Agc constant for headset/Aux input, ++ * attack time = 8 mc, decay time = 100 ms ++ * D7 - D5 = 000 ++ * --> AGC target gain for headset input = -5.5 db ++ * D14 - D8 = 000 0000 ++ * --> Adc headset/AUX pga settings = 0 db ++ * D15 = 1 ++ * --> Headset/AUX input muted ++ * ++ * Mute headset aux input ++ */ ++ val = 0x8000; // 1000 0000 0000 0000 ++ omap_tsc2101_audio_write(TSC2101_HEADSET_GAIN_CTRL, val); ++ set_record_source(REC_SRC_MICIN_HND_AND_AUX1); ++ ++ // hacks start ++ /* D0 = flag, Headset/Aux or handset PGA flag ++ * --> & with 1 (= 1 -->gain applied == pga register settings) ++ * D1 = 0, DAC channel PGA soft stepping control ++ * --> 0.5 db change every WCLK ++ * D2 = flag, DAC right channel PGA flag ++ * --> & with 1 ++ * D3 = flag, DAC left channel PGA flag ++ * -- > & with 1 ++ * D7 - D4 = 0001, keyclick length ++ * --> 4 periods key clicks ++ * D10 - D8 = 100, keyclick frequenzy ++ * --> 1 kHz, ++ * D11 = 0, Headset/Aux or handset soft stepping control ++ * --> 0,5 db change every WCLK or ADWS ++ * D14 -D12 = 100, Keyclick applitude control ++ * --> Medium amplitude ++ * D15 = 0, keyclick disabled ++ */ ++ val = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_2); ++ val = val & 0x441d; ++ val = val | 0x4410; // D14, D10, D4 bits == 1 ++ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_2, val); ++ ++ /* ++ * D0 = 0 (reserved, write always 0) ++ * D1 = flag, ++ * --> & with 1 ++ * D2 - D5 = 0000 (reserved, write always 0000) ++ * D6 = 1 ++ * --> MICBIAS_HND = 2.0 v ++ * D8 - D7 = 00 ++ * --> MICBIAS_HED = 3.3 v ++ * D10 - D9 = 01, ++ * --> Mic AGC hysteric selection = 2 db ++ * D11 = 1, ++ * --> Disable buzzer PGA soft stepping ++ * D12 = 0, ++ * --> Enable CELL phone PGA soft stepping control ++ * D13 = 1 ++ * --> Disable analog sidetone soft stepping control ++ * D14 = 0 ++ * --> Enable DAC PGA soft stepping control ++ * D15 = 0, ++ * --> Enable headset/Aux or Handset soft stepping control ++ */ ++ val = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4); ++ val = val & 0x2a42; // 0010 1010 0100 0010 ++ val = val | 0x2a40; // bits D13, D11, D9, D6 == 1 ++ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, val); ++ printk("set_telephone_to_record_source(), TSC2101_AUDIO_CTRL_4 = %d\n", omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4)); ++ /* ++ * D0 = 0 ++ * --> reserved, write always = 0 ++ * D1 = flag, read only ++ * --> & with 1 ++ * D5 - D2 = 1111, Buzzer input PGA settings ++ * --> 0 db ++ * D6 = 1, ++ * --> power down buzzer input pga ++ * D7 = flag, read only ++ * --> & with 1 ++ * D14 - D8 = 101 1101 ++ * --> 12 DB ++ * D15 = 0 ++ * --> power up cell phone input PGA ++ */ ++ val = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL); ++ val = val & 0x5dfe; ++ val = val | 0x5dfe; // bits, D14, D12, D11, D10, D8, D6, D5,D4,D3,D2 ++ omap_tsc2101_audio_write(TSC2101_BUZZER_GAIN_CTRL, val); ++ ++ /* D6 - D0 = 000 1001 ++ * --> -4.5 db for DAC right channel volume control ++ * D7 = 1 ++ * --> DAC right channel muted ++ * D14 - D8 = 000 1001 ++ * --> -4.5 db for DAC left channel volume control ++ * D15 = 1 ++ * --> DAC left channel muted ++ */ ++ //val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL); ++ val = 0x8989; ++ omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val); ++ ++ /* 0000 0000 0100 0000 ++ * ++ * D1 - D0 = 0 ++ * --> GPIO 1 pin output is three stated ++ * D2 = 0 ++ * --> Disaple GPIO2 for CLKOUT mode ++ * D3 = 0 ++ * --> Disable GPUI1 for interrupt detection ++ * D4 = 0 ++ * --> Disable GPIO2 for headset detection interrupt ++ * D5 = reserved, always 0 ++ * D7 - D6 = 01 ++ * --> 8 ms clitch detection ++ * D8 = reserved, write only 0 ++ * D10 -D9 = 00 ++ * --> 16 ms de bouncing programmatitily ++ * for glitch detection during headset detection ++ * D11 = flag for button press ++ * D12 = flag for headset detection ++ * D14-D13 = 00 ++ * --> type of headset detected = 00 == no stereo headset deected ++ * D15 = 0 ++ * --> Disable headset detection ++ * ++ * */ ++ val = 0x40; ++ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_7, val); ++} ++ + /* + * Checks whether the headset is detected. + * If headset is detected, the type is returned. Type can be +@@ -433,8 +636,7 @@ + u16 curVal; + + curType = 0; /* not detected */ +- curVal = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_AUDIO_CTRL_7); ++ curVal = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_7); + curDetected = curVal & AC7_HDDETFL; + if (curDetected) { + printk("headset detected, checking type from %d \n", curVal); +@@ -461,13 +663,10 @@ + * AGC enable for handset input + * Handset input not muted + */ +- val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_HANDSET_GAIN_CTRL); ++ val = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL); + val = val | HNGC_AGCEN_HND; + val = val & ~HNGC_ADMUT_HND; +- omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_HANDSET_GAIN_CTRL, +- val); ++ omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val); + + /* mic input volume control + * SET_MIC in the OSS driver +@@ -479,7 +678,7 @@ + */ + set_mixer_volume_as_dac_gain_control_volume(DEFAULT_OUTPUT_VOLUME, DEFAULT_OUTPUT_VOLUME); + /* unmute */ +- dac_gain_control_unmute_control(1, 1); ++ dac_gain_control_unmute(1, 1); + } + + /* +@@ -490,11 +689,11 @@ + FN_IN; + + /* Headset/Hook switch detect enabled */ +- omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_AUDIO_CTRL_7, +- AC7_DETECT); ++ omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_7, AC7_DETECT); + +- init_record_sources(); ++ /* Select headset to record source (MIC_INHED)*/ ++ set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED); ++ /* Init loudspeaker as a default playback target*/ + init_playback_targets(); + + FN_OUT(0); +@@ -503,7 +702,7 @@ + static int __pcm_playback_target_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) + { + static char *texts[PLAYBACK_TARGET_COUNT] = { +- "Loudspeaker", "Headphone" ++ "Loudspeaker", "Headphone", "Cellphone" + }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; +@@ -533,12 +732,18 @@ + if ((curVal >= 0) && + (curVal < PLAYBACK_TARGET_COUNT) && + (curVal != current_playback_target)) { +- if (curVal == 0) { +- set_loudspeaker_to_playback_target(); ++ if (curVal == PLAYBACK_TARGET_LOUDSPEAKER) { ++ set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED); ++ set_loudspeaker_to_playback_target(); + } +- else { ++ else if (curVal == PLAYBACK_TARGET_HEADPHONE) { ++ set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HND); + set_headphone_to_playback_target(); + } ++ else if (curVal == PLAYBACK_TARGET_CELLPHONE) { ++ set_telephone_to_record_source(); ++ set_telephone_to_playback_target(); ++ } + retVal = 1; + } + return retVal; +@@ -563,7 +768,7 @@ + u16 volR; + u16 val; + +- val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_DAC_GAIN_CTRL); ++ val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL); + M_DPRINTK("registry value = %d!\n", val); + volL = DGC_DALVL_EXTRACT(val); + volR = DGC_DARVL_EXTRACT(val); +@@ -603,16 +808,16 @@ + */ + static int __pcm_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) + { +- u16 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_DAC_GAIN_CTRL); ++ u16 val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL); + +- ucontrol->value.integer.value[0] = IS_DGC_DALMU_UNMUTED(val); +- ucontrol->value.integer.value[1] = IS_DGC_DARMU_UNMUTED(val); ++ ucontrol->value.integer.value[0] = IS_UNMUTED(15, val); // left ++ ucontrol->value.integer.value[1] = IS_UNMUTED(7, val); // right + return 0; + } + + static int __pcm_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) + { +- return dac_gain_control_unmute_control(ucontrol->value.integer.value[0], ++ return dac_gain_control_unmute(ucontrol->value.integer.value[0], + ucontrol->value.integer.value[1]); + } + +@@ -630,8 +835,7 @@ + u16 val; + u16 vol; + +- val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_HEADSET_GAIN_CTRL); ++ val = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL); + M_DPRINTK("registry value = %d\n", val); + vol = HGC_ADPGA_HED_EXTRACT(val); + vol = vol & ~HGC_ADMUT_HED; +@@ -662,38 +866,17 @@ + */ + static int __headset_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) + { +- u16 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_HEADSET_GAIN_CTRL); +- ucontrol->value.integer.value[0] = IS_DGC_HGCMU_UNMUTED(val); ++ u16 val = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL); ++ ucontrol->value.integer.value[0] = IS_UNMUTED(15, val); + return 0; + } + + static int __headset_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) + { +- int count = 0; +- u16 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_HEADSET_GAIN_CTRL); +- /* in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on +- * so if values are same, it's time to change the registry value... +- */ +- if (ucontrol->value.integer.value[0] == GET_DGC_HGCMU_BIT_VALUE(val)) { +- if (ucontrol->value.integer.value[0] == 0) { +- /* mute --> turn bit on */ +- val = val | HGC_ADMUT_HED; +- } +- else { +- /* unmute --> turn bit off */ +- val = val & ~HGC_ADMUT_HED; +- } +- count++; +- M_DPRINTK("changed value, is_unmuted = %d\n", IS_DGC_HGCMU_UNMUTED(val)); +- } +- if (count) { +- omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_HEADSET_GAIN_CTRL, +- val); +- } +- return count; ++ // mute/unmute headset ++ return adc_pga_unmute_control(ucontrol->value.integer.value[0], ++ TSC2101_HEADSET_GAIN_CTRL, ++ 15); + } + + static int __handset_playback_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +@@ -710,7 +893,7 @@ + u16 val; + u16 vol; + +- val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_HANDSET_GAIN_CTRL); ++ val = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL); + M_DPRINTK("registry value = %d\n", val); + vol = HNGC_ADPGA_HND_EXTRACT(val); + vol = vol & ~HNGC_ADMUT_HND; +@@ -740,42 +923,74 @@ + */ + static int __handset_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) + { +- u16 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_HANDSET_GAIN_CTRL); +- ucontrol->value.integer.value[0] = IS_DGC_HNGCMU_UNMUTED(val); ++ u16 val = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL); ++ ucontrol->value.integer.value[0] = IS_UNMUTED(15, val); + return 0; + } + + static int __handset_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) + { +- int count = 0; +- u16 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_HANDSET_GAIN_CTRL); +- +- /* in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on +- * so if values are same, it's time to change the registry value... +- */ +- if (ucontrol->value.integer.value[0] == GET_DGC_HNGCMU_BIT_VALUE(val)) { +- if (ucontrol->value.integer.value[0] == 0) { +- /* mute --> turn bit on */ +- val = val | HNGC_ADMUT_HND; +- } +- else { +- /* unmute --> turn bit off */ +- val = val & ~HNGC_ADMUT_HND; +- } +- M_DPRINTK("changed value, is_unmuted = %d\n", IS_DGC_HNGCMU_UNMUTED(val)); +- count++; +- } +- if (count) { +- omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, +- TSC2101_HANDSET_GAIN_CTRL, +- val); +- } +- return count; ++ // handset mute/unmute ++ return adc_pga_unmute_control(ucontrol->value.integer.value[0], ++ TSC2101_HANDSET_GAIN_CTRL, ++ 15); ++} ++ ++static int __cellphone_input_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; ++ uinfo->count = 1; ++ uinfo->value.integer.min = 0; ++ uinfo->value.integer.max = 1; ++ return 0; ++} ++ ++/* When BGC_MUT_CP (bit 15) = 1, power down cellphone input pga. ++ * When BGC_MUT_CP = 0, power up cellphone input pga. ++ */ ++static int __cellphone_input_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) ++{ ++ u16 val = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL); ++ ucontrol->value.integer.value[0] = IS_UNMUTED(15, val); ++ return 0; ++} ++ ++static int __cellphone_input_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) ++{ ++ return adc_pga_unmute_control(ucontrol->value.integer.value[0], ++ TSC2101_BUZZER_GAIN_CTRL, ++ 15); ++} ++ ++static int __buzzer_input_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; ++ uinfo->count = 1; ++ uinfo->value.integer.min = 0; ++ uinfo->value.integer.max = 1; ++ return 0; ++} ++ ++/* When BGC_MUT_BU (bit 6) = 1, power down cellphone input pga. ++ * When BGC_MUT_BU = 0, power up cellphone input pga. ++ */ ++static int __buzzer_input_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) ++{ ++ u16 val = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL); ++ ucontrol->value.integer.value[0] = IS_UNMUTED(6, val); ++ return 0; ++} ++ ++static int __buzzer_input_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) ++{ ++ return adc_pga_unmute_control(ucontrol->value.integer.value[0], ++ TSC2101_BUZZER_GAIN_CTRL, ++ 6); + } + + static snd_kcontrol_new_t tsc2101_control[] __devinitdata = { + { +- .name = "Playback Playback Route", ++ .name = "Target Playback Route", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .index = 0, + .access= SNDRV_CTL_ELEM_ACCESS_READWRITE, +@@ -801,7 +1016,7 @@ + }, { + .name = "Headset Playback Volume", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, +- .index = 1, ++ .index = 0, + .access= SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = __headset_playback_volume_info, + .get = __headset_playback_volume_get, +@@ -809,7 +1024,7 @@ + }, { + .name = "Headset Playback Switch", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, +- .index = 1, ++ .index = 0, + .access= SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = __headset_playback_switch_info, + .get = __headset_playback_switch_get, +@@ -817,7 +1032,7 @@ + }, { + .name = "Handset Playback Volume", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, +- .index = 2, ++ .index = 0, + .access= SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = __handset_playback_volume_info, + .get = __handset_playback_volume_get, +@@ -825,12 +1040,28 @@ + }, { + .name = "Handset Playback Switch", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, +- .index = 2, ++ .index = 0, + .access= SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = __handset_playback_switch_info, + .get = __handset_playback_switch_get, + .put = __handset_playback_switch_put, +- } ++ }, { ++ .name = "Cellphone Input Switch", ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .index = 0, ++ .access= SNDRV_CTL_ELEM_ACCESS_READWRITE, ++ .info = __cellphone_input_switch_info, ++ .get = __cellphone_input_switch_get, ++ .put = __cellphone_input_switch_put, ++ }, { ++ .name = "Buzzer Input Switch", ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .index = 0, ++ .access= SNDRV_CTL_ELEM_ACCESS_READWRITE, ++ .info = __buzzer_input_switch_info, ++ .get = __buzzer_input_switch_get, ++ .put = __buzzer_input_switch_put, ++ } + }; + + #ifdef CONFIG_PM +diff -Naur linux-2.6.16.16/sound/arm/omap/omap-alsa-tsc2101-mixer.h h6300_dev/sound/arm/omap/omap-alsa-tsc2101-mixer.h +--- linux-2.6.16.16/sound/arm/omap/omap-alsa-tsc2101-mixer.h 2006-05-17 21:41:31.000000000 +0300 ++++ h6300_dev/sound/arm/omap/omap-alsa-tsc2101-mixer.h 2006-03-30 23:15:31.000000000 +0300 +@@ -56,20 +56,21 @@ + #define INPUT_VOLUME_MAX 0x7D + #define INPUT_VOLUME_RANGE (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN) + +-#define PLAYBACK_TARGET_COUNT 0x02 ++#define PLAYBACK_TARGET_COUNT 0x03 + #define PLAYBACK_TARGET_LOUDSPEAKER 0x00 + #define PLAYBACK_TARGET_HEADPHONE 0x01 ++#define PLAYBACK_TARGET_CELLPHONE 0x02 + + /* following are used for register 03h Mixer PGA control bits D7-D5 for selecting record source */ + #define REC_SRC_TARGET_COUNT 0x08 +-#define REC_SRC_SINGLE_ENDED_MICIN_HED MPC_MICSEL(0) // oss code referred to MIXER_LINE +-#define REC_SRC_SINGLE_ENDED_MICIN_HND MPC_MICSEL(1) // oss code referred to MIXER_MIC +-#define REC_SRC_SINGLE_ENDED_AUX1 MPC_MICSEL(2) +-#define REC_SRC_SINGLE_ENDED_AUX2 MPC_MICSEL(3) +-#define REC_SRC_MICIN_HED_AND_AUX1 MPC_MICSEL(4) +-#define REC_SRC_MICIN_HED_AND_AUX2 MPC_MICSEL(5) +-#define REC_SRC_MICIN_HND_AND_AUX1 MPC_MICSEL(6) +-#define REC_SRC_MICIN_HND_AND_AUX2 MPC_MICSEL(7) ++#define REC_SRC_SINGLE_ENDED_MICIN_HED 0x00 // oss code referred to MIXER_LINE ++#define REC_SRC_SINGLE_ENDED_MICIN_HND 0x01 // oss code referred to MIXER_MIC ++#define REC_SRC_SINGLE_ENDED_AUX1 0x02 ++#define REC_SRC_SINGLE_ENDED_AUX2 0x03 ++#define REC_SRC_MICIN_HED_AND_AUX1 0x04 ++#define REC_SRC_MICIN_HED_AND_AUX2 0x05 ++#define REC_SRC_MICIN_HND_AND_AUX1 0x06 ++#define REC_SRC_MICIN_HND_AND_AUX2 0x07 + + #define DEFAULT_OUTPUT_VOLUME 90 // default output volume to dac dgc + #define DEFAULT_INPUT_VOLUME 20 // default record volume +diff -Naur linux-2.6.16.16/sound/oss/Kconfig h6300_dev/sound/oss/Kconfig +--- linux-2.6.16.16/sound/oss/Kconfig 2006-05-17 21:41:31.000000000 +0300 ++++ h6300_dev/sound/oss/Kconfig 2006-02-06 15:36:21.000000000 +0200 +@@ -13,8 +13,8 @@ + + config SOUND_OMAP_TSC2101 + tristate "TSC2101 Stereo Codec" +- depends on SOUND_OMAP && ( MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4 || MACH_OMAP_APOLLON) +- select OMAP_TSC2101 if ( MACH_OMAP_H2 || MACH_OMAP_H3 ) ++ depends on SOUND_OMAP && ( MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4 || MACH_OMAP_APOLLON || MACH_OMAP_H6300) ++ select OMAP_TSC2101 if ( MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H6300 ) + select OMAP_UWIRE if ARCH_OMAP1 + ---help--- + Tsc2101 Audio Codec Driver for OMAP will be enabled. +diff -Naur linux-2.6.16.16/sound/oss/omap-audio-tsc2101.c h6300_dev/sound/oss/omap-audio-tsc2101.c +--- linux-2.6.16.16/sound/oss/omap-audio-tsc2101.c 2006-05-17 21:41:31.000000000 +0300 ++++ h6300_dev/sound/oss/omap-audio-tsc2101.c 2006-04-02 00:23:01.000000000 +0300 +@@ -48,7 +48,7 @@ + #include "omap-audio.h" + #include "omap-audio-dma-intfc.h" + #include <asm/arch/mcbsp.h> +-#ifdef CONFIG_ARCH_OMAP16XX ++#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_MACH_OMAP_H6300) + #include <../drivers/ssi/omap-uwire.h> + #include <asm/arch/dsp_common.h> + #elif defined(CONFIG_ARCH_OMAP24XX) +@@ -73,10 +73,16 @@ + + #ifdef CONFIG_ARCH_OMAP16XX + #define PLATFORM_NAME "OMAP16XX" ++#elif CONFIG_MACH_OMAP_H6300 ++#define PLATFORM_NAME "OMAP15XX" + #elif defined(CONFIG_ARCH_OMAP24XX) + #define PLATFORM_NAME "OMAP2" + #endif + ++#if CONFIG_ARCH_OMAP16XX ++#define OMAP_DSP_BASE 0xE0000000 ++#endif ++ + /* Define to set the tsc as the master w.r.t McBSP */ + #define TSC_MASTER + +@@ -123,7 +129,7 @@ + /*********** Debug Macros ********/ + /* To Generate a rather shrill tone -test the entire path */ + //#define TONE_GEN +-/* To Generate a tone for each keyclick - test the tsc,spi paths*/ ++///* To Generate a tone for each keyclick - test the tsc,spi paths*/ + //#define TEST_KEYCLICK + /* To dump the tsc registers for debug */ + //#define TSC_DUMP_REGISTERS +@@ -230,6 +236,17 @@ + }; + + static struct omap_mcbsp_reg_cfg initial_config = { ++#ifdef CONFIG_MACH_OMAP_H6300 ++ .spcr2 = 0x0005, ++ .spcr1 = 0x0005, ++ .rcr2 = 0x8041, ++ .rcr1 = 0x8041, ++ .xcr2 = 0x00a1, ++ .xcr1 = 0x00a1, ++ .srgr2 = 0xb000, ++ .srgr1 = 0xb000, ++ .pcr0 = 0x0081, ++#else + .spcr2 = FREE | FRST | GRST | XRST | XINTM(3), + .spcr1 = RINTM(3) | RRST, + .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) | +@@ -253,6 +270,7 @@ + #endif /* tsc Master defs */ + + #endif /* platform specific inits */ ++#endif /* CONFIG_MACH_OMAP_H6300 */ + }; + + /***************************** MODULES SPECIFIC FUNCTION PROTOTYPES ********************/ |