generic-poky/meta/packages/linux/linux-rp-2.6.22+2.6.23-rc4/htcuni.patch

8045 lines
256 KiB
Diff
Raw Normal View History

---
arch/arm/Kconfig | 2
arch/arm/mach-pxa/Kconfig | 89 +
arch/arm/mach-pxa/Makefile | 1
arch/arm/mach-pxa/corgi.c | 3
arch/arm/mach-pxa/generic.c | 13
arch/arm/mach-pxa/htcuniversal/Makefile | 19
arch/arm/mach-pxa/htcuniversal/htcuniversal.c | 468 +++++
arch/arm/mach-pxa/htcuniversal/htcuniversal_ak4641.c | 917 +++++++++++
arch/arm/mach-pxa/htcuniversal/htcuniversal_ak4641.h | 65
arch/arm/mach-pxa/htcuniversal/htcuniversal_asic3_leds.c | 143 +
arch/arm/mach-pxa/htcuniversal/htcuniversal_bl.c | 61
arch/arm/mach-pxa/htcuniversal/htcuniversal_bt.c | 135 +
arch/arm/mach-pxa/htcuniversal/htcuniversal_bt.h | 17
arch/arm/mach-pxa/htcuniversal/htcuniversal_buttons.c | 87 +
arch/arm/mach-pxa/htcuniversal/htcuniversal_core.c | 226 ++
arch/arm/mach-pxa/htcuniversal/htcuniversal_lcd.c | 212 ++
arch/arm/mach-pxa/htcuniversal/htcuniversal_phone.c | 167 ++
arch/arm/mach-pxa/htcuniversal/htcuniversal_phone.h | 16
arch/arm/mach-pxa/htcuniversal/htcuniversal_pm.c | 69
arch/arm/mach-pxa/htcuniversal/htcuniversal_power2.c | 97 +
arch/arm/mach-pxa/htcuniversal/htcuniversal_ts2.c | 490 ++++++
arch/arm/mach-pxa/htcuniversal/htcuniversal_udc.c | 71
arch/arm/mach-pxa/htcuniversal/tsc2046_ts.h | 20
arch/arm/mach-pxa/spitz.c | 2
drivers/input/keyboard/Kconfig | 7
drivers/input/keyboard/Makefile | 2
drivers/input/keyboard/asic3_keys.c | 131 +
drivers/leds/Kconfig | 7
drivers/leds/Makefile | 1
drivers/leds/leds-asic3.c | 189 ++
drivers/mfd/Kconfig | 10
drivers/mfd/Makefile | 2
drivers/mfd/asic3_base.c | 1208 +++++++++++++++
drivers/mfd/soc-core.c | 106 +
drivers/mfd/soc-core.h | 30
drivers/mmc/host/Kconfig | 6
drivers/mmc/host/Makefile | 2
drivers/mmc/host/asic3_mmc.c | 900 +++++++++++
drivers/mmc/host/asic3_mmc.h | 25
drivers/serial/pxa.c | 22
drivers/video/backlight/Kconfig | 2
drivers/video/backlight/corgi_bl.c | 4
include/asm-arm/arch-pxa/clock.h | 27
include/asm-arm/arch-pxa/htcuniversal-asic.h | 213 ++
include/asm-arm/arch-pxa/htcuniversal-gpio.h | 220 ++
include/asm-arm/arch-pxa/htcuniversal-init.h | 14
include/asm-arm/arch-pxa/htcuniversal.h | 3
include/asm-arm/arch-pxa/irqs.h | 2
include/asm-arm/arch-pxa/pxa-pm_ll.h | 6
include/asm-arm/arch-pxa/pxa-regs.h | 2
include/asm-arm/arch-pxa/serial.h | 78
include/asm-arm/arch-pxa/sharpsl.h | 6
include/asm-arm/hardware/asic3_keys.h | 18
include/asm-arm/hardware/asic3_leds.h | 34
include/asm-arm/hardware/ipaq-asic3.h | 602 +++++++
include/linux/backlight.h | 7
include/linux/gpiodev.h | 44
include/linux/input_pda.h | 47
include/linux/ioport.h | 1
include/linux/soc/asic3_base.h | 104 +
include/linux/soc/tmio_mmc.h | 17
61 files changed, 7475 insertions(+), 14 deletions(-)
Index: linux-2.6.22/arch/arm/mach-pxa/htcuniversal/Makefile
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/arch/arm/mach-pxa/htcuniversal/Makefile 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,19 @@
+#
+# Makefile for HTC Universal
+#
+
+snd-htcuniversal-ak4641-objs := htcuniversal_ak4641.o
+
+obj-$(CONFIG_MACH_HTCUNIVERSAL) += htcuniversal.o
+obj-$(CONFIG_HTCUNIVERSAL_CORE) += htcuniversal_core.o
+obj-$(CONFIG_HTCUNIVERSAL_POWER) += htcuniversal_power2.o
+obj-$(CONFIG_HTCUNIVERSAL_LCD) += htcuniversal_lcd.o
+obj-$(CONFIG_HTCUNIVERSAL_BACKLIGHT) += htcuniversal_bl.o
+obj-$(CONFIG_HTCUNIVERSAL_TS2) += htcuniversal_ts2.o
+obj-$(CONFIG_HTCUNIVERSAL_BUTTONS) += htcuniversal_buttons.o
+obj-$(CONFIG_HTCUNIVERSAL_BLUETOOTH) += htcuniversal_bt.o
+obj-$(CONFIG_HTCUNIVERSAL_PHONE) += htcuniversal_phone.o
+obj-$(CONFIG_HTCUNIVERSAL_ASIC3_LEDS) += htcuniversal_asic3_leds.o
+obj-$(CONFIG_HTCUNIVERSAL_UDC) += htcuniversal_udc.o
+
+obj-$(CONFIG_HTCUNIVERSAL_AK4641) += htcuniversal_ak4641.o
Index: linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal.c 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,468 @@
+/*
+ * Hardware definitions for HTC Universal
+ *
+ * Copyright (c) 2006 Oleg Gusev
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/soc/asic3_base.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/setup.h>
+
+#include <asm/mach/irq.h>
+#include <asm/mach/arch.h>
+
+#include <asm/arch/bitfield.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/serial.h>
+#include <asm/arch/pxa27x_keyboard.h>
+#include <asm/arch/pxafb.h>
+#include <asm/arch/irda.h>
+#include <asm/arch/ohci.h>
+
+#include <asm/arch/htcuniversal.h>
+#include <asm/arch/htcuniversal-gpio.h>
+#include <asm/arch/htcuniversal-init.h>
+#include <asm/arch/htcuniversal-asic.h>
+
+#include <asm/hardware/ipaq-asic3.h>
+
+#include "../generic.h"
+
+#include "htcuniversal_bt.h"
+#include "htcuniversal_phone.h"
+#include "tsc2046_ts.h"
+
+/*
+ * IRDA
+ */
+
+static void htcuniversal_irda_transceiver_mode(struct device *dev, int mode)
+{
+ /* */
+}
+
+static struct pxaficp_platform_data htcuniversal_ficp_platform_data = {
+ .transceiver_cap = IR_SIRMODE | IR_FIRMODE,
+ .transceiver_mode = htcuniversal_irda_transceiver_mode,
+};
+
+/*
+ * Bluetooth - Relies on other loadable modules, like ASIC3 and Core,
+ * so make the calls indirectly through pointers. Requires that the
+ * htcuniversal_bt module be loaded before any attempt to use
+ * bluetooth (obviously).
+ */
+
+static struct htcuniversal_bt_funcs bt_funcs;
+
+static void
+htcuniversal_bt_configure( int state )
+{
+ if (bt_funcs.configure != NULL)
+ bt_funcs.configure( state );
+}
+
+static struct htcuniversal_phone_funcs phone_funcs;
+
+static void
+htcuniversal_phone_configure( int state )
+{
+ if (phone_funcs.configure != NULL)
+ phone_funcs.configure( state );
+}
+
+//void htcuniversal_ll_pm_init(void);
+
+extern struct platform_device htcuniversal_bl;
+static struct platform_device htcuniversal_lcd = { .name = "htcuniversal_lcd", };
+//static struct platform_device htcuniversal_kbd = { .name = "htcuniversal_kbd", };
+static struct platform_device htcuniversal_buttons = { .name = "htcuniversal_buttons", };
+//static struct platform_device htcuniversal_ts = { .name = "htcuniversal_ts", };
+//static struct platform_device htcuniversal_bt = { .name = "htcuniversal_bt", };
+//static struct platform_device htcuniversal_phone = { .name = "htcuniversal_phone", };
+static struct platform_device htcuniversal_power = { .name = "htcuniversal_power", };
+static struct platform_device htcuniversal_udc = { .name = "htcuniversal_udc", };
+
+static struct tsc2046_mach_info htcuniversal_ts_platform_data = {
+ .port = 1,
+ .clock = CKEN_SSP1,
+ .pwrbit_X = 1,
+ .pwrbit_Y = 1,
+ .irq = 0 /* asic3 irq */
+};
+
+static struct platform_device htcuniversal_ts = {
+ .name = "htcuniversal_ts",
+ .dev = {
+ .platform_data = &htcuniversal_ts_platform_data,
+ },
+};
+
+
+/* Bluetooth */
+
+static struct platform_device htcuniversal_bt = {
+ .name = "htcuniversal_bt",
+ .id = -1,
+ .dev = {
+ .platform_data = &bt_funcs,
+ },
+};
+
+static struct platform_device htcuniversal_phone = {
+ .name = "htcuniversal_phone",
+ .id = -1,
+ .dev = {
+ .platform_data = &phone_funcs,
+ },
+};
+
+/* PXA2xx Keys */
+
+static struct gpio_keys_button htcuniversal_button_table[] = {
+ { KEY_POWER, GPIO_NR_HTCUNIVERSAL_KEY_ON_N, 1 },
+};
+
+static struct gpio_keys_platform_data htcuniversal_pxa_keys_data = {
+ .buttons = htcuniversal_button_table,
+ .nbuttons = ARRAY_SIZE(htcuniversal_button_table),
+};
+
+static struct platform_device htcuniversal_pxa_keys = {
+ .name = "gpio-keys",
+ .dev = {
+ .platform_data = &htcuniversal_pxa_keys_data,
+ },
+ .id = -1,
+};
+
+/****************************************************************
+ * Keyboard
+ ****************************************************************/
+
+static struct pxa27x_keyboard_platform_data htcuniversal_kbd = {
+ .nr_rows = 8,
+ .nr_cols = 8,
+ .keycodes = {
+ {
+ /* row 0 */
+ KEY_ENTER,
+ KEY_MINUS,
+ KEY_ESC,
+ KEY_1,
+ KEY_TAB,
+ KEY_CAPSLOCK,
+ KEY_LEFTSHIFT,
+ KEY_RIGHTALT, /* Fn */
+ }, { /* row 1 */
+ KEY_COMMA,
+ KEY_EQUAL,
+ KEY_F1,
+ KEY_2,
+ KEY_Q,
+ KEY_A,
+ KEY_Z,
+ KEY_LEFTCTRL,
+ }, { /* row 2 */
+ KEY_UP,
+ KEY_I,
+ KEY_F2,
+ KEY_3,
+ KEY_W,
+ KEY_S,
+ KEY_X,
+ KEY_F6,
+ }, { /* row 3 */
+ KEY_DOT,
+ KEY_O,
+ KEY_F3,
+ KEY_4,
+ KEY_E,
+ KEY_D,
+ KEY_C,
+ KEY_LEFTALT,
+ }, { /* row 4 */
+ KEY_F9,
+ KEY_P,
+ KEY_F4,
+ KEY_5,
+ KEY_R,
+ KEY_F,
+ KEY_V,
+ KEY_SPACE,
+ }, { /* row 5 */
+ KEY_RIGHT,
+ KEY_BACKSPACE,
+ KEY_F5,
+ KEY_6,
+ KEY_T,
+ KEY_G,
+ KEY_B,
+ KEY_F7,
+ }, { /* row 6 */
+ KEY_F9,
+ KEY_K,
+ KEY_9,
+ KEY_7,
+ KEY_Y,
+ KEY_H,
+ KEY_N,
+ KEY_LEFT,
+ }, { /* row 7 */
+ KEY_F10,
+ KEY_L,
+ KEY_0,
+ KEY_8,
+ KEY_U,
+ KEY_J,
+ KEY_M,
+ KEY_DOWN,
+ },
+ },
+ .gpio_modes = {
+ GPIO_NR_HTCUNIVERSAL_KP_MKIN0_MD,
+ GPIO_NR_HTCUNIVERSAL_KP_MKIN1_MD,
+ GPIO_NR_HTCUNIVERSAL_KP_MKIN2_MD,
+ GPIO_NR_HTCUNIVERSAL_KP_MKIN3_MD,
+ GPIO_NR_HTCUNIVERSAL_KP_MKIN4_MD,
+ GPIO_NR_HTCUNIVERSAL_KP_MKIN5_MD,
+ GPIO_NR_HTCUNIVERSAL_KP_MKIN6_MD,
+ GPIO_NR_HTCUNIVERSAL_KP_MKIN7_MD,
+ GPIO_NR_HTCUNIVERSAL_KP_MKOUT0_MD,
+ GPIO_NR_HTCUNIVERSAL_KP_MKOUT1_MD,
+ GPIO_NR_HTCUNIVERSAL_KP_MKOUT2_MD,
+ GPIO_NR_HTCUNIVERSAL_KP_MKOUT3_MD,
+ GPIO_NR_HTCUNIVERSAL_KP_MKOUT4_MD,
+ GPIO_NR_HTCUNIVERSAL_KP_MKOUT5_MD,
+ GPIO_NR_HTCUNIVERSAL_KP_MKOUT6_MD,
+ GPIO_NR_HTCUNIVERSAL_KP_MKOUT7_MD,
+ },
+};
+
+static struct platform_device htcuniversal_pxa_keyboard = {
+ .name = "pxa27x-keyboard",
+ .id = -1,
+ .dev = {
+ .platform_data = &htcuniversal_kbd,
+ },
+};
+/* Core Hardware Functions */
+
+struct platform_device htcuniversal_core = {
+ .name = "htcuniversal_core",
+ .id = 0,
+ .dev = {
+ .platform_data = NULL,
+ },
+};
+
+static struct platform_device *devices[] __initdata = {
+ &htcuniversal_core,
+// &htcuniversal_flash,
+ &htcuniversal_pxa_keyboard,
+ &htcuniversal_pxa_keys,
+};
+
+static struct platform_device *htcuniversal_asic3_devices[] __initdata = {
+ &htcuniversal_lcd,
+#ifdef CONFIG_HTCUNIVERSAL_BACKLIGHT
+ &htcuniversal_bl,
+#endif
+ &htcuniversal_buttons,
+ &htcuniversal_ts,
+ &htcuniversal_bt,
+ &htcuniversal_phone,
+ &htcuniversal_power,
+ &htcuniversal_udc,
+};
+
+static struct asic3_platform_data htcuniversal_asic3_platform_data = {
+
+ /* Setting ASIC3 GPIO registers to the below initialization states
+ * HTC Universal asic3 information:
+ * http://wiki.xda-developers.com/index.php?pagename=UniversalASIC3
+ * http://wiki.xda-developers.com/index.php?pagename=ASIC3
+ *
+ * dir: Direction of the GPIO pin. 0: input, 1: output.
+ * If unknown, set as output to avoid power consuming floating input nodes
+ * init: Initial state of the GPIO bits
+ *
+ * These registers are configured as they are on Wince.
+ */
+ .gpio_a = {
+ .dir = (1<<GPIOA_LCD_PWR5_ON) |
+ (1<<GPIOA_FLASHLIGHT) |
+ (1<<GPIOA_UNKNOWN9) |
+ (1<<GPIOA_SPK_PWR2_ON) |
+ (1<<GPIOA_UNKNOWN4) |
+ (1<<GPIOA_EARPHONE_PWR_ON)|
+ (1<<GPIOA_AUDIO_PWR_ON) |
+ (1<<GPIOA_SPK_PWR1_ON) |
+ (1<<GPIOA_I2C_EN),
+ .init = (1<<GPIOA_LCD_PWR5_ON) |
+ (1<<GPIOA_I2C_EN),
+ .sleep_out = 0x0000,
+ .batt_fault_out = 0x0000,
+ .alt_function = 0x0000,
+ .sleep_conf = 0x000c,
+ },
+ .gpio_b = {
+ .dir = 0xc142,
+ .init = 0x8842, // TODO: 0x0900
+ .sleep_out = 0x0000,
+ .batt_fault_out = 0x0000,
+ .alt_function = 0x0000,
+ .sleep_conf = 0x000c,
+ },
+ .gpio_c = {
+ .dir = 0xc7e7,
+ .init = 0xc6e0, // TODO: 0x8000
+ .sleep_out = 0x0000,
+ .batt_fault_out = 0x0000,
+ .alt_function = 0x0007, // GPIOC_LED_RED | GPIOC_LED_GREEN | GPIOC_LED_BLUE
+ .sleep_conf = 0x000c,
+ },
+ .gpio_d = {
+ .dir = 0xffc0,
+ .init = 0x7840, // TODO: 0x0000
+ .sleep_out = 0x0000,
+ .batt_fault_out = 0x0000,
+ .alt_function = 0x0000,
+ .sleep_conf = 0x0008,
+ },
+ .bus_shift = 1,
+ .irq_base = HTCUNIVERSAL_ASIC3_IRQ_BASE,
+
+ .child_platform_devs = htcuniversal_asic3_devices,
+ .num_child_platform_devs = ARRAY_SIZE(htcuniversal_asic3_devices),
+};
+
+static struct resource htcuniversal_asic3_resources[] = {
+ [0] = {
+ .start = HTCUNIVERSAL_ASIC3_GPIO_PHYS,
+ .end = HTCUNIVERSAL_ASIC3_GPIO_PHYS + IPAQ_ASIC3_MAP_SIZE,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = HTCUNIVERSAL_IRQ(ASIC3_EXT_INT),
+ .end = HTCUNIVERSAL_IRQ(ASIC3_EXT_INT),
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = HTCUNIVERSAL_ASIC3_MMC_PHYS,
+ .end = HTCUNIVERSAL_ASIC3_MMC_PHYS + IPAQ_ASIC3_MAP_SIZE,
+ .flags = IORESOURCE_MEM,
+ },
+ [3] = {
+ .start = HTCUNIVERSAL_IRQ(ASIC3_SDIO_INT_N),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device htcuniversal_asic3 = {
+ .name = "asic3",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(htcuniversal_asic3_resources),
+ .resource = htcuniversal_asic3_resources,
+ .dev = { .platform_data = &htcuniversal_asic3_platform_data, },
+};
+EXPORT_SYMBOL(htcuniversal_asic3);
+
+static struct pxafb_mode_info htcuniversal_lcd_modes[] = {
+{
+ .pixclock = 96153,
+ .xres = 480,
+ .yres = 640,
+ .bpp = 16,
+ .hsync_len = 4,
+ .vsync_len = 1,
+ .left_margin = 20,
+ .right_margin = 8,
+ .upper_margin = 7,
+ .lower_margin = 8,
+
+// .sync = FB_SYNC_HOR_LOW_ACT|FB_SYNC_VERT_LOW_ACT,
+
+},
+};
+
+static struct pxafb_mach_info sony_acx526akm = {
+ .modes = htcuniversal_lcd_modes,
+ .num_modes = ARRAY_SIZE(htcuniversal_lcd_modes),
+
+ /* fixme: use constants defined in pxafb.h */
+ .lccr0 = 0x00000080,
+ .lccr3 = 0x00400000,
+// .lccr4 = 0x80000000,
+};
+
+static void __init htcuniversal_init_irq(void)
+{
+ pxa27x_init_irq();
+}
+
+static struct platform_pxa_serial_funcs htcuniversal_pxa_bt_funcs = {
+ .configure = htcuniversal_bt_configure,
+};
+static struct platform_pxa_serial_funcs htcuniversal_pxa_phone_funcs = {
+ .configure = htcuniversal_phone_configure,
+};
+
+/* USB OHCI */
+
+static int htcuniversal_ohci_init(struct device *dev)
+{
+ /* missing GPIO setup here */
+
+ /* got the value from wince */
+ UHCHR=UHCHR_CGR;
+
+ return 0;
+}
+
+static struct pxaohci_platform_data htcuniversal_ohci_platform_data = {
+ .port_mode = PMM_PERPORT_MODE,
+ .init = htcuniversal_ohci_init,
+};
+
+static void __init htcuniversal_map_io(void)
+{
+ pxa_map_io();
+
+ pxa_set_btuart_info(&htcuniversal_pxa_bt_funcs);
+ pxa_set_ffuart_info(&htcuniversal_pxa_phone_funcs);
+}
+
+static void __init htcuniversal_init(void)
+{
+ set_pxa_fb_info(&sony_acx526akm);
+
+ platform_device_register(&htcuniversal_asic3);
+ platform_add_devices(devices, ARRAY_SIZE(devices) );
+ pxa_set_ficp_info(&htcuniversal_ficp_platform_data);
+ pxa_set_ohci_info(&htcuniversal_ohci_platform_data);
+}
+
+MACHINE_START(HTCUNIVERSAL, "HTC Universal")
+ /* Maintainer xanadux.org */
+ .phys_io = 0x40000000,
+ .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
+ .boot_params = 0xa0000100,
+ .map_io = htcuniversal_map_io,
+ .init_irq = htcuniversal_init_irq,
+ .init_machine = htcuniversal_init,
+ .timer = &pxa_timer,
+MACHINE_END
Index: linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_ak4641.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_ak4641.c 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,917 @@
+/*
+ * Audio support for codec Asahi Kasei AK4641
+ *
+ * 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.
+ *
+ * Copyright (c) 2006 Giorgio Padrin <giorgio@mandarinlogiq.org>
+ *
+ * History:
+ *
+ * 2006-03 Written -- Giorgio Padrin
+ * 2006-09 Test and debug on machine (HP hx4700) -- Elshin Roman <roxmail@list.ru>
+ *
+ * AK4641 codec device driver
+ *
+ * Copyright (c) 2005 SDG Systems, LLC
+ *
+ * Based on code:
+ * Copyright (c) 2002 Hewlett-Packard Company
+ * Copyright (c) 2000 Nicolas Pitre <nico@cam.org>
+ * Copyright (c) 2000 Lernout & Hauspie Speech Products, N.V.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License.
+ */
+
+#include <sound/driver.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+#include <sound/info.h>
+
+#include "htcuniversal_ak4641.h"
+
+/* Registers */
+#define R_PM1 0x00
+#define R_PM2 0x01
+#define R_SEL1 0x02
+#define R_SEL2 0x03
+#define R_MODE1 0x04
+#define R_MODE2 0x05
+#define R_DAC 0x06
+#define R_MIC 0x07
+#define REG_TIMER 0x08
+#define REG_ALC1 0x09
+#define REG_ALC2 0x0a
+#define R_PGA 0x0b
+#define R_ATTL 0x0c
+#define R_ATTR 0x0d
+#define REG_VOL 0x0e
+#define R_STATUS 0x0f
+#define REG_EQLO 0x10
+#define REG_EQMID 0x11
+#define REG_EQHI 0x12
+#define REG_BTIF 0x13
+
+/* Register flags */
+/* REG_PWR1 */
+#define R_PM1_PMADC 0x01
+#define R_PM1_PMMIC 0x02
+#define REG_PWR1_PMAUX 0x04
+#define REG_PWR1_PMMO 0x08
+#define R_PM1_PMLO 0x10
+/* unused 0x20 */
+/* unused 0x40 */
+#define R_PM1_PMVCM 0x80
+
+/* REG_PWR2 */
+#define R_PM2_PMDAC 0x01
+/* unused 0x02 */
+/* unused 0x04 */
+#define R_PM2_PMMO2 0x08
+#define REG_PWR2_MCKAC 0x10
+/* unused 0x20 */
+/* unused 0x40 */
+#define R_PM2_MCKPD 0x80
+
+/* REG_SEL1 */
+#define R_SEL1_PSMO2 0x01
+/* unused 0x02 */
+/* unused 0x04 */
+/* unused 0x08 */
+#define REG_SEL1_MICM 0x10
+#define REG_SEL1_DACM 0x20
+#define REG_SEL1_PSMO 0x40
+#define REG_SEL1_MOGN 0x80
+
+/* REG_SEL2 */
+#define R_SEL2_PSLOR 0x01
+#define R_SEL2_PSLOL 0x02
+#define REG_SEL2_AUXSI 0x04
+/* unused 0x08 */
+#define REG_SEL2_MICL 0x10
+#define REG_SEL2_AUXL 0x20
+/* unused 0x40 */
+#define R_SEL2_DACL 0x80
+
+/* REG_MODE1 */
+#define REG_MODE1_DIF0 0x01
+#define REG_MODE1_DIF1 0x02
+/* unused 0x04 */
+/* unused 0x08 */
+/* unused 0x10 */
+/* unused 0x20 */
+/* unused 0x40 */
+/* unused 0x80 */
+
+/* REG_MODE2 */
+/* unused 0x01 */
+#define REG_MODE2_LOOP 0x02
+#define REG_MODE2_HPM 0x04
+/* unused 0x08 */
+/* unused 0x10 */
+#define REG_MODE2_MCK0 0x20
+#define REG_MODE2_MCK1 0x40
+/* unused 0x80 */
+
+/* REG_DAC */
+#define REG_DAC_DEM0 0x01
+#define REG_DAC_DEM1 0x02
+#define REG_DAC_EQ 0x04
+/* unused 0x08 */
+#define R_DAC_DATTC 0x10
+#define R_DAC_SMUTE 0x20
+#define REG_DAC_TM 0x40
+/* unused 0x80 */
+
+/* REG_MIC */
+#define R_MIC_MGAIN 0x01
+#define R_MIC_MSEL 0x02
+#define R_MIC_MICAD 0x04
+#define R_MIC_MPWRI 0x08
+#define R_MIC_MPWRE 0x10
+#define REG_MIC_AUXAD 0x20
+/* unused 0x40 */
+/* unused 0x80 */
+
+/* REG_TIMER */
+
+#define REG_TIMER_LTM0 0x01
+#define REG_TIMER_LTM1 0x02
+#define REG_TIMER_WTM0 0x04
+#define REG_TIMER_WTM1 0x08
+#define REG_TIMER_ZTM0 0x10
+#define REG_TIMER_ZTM1 0x20
+/* unused 0x40 */
+/* unused 0x80 */
+
+#define REG_ALC1_LMTH 0x01
+#define REG_ALC1_RATT 0x02
+#define REG_ALC1_LMAT0 0x04
+#define REG_ALC1_LMAT1 0x08
+#define REG_ALC1_ZELM 0x10
+#define REG_ALC1_ALC1 0x20
+/* unused 0x40 */
+/* unused 0x80 */
+
+/* REG_ALC2 */
+
+/* REG_PGA */
+
+/* REG_ATTL */
+
+/* REG_ATTR */
+
+/* REG_VOL */
+#define REG_VOL_ATTM 0x80
+
+/* REG_STATUS */
+#define R_STATUS_DTMIC 0x01
+
+/* REG_EQ controls use 4 bits for each of 5 EQ levels */
+
+/* Bluetooth not yet implemented */
+#define REG_BTIF_PMAD2 0x01
+#define REG_BTIF_PMDA2 0x02
+#define REG_BTIF_PMBIF 0x04
+#define REG_BTIF_ADC2 0x08
+#define REG_BTIF_DAC2 0x10
+#define REG_BTIF_BTFMT0 0x20
+#define REG_BTIF_BTFMT1 0x40
+/* unused 0x80 */
+
+/* begin {{ I2C }} */
+
+static struct i2c_driver snd_ak4641_i2c_driver = {
+ .driver = {
+ .name = "ak4641-i2c"
+ },
+};
+
+static int snd_ak4641_i2c_init(void)
+{
+ return i2c_add_driver(&snd_ak4641_i2c_driver);
+}
+
+static void snd_ak4641_i2c_free(void)
+{
+ i2c_del_driver(&snd_ak4641_i2c_driver);
+}
+
+static inline int snd_ak4641_i2c_probe(struct snd_ak4641 *ak)
+{
+ if (ak->i2c_client.adapter == NULL) return -EINVAL;
+ ak->i2c_client.addr = 0x12;
+ if (i2c_smbus_xfer(ak->i2c_client.adapter, ak->i2c_client.addr,
+ 0, 0, 0, I2C_SMBUS_QUICK, NULL) < 0)
+ return -ENODEV;
+ else return 0;
+}
+
+static int snd_ak4641_i2c_attach(struct snd_ak4641 *ak)
+{
+ int ret = 0;
+ if ((ret = snd_ak4641_i2c_probe(ak)) < 0) return ret;
+ snprintf(ak->i2c_client.name, sizeof(ak->i2c_client.name),
+ "ak4641-i2c at %d-%04x",
+ i2c_adapter_id(ak->i2c_client.adapter), ak->i2c_client.addr);
+ return i2c_attach_client(&ak->i2c_client);
+}
+
+static void snd_ak4641_i2c_detach(struct snd_ak4641 *ak)
+{
+ i2c_detach_client(&ak->i2c_client);
+}
+
+/* end {{ I2C }} */
+
+
+/* begin {{ Registers & Cache Ops }} */
+
+static int snd_ak4641_hwsync(struct snd_ak4641 *ak, int read, u8 reg)
+{
+ struct i2c_msg msgs[2];
+ u8 buf[2];
+ int ret;
+
+ snd_assert(reg < ARRAY_SIZE(ak->regs), return -EINVAL);
+
+ /* setup i2c msgs */
+ msgs[0].addr = ak->i2c_client.addr;
+ msgs[0].flags = 0;
+ msgs[0].buf = buf;
+ if (!read)
+ msgs[0].len = 2;
+ else {
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].addr = msgs[0].addr;
+ msgs[1].buf = msgs[0].buf + 1;
+ msgs[0].len = 1;
+ msgs[1].len = 1;
+ }
+
+ buf[0] = reg;
+
+ /* regs[reg] -> buffer, on write */
+ if (!read) buf[1] = ak->regs[reg];
+
+ /* i2c transfer */
+ ret = i2c_transfer(ak->i2c_client.adapter, msgs, read ? 2 : 1);
+ if (ret != (read ? 2 : 1)) return ret; /* transfer error */ //@@ error ret < 0, or not ?
+
+ /* regs[reg] <- buffer, on read */
+ if (read) ak->regs[reg] = buf[1];
+
+ return 0;
+}
+
+static inline int snd_ak4641_hwsync_read(struct snd_ak4641 *ak, u8 reg)
+{
+ return snd_ak4641_hwsync(ak, 1, reg);
+}
+
+static inline int snd_ak4641_hwsync_write(struct snd_ak4641 *ak, u8 reg)
+{
+ return snd_ak4641_hwsync(ak, 0, reg);
+}
+
+static int snd_ak4641_hwsync_read_all(struct snd_ak4641 *ak)
+{
+ u8 reg;
+ for (reg = 0; reg < ARRAY_SIZE(ak->regs); reg++)
+ if (snd_ak4641_hwsync_read(ak, reg) < 0) return -1;
+ return 0;
+}
+
+static int snd_ak4641_hwsync_write_all(struct snd_ak4641 *ak)
+{
+ u8 reg;
+ for (reg = 0; reg < ARRAY_SIZE(ak->regs); reg++)
+ if (snd_ak4641_hwsync_write(ak, reg) < 0) return -1;
+ return 0;
+}
+
+static int snd_ak4641_reg_changed(struct snd_ak4641 *ak, u8 reg)
+{
+ if ((reg != R_PGA && ak->powered_on) ||
+ (reg == R_PGA && (ak->regs[R_PM1] & R_PM1_PMMIC)))
+ return snd_ak4641_hwsync_write(ak, reg);
+ return 0;
+}
+
+/* end {{ Registers & Cache Ops }}*/
+
+
+static inline void snd_ak4641_lock(struct snd_ak4641 *ak)
+{
+ down(&ak->sem);
+}
+
+static inline void snd_ak4641_unlock(struct snd_ak4641 *ak)
+{
+ up(&ak->sem);
+}
+
+#define WRITE_MASK(i, val, mask) (((i) & ~(mask)) | ((val) & (mask)))
+
+
+/* begin {{ Controls }} */
+
+#define INV_RANGE(val, mask) \
+ (~(val) & (mask))
+
+/*-begin----------------------------------------------------------*/
+static int snd_ak4641_actl_playback_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 0xff;
+ return 0;
+}
+
+static int snd_ak4641_actl_playback_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ak4641 *ak = (struct snd_ak4641 *) kcontrol->private_data;
+
+ snd_ak4641_lock(ak);
+ ucontrol->value.integer.value[0] = INV_RANGE(ak->regs[R_ATTL], 0xff);
+ ucontrol->value.integer.value[1] = INV_RANGE(ak->regs[R_ATTR], 0xff);
+ snd_ak4641_unlock(ak);
+ return 0;
+}
+
+static int snd_ak4641_actl_playback_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ak4641 *ak = (struct snd_ak4641 *) kcontrol->private_data;
+
+ snd_ak4641_lock(ak);
+ ak->regs[R_ATTL] = INV_RANGE(ucontrol->value.integer.value[0], 0xff);
+ ak->regs[R_ATTR] = INV_RANGE(ucontrol->value.integer.value[1], 0xff);
+ snd_ak4641_reg_changed(ak, R_ATTL);
+ snd_ak4641_reg_changed(ak, R_ATTR);
+ snd_ak4641_unlock(ak);
+ return 0;
+}
+/*-end------------------------------------------------------------*/
+
+/*-begin----------------------------------------------------------*/
+static int snd_ak4641_actl_mic_gain_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 0x7f;
+ return 0;
+}
+
+static int snd_ak4641_actl_mic_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ak4641 *ak = (struct snd_ak4641 *) kcontrol->private_data;
+
+ ucontrol->value.integer.value[0] = ak->regs[R_PGA];
+ return 0;
+}
+
+static int snd_ak4641_actl_mic_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ak4641 *ak = (struct snd_ak4641 *) kcontrol->private_data;
+
+ snd_ak4641_lock(ak);
+ ak->regs[R_PGA] = ucontrol->value.integer.value[0];
+ snd_ak4641_reg_changed(ak, R_PGA);
+ snd_ak4641_unlock(ak);
+ return 0;
+}
+/*-end------------------------------------------------------------*/
+
+#define ACTL(ctl_name, _name) \
+static struct snd_kcontrol_new snd_ak4641_actl_ ## ctl_name = \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = _name, \
+ .info = snd_ak4641_actl_ ## ctl_name ## _info, \
+ .get = snd_ak4641_actl_ ## ctl_name ## _get, .put = snd_ak4641_actl_ ## ctl_name ## _put };
+
+ACTL(playback_volume, "Master Playback Volume")
+ACTL(mic_gain, "Mic Capture Gain")
+
+struct snd_ak4641_uctl_bool {
+ int (*get) (struct snd_ak4641 *uda);
+ int (*set) (struct snd_ak4641 *uda, int on);
+};
+
+static int snd_ak4641_actl_bool_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ return 0;
+}
+
+static int snd_ak4641_actl_bool_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ak4641 *ak = (struct snd_ak4641 *) kcontrol->private_data;
+ struct snd_ak4641_uctl_bool *uctl =
+ (struct snd_ak4641_uctl_bool *) kcontrol->private_value;
+
+ ucontrol->value.integer.value[0] = uctl->get(ak);
+ return 0;
+}
+
+static int snd_ak4641_actl_bool_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ak4641 *ak = (struct snd_ak4641 *) kcontrol->private_data;
+ struct snd_ak4641_uctl_bool *uctl =
+ (struct snd_ak4641_uctl_bool *) kcontrol->private_value;
+
+ return uctl->set(ak, ucontrol->value.integer.value[0]);
+}
+
+/*-begin----------------------------------------------------------*/
+static int snd_ak4641_uctl_playback_switch_get(struct snd_ak4641 *ak)
+{
+ return (ak->regs[R_DAC] & R_DAC_SMUTE) == 0x00;
+}
+
+static int snd_ak4641_uctl_playback_switch_set(struct snd_ak4641 *ak, int on)
+{
+ snd_ak4641_lock(ak);
+ ak->regs[R_DAC] = WRITE_MASK(ak->regs[R_DAC],
+ on ? 0x00 : R_DAC_SMUTE, R_DAC_SMUTE);
+ snd_ak4641_reg_changed(ak, R_DAC);
+ snd_ak4641_unlock(ak);
+ return 0;
+}
+/*-end------------------------------------------------------------*/
+
+/*-begin----------------------------------------------------------*/
+static int snd_ak4641_uctl_mic_boost_get(struct snd_ak4641 *ak)
+{
+ return (ak->regs[R_MIC] & R_MIC_MGAIN) == R_MIC_MGAIN;
+}
+
+static int snd_ak4641_uctl_mic_boost_set(struct snd_ak4641 *ak, int on)
+{
+ snd_ak4641_lock(ak);
+ ak->regs[R_MIC] = WRITE_MASK(ak->regs[R_MIC],
+ on ? R_MIC_MGAIN : 0x00, R_MIC_MGAIN);
+ snd_ak4641_reg_changed(ak, R_MIC);
+ snd_ak4641_unlock(ak);
+ return 0;
+}
+/*-end------------------------------------------------------------*/
+
+/*-begin----------------------------------------------------------*/
+static int snd_ak4641_uctl_mono_out_get(struct snd_ak4641 *ak)
+{
+ printk("mono_out status 0x%8.8x -> 0x%8.8x\n",ak->regs[R_SEL1], ak->regs[R_SEL1] & REG_SEL1_PSMO);
+ return (ak->regs[R_SEL1] & REG_SEL1_PSMO) == REG_SEL1_PSMO;
+}
+
+static int snd_ak4641_uctl_mono_out_set(struct snd_ak4641 *ak, int on)
+{
+ printk("phone mic enable called. on=%d\n",on);
+ snd_ak4641_lock(ak);
+ ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], on ? R_PM1_PMMIC : 0x00, R_PM1_PMMIC);
+ ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], on ? REG_PWR1_PMMO : 0x00, REG_PWR1_PMMO);
+ snd_ak4641_reg_changed(ak, R_PM1);
+
+ snd_ak4641_hwsync_write(ak, R_PGA); /* mic PGA gain is reset when PMMIC = 0 */
+
+ /* internal mic */
+ ak->regs[R_MIC] = WRITE_MASK(ak->regs[R_MIC], on ? R_MIC_MPWRI : 0x0, R_MIC_MPWRI);
+ ak->regs[R_MIC] = WRITE_MASK(ak->regs[R_MIC], 0x0, R_MIC_MSEL);
+ snd_ak4641_hwsync_write(ak, R_MIC);
+
+// ak->regs[REG_BTIF] = WRITE_MASK(ak->regs[REG_BTIF], 0x0, REG_BTIF_DAC2);
+// snd_ak4641_hwsync_write(ak, REG_BTIF);
+ /* */
+// ak->regs[REG_VOL] = WRITE_MASK(ak->regs[REG_VOL], on ? REG_VOL_ATTM : 0x00, REG_VOL_ATTM);
+// ak->regs[R_SEL1] = WRITE_MASK(ak->regs[R_SEL1], on ? REG_SEL1_MOGN : 0x00, REG_SEL1_MOGN);
+ ak->regs[R_SEL1] = WRITE_MASK(ak->regs[R_SEL1], on ? REG_SEL1_MICM : 0x00, REG_SEL1_MICM);
+ ak->regs[R_SEL1] = WRITE_MASK(ak->regs[R_SEL1], on ? REG_SEL1_PSMO : 0x00, REG_SEL1_PSMO);
+ snd_ak4641_reg_changed(ak, R_SEL1);
+ snd_ak4641_unlock(ak);
+ return 0;
+}
+/*-end------------------------------------------------------------*/
+
+#define ACTL_BOOL(ctl_name, _name) \
+static struct snd_ak4641_uctl_bool snd_ak4641_actl_ ## ctl_name ## _pvalue = \
+{ .get = snd_ak4641_uctl_ ## ctl_name ## _get, \
+ .set = snd_ak4641_uctl_ ## ctl_name ## _set }; \
+static struct snd_kcontrol_new snd_ak4641_actl_ ## ctl_name = \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = _name, .info = snd_ak4641_actl_bool_info, \
+ .get = snd_ak4641_actl_bool_get, .put = snd_ak4641_actl_bool_put, \
+ .private_value = (unsigned long) &snd_ak4641_actl_ ## ctl_name ## _pvalue };
+
+ACTL_BOOL(playback_switch, "Master Playback Switch")
+ACTL_BOOL(mic_boost, "Mic Boost (+20dB)")
+ACTL_BOOL(mono_out, "Phone mic enable")
+
+static void snd_ak4641_headphone_on(struct snd_ak4641 *ak, int on);
+static void snd_ak4641_speaker_on(struct snd_ak4641 *ak, int on);
+static void snd_ak4641_select_mic(struct snd_ak4641 *ak);
+
+void snd_ak4641_hp_connected(struct snd_ak4641 *ak, int connected)
+{
+ snd_ak4641_lock(ak);
+ if (connected != ak->hp_connected) {
+ ak->hp_connected = connected;
+
+ /* headphone or speaker, on playback */
+ if (ak->playback_on) {
+ if (connected) {
+ snd_ak4641_headphone_on(ak, 1);
+ snd_ak4641_speaker_on(ak, 0);
+ } else {
+ snd_ak4641_speaker_on(ak, 1);
+ snd_ak4641_headphone_on(ak, 0);
+ }
+ }
+
+ /* headset or internal mic, on capture */
+ if (ak->capture_on)
+ snd_ak4641_select_mic(ak);
+ }
+ snd_ak4641_unlock(ak);
+}
+
+/* end {{ Controls }} */
+
+
+/* begin {{ Headphone Detected Notification }} */
+
+static void snd_ak4641_hp_detected_w_fn(void *p)
+{
+ struct snd_ak4641 *ak = (struct snd_ak4641 *)p;
+
+ snd_ak4641_hp_connected(ak, ak->hp_detected.detected);
+}
+
+void snd_ak4641_hp_detected(struct snd_ak4641 *ak, int detected)
+{
+ if (detected != ak->hp_detected.detected) {
+ ak->hp_detected.detected = detected;
+ queue_work(ak->hp_detected.wq, &ak->hp_detected.w);
+ }
+}
+
+static int snd_ak4641_hp_detected_init(struct snd_ak4641 *ak)
+{
+ INIT_WORK(&ak->hp_detected.w, snd_ak4641_hp_detected_w_fn);
+ ak->hp_detected.detected = ak->hp_connected;
+ ak->hp_detected.wq = create_singlethread_workqueue("ak4641");
+ if (ak->hp_detected.wq) return 0;
+ else return -1;
+}
+
+static void snd_ak4641_hp_detected_free(struct snd_ak4641 *ak)
+{
+ destroy_workqueue(ak->hp_detected.wq);
+}
+
+/* end {{ Headphone Detected Notification }} */
+
+
+/* begin {{ Codec Control }} */
+
+static void snd_ak4641_headphone_on(struct snd_ak4641 *ak, int on)
+{
+ if (on) {
+ ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], R_PM1_PMLO, R_PM1_PMLO);
+ snd_ak4641_hwsync_write(ak, R_PM1);
+ ak->headphone_out_on(1);
+ ak->regs[R_SEL2] = WRITE_MASK(ak->regs[R_SEL2],
+ R_SEL2_PSLOL | R_SEL2_PSLOR,
+ R_SEL2_PSLOL | R_SEL2_PSLOR);
+ snd_ak4641_hwsync_write(ak, R_SEL2);
+ } else {
+ ak->regs[R_SEL2] = WRITE_MASK(ak->regs[R_SEL2],
+ 0x00, R_SEL2_PSLOL | R_SEL2_PSLOR);
+ snd_ak4641_hwsync_write(ak, R_SEL2);
+ ak->headphone_out_on(0);
+ ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], 0x00, R_PM1_PMLO);
+ snd_ak4641_hwsync_write(ak, R_PM1);
+ }
+}
+
+static void snd_ak4641_speaker_on(struct snd_ak4641 *ak, int on)
+{
+ if (on) {
+ ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], R_PM1_PMLO, R_PM1_PMLO);
+ snd_ak4641_hwsync_write(ak, R_PM1);
+ ak->speaker_out_on(1);
+ ak->regs[R_SEL2] = WRITE_MASK(ak->regs[R_SEL2],
+ R_SEL2_PSLOL | R_SEL2_PSLOR,
+ R_SEL2_PSLOL | R_SEL2_PSLOR);
+ snd_ak4641_hwsync_write(ak, R_SEL2);
+ } else {
+ ak->regs[R_SEL2] = WRITE_MASK(ak->regs[R_SEL2],
+ 0x00, R_SEL2_PSLOL | R_SEL2_PSLOR);
+ snd_ak4641_hwsync_write(ak, R_SEL2);
+ ak->speaker_out_on(0);
+ ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], 0x00, R_PM1_PMLO);
+ snd_ak4641_hwsync_write(ak, R_PM1);
+ }
+}
+
+static inline int snd_ak4641_power_on(struct snd_ak4641 *ak)
+{
+ ak->reset_pin(1);
+ ak->power_on_chip(1);
+ msleep(1);
+ ak->reset_pin(0);
+ ak->powered_on = 1;
+ return 0;
+}
+
+static inline int snd_ak4641_power_off(struct snd_ak4641 *ak)
+{
+ ak->powered_on = 0;
+ ak->power_on_chip(0);
+ return 0;
+}
+
+static inline void snd_ak4641_headphone_out_on(struct snd_ak4641 *ak, int on)
+{
+ if (ak->headphone_out_on) ak->headphone_out_on(on);
+}
+
+static inline void snd_ak4641_speaker_out_on(struct snd_ak4641 *ak, int on)
+{
+ if (ak->speaker_out_on) ak->speaker_out_on(on);
+}
+
+static int snd_ak4641_playback_on(struct snd_ak4641 *ak)
+{
+ if (ak->playback_on) return 0;
+
+ ak->regs[R_PM2] = WRITE_MASK(ak->regs[R_PM2],
+ R_PM2_PMDAC, R_PM2_MCKPD | R_PM2_PMDAC);
+ ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], R_PM1_PMLO, R_PM1_PMLO);
+ snd_ak4641_hwsync_write(ak, R_PM2);
+ snd_ak4641_hwsync_write(ak, R_PM1);
+ if (ak->hp_connected) snd_ak4641_headphone_on(ak, 1);
+ else snd_ak4641_speaker_on(ak, 1);
+
+ ak->playback_on = 1;
+
+ return 0;
+}
+
+static int snd_ak4641_playback_off(struct snd_ak4641 *ak)
+{
+ if (!ak->playback_on) return 0;
+
+ ak->playback_on = 0;
+
+ if (ak->hp_connected) snd_ak4641_headphone_on(ak, 0);
+ else snd_ak4641_speaker_on(ak, 0);
+ ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], 0x00, R_PM1_PMLO);
+ ak->regs[R_PM2] = WRITE_MASK(ak->regs[R_PM2],
+ (!ak->capture_on ? R_PM2_MCKPD : 0x00) | R_PM2_PMDAC,
+ R_PM2_MCKPD | R_PM2_PMDAC);
+ snd_ak4641_hwsync_write(ak, R_PM1);
+ snd_ak4641_hwsync_write(ak, R_PM2);
+
+ return 0;
+}
+
+static void snd_ak4641_select_mic(struct snd_ak4641 *ak)
+{
+ int mic = 0;
+ u8 r_mic;
+
+ if (ak->hp_connected) {
+ /* check headset mic */
+ ak->regs[R_MIC] = WRITE_MASK(ak->regs[R_MIC], R_MIC_MPWRE, R_MIC_MPWRE);
+ snd_ak4641_hwsync_write(ak, R_MIC);
+ snd_ak4641_hwsync_read(ak, R_STATUS);
+ mic = (ak->regs[R_STATUS] & R_STATUS_DTMIC) == R_STATUS_DTMIC;
+
+ printk("htcuniversal_ak4641_select_mic: mic=%d\n",mic);
+
+ r_mic = WRITE_MASK(ak->regs[R_MIC],
+ R_MIC_MSEL | (ak->capture_on ? R_MIC_MPWRE : 0x00),
+ R_MIC_MSEL | R_MIC_MPWRI | R_MIC_MPWRE);
+ }
+ else
+ r_mic = WRITE_MASK(ak->regs[R_MIC],
+ 0x00 | (ak->capture_on ? R_MIC_MPWRI : 0x00),
+ R_MIC_MSEL | R_MIC_MPWRI | R_MIC_MPWRE);
+
+ if (r_mic != ak->regs[R_MIC]) {
+ ak->regs[R_MIC] = r_mic;
+ snd_ak4641_hwsync_write(ak, R_MIC);
+ }
+}
+
+static int snd_ak4641_capture_on(struct snd_ak4641 *ak)
+{
+ if (ak->capture_on) return 0;
+
+ if (!ak->playback_on) {
+ ak->regs[R_PM2] = WRITE_MASK(ak->regs[R_PM2], 0x00, R_PM2_MCKPD);
+ snd_ak4641_hwsync_write(ak, R_PM2);
+ }
+ ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], R_PM1_PMMIC | R_PM1_PMADC,
+ R_PM1_PMMIC | R_PM1_PMADC);
+ snd_ak4641_hwsync_write(ak, R_PM1);
+ snd_ak4641_hwsync_write(ak, R_PGA); /* mic PGA gain is reset when PMMIC = 0 */
+
+ ak->capture_on = 1;
+
+ snd_ak4641_select_mic(ak);
+
+ msleep(47); /* accounts for ADC init cycle, time enough for fs >= 44.1 kHz */
+
+ return 0;
+}
+
+static int snd_ak4641_capture_off(struct snd_ak4641 *ak)
+{
+ if (!ak->capture_on) return 0;
+
+ ak->regs[R_MIC] = WRITE_MASK(ak->regs[R_MIC],
+ 0x00, R_MIC_MPWRI | R_MIC_MPWRE | R_MIC_MSEL);
+ ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], 0x00, R_PM1_PMMIC | R_PM1_PMADC);
+ snd_ak4641_hwsync_write(ak, R_MIC);
+ snd_ak4641_hwsync_write(ak, R_PM1);
+ if (!ak->playback_on) {
+ ak->regs[R_PM2] = WRITE_MASK(ak->regs[R_PM2], R_PM2_MCKPD, R_PM2_MCKPD);
+ snd_ak4641_hwsync_write(ak, R_PM2);
+ }
+
+ ak->capture_on = 0;
+
+ return 0;
+}
+
+int snd_ak4641_open_stream(struct snd_ak4641 *ak, int stream)
+{
+ snd_ak4641_lock(ak);
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ak->playback_stream_opened = 1;
+ snd_ak4641_playback_on(ak);
+ } else {
+ ak->capture_stream_opened = 1;
+ snd_ak4641_capture_on(ak);
+ }
+ snd_ak4641_unlock(ak);
+ return 0;
+}
+
+int snd_ak4641_close_stream(struct snd_ak4641 *ak, int stream)
+{
+ snd_ak4641_lock(ak);
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ak->playback_stream_opened = 0;
+ snd_ak4641_playback_off(ak);
+ } else {
+ ak->capture_stream_opened = 0;
+ snd_ak4641_capture_off(ak);
+ }
+ snd_ak4641_unlock(ak);
+ return 0;
+}
+
+static int snd_ak4641_init_regs(struct snd_ak4641 *ak)
+{
+ snd_ak4641_hwsync_read_all(ak);
+
+ //@@ MEMO: add some configs
+
+ ak->regs[R_PM1] = WRITE_MASK(ak->regs[R_PM1], R_PM1_PMVCM, R_PM1_PMVCM);
+ ak->regs[R_DAC] = WRITE_MASK(ak->regs[R_DAC], 0x00, R_DAC_DATTC);
+ snd_ak4641_hwsync_write(ak, R_PM1);
+ snd_ak4641_hwsync_write(ak, R_DAC);
+
+ return 0;
+}
+
+int snd_ak4641_suspend(struct snd_ak4641 *ak, pm_message_t state)
+{
+ snd_ak4641_lock(ak);
+ if (ak->playback_on) snd_ak4641_playback_off(ak);
+ if (ak->capture_on) snd_ak4641_capture_off(ak);
+ snd_ak4641_power_off(ak);
+ snd_ak4641_unlock(ak);
+ return 0;
+}
+
+int snd_ak4641_resume(struct snd_ak4641 *ak)
+{
+ snd_ak4641_lock(ak);
+ snd_ak4641_power_on(ak);
+ snd_ak4641_hwsync_write_all(ak);
+ if (ak->playback_stream_opened) snd_ak4641_playback_on(ak);
+ if (ak->capture_stream_opened) snd_ak4641_capture_on(ak);
+ snd_ak4641_unlock(ak);
+ return 0;
+}
+
+static void snd_ak4641_init_ak(struct snd_ak4641 *ak)
+{
+ init_MUTEX(&ak->sem);
+ ak->i2c_client.driver = &snd_ak4641_i2c_driver;
+}
+
+int snd_ak4641_activate(struct snd_ak4641 *ak)
+{
+ int ret = 0;
+
+ snd_ak4641_init_ak(ak);
+ snd_ak4641_lock(ak);
+ snd_ak4641_power_on(ak);
+ if ((ret = snd_ak4641_i2c_attach(ak)) < 0)
+ goto failed_i2c_attach;
+ snd_ak4641_init_regs(ak);
+ if ((ret = snd_ak4641_hp_detected_init(ak)) < 0)
+ goto failed_hp_detected_init;
+ snd_ak4641_unlock(ak);
+ return 0;
+
+ failed_hp_detected_init:
+ snd_ak4641_i2c_detach(ak);
+ failed_i2c_attach:
+ snd_ak4641_power_off(ak);
+ snd_ak4641_unlock(ak);
+ return ret;
+}
+
+void snd_ak4641_deactivate(struct snd_ak4641 *ak)
+{
+ snd_ak4641_lock(ak);
+ snd_ak4641_hp_detected_free(ak);
+ snd_ak4641_i2c_detach(ak);
+ snd_ak4641_power_off(ak);
+ snd_ak4641_unlock(ak);
+}
+
+int snd_ak4641_add_mixer_controls(struct snd_ak4641 *ak, struct snd_card *card)
+{
+ snd_ak4641_lock(ak);
+ snd_ctl_add(card, snd_ctl_new1(&snd_ak4641_actl_playback_volume, ak));
+ snd_ctl_add(card, snd_ctl_new1(&snd_ak4641_actl_playback_switch, ak));
+ snd_ctl_add(card, snd_ctl_new1(&snd_ak4641_actl_mic_gain, ak));
+ snd_ctl_add(card, snd_ctl_new1(&snd_ak4641_actl_mic_boost, ak));
+ snd_ctl_add(card, snd_ctl_new1(&snd_ak4641_actl_mono_out, ak));
+ snd_ak4641_unlock(ak);
+ return 0;
+}
+
+/* end {{ Codec Control }} */
+
+
+/* begin {{ Module }} */
+
+static int __init snd_ak4641_module_on_load(void)
+{
+ snd_ak4641_i2c_init();
+ return 0;
+}
+
+static void __exit snd_ak4641_module_on_unload(void)
+{
+ snd_ak4641_i2c_free();
+}
+
+module_init(snd_ak4641_module_on_load);
+module_exit(snd_ak4641_module_on_unload);
+
+EXPORT_SYMBOL(snd_ak4641_activate);
+EXPORT_SYMBOL(snd_ak4641_deactivate);
+EXPORT_SYMBOL(snd_ak4641_add_mixer_controls);
+EXPORT_SYMBOL(snd_ak4641_open_stream);
+EXPORT_SYMBOL(snd_ak4641_close_stream);
+EXPORT_SYMBOL(snd_ak4641_suspend);
+EXPORT_SYMBOL(snd_ak4641_resume);
+EXPORT_SYMBOL(snd_ak4641_hp_connected);
+EXPORT_SYMBOL(snd_ak4641_hp_detected);
+
+MODULE_AUTHOR("Giorgio Padrin");
+MODULE_DESCRIPTION("Audio support for codec Asahi Kasei AK4641");
+MODULE_LICENSE("GPL");
+
+/* end {{ Module }} */
Index: linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_ak4641.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_ak4641.h 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,65 @@
+/*
+ * Audio support for codec Asahi Kasei AK4641
+ *
+ * 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.
+ *
+ * Copyright (c) 2006 Giorgio Padrin <giorgio@mandarinlogiq.org>
+ */
+
+#ifndef __SOUND_AK4641_H
+#define __SOUND_AK4641_H
+
+#include <linux/i2c.h>
+
+struct snd_ak4641 {
+ struct semaphore sem;
+
+ u8 regs[0x14]; /* registers cache */
+
+ unsigned int
+ powered_on:1,
+ playback_on:1,
+ playback_stream_opened:1,
+ capture_on:1,
+ capture_stream_opened:1;
+
+ unsigned int
+ hp_connected:1;
+
+ /* -- configuration (to fill before activation) -- */
+ void (*power_on_chip)(int on);
+ void (*reset_pin)(int on);
+ void (*headphone_out_on)(int on);
+ void (*speaker_out_on)(int on);
+
+ struct i2c_client i2c_client; /* to fill .adapter */
+ /* ----------------------------------------------- */
+
+ struct {
+ int detected;
+ struct workqueue_struct *wq;
+ struct work_struct w;
+ } hp_detected;
+};
+
+
+/* Note: opening, closing, suspending and resuming a stream
+ * require the clocks (MCLK and I2S ones) running
+ */
+
+/* don't forget to specify I2C adapter in i2c_client field */
+int snd_ak4641_activate(struct snd_ak4641 *ak);
+
+void snd_ak4641_deactivate(struct snd_ak4641 *ak);
+int snd_ak4641_add_mixer_controls(struct snd_ak4641 *ak, struct snd_card *card);
+int snd_ak4641_open_stream(struct snd_ak4641 *ak, int stream);
+int snd_ak4641_close_stream(struct snd_ak4641 *ak, int stream);
+int snd_ak4641_suspend(struct snd_ak4641 *ak, pm_message_t state);
+int snd_ak4641_resume(struct snd_ak4641 *ak);
+
+void snd_ak4641_hp_connected(struct snd_ak4641 *ak, int connected); /* non atomic context */
+void snd_ak4641_hp_detected(struct snd_ak4641 *ak, int detected); /* atomic context */
+
+#endif /* __SOUND_AK4641_H */
Index: linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_asic3_leds.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_asic3_leds.c 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,143 @@
+/*
+ * LEDs support for the HP iPaq hx4700
+ *
+ * Copyright (c) 2006 Anton Vorontsov <cbou@mail.ru>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/soc/asic3_base.h>
+
+#include <asm/hardware/ipaq-asic3.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/asic3_leds.h>
+#include <asm/arch/htcuniversal-asic.h>
+
+//FIXME
+//DEFINE_LED_TRIGGER_SHARED_GLOBAL(htcuniversal_radio_trig);
+//EXPORT_LED_TRIGGER_SHARED(htcuniversal_radio_trig);
+
+static struct asic3_led htcuniversal_leds[] = {
+ {
+ .led_cdev = {
+ .name = "htcuniversal:red",
+ .default_trigger = "htcuniversal-charging",
+ },
+ .hw_num = 2,
+
+ },
+ {
+ .led_cdev = {
+ .name = "htcuniversal:green",
+ .default_trigger = "htcuniversal-chargefull",
+ },
+ .hw_num = 1,
+ },
+ {
+ .led_cdev = {
+ .name = "htcuniversal:wifi-bt",
+ .default_trigger = "htcuniversal-radio",
+ },
+ .hw_num = 0,
+ },
+ {
+ .led_cdev = {
+ .name = "htcuniversal:phonebuttons",
+ .default_trigger = "htcuniversal-phonebuttons",
+ },
+ .hw_num = -1,
+ .gpio_num = ('D'-'A')*16+GPIOD_BL_KEYP_PWR_ON,
+ },
+ {
+ .led_cdev = {
+ .name = "htcuniversal:vibra",
+ .default_trigger = "htcuniversal-vibra",
+ },
+ .hw_num = -1,
+ .gpio_num = ('D'-'A')*16+GPIOD_VIBRA_PWR_ON,
+ },
+ {
+ .led_cdev = {
+ .name = "htcuniversal:flashlight1",
+ .default_trigger = "htcuniversal-flashlight1",
+ },
+ .hw_num = -1,
+ .gpio_num = ('A'-'A')*16+GPIOA_FLASHLIGHT,
+ },
+ {
+ .led_cdev = {
+ .name = "htcuniversal:kbdbacklight",
+ .default_trigger = "htcuniversal-kbdbacklight",
+ },
+ .hw_num = -1,
+ .gpio_num = ('D'-'A')*16+GPIOD_BL_KEYB_PWR_ON,
+ },
+};
+
+void htcuniversal_leds_release(struct device *dev)
+{
+ return;
+}
+
+static
+struct asic3_leds_machinfo htcuniversal_leds_machinfo = {
+ .num_leds = ARRAY_SIZE(htcuniversal_leds),
+ .leds = htcuniversal_leds,
+ .asic3_pdev = &htcuniversal_asic3,
+};
+
+static
+struct platform_device htcuniversal_leds_pdev = {
+ .name = "asic3-leds",
+ .dev = {
+ .platform_data = &htcuniversal_leds_machinfo,
+ .release = htcuniversal_leds_release,
+ },
+};
+
+static
+int __init htcuniversal_leds_init(void)
+{
+ int ret;
+ printk("htcuniversal LEDs Driver\n");
+// led_trigger_register_shared("htcuniversal-radio", &htcuniversal_radio_trig);
+
+ ret = asic3_leds_register();
+ if (ret) goto asic3_leds_failed;
+
+ ret = platform_device_register(&htcuniversal_leds_pdev);
+ if (ret) goto platform_device_failed;
+
+ goto success;
+
+platform_device_failed:
+ asic3_leds_unregister();
+asic3_leds_failed:
+// led_trigger_unregister_shared(htcuniversal_radio_trig);
+ printk("htcuniversal LEDs Driver failed to init");
+success:
+ return ret;
+}
+
+static
+void __exit htcuniversal_leds_exit(void)
+{
+// led_trigger_unregister_shared(htcuniversal_radio_trig);
+ platform_device_unregister(&htcuniversal_leds_pdev);
+ asic3_leds_unregister();
+ return;
+}
+
+module_init(htcuniversal_leds_init);
+module_exit(htcuniversal_leds_exit);
+
+MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>");
+MODULE_DESCRIPTION("htcuniversal LEDs driver");
+MODULE_LICENSE("GPL");
Index: linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_bl.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_bl.c 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,61 @@
+/*
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * Copyright (C) 2006 Paul Sokolosvky
+ * Based on code from older versions of htcuniversal_lcd.c
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <asm/arch/hardware.h> /* for pxa-regs.h (__REG) */
+#include <asm/arch/pxa-regs.h>
+#include <asm/mach-types.h> /* machine_is_htcuniversal */
+//#include <linux/corgi_bl.h>
+#include <linux/backlight.h>
+#include <linux/err.h>
+
+#include <asm/arch/htcuniversal-gpio.h>
+#include <asm/arch/htcuniversal-asic.h>
+#include <asm/hardware/ipaq-asic3.h>
+#include <linux/soc/asic3_base.h>
+
+#define HTCUNIVERSAL_MAX_INTENSITY 0xc7
+
+static void htcuniversal_set_bl_intensity(int intensity)
+{
+ PWM_CTRL1 = 1; /* pre-scaler */
+ PWM_PWDUTY1 = intensity; /* duty cycle */
+ PWM_PERVAL1 = HTCUNIVERSAL_MAX_INTENSITY+1; /* period */
+
+ if (intensity > 0) {
+ pxa_set_cken(CKEN_PWM1, 1);
+ asic3_set_gpio_out_d(&htcuniversal_asic3.dev,
+ (1<<GPIOD_FL_PWR_ON), (1<<GPIOD_FL_PWR_ON));
+ } else {
+ pxa_set_cken(CKEN_PWM1, 0);
+ asic3_set_gpio_out_d(&htcuniversal_asic3.dev,
+ (1<<GPIOD_FL_PWR_ON), 0);
+ }
+}
+
+
+static struct generic_bl_info htcuniversal_bl_machinfo = {
+ .default_intensity = HTCUNIVERSAL_MAX_INTENSITY / 4,
+ .limit_mask = 0xff,
+ .max_intensity = HTCUNIVERSAL_MAX_INTENSITY,
+ .set_bl_intensity = htcuniversal_set_bl_intensity,
+};
+
+struct platform_device htcuniversal_bl = {
+ .name = "corgi-bl",
+ .dev = {
+ .platform_data = &htcuniversal_bl_machinfo,
+ },
+};
+
+MODULE_AUTHOR("Paul Sokolovsky <pmiscml@gmail.com>");
+MODULE_DESCRIPTION("Backlight driver for HTC Universal");
+MODULE_LICENSE("GPL");
Index: linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_bt.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_bt.c 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,135 @@
+/* Bluetooth interface driver for TI BRF6150 on HX4700
+ *
+ * Copyright (c) 2005 SDG Systems, LLC
+ *
+ * 2005-04-21 Todd Blumer Created.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/soc/asic3_base.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/serial.h>
+#include <asm/hardware/ipaq-asic3.h>
+#include <asm/arch/htcuniversal-gpio.h>
+#include <asm/arch/htcuniversal-asic.h>
+
+#include "htcuniversal_bt.h"
+
+static uint use_led=1;
+
+static void
+htcuniversal_bt_configure( int state )
+{
+ int tries;
+
+ printk( KERN_NOTICE "htcuniversal configure bluetooth: %d\n", state );
+ switch (state) {
+
+ case PXA_UART_CFG_PRE_STARTUP:
+ break;
+
+ case PXA_UART_CFG_POST_STARTUP:
+ /* pre-serial-up hardware configuration */
+ htcuniversal_egpio_enable(1<<EGPIO5_BT_3V3_ON);
+ mdelay(50);
+ asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_BT_PWR_ON, 1<<GPIOC_BT_PWR_ON);
+ mdelay(10);
+ asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_BT_RESET, 0);
+ mdelay(10);
+ asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_BT_RESET, 1<<GPIOC_BT_RESET);
+ mdelay(10);
+
+ /*
+ * BRF6150's RTS goes low when firmware is ready
+ * so check for CTS=1 (nCTS=0 -> CTS=1). Typical 150ms
+ */
+ tries = 0;
+ do {
+ mdelay(10);
+ } while ((BTMSR & MSR_CTS) == 0 && tries++ < 50);
+ if (use_led) {
+// htcuniversal_set_led(2, 16, 16);
+ }
+ break;
+
+ case PXA_UART_CFG_PRE_SHUTDOWN:
+ htcuniversal_egpio_disable(1<<EGPIO5_BT_3V3_ON );
+ mdelay(50);
+// htcuniversal_clear_led(2);
+ asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_BT_PWR_ON, 0);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+static int
+htcuniversal_bt_probe( struct platform_device *dev )
+{
+ struct htcuniversal_bt_funcs *funcs = dev->dev.platform_data;
+
+ /* configure bluetooth UART */
+ pxa_gpio_mode( GPIO_NR_HTCUNIVERSAL_BT_RXD_MD );
+ pxa_gpio_mode( GPIO_NR_HTCUNIVERSAL_BT_TXD_MD );
+ pxa_gpio_mode( GPIO_NR_HTCUNIVERSAL_BT_UART_CTS_MD );
+ pxa_gpio_mode( GPIO_NR_HTCUNIVERSAL_BT_UART_RTS_MD );
+
+ funcs->configure = htcuniversal_bt_configure;
+
+ /* Make sure the LED is off */
+// htcuniversal_clear_led(2);
+
+ return 0;
+}
+
+static int
+htcuniversal_bt_remove( struct platform_device *dev )
+{
+ struct htcuniversal_bt_funcs *funcs = dev->dev.platform_data;
+
+ funcs->configure = NULL;
+
+ /* Make sure the LED is off */
+// htcuniversal_clear_led(2);
+
+ return 0;
+}
+
+static struct platform_driver bt_driver = {
+ .driver = {
+ .name = "htcuniversal_bt",
+ },
+ .probe = htcuniversal_bt_probe,
+ .remove = htcuniversal_bt_remove,
+};
+
+module_param(use_led, uint, 0);
+
+static int __init
+htcuniversal_bt_init( void )
+{
+ printk(KERN_NOTICE "htcuniversal Bluetooth Driver\n");
+ return platform_driver_register( &bt_driver );
+}
+
+static void __exit
+htcuniversal_bt_exit( void )
+{
+ platform_driver_unregister( &bt_driver );
+}
+
+module_init( htcuniversal_bt_init );
+module_exit( htcuniversal_bt_exit );
+
+MODULE_AUTHOR("Todd Blumer, SDG Systems, LLC");
+MODULE_DESCRIPTION("HTC Universal Bluetooth Support Driver");
+MODULE_LICENSE("GPL");
+
+/* vim600: set noexpandtab sw=8 ts=8 :*/
+
Index: linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_bt.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_bt.h 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,17 @@
+/*
+ * Bluetooth support file for calling bluetooth configuration functions
+ *
+ * Copyright (c) 2005 SDG Systems, LLC
+ *
+ * 2005-06 Todd Blumer Initial Revision
+ */
+
+#ifndef _HTCUNIVERSAL_BT_H
+#define _HTCUNIVERSAL_BT_H
+
+struct htcuniversal_bt_funcs {
+ void (*configure) ( int state );
+};
+
+
+#endif
Index: linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_buttons.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_buttons.c 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,87 @@
+/*
+ * Buttons driver for HTC Universal
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.
+ *
+ * Copyright (C) 2005 Pawel Kolodziejski
+ * Copyright (C) 2003 Joshua Wise
+ *
+ */
+
+#include <linux/input.h>
+#include <linux/input_pda.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/gpio_keys.h>
+#include <linux/soc/asic3_base.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/asic3_keys.h>
+#include <asm/arch/htcuniversal-gpio.h>
+#include <asm/arch/htcuniversal-asic.h>
+
+static struct asic3_keys_button asic3_buttons[] = {
+//{KEY_SCREEN, ASIC3_GPIOA_IRQ_BASE+GPIOA_COVER_ROTATE_N, 1, "screen_cover", EV_SW},
+//{KEY_SWITCHVIDEOMODE, ASIC3_GPIOB_IRQ_BASE+GPIOB_CLAMSHELL_N, 1, "clamshell_rotate", EV_SW},
+//{KEY_KBDILLUMTOGGLE, ASIC3_GPIOB_IRQ_BASE+GPIOB_NIGHT_SENSOR, 1, "night_sensor", EV_SW},
+{SW_LID, ASIC3_GPIOA_IRQ_BASE+GPIOA_COVER_ROTATE_N, 1, "screen_cover", EV_SW},
+{SW_TABLET_MODE, ASIC3_GPIOB_IRQ_BASE+GPIOB_CLAMSHELL_N, 1, "clamshell_rotate", EV_SW},
+//{SW_NIGHT_SENSOR, ASIC3_GPIOB_IRQ_BASE+GPIOB_NIGHT_SENSOR, 1, "night_sensor", EV_SW},
+{KEY_F10, ASIC3_GPIOA_IRQ_BASE+GPIOA_BUTTON_BACKLIGHT_N, 1, "backlight_button"},
+{KEY_RECORD, ASIC3_GPIOA_IRQ_BASE+GPIOA_BUTTON_RECORD_N, 1, "record_button"},
+{KEY_CAMERA, ASIC3_GPIOA_IRQ_BASE+GPIOA_BUTTON_CAMERA_N, 1, "camera_button"},
+{KEY_VOLUMEDOWN, ASIC3_GPIOA_IRQ_BASE+GPIOA_VOL_UP_N, 1, "volume_slider_down"},
+{KEY_VOLUMEUP, ASIC3_GPIOA_IRQ_BASE+GPIOA_VOL_DOWN_N, 1, "volume_slider_up"},
+{KEY_KPENTER, ASIC3_GPIOD_IRQ_BASE+GPIOD_KEY_OK_N, 1, "select"},
+{KEY_RIGHT, ASIC3_GPIOD_IRQ_BASE+GPIOD_KEY_RIGHT_N, 1, "right"},
+{KEY_LEFT, ASIC3_GPIOD_IRQ_BASE+GPIOD_KEY_LEFT_N, 1, "left"},
+{KEY_DOWN, ASIC3_GPIOD_IRQ_BASE+GPIOD_KEY_DOWN_N, 1, "down"},
+{KEY_UP, ASIC3_GPIOD_IRQ_BASE+GPIOD_KEY_UP_N, 1, "up"},
+};
+
+static struct asic3_keys_platform_data asic3_keys_data = {
+ .buttons = asic3_buttons,
+ .nbuttons = ARRAY_SIZE(asic3_buttons),
+ .asic3_dev = &htcuniversal_asic3.dev,
+};
+
+static struct platform_device htcuniversal_keys_asic3 = {
+ .name = "asic3-keys",
+ .dev = { .platform_data = &asic3_keys_data, }
+};
+
+static int __init htcuniversal_buttons_probe(struct platform_device *dev)
+{
+ platform_device_register(&htcuniversal_keys_asic3);
+ return 0;
+}
+
+static struct platform_driver htcuniversal_buttons_driver = {
+ .driver = {
+ .name = "htcuniversal_buttons",
+ },
+ .probe = htcuniversal_buttons_probe,
+};
+
+static int __init htcuniversal_buttons_init(void)
+{
+ if (!machine_is_htcuniversal())
+ return -ENODEV;
+
+ return platform_driver_register(&htcuniversal_buttons_driver);
+}
+
+static void __exit htcuniversal_buttons_exit(void)
+{
+ platform_driver_unregister(&htcuniversal_buttons_driver);
+}
+
+module_init(htcuniversal_buttons_init);
+module_exit(htcuniversal_buttons_exit);
+
+MODULE_AUTHOR ("Joshua Wise, Pawel Kolodziejski, Paul Sokolosvky");
+MODULE_DESCRIPTION ("Buttons support for HTC Universal");
+MODULE_LICENSE ("GPL");
Index: linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_core.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_core.c 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,226 @@
+/* Core Hardware driver for Hx4700 (Serial, ASIC3, EGPIOs)
+ *
+ * Copyright (c) 2005 SDG Systems, LLC
+ *
+ * 2005-03-29 Todd Blumer Converted basic structure to support hx4700
+ * 2005-04-30 Todd Blumer Add IRDA code from H2200
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/mach/irq.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa-pm_ll.h>
+#include <asm/arch/htcuniversal-gpio.h>
+#include <asm/arch/htcuniversal-asic.h>
+
+#include <linux/soc/asic3_base.h>
+#include <asm/hardware/ipaq-asic3.h>
+
+volatile u_int16_t *egpios;
+u_int16_t egpio_reg;
+
+static int htc_bootloader = 0; /* Is the stock HTC bootloader installed? */
+
+/*
+ * may make sense to put egpios elsewhere, but they're here now
+ * since they share some of the same address space with the TI WLAN
+ *
+ * EGPIO register is write-only
+ */
+
+void
+htcuniversal_egpio_enable( u_int16_t bits )
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ egpio_reg |= bits;
+ *egpios = egpio_reg;
+
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(htcuniversal_egpio_enable);
+
+void
+htcuniversal_egpio_disable( u_int16_t bits )
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ egpio_reg &= ~bits;
+ *egpios = egpio_reg;
+
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(htcuniversal_egpio_disable);
+
+#ifdef CONFIG_PM
+
+//void htcuniversal_ll_pm_init(void);
+
+static int htcuniversal_suspend(struct platform_device *dev, pm_message_t state)
+{
+ /* Turn off external clocks here, because htcuniversal_power and asic3_mmc
+ * scared to do so to not hurt each other. (-5 mA) */
+
+
+ /* 0x20c2 is HTC clock value
+ * CLOCK_CDEX_SOURCE 2
+ * CLOCK_CDEX_SPI 0
+ * CLOCK_CDEX_OWM 0
+ *
+ * CLOCK_CDEX_PWM0 0
+ * CLOCK_CDEX_PWM1 0
+ * CLOCK_CDEX_LED0 1
+ * CLOCK_CDEX_LED1 1
+ *
+ * CLOCK_CDEX_LED2 0
+ * CLOCK_CDEX_SD_HOST 0
+ * CLOCK_CDEX_SD_BUS 0
+ * CLOCK_CDEX_SMBUS 0
+ *
+ * CLOCK_CDEX_CONTROL_CX 0
+ * CLOCK_CDEX_EX0 1
+ * CLOCK_CDEX_EX1 0
+ * */
+ asic3_set_clock_cdex(&htcuniversal_asic3.dev, 0xffff, CLOCK_CDEX_SOURCE1
+ |CLOCK_CDEX_LED0
+ |CLOCK_CDEX_LED1
+ |CLOCK_CDEX_LED2
+ |CLOCK_CDEX_EX0
+ |CLOCK_CDEX_EX1);
+
+ *egpios = 0; /* turn off all egpio power */
+
+ /* Wake up enable. */
+ PWER = PWER_GPIO0
+ | PWER_GPIO1 /* reset */
+ | PWER_GPIO9 /* USB */
+ | PWER_GPIO10 /* AC on USB */
+ | PWER_GPIO14 /* ASIC3 mux */
+ | PWER_RTC;
+ /* Wake up on falling edge. */
+ PFER = PWER_GPIO0
+ | PWER_GPIO1
+ | PWER_GPIO9
+ | PWER_GPIO10
+ | PWER_GPIO14;
+
+ /* Wake up on rising edge. */
+ PRER = PWER_GPIO0
+ | PWER_GPIO1
+ | PWER_GPIO9
+ | PWER_GPIO10;
+ /* 3.6864 MHz oscillator power-down enable */
+ PCFR = PCFR_OPDE | PCFR_PI2CEN | PCFR_GPROD | PCFR_GPR_EN;
+
+ PGSR0 = 0x09088004;
+ PGSR1 = 0x00020002;
+ PGSR2 = 0x8001c000;
+ PGSR3 = 0x00106284;
+
+ PSLR = 0xcc000000;
+
+#if 0
+ /*
+ * If we're using bootldr and not the stock HTC bootloader,
+ * we want to wake up periodically to see if the charge is full while
+ * it is suspended. We do this with the OS timer 4 in the pxa270.
+ */
+ if (!htc_bootloader) {
+ OMCR4 = 0x4b; /* Periodic, self-resetting, 1-second timer */
+ OSMR4 = 5; /* Wake up bootldr after x seconds so it can
+ figure out what to do with the LEDs. */
+ OIER |= 0x10; /* Enable interrupt source for Timer 4 */
+ OSCR4 = 0; /* This starts the timer */
+ }
+#endif
+
+ asic3_set_extcf_select(&htcuniversal_asic3.dev, ASIC3_EXTCF_OWM_EN, 0);
+
+ return 0;
+}
+
+static int htcuniversal_resume(struct platform_device *dev)
+{
+ htcuniversal_egpio_enable(0);
+
+ return 0;
+}
+#else
+# define htcuniversal_suspend NULL
+# define htcuniversal_resume NULL
+#endif
+
+static int
+htcuniversal_core_probe( struct platform_device *dev )
+{
+
+ printk( KERN_NOTICE "HTC Universal Core Hardware Driver\n" );
+
+ egpios = (volatile u_int16_t *)ioremap_nocache(HTCUNIVERSAL_EGPIO_BASE, sizeof *egpios );
+ if (!egpios)
+ return -ENODEV;
+ else
+ printk( KERN_NOTICE "HTC Universal Core: egpio at phy=0x%8.8x is at virt=0x%p\n",
+ HTCUNIVERSAL_EGPIO_BASE, egpios );
+
+ printk("Using stock HTC first stage bootloader\n");
+ htc_bootloader = 1;
+
+// htcuniversal_ll_pm_init();
+
+ return 0;
+}
+
+static int
+htcuniversal_core_remove( struct platform_device *dev )
+{
+
+ if (egpios != NULL)
+ iounmap( (void *)egpios );
+
+ return 0;
+}
+
+static struct platform_driver htcuniversal_core_driver = {
+ .driver = {
+ .name = "htcuniversal_core",
+ },
+ .probe = htcuniversal_core_probe,
+ .remove = htcuniversal_core_remove,
+ .suspend = htcuniversal_suspend,
+ .resume = htcuniversal_resume,
+};
+
+static int __init
+htcuniversal_core_init( void )
+{
+ return platform_driver_register( &htcuniversal_core_driver );
+}
+
+
+static void __exit
+htcuniversal_core_exit( void )
+{
+ platform_driver_unregister( &htcuniversal_core_driver );
+}
+
+module_init( htcuniversal_core_init );
+module_exit( htcuniversal_core_exit );
+
+MODULE_AUTHOR("Todd Blumer, SDG Systems, LLC");
+MODULE_DESCRIPTION("HTC Universal Core Hardware Driver");
+MODULE_LICENSE("GPL");
+
+/* vim600: set noexpandtab sw=8 ts=8 :*/
Index: linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_lcd.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_lcd.c 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,212 @@
+/*
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * History:
+ *
+ * 2004-03-01 Eddi De Pieri Adapted for htcuniversal using h3900_lcd.c
+ * 2004 Shawn Anderson Lcd hacking on htcuniversal
+ * see h3900_lcd.c for more history.
+ *
+ */
+
+#include <linux/types.h>
+#include <asm/arch/hardware.h> /* for pxa-regs.h (__REG) */
+#include <linux/platform_device.h>
+#include <asm/arch/pxa-regs.h> /* LCCR[0,1,2,3]* */
+#include <asm/arch/bitfield.h> /* for pxa-regs.h (Fld, etc) */
+#include <asm/arch/pxafb.h> /* pxafb_mach_info, set_pxa_fb_info */
+#include <asm/mach-types.h> /* machine_is_htcuniversal */
+#include <linux/lcd.h> /* lcd_device */
+#include <linux/err.h>
+#include <linux/delay.h>
+
+#include <asm/arch/htcuniversal-gpio.h>
+#include <asm/arch/htcuniversal-asic.h>
+#include <asm/hardware/ipaq-asic3.h>
+#include <linux/soc/asic3_base.h>
+
+static int saved_lcdpower=-1;
+
+static int powerup_lcd(void)
+{
+ printk( KERN_INFO "htcuniversal powerup_lcd: called\n");
+
+ asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_LCD_PWR1_ON, 0);
+ asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_LCD_PWR2_ON, 0);
+ asic3_set_gpio_out_b(&htcuniversal_asic3.dev, 1<<GPIOB_LCD_PWR3_ON, 0);
+ asic3_set_gpio_out_d(&htcuniversal_asic3.dev, 1<<GPIOD_LCD_PWR4_ON, 0);
+ asic3_set_gpio_out_a(&htcuniversal_asic3.dev, 1<<GPIOA_LCD_PWR5_ON, 0);
+#if 1
+ LCCR4|=LCCR4_PCDDIV;
+#endif
+ pxa_set_cken(CKEN_LCD, 0);
+
+ mdelay(100);
+ asic3_set_gpio_out_a(&htcuniversal_asic3.dev, 1<<GPIOA_LCD_PWR5_ON, 1<<GPIOA_LCD_PWR5_ON);
+ mdelay(5);
+ asic3_set_gpio_out_b(&htcuniversal_asic3.dev, 1<<GPIOB_LCD_PWR3_ON, 1<<GPIOB_LCD_PWR3_ON);
+ mdelay(2);
+ asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_LCD_PWR1_ON, 1<<GPIOC_LCD_PWR1_ON);
+ mdelay(2);
+ asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_LCD_PWR2_ON, 1<<GPIOC_LCD_PWR2_ON);
+ mdelay(20);
+ asic3_set_gpio_out_d(&htcuniversal_asic3.dev, 1<<GPIOD_LCD_PWR4_ON, 1<<GPIOD_LCD_PWR4_ON);
+ mdelay(1);
+ pxa_set_cken(CKEN_LCD, 1);
+
+ SET_HTCUNIVERSAL_GPIO(LCD1,1);
+ SET_HTCUNIVERSAL_GPIO(LCD2,1);
+ return 0;
+}
+
+static int powerdown_lcd(void)
+{
+ printk( KERN_INFO "htcuniversal powerdown_lcd: called\n");
+
+#if 1
+ asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_LCD_PWR2_ON, 0);
+ mdelay(100);
+ asic3_set_gpio_out_d(&htcuniversal_asic3.dev, 1<<GPIOD_LCD_PWR4_ON, 0);
+ mdelay(10);
+ asic3_set_gpio_out_a(&htcuniversal_asic3.dev, 1<<GPIOA_LCD_PWR5_ON, 0);
+ mdelay(1);
+ asic3_set_gpio_out_b(&htcuniversal_asic3.dev, 1<<GPIOB_LCD_PWR3_ON, 0);
+ mdelay(1);
+ asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_LCD_PWR1_ON, 0);
+ pxa_set_cken(CKEN_LCD, 0);
+
+ SET_HTCUNIVERSAL_GPIO(LCD1,0);
+ SET_HTCUNIVERSAL_GPIO(LCD2,0);
+#else
+ pxa_set_cken(CKEN_LCD, 0);
+
+ SET_HTCUNIVERSAL_GPIO(LCD1,0);
+ SET_HTCUNIVERSAL_GPIO(LCD2,0);
+
+ asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_LCD_PWR2_ON, 0);
+ mdelay(100);
+ asic3_set_gpio_out_d(&htcuniversal_asic3.dev, 1<<GPIOD_LCD_PWR4_ON, 0);
+ mdelay(10);
+ asic3_set_gpio_out_a(&htcuniversal_asic3.dev, 1<<GPIOA_LCD_PWR5_ON, 0);
+ mdelay(1);
+ asic3_set_gpio_out_b(&htcuniversal_asic3.dev, 1<<GPIOB_LCD_PWR3_ON, 0);
+ mdelay(1);
+ asic3_set_gpio_out_c(&htcuniversal_asic3.dev, 1<<GPIOC_LCD_PWR1_ON, 0);
+#endif
+ return 0;
+}
+
+static int htcuniversal_lcd_set_power(struct lcd_device *lm, int power)
+{
+ /* Enable or disable power to the LCD (0: on; 4: off) */
+
+ if ( power < 1 ) {
+
+ powerup_lcd();
+
+ } else {
+
+ powerdown_lcd();
+
+ }
+
+ saved_lcdpower=power;
+
+ return 0;
+}
+
+static int htcuniversal_lcd_get_power(struct lcd_device *lm)
+{
+ /* Get the LCD panel power status (0: full on, 1..3: controller
+ * power on, flat panel power off, 4: full off) */
+
+ if (saved_lcdpower == -1)
+ {
+ htcuniversal_lcd_set_power(lm, 4);
+ saved_lcdpower=4;
+ }
+
+ return saved_lcdpower;
+}
+
+static struct lcd_ops htcuniversal_lcd_properties =
+{
+ .get_power = htcuniversal_lcd_get_power,
+ .set_power = htcuniversal_lcd_set_power,
+};
+
+static struct lcd_device *htcuniversal_lcd_dev;
+
+static int htcuniversal_lcd_probe(struct platform_device * dev)
+{
+ htcuniversal_lcd_dev = lcd_device_register("pxa2xx-fb", &dev->dev, NULL,
+ &htcuniversal_lcd_properties);
+ if (IS_ERR(htcuniversal_lcd_dev)) {
+ printk("htcuniversal_lcd_probe: error registering devices\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int htcuniversal_lcd_remove(struct platform_device * dev)
+{
+ htcuniversal_lcd_set_power(htcuniversal_lcd_dev, 4);
+ lcd_device_unregister(htcuniversal_lcd_dev);
+
+ return 0;
+}
+
+static int htcuniversal_lcd_suspend(struct platform_device * dev, pm_message_t state)
+{
+// printk("htcuniversal_lcd_suspend: called.\n");
+ htcuniversal_lcd_set_power(htcuniversal_lcd_dev, 4);
+ return 0;
+}
+
+static int htcuniversal_lcd_resume(struct platform_device * dev)
+{
+// printk("htcuniversal_lcd_resume: called.\n");
+
+ /* */
+#if 1
+ LCCR4|=LCCR4_PCDDIV;
+#endif
+
+ htcuniversal_lcd_set_power(htcuniversal_lcd_dev, 0);
+ return 0;
+}
+
+static struct platform_driver htcuniversal_lcd_driver = {
+ .driver = {
+ .name = "htcuniversal_lcd",
+ },
+ .probe = htcuniversal_lcd_probe,
+ .remove = htcuniversal_lcd_remove,
+ .suspend = htcuniversal_lcd_suspend,
+ .resume = htcuniversal_lcd_resume,
+};
+
+static int htcuniversal_lcd_init(void)
+{
+ if (!machine_is_htcuniversal())
+ return -ENODEV;
+
+ return platform_driver_register(&htcuniversal_lcd_driver);
+}
+
+static void htcuniversal_lcd_exit(void)
+{
+ lcd_device_unregister(htcuniversal_lcd_dev);
+ platform_driver_unregister(&htcuniversal_lcd_driver);
+}
+
+module_init(htcuniversal_lcd_init);
+module_exit(htcuniversal_lcd_exit);
+
+MODULE_AUTHOR("xanadux.org");
+MODULE_DESCRIPTION("Framebuffer driver for HTC Universal");
+MODULE_LICENSE("GPL");
+
Index: linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_phone.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_phone.c 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,167 @@
+
+/* Phone interface driver for Qualcomm MSM6250 on HTC Universal
+ *
+ * Copyright (c) 2005 SDG Systems, LLC
+ *
+ * 2005-04-21 Todd Blumer Created.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/soc/asic3_base.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/serial.h>
+#include <asm/hardware/ipaq-asic3.h>
+#include <asm/arch/htcuniversal-gpio.h>
+#include <asm/arch/htcuniversal-asic.h>
+
+#include "htcuniversal_phone.h"
+
+static void phone_reset(void)
+{
+ asic3_set_gpio_out_b(&htcuniversal_asic3.dev, 1<<GPIOB_BB_RESET2, 0);
+
+ SET_HTCUNIVERSAL_GPIO(PHONE_RESET,0);
+ asic3_set_gpio_out_d(&htcuniversal_asic3.dev, 1<<GPIOD_BB_RESET1, 0);
+ mdelay(1);
+ asic3_set_gpio_out_d(&htcuniversal_asic3.dev, 1<<GPIOD_BB_RESET1, 1<<GPIOD_BB_RESET1);
+ mdelay(20);
+ SET_HTCUNIVERSAL_GPIO(PHONE_RESET,1);
+ mdelay(200);
+ asic3_set_gpio_out_d(&htcuniversal_asic3.dev, 1<<GPIOD_BB_RESET1, 0);
+}
+
+static void phone_off(void)
+{
+ asic3_set_gpio_out_d(&htcuniversal_asic3.dev, 1<<GPIOD_BB_RESET1, 1<<GPIOD_BB_RESET1);
+ mdelay(2000);
+ asic3_set_gpio_out_d(&htcuniversal_asic3.dev, 1<<GPIOD_BB_RESET1, 0);
+
+ asic3_set_gpio_out_b(&htcuniversal_asic3.dev, 1<<GPIOB_BB_RESET2, 1<<GPIOB_BB_RESET2);
+ SET_HTCUNIVERSAL_GPIO(PHONE_OFF,0);
+}
+
+static void
+htcuniversal_phone_configure( int state )
+{
+ int tries;
+ unsigned short statusb;
+
+ printk( KERN_NOTICE "htcuniversal configure phone: %d\n", state );
+ switch (state) {
+
+ case PXA_UART_CFG_PRE_STARTUP:
+ break;
+
+ case PXA_UART_CFG_POST_STARTUP:
+ /* pre-serial-up hardware configuration */
+
+ SET_HTCUNIVERSAL_GPIO(PHONE_START,0); /* "bootloader" */
+ SET_HTCUNIVERSAL_GPIO(PHONE_UNKNOWN,0); /* not used */
+ SET_HTCUNIVERSAL_GPIO(PHONE_OFF,0); /* PHONE_OFF */
+
+ phone_reset();
+
+ SET_HTCUNIVERSAL_GPIO(PHONE_START,1); /* phone */
+
+ phone_reset();
+
+ asic3_set_gpio_dir_b(&htcuniversal_asic3.dev, 1<<GPIOB_BB_READY, 0);
+ asic3_set_gpio_dir_b(&htcuniversal_asic3.dev, 1<<GPIOB_BB_UNKNOWN3, 0);
+
+ /*
+ */
+ tries = 0;
+ do {
+ mdelay(10);
+ statusb = asic3_get_gpio_status_b( &htcuniversal_asic3.dev );
+ } while ( (statusb & (1<<GPIOB_UMTS_DCD)) == 0 && tries++ < 200);
+
+ printk("UMTS_DCD tries=%d of 200\n",tries);
+
+ tries = 0;
+ do {
+ SET_HTCUNIVERSAL_GPIO(PHONE_OFF,1);
+ mdelay(10);
+ SET_HTCUNIVERSAL_GPIO(PHONE_OFF,0);
+ mdelay(20);
+ statusb = asic3_get_gpio_status_b( &htcuniversal_asic3.dev );
+ } while ( (statusb & (1<<GPIOB_BB_READY)) == 0 && tries++ < 200);
+
+ printk("BB_READY tries=%d of 200\n",tries);
+
+ break;
+
+ case PXA_UART_CFG_PRE_SHUTDOWN:
+
+ phone_off();
+
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+static int
+htcuniversal_phone_probe( struct platform_device *dev )
+{
+ struct htcuniversal_phone_funcs *funcs = dev->dev.platform_data;
+
+ /* configure phone UART */
+ pxa_gpio_mode( GPIO_NR_HTCUNIVERSAL_PHONE_RXD_MD );
+ pxa_gpio_mode( GPIO_NR_HTCUNIVERSAL_PHONE_TXD_MD );
+ pxa_gpio_mode( GPIO_NR_HTCUNIVERSAL_PHONE_UART_CTS_MD );
+ pxa_gpio_mode( GPIO_NR_HTCUNIVERSAL_PHONE_UART_RTS_MD );
+
+ funcs->configure = htcuniversal_phone_configure;
+
+ return 0;
+}
+
+static int
+htcuniversal_phone_remove( struct platform_device *dev )
+{
+ struct htcuniversal_phone_funcs *funcs = dev->dev.platform_data;
+
+ funcs->configure = NULL;
+
+ asic3_set_gpio_dir_b(&htcuniversal_asic3.dev, 1<<GPIOB_BB_READY, 1<<GPIOB_BB_READY);
+ asic3_set_gpio_dir_b(&htcuniversal_asic3.dev, 1<<GPIOB_BB_UNKNOWN3, 1<<GPIOB_BB_UNKNOWN3);
+
+ return 0;
+}
+
+static struct platform_driver phone_driver = {
+ .driver = {
+ .name = "htcuniversal_phone",
+ },
+ .probe = htcuniversal_phone_probe,
+ .remove = htcuniversal_phone_remove,
+};
+
+static int __init
+htcuniversal_phone_init( void )
+{
+ printk(KERN_NOTICE "htcuniversal Phone Driver\n");
+ return platform_driver_register( &phone_driver );
+}
+
+static void __exit
+htcuniversal_phone_exit( void )
+{
+ platform_driver_unregister( &phone_driver );
+}
+
+module_init( htcuniversal_phone_init );
+module_exit( htcuniversal_phone_exit );
+
+MODULE_AUTHOR("Todd Blumer, SDG Systems, LLC");
+MODULE_DESCRIPTION("HTC Universal Phone Support Driver");
+MODULE_LICENSE("GPL");
+
+/* vim600: set noexpandtab sw=8 ts=8 :*/
Index: linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_phone.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_phone.h 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,16 @@
+/*
+ * Bluetooth support file for calling bluetooth configuration functions
+ *
+ * Copyright (c) 2005 SDG Systems, LLC
+ *
+ * 2005-06 Todd Blumer Initial Revision
+ */
+
+#ifndef _HTCUNIVERSAL_PHONE_H
+#define _HTCUNIVERSAL_PHONE_H
+
+struct htcuniversal_phone_funcs {
+ void (*configure) ( int state );
+};
+
+#endif
Index: linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_pm.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_pm.c 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,69 @@
+/*
+ * MyPal 716 power management support for the original HTC IPL in DoC G3
+ *
+ * Use consistent with the GNU GPL is permitted, provided that this
+ * copyright notice is preserved in its entirety in all copies and
+ * derived works.
+ *
+ * Copyright (C) 2005 Pawel Kolodziejski
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/pm.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa-pm_ll.h>
+
+#ifdef CONFIG_PM
+
+static u32 *addr_a0040000;
+static u32 *addr_a0040004;
+static u32 *addr_a0040008;
+static u32 *addr_a004000c;
+
+static u32 save_a0040000;
+static u32 save_a0040004;
+static u32 save_a0040008;
+static u32 save_a004000c;
+
+static void htcuniversal_pxa_ll_pm_suspend(unsigned long resume_addr)
+{
+ save_a0040000 = *addr_a0040000;
+ save_a0040004 = *addr_a0040004;
+ save_a0040008 = *addr_a0040008;
+ save_a004000c = *addr_a004000c;
+
+ /* jump to PSPR */
+ *addr_a0040000 = 0xe3a00101; // mov r0, #0x40000000
+ *addr_a0040004 = 0xe380060f; // orr r0, r0, #0x0f000000
+ *addr_a0040008 = 0xe3800008; // orr r0, r0, #8
+ *addr_a004000c = 0xe590f000; // ldr pc, [r0]
+}
+
+static void htcuniversal_pxa_ll_pm_resume(void)
+{
+ *addr_a0040000 = save_a0040000;
+ *addr_a0040004 = save_a0040004;
+ *addr_a0040008 = save_a0040008;
+ *addr_a004000c = save_a004000c;
+}
+
+static struct pxa_ll_pm_ops htcuniversal_ll_pm_ops = {
+ .suspend = htcuniversal_pxa_ll_pm_suspend,
+ .resume = htcuniversal_pxa_ll_pm_resume,
+};
+
+void htcuniversal_ll_pm_init(void) {
+ addr_a0040000 = phys_to_virt(0xa0040000);
+ addr_a0040004 = phys_to_virt(0xa0040004);
+ addr_a0040008 = phys_to_virt(0xa0040008);
+ addr_a004000c = phys_to_virt(0xa004000c);
+
+ pxa_pm_set_ll_ops(&htcuniversal_ll_pm_ops);
+}
+#endif /* CONFIG_PM */
Index: linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_power2.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_power2.c 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,97 @@
+/*
+ * pda_power driver for HTC Universal
+ *
+ * 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.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/pda_power.h>
+#include <linux/soc/asic3_base.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/arch/htcuniversal-gpio.h>
+#include <asm/arch/htcuniversal-asic.h>
+
+static void charge_on(int flags)
+{
+ asic3_set_gpio_out_b(&htcuniversal_asic3.dev, 1<<GPIOB_CHARGE_EN, 0);
+}
+
+static int ac_on(void)
+{
+ return (GET_HTCUNIVERSAL_GPIO(POWER_DET) == 0);
+}
+
+static int usb_on(void)
+{
+ return (GET_HTCUNIVERSAL_GPIO(USB_DET) == 0);
+}
+
+static char *supplicants[] = {
+ "ds2760-battery.0", "backup-battery"
+};
+
+static struct pda_power_pdata power_pdata = {
+ .is_ac_online = ac_on,
+ .is_usb_online = usb_on,
+ .set_charge = charge_on,
+ .supplied_to = supplicants,
+ .num_supplicants = ARRAY_SIZE(supplicants),
+};
+
+static struct resource power_resources[] = {
+ [0] = {
+ .name = "ac",
+ .start = HTCUNIVERSAL_IRQ(POWER_DET),
+ .end = HTCUNIVERSAL_IRQ(POWER_DET),
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE,
+ },
+ [1] = {
+ .name = "usb",
+ .start = HTCUNIVERSAL_IRQ(USB_DET),
+ .end = HTCUNIVERSAL_IRQ(USB_DET),
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE,
+ },
+};
+
+static void dev_release(struct device *dev)
+{
+ return;
+}
+
+static struct platform_device power_dev =
+{
+ .name = "pda-power",
+ .id = -1,
+ .resource = power_resources,
+ .num_resources = ARRAY_SIZE(power_resources),
+ .dev =
+ {
+ .platform_data = &power_pdata,
+ .release = dev_release,
+ },
+};
+
+static int htcuniversal_power_init(void)
+{
+ return platform_device_register(&power_dev);
+}
+
+static void htcuniversal_power_exit(void)
+{
+ platform_device_unregister(&power_dev);
+
+ return;
+}
+
+module_init(htcuniversal_power_init);
+module_exit(htcuniversal_power_exit);
+
+MODULE_DESCRIPTION("Power driver for HTC Universal");
+MODULE_LICENSE("GPL");
Index: linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_ts2.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_ts2.c 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,490 @@
+/* Touch screen driver for the TI something-or-other
+ *
+ * Copyright © 2005 SDG Systems, LLC
+ *
+ * Based on code that was based on the SAMCOP driver.
+ * Copyright © 2003, 2004 Compaq Computer Corporation.
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Author: Keith Packard <keith.packard@hp.com>
+ * May 2003
+ *
+ * Updates:
+ *
+ * 2004-02-11 Michael Opdenacker Renamed names from samcop to shamcop,
+ * Goal:support HAMCOP and SAMCOP.
+ * 2004-02-14 Michael Opdenacker Temporary fix for device id handling
+ *
+ * 2005-02-18 Aric Blumer Converted basic structure to support hx4700
+ *
+ * 2005-06-07 Aric Blumer Added tssim device handling so we can
+ * hook in the fbvncserver.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/mach/irq.h>
+#include <asm/io.h>
+
+/* remove me */
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/htcuniversal-gpio.h>
+#include <asm/arch/htcuniversal-asic.h>
+#include <asm/mach-types.h>
+
+#include <asm/hardware/ipaq-asic3.h>
+#include <linux/soc/asic3_base.h>
+
+
+#include "tsc2046_ts.h"
+
+enum touchscreen_state {
+ STATE_WAIT_FOR_TOUCH, /* Waiting for a PEN interrupt */
+ STATE_SAMPLING /* Actively sampling ADC */
+};
+
+struct touchscreen_data {
+ enum touchscreen_state state;
+ struct timer_list timer;
+ int irq;
+ struct input_dev *input;
+ /* */
+ int port;
+ int clock;
+ int pwrbit_X;
+ int pwrbit_Y;
+ int (*pen_down)(void);
+};
+
+static unsigned long poll_sample_time = 10; /* Sample every 10 milliseconds */
+
+static struct touchscreen_data *ts_data;
+
+static int irqblock;
+
+module_param(poll_sample_time, ulong, 0644);
+MODULE_PARM_DESC(poll_sample_time, "Poll sample time");
+
+static inline void
+report_touchpanel(struct touchscreen_data *ts, int pressure, int x, int y)
+{
+ input_report_abs(ts->input, ABS_PRESSURE, pressure);
+ input_report_abs(ts->input, ABS_X, x);
+ input_report_abs(ts->input, ABS_Y, y);
+ input_sync(ts->input);
+}
+
+static void start_read(struct touchscreen_data *touch);
+
+static irqreturn_t
+pen_isr(int irq, void *irq_desc)
+{
+ struct touchscreen_data *ts = ts_data;
+
+ if(irq == ts->irq /* && !irqblock */) {
+ irqblock = 1;
+
+ /*
+ * Disable the pen interrupt. It's reenabled when the user lifts the
+ * pen.
+ */
+ disable_irq(ts->irq);
+
+ if (ts->state == STATE_WAIT_FOR_TOUCH) {
+ ts->state = STATE_SAMPLING;
+ start_read(ts);
+ } else {
+ /* Shouldn't happen */
+ printk(KERN_ERR "Unexpected ts interrupt\n");
+ }
+
+ }
+ return IRQ_HANDLED;
+}
+
+static void
+ssp_init(int port, int clock)
+{
+
+ pxa_set_cken(clock, 0);
+
+ pxa_gpio_mode(GPIO_NR_HTCUNIVERSAL_TOUCHSCREEN_SPI_CLK_MD);
+ pxa_gpio_mode(GPIO_NR_HTCUNIVERSAL_TOUCHSCREEN_SPI_FRM_MD);
+ pxa_gpio_mode(GPIO_NR_HTCUNIVERSAL_TOUCHSCREEN_SPI_DO_MD);
+ pxa_gpio_mode(GPIO_NR_HTCUNIVERSAL_TOUCHSCREEN_SPI_DI_MD);
+
+ SET_HTCUNIVERSAL_GPIO(SPI_FRM,1);
+
+ /* *** Set up the SPI Registers *** */
+ SSCR0_P(port) =
+ SSCR0_EDSS /* Extended Data Size Select */
+ | SSCR0_SerClkDiv(7) /* Serial Clock Rate */
+ /* Synchronous Serial Enable (Disable for now) */
+ | SSCR0_Motorola /* Motorola SPI Interface */
+ | SSCR0_DataSize(8) /* Data Size Select (24-bit) */
+ ;
+ SSCR1_P(port) = 0;
+ SSPSP_P(port) = 0;
+
+ /* Clear the Status */
+ SSSR_P(port) = SSSR_P(port) & 0x00fcfffc;
+
+ /* Now enable it */
+ SSCR0_P(port) =
+ SSCR0_EDSS /* Extended Data Size Select */
+ | SSCR0_SerClkDiv(7) /* Serial Clock Rate */
+ | SSCR0_SSE /* Synchronous Serial Enable */
+ | SSCR0_Motorola /* Motorola SPI Interface */
+ | SSCR0_DataSize(8) /* Data Size Select (24-bit) */
+ ;
+
+ pxa_set_cken(clock, 1);
+}
+
+static void
+start_read(struct touchscreen_data *touch)
+{
+ unsigned long inc = (poll_sample_time * HZ) / 1000;
+ int i;
+
+ /* Write here to the serial port. We request X and Y only for now.
+ * Then we have to wait for poll_sample_time before we read out the serial
+ * port. Then, when we read it out, we check to see if the pen is still
+ * down. If so, then we issue another request here.
+ */
+#define TS_SAMPLES 7
+
+ /*
+ * We do four samples for each, and throw out the highest and lowest, then
+ * average the other two.
+ */
+
+ for(i = 0; i < TS_SAMPLES; i++) {
+ while(!(SSSR_P(touch->port) & SSSR_TNF))
+ ;
+ /* It's not full. Write the command for X */
+ SSDR_P(touch->port) = (TSC2046_SAMPLE_X|(touch->pwrbit_X))<<16;
+ }
+
+ for(i = 0; i < TS_SAMPLES; i++) {
+ while(!(SSSR_P(touch->port) & SSSR_TNF))
+ ;
+ /* It's not full. Write the command for Y */
+ SSDR_P(touch->port) = (TSC2046_SAMPLE_Y|(touch->pwrbit_Y))<<16;
+ }
+
+ /*
+ * Enable the timer. We should get an interrupt, but we want keep a timer
+ * to ensure that we can detect missing data
+ */
+ mod_timer(&touch->timer, jiffies + inc);
+}
+
+static void
+ts_timer_callback(unsigned long data)
+{
+ struct touchscreen_data *ts = (struct touchscreen_data *)data;
+ int x, a[TS_SAMPLES], y;
+ static int oldx, oldy;
+ int ssrval;
+
+ /*
+ * Check here to see if there is anything in the SPI FIFO. If so,
+ * return it if there has been a change. If not, then we have a
+ * timeout. Generate an erro somehow.
+ */
+ ssrval = SSSR_P(ts->port);
+
+ if(ssrval & SSSR_RNE) { /* Look at Rx Not Empty bit */
+ int number_of_entries_in_fifo;
+
+ /* The FIFO is not emtpy. Good! Now make sure there are at least two
+ * entries. (Should be two exactly.) */
+
+ number_of_entries_in_fifo = ((ssrval >> 12) & 0xf) + 1;
+
+ if(number_of_entries_in_fifo < TS_SAMPLES * 2) {
+ /* Not ready yet. Come back later. */
+ unsigned long inc = (poll_sample_time * HZ) / 1000;
+ mod_timer(&ts->timer, jiffies + inc);
+ return;
+ }
+
+ if(number_of_entries_in_fifo == TS_SAMPLES * 2) {
+ int i, j;
+
+ for(i = 0; i < TS_SAMPLES; i++) {
+ a[i] = SSDR_P(ts->port);
+ }
+ /* Sort them (bubble) */
+ for(j = TS_SAMPLES - 1; j > 0; j--) {
+ for(i = 0; i < j; i++) {
+ if(a[i] > a[i + 1]) {
+ int tmp;
+ tmp = a[i+1];
+ a[i+1] = a[i];
+ a[i] = tmp;
+ }
+ }
+ }
+
+ /* Take the average of the middle two */
+ /* x = (a[TS_SAMPLES/2 - 1] + a[TS_SAMPLES/2] + a[TS_SAMPLES/2+1] + a[TS_SAMPLES/2+2]) >> 2; */
+ x = a[TS_SAMPLES/2];
+
+ for(i = 0; i < TS_SAMPLES; i++) {
+ a[i] = SSDR_P(ts->port);
+ }
+ /* Sort them (bubble) */
+ for(j = TS_SAMPLES - 1; j > 0; j--) {
+ for(i = 0; i < j; i++) {
+ if(a[i] > a[i + 1]) {
+ int tmp;
+ tmp = a[i+1];
+ a[i+1] = a[i];
+ a[i] = tmp;
+ }
+ }
+ }
+
+
+ /* Take the average of the middle two */
+ /* y = (a[TS_SAMPLES/2 - 1] + a[TS_SAMPLES/2] + a[TS_SAMPLES/2+1] + a[TS_SAMPLES/2+2]) >> 2; */
+ y = a[TS_SAMPLES/2];
+ } else {
+ /* We have an error! Too many entries. */
+ printk(KERN_ERR "TS: Expected %d entries. Got %d\n", TS_SAMPLES*2, number_of_entries_in_fifo);
+ /* Try to clear the FIFO */
+ while(number_of_entries_in_fifo--) {
+ (void)SSDR_P(ts->port);
+ }
+
+ if (ts->pen_down())
+ start_read(ts);
+
+ return;
+ }
+ } else {
+ /* Not ready yet. Come back later. */
+ unsigned long inc = (poll_sample_time * HZ) / 1000;
+ mod_timer(&ts->timer, jiffies + inc);
+ return;
+ }
+
+ /*
+ * Now we check to see if the pen is still down. If it is, then call
+ * start_read().
+ */
+ if (ts->pen_down())
+ {
+ /* Still down */
+ if(oldx != x || oldy != y) {
+ oldx = x;
+ oldy = y;
+ report_touchpanel(ts, 1, x, y);
+ }
+ start_read(ts);
+ } else {
+ /* Up */
+ report_touchpanel(ts, 0, 0, 0);
+ irqblock = 0;
+ ts->state = STATE_WAIT_FOR_TOUCH;
+ /* Re-enable pen down interrupt */
+ enable_irq(ts->irq);
+ }
+}
+
+static int pen_down(void)
+{
+ return ( asic3_get_gpio_status_a( &htcuniversal_asic3.dev ) & (1<<GPIOA_TOUCHSCREEN_N)) == 0 ;
+}
+
+static int
+ts_probe (struct platform_device *dev)
+{
+ int retval;
+ struct touchscreen_data *ts;
+ struct tsc2046_mach_info *mach = dev->dev.platform_data;
+
+ printk("htcuniversal: ts_probe\n");
+
+ ts = ts_data = kmalloc (sizeof (*ts), GFP_KERNEL);
+ if (ts == NULL) {
+ printk( KERN_NOTICE "htcuniversal_ts: unable to allocate memory\n" );
+ return -ENOMEM;
+ }
+ memset (ts, 0, sizeof (*ts));
+
+ ts->input = input_allocate_device();
+ if (ts->input == NULL) {
+ printk( KERN_NOTICE "htcuniversal_ts: unable to allocation touchscreen input\n" );
+ kfree(ts);
+ return -ENOMEM;
+ }
+ ts->input->evbit[0] = BIT(EV_ABS);
+ ts->input->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+ ts->input->absmin[ABS_X] = 0;
+ ts->input->absmax[ABS_X] = 32767;
+ ts->input->absmin[ABS_Y] = 0;
+ ts->input->absmax[ABS_Y] = 32767;
+ ts->input->absmin[ABS_PRESSURE] = 0;
+ ts->input->absmax[ABS_PRESSURE] = 1;
+
+ ts->input->name = "htcuniversal_ts";
+ ts->input->phys = "touchscreen/htcuniversal_ts";
+ ts->input->private = ts;
+
+ input_register_device(ts->input);
+
+ ts->timer.function = ts_timer_callback;
+ ts->timer.data = (unsigned long)ts;
+ ts->state = STATE_WAIT_FOR_TOUCH;
+ init_timer (&ts->timer);
+
+ platform_set_drvdata(dev, ts);
+
+ ts->port=-1;
+
+ if (mach) {
+ ts->port = mach->port;
+ ts->clock = mach->clock;
+ ts->pwrbit_X = mach->pwrbit_X;
+ ts->pwrbit_Y = mach->pwrbit_Y;
+
+ /* static irq */
+ if (mach->irq)
+ ts->irq = mach->irq;
+
+ if (mach->pen_down)
+ ts->pen_down=mach->pen_down;
+ }
+
+ if (ts->port == -1)
+ {
+ printk("tsc2046: your device is not supported by this driver\n");
+ return -ENODEV;
+ }
+
+ /* *** Initialize the SSP interface *** */
+ ssp_init(ts->port, ts->clock);
+
+ while(!(SSSR_P(ts->port) & SSSR_TNF))
+ ;
+ SSDR_P(ts->port) = (TSC2046_SAMPLE_X|(ts->pwrbit_X))<<16;
+
+ for(retval = 0; retval < 100; retval++) {
+ if(SSSR_P(ts->port) & SSSR_RNE) {
+ while(SSSR_P(ts->port) & SSSR_RNE) {
+ (void)SSDR_P(ts->port);
+ }
+ break;
+ }
+ mdelay(1);
+ }
+
+ if (machine_is_htcuniversal() )
+ {
+ ts->irq = asic3_irq_base( &htcuniversal_asic3.dev ) + ASIC3_GPIOA_IRQ_BASE + GPIOA_TOUCHSCREEN_N;
+ ts->pen_down=pen_down;
+ }
+
+ retval = request_irq(ts->irq, pen_isr, IRQF_DISABLED, "tsc2046_ts", ts);
+ if(retval) {
+ printk("Unable to get interrupt\n");
+ input_unregister_device (ts->input);
+ return -ENODEV;
+ }
+ set_irq_type(ts->irq, IRQ_TYPE_EDGE_FALLING);
+
+ return 0;
+}
+
+static int
+ts_remove (struct platform_device *dev)
+{
+ struct touchscreen_data *ts = platform_get_drvdata(dev);
+
+ input_unregister_device (ts->input);
+ del_timer_sync (&ts->timer);
+ free_irq (ts->irq, ts);
+ pxa_set_cken(ts->clock, 0);
+
+ kfree(ts);
+ return 0;
+}
+
+static int
+ts_suspend (struct platform_device *dev, pm_message_t state)
+{
+ struct touchscreen_data *ts = platform_get_drvdata(dev);
+
+ disable_irq(ts->irq);
+
+ printk("htcuniversal_ts2_suspend: called.\n");
+ return 0;
+}
+
+static int
+ts_resume (struct platform_device *dev)
+{
+ struct touchscreen_data *ts = platform_get_drvdata(dev);
+
+ ts->state = STATE_WAIT_FOR_TOUCH;
+ ssp_init(ts->port, ts->clock);
+ enable_irq(ts->irq);
+
+ printk("htcuniversal_ts2_resume: called.\n");
+ return 0;
+}
+
+static struct platform_driver ts_driver = {
+ .probe = ts_probe,
+ .remove = ts_remove,
+ .suspend = ts_suspend,
+ .resume = ts_resume,
+ .driver = {
+ .name = "htcuniversal_ts",
+ },
+};
+
+
+static int
+ts_module_init (void)
+{
+ printk(KERN_NOTICE "HTC Universal Touch Screen Driver\n");
+
+ return platform_driver_register(&ts_driver);
+}
+
+static void
+ts_module_cleanup (void)
+{
+ platform_driver_unregister (&ts_driver);
+}
+
+module_init(ts_module_init);
+module_exit(ts_module_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Aric Blumer, SDG Systems, LLC");
+MODULE_DESCRIPTION("HTC Universal Touch Screen Driver");
Index: linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_udc.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/arch/arm/mach-pxa/htcuniversal/htcuniversal_udc.c 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,71 @@
+
+/*
+ *
+ * htcuniversal_udc.c:
+ * htcuniversal specific code for the pxa27x usb device controller.
+ *
+ * Use consistent with the GNU GPL is permitted.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/udc.h>
+#include <linux/soc/asic3_base.h>
+#include <asm/arch/htcuniversal-gpio.h>
+#include <asm/arch/htcuniversal-asic.h>
+
+static void htcuniversal_udc_command(int cmd)
+{
+ switch (cmd) {
+ case PXA2XX_UDC_CMD_DISCONNECT:
+ asic3_set_gpio_out_b(&htcuniversal_asic3.dev,
+ 1<<GPIOB_USB_PUEN, 0);
+// SET_HTCUNIVERSAL_GPIO(USB_PUEN,0);
+ break;
+ case PXA2XX_UDC_CMD_CONNECT:
+ asic3_set_gpio_out_b(&htcuniversal_asic3.dev,
+ 1<<GPIOB_USB_PUEN, 1<<GPIOB_USB_PUEN);
+// SET_HTCUNIVERSAL_GPIO(USB_PUEN,1);
+ break;
+ default:
+ printk("_udc_control: unknown command!\n");
+ break;
+ }
+}
+
+static int htcuniversal_udc_is_connected(void)
+{
+ return (GET_HTCUNIVERSAL_GPIO(USB_DET) != 0);
+}
+
+static struct pxa2xx_udc_mach_info htcuniversal_udc_info __initdata = {
+ .udc_is_connected = htcuniversal_udc_is_connected,
+ .udc_command = htcuniversal_udc_command,
+};
+
+static int htcuniversal_udc_probe(struct platform_device * dev)
+{
+ asic3_set_gpio_dir_b(&htcuniversal_asic3.dev, 1<<GPIOB_USB_PUEN, 1<<GPIOB_USB_PUEN);
+
+ pxa_set_udc_info(&htcuniversal_udc_info);
+ return 0;
+}
+
+static struct platform_driver htcuniversal_udc_driver = {
+ .driver = {
+ .name = "htcuniversal_udc",
+ },
+ .probe = htcuniversal_udc_probe,
+};
+
+static int __init htcuniversal_udc_init(void)
+{
+ return platform_driver_register(&htcuniversal_udc_driver);
+}
+
+module_init(htcuniversal_udc_init);
+MODULE_LICENSE("GPL");
Index: linux-2.6.22/arch/arm/mach-pxa/htcuniversal/tsc2046_ts.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/arch/arm/mach-pxa/htcuniversal/tsc2046_ts.h 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,20 @@
+/*
+ * temporary TSC2046 touchscreen hack
+ */
+
+#ifndef _TSC2046_TS_H
+#define _TSC2046_TS_H
+
+struct tsc2046_mach_info {
+ int port;
+ int clock;
+ int pwrbit_X;
+ int pwrbit_Y;
+ int irq;
+ int (*pen_down)(void);
+};
+
+#define TSC2046_SAMPLE_X 0xd0
+#define TSC2046_SAMPLE_Y 0x90
+
+#endif
Index: linux-2.6.22/arch/arm/mach-pxa/Kconfig
===================================================================
--- linux-2.6.22.orig/arch/arm/mach-pxa/Kconfig 2007-09-11 12:53:33.000000000 +0200
+++ linux-2.6.22/arch/arm/mach-pxa/Kconfig 2007-09-11 12:53:37.000000000 +0200
@@ -50,6 +50,14 @@
help
This enables support for the HP iPAQ HX2750 handheld.
+config MACH_HTCUNIVERSAL
+ bool "HTC Universal"
+ select PXA27x
+ help
+ Say Y here if you intend to run this kernel on a
+ HTC Universal. Currently there is only basic support
+ for this PDA.
+
endchoice
if PXA_SHARPSL
@@ -84,6 +92,86 @@
endif
+if MACH_HTCUNIVERSAL
+
+menu "HTC Universal support"
+
+config HTCUNIVERSAL_CORE
+ tristate "HTC Universal core"
+ depends on MACH_HTCUNIVERSAL
+ help
+ This selection enables HTC Universal core support.
+
+config HTCUNIVERSAL_UDC
+ bool "USB Device Controller support"
+ depends on MACH_HTCUNIVERSAL && HTC_ASIC3 && USB_PXA27X
+ help
+ Enables HTC Universal specific USB detection
+
+config HTCUNIVERSAL_POWER
+ tristate "HTC Universal power"
+ depends on MACH_HTCUNIVERSAL && HTC_ASIC3
+ help
+ This selection enables HTC Universal power monitoring
+ hardware support (through ASIC3).
+
+config HTCUNIVERSAL_BACKLIGHT
+ bool "HTC Universal Backlight"
+ depends on MACH_HTCUNIVERSAL && HTC_ASIC3 && BACKLIGHT_CLASS_DEVICE
+ help
+ This driver provides support for changing power and brightness
+ on HTC Universal LCD backlight.
+
+config HTCUNIVERSAL_LCD
+ tristate "HTC Universal LCD"
+ depends on MACH_HTCUNIVERSAL && HTC_ASIC3 && LCD_CLASS_DEVICE
+ help
+ This driver provides support for changing power and brightness
+ on HTC Universal LCD display.
+
+config HTCUNIVERSAL_TS2
+ tristate "HTC Universal Touchscreen (old)"
+ depends on MACH_HTCUNIVERSAL && HTC_ASIC3
+ help
+ Enable support for the HTC Universal Touchscreen Panel.
+
+config HTCUNIVERSAL_BUTTONS
+ tristate "HTC Universal buttons support"
+ depends on MACH_HTCUNIVERSAL && HTC_ASIC3
+
+config HTCUNIVERSAL_BLUETOOTH
+ tristate "HTC Universal Bluetooth"
+ depends on MACH_HTCUNIVERSAL && HTCUNIVERSAL_CORE && HTC_ASIC3
+ help
+ Enables support for the TI BRF6150 Bluetooth Module
+ in the HTC Universal.
+
+config HTCUNIVERSAL_ASIC3_LEDS
+ tristate "HTC Universal ASIC3 LED support"
+ select LEDS_ASIC3
+ depends on MACH_HTCUNIVERSAL && HTCUNIVERSAL_CORE && HTC_ASIC3
+ ---help---
+ Support for right (colors red+green+(amber)) and left (green+blue) led
+ Off/on hook keys LED backlight
+ Keyboard backlight
+ Vibra
+ Flashlight
+
+config HTCUNIVERSAL_PHONE
+ tristate "HTC Universal Phone"
+ depends on MACH_HTCUNIVERSAL && HTCUNIVERSAL_CORE && HTC_ASIC3
+ help
+ Enables support for the Qualcomm MSM6520 Phone Module
+ in the HTC Universal.
+
+config HTCUNIVERSAL_AK4641
+ depends on SND && I2C
+ tristate "AK4641 chipset support"
+
+endmenu
+
+endif
+
endmenu
config MACH_POODLE
@@ -164,4 +252,3 @@
depends on (PXA25x || PXA27x) && INPUT
endif
-
Index: linux-2.6.22/arch/arm/mach-pxa/Makefile
===================================================================
--- linux-2.6.22.orig/arch/arm/mach-pxa/Makefile 2007-09-11 12:53:33.000000000 +0200
+++ linux-2.6.22/arch/arm/mach-pxa/Makefile 2007-09-11 12:53:37.000000000 +0200
@@ -20,6 +20,7 @@
obj-$(CONFIG_MACH_TOSA) += tosa.o
obj-$(CONFIG_MACH_EM_X270) += em-x270.o
obj-$(CONFIG_MACH_HX2750) += hx2750.o hx2750_test.o
+obj-$(CONFIG_MACH_HTCUNIVERSAL) += htcuniversal/
# Support for blinky lights
led-y := leds.o
Index: linux-2.6.22/drivers/leds/Kconfig
===================================================================
--- linux-2.6.22.orig/drivers/leds/Kconfig 2007-09-11 12:53:14.000000000 +0200
+++ linux-2.6.22/drivers/leds/Kconfig 2007-09-11 12:53:37.000000000 +0200
@@ -101,6 +101,13 @@
outputs. To be useful the particular board must have LEDs
and they must be connected to the GPIO lines.
+config LEDS_ASIC3
+ tristate "LED Support for the HTC ASIC3 chip"
+ depends LEDS_CLASS && HTC_ASIC3
+ help
+ This option enables support for the LEDs connected to the
+ HTC ASIC3 chip.
+
comment "LED Triggers"
config LEDS_TRIGGERS
Index: linux-2.6.22/drivers/leds/leds-asic3.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/drivers/leds/leds-asic3.c 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,189 @@
+/*
+ * LEDs support for HTC ASIC3 devices.
+ *
+ * Copyright (c) 2006 Anton Vorontsov <cbou@mail.ru>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include "leds.h"
+
+#include <asm/hardware/ipaq-asic3.h>
+#include <linux/soc/asic3_base.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/asic3_leds.h>
+
+#ifdef DEBUG
+#define dbg(msg, ...) printk(msg, __VA_ARGS__)
+#else
+#define dbg(msg, ...)
+#endif
+
+static
+void asic3_leds_set(struct led_classdev *led_cdev, enum led_brightness b)
+{
+ struct asic3_led *led = container_of(led_cdev, struct asic3_led,
+ led_cdev);
+ struct asic3_leds_machinfo *machinfo = led->machinfo;
+ struct device *asic3_dev = &machinfo->asic3_pdev->dev;
+
+ dbg("%s:%s %d(%d)-%s %d\n", __FILE__, __FUNCTION__, led->hw_num,
+ led->gpio_num, led->led_cdev.name, b);
+
+ if (led->hw_num == -1) {
+ asic3_gpio_set_value(asic3_dev, led->gpio_num, b);
+ return;
+ }
+
+ if (b == LED_OFF) {
+ asic3_set_led(asic3_dev, led->hw_num, 0, 16, 6);
+ asic3_set_gpio_out_c(asic3_dev, led->hw_num, 0);
+ }
+ else {
+ asic3_set_gpio_out_c(asic3_dev, led->hw_num, led->hw_num);
+ #ifdef CONFIG_LEDS_TRIGGER_HWTIMER
+ if (led_cdev->trigger && led_cdev->trigger->is_led_supported &&
+ (led_cdev->trigger->is_led_supported(led_cdev) &
+ LED_SUPPORTS_HWTIMER)) {
+ struct hwtimer_data *td = led_cdev->trigger_data;
+ if (!td) return;
+ asic3_set_led(asic3_dev, led->hw_num, td->delay_on/8,
+ (td->delay_on + td->delay_off)/8, 6);
+ }
+ else
+ #endif
+ asic3_set_led(asic3_dev, led->hw_num, 16, 16, 6);
+ }
+
+ return;
+}
+
+static
+int asic3_leds_probe(struct platform_device *pdev)
+{
+ struct asic3_leds_machinfo *machinfo = pdev->dev.platform_data;
+ struct asic3_led *leds = machinfo->leds;
+ int ret, i = 0;
+
+ dbg("%s:%s\n", __FILE__, __FUNCTION__);
+
+ // Turn on clocks early, for the case if trigger would enable
+ // led immediately after led_classdev_register().
+ asic3_set_clock_cdex(&machinfo->asic3_pdev->dev,
+ CLOCK_CDEX_LED0 | CLOCK_CDEX_LED1 | CLOCK_CDEX_LED2,
+ CLOCK_CDEX_LED0 | CLOCK_CDEX_LED1 | CLOCK_CDEX_LED2);
+
+ for (i = 0; i < machinfo->num_leds; i++) {
+ leds[i].machinfo = machinfo;
+ leds[i].led_cdev.brightness_set = asic3_leds_set;
+ ret = led_classdev_register(&pdev->dev, &leds[i].led_cdev);
+ if (ret) {
+ printk(KERN_ERR "Error: can't register %s led\n",
+ leds[i].led_cdev.name);
+ goto out_err;
+ }
+ }
+
+ return 0;
+
+out_err:
+ while (--i >= 0) led_classdev_unregister(&leds[i].led_cdev);
+
+ asic3_set_clock_cdex(&machinfo->asic3_pdev->dev,
+ CLOCK_CDEX_LED0 | CLOCK_CDEX_LED1 | CLOCK_CDEX_LED2,
+ 0 | 0 | 0);
+
+ return ret;
+}
+
+static
+int asic3_leds_remove(struct platform_device *pdev)
+{
+ struct asic3_leds_machinfo *machinfo = pdev->dev.platform_data;
+ struct asic3_led *leds = machinfo->leds;
+ int i = 0;
+
+ dbg("%s:%s\n", __FILE__, __FUNCTION__);
+
+ for (i = 0; i < machinfo->num_leds; i++)
+ led_classdev_unregister(&leds[i].led_cdev);
+
+ asic3_set_clock_cdex(&machinfo->asic3_pdev->dev,
+ CLOCK_CDEX_LED0 | CLOCK_CDEX_LED1 | CLOCK_CDEX_LED2,
+ 0 | 0 | 0);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static
+int asic3_leds_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct asic3_leds_machinfo *machinfo = pdev->dev.platform_data;
+ struct asic3_led *leds = machinfo->leds;
+ int i = 0;
+
+ dbg("%s:%s\n", __FILE__, __FUNCTION__);
+
+ for (i = 0; i < machinfo->num_leds; i++)
+ led_classdev_suspend(&leds[i].led_cdev);
+
+ return 0;
+}
+
+static
+int asic3_leds_resume(struct platform_device *pdev)
+{
+ struct asic3_leds_machinfo *machinfo = pdev->dev.platform_data;
+ struct asic3_led *leds = machinfo->leds;
+ int i = 0;
+
+ dbg("%s:%s\n", __FILE__, __FUNCTION__);
+
+ for (i = 0; i < machinfo->num_leds; i++)
+ led_classdev_resume(&leds[i].led_cdev);
+
+ return 0;
+}
+
+#endif
+
+static
+struct platform_driver asic3_leds_driver = {
+ .probe = asic3_leds_probe,
+ .remove = asic3_leds_remove,
+#ifdef CONFIG_PM
+ .suspend = asic3_leds_suspend,
+ .resume = asic3_leds_resume,
+#endif
+ .driver = {
+ .name = "asic3-leds",
+ },
+};
+
+int asic3_leds_register(void)
+{
+ dbg("%s:%s\n", __FILE__, __FUNCTION__);
+ return platform_driver_register(&asic3_leds_driver);
+}
+
+void asic3_leds_unregister(void)
+{
+ platform_driver_unregister(&asic3_leds_driver);
+ return;
+}
+
+EXPORT_SYMBOL_GPL(asic3_leds_register);
+EXPORT_SYMBOL_GPL(asic3_leds_unregister);
+
+MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>");
+MODULE_DESCRIPTION("HTC ASIC3 LEDs driver");
+MODULE_LICENSE("GPL");
Index: linux-2.6.22/drivers/mfd/Kconfig
===================================================================
--- linux-2.6.22.orig/drivers/mfd/Kconfig 2007-09-11 12:53:30.000000000 +0200
+++ linux-2.6.22/drivers/mfd/Kconfig 2007-09-11 12:53:37.000000000 +0200
@@ -15,6 +15,16 @@
interface. The device may be connected by PCI or local bus with
varying functions enabled.
+config HTC_ASIC3
+ tristate "HTC ASIC3 (iPAQ h1900/h3900/h4000/hx4700/rx3000) support"
+
+config HTC_ASIC3_DS1WM
+ bool "Support HTC ASIC3 builtin DS1WM block"
+ help
+ Choose Y here if you want to include support for ASIC3's builtin
+ W1 controller. Some devices do not use it, and yet other have
+ separate DS1WM controller. For them, choose N.
+
endmenu
menu "Multimedia Capabilities Port drivers"
Index: linux-2.6.22/drivers/mfd/Makefile
===================================================================
--- linux-2.6.22.orig/drivers/mfd/Makefile 2007-09-11 12:53:30.000000000 +0200
+++ linux-2.6.22/drivers/mfd/Makefile 2007-09-11 12:53:37.000000000 +0200
@@ -2,6 +2,8 @@
# Makefile for multifunction miscellaneous devices
#
+obj-$(CONFIG_HTC_ASIC3) += asic3_base.o soc-core.o
+
obj-$(CONFIG_MFD_SM501) += sm501.o
obj-$(CONFIG_MCP) += mcp-core.o
Index: linux-2.6.22/drivers/mfd/asic3_base.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/drivers/mfd/asic3_base.c 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,1208 @@
+/*
+ * Driver interface to HTC "ASIC3"
+ *
+ * Copyright 2001 Compaq Computer Corporation.
+ * Copyright 2004-2005 Phil Blundell
+ *
+ * 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.
+ *
+ * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Author: Andrew Christian
+ * <Andrew.Christian@compaq.com>
+ * October 2001
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/ds1wm.h>
+#include <asm/arch/clock.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/hardware/ipaq-asic3.h>
+#include <linux/soc/asic3_base.h>
+#include <linux/soc/tmio_mmc.h>
+#include "soc-core.h"
+
+
+struct asic3_data {
+ void *mapping;
+ unsigned int bus_shift;
+ int irq_base;
+ int irq_nr;
+
+ u16 irq_bothedge[4];
+ struct device *dev;
+
+ struct platform_device *mmc_dev;
+};
+
+static DEFINE_SPINLOCK(asic3_gpio_lock);
+
+static int asic3_remove(struct platform_device *dev);
+
+static inline unsigned long asic3_address(struct device *dev,
+ unsigned int reg)
+{
+ struct asic3_data *adata;
+
+ adata = (struct asic3_data *)dev->driver_data;
+
+ return (unsigned long)adata->mapping + (reg >> (2 - adata->bus_shift));
+}
+
+void asic3_write_register(struct device *dev, unsigned int reg, u32 value)
+{
+ __raw_writew(value, asic3_address(dev, reg));
+}
+EXPORT_SYMBOL(asic3_write_register);
+
+u32 asic3_read_register(struct device *dev, unsigned int reg)
+{
+ return __raw_readw(asic3_address(dev, reg));
+}
+EXPORT_SYMBOL(asic3_read_register);
+
+static inline void __asic3_write_register(struct asic3_data *asic,
+ unsigned int reg, u32 value)
+{
+ __raw_writew(value, (unsigned long)asic->mapping
+ + (reg >> (2 - asic->bus_shift)));
+}
+
+static inline u32 __asic3_read_register(struct asic3_data *asic,
+ unsigned int reg)
+{
+ return __raw_readw((unsigned long)asic->mapping
+ + (reg >> (2 - asic->bus_shift)));
+}
+
+#define ASIC3_GPIO_FN(get_fn_name, set_fn_name, REG) \
+u32 get_fn_name(struct device *dev) \
+{ \
+ return asic3_read_register(dev, REG); \
+} \
+EXPORT_SYMBOL(get_fn_name); \
+ \
+void set_fn_name(struct device *dev, u32 bits, u32 val) \
+{ \
+ unsigned long flags; \
+ \
+ spin_lock_irqsave(&asic3_gpio_lock, flags); \
+ val |= (asic3_read_register(dev, REG) & ~bits); \
+ asic3_write_register(dev, REG, val); \
+ spin_unlock_irqrestore(&asic3_gpio_lock, flags); \
+} \
+EXPORT_SYMBOL(set_fn_name);
+
+#define ASIC3_GPIO_REGISTER(ACTION, action, fn, FN) \
+ ASIC3_GPIO_FN(asic3_get_gpio_ ## action ## _ ## fn , \
+ asic3_set_gpio_ ## action ## _ ## fn , \
+ _IPAQ_ASIC3_GPIO_ ## FN ## _Base \
+ + _IPAQ_ASIC3_GPIO_ ## ACTION )
+
+#define ASIC3_GPIO_FUNCTIONS(fn, FN) \
+ ASIC3_GPIO_REGISTER(Direction, dir, fn, FN) \
+ ASIC3_GPIO_REGISTER(Out, out, fn, FN) \
+ ASIC3_GPIO_REGISTER(SleepMask, sleepmask, fn, FN) \
+ ASIC3_GPIO_REGISTER(SleepOut, sleepout, fn, FN) \
+ ASIC3_GPIO_REGISTER(BattFaultOut, battfaultout, fn, FN) \
+ ASIC3_GPIO_REGISTER(AltFunction, alt_fn, fn, FN) \
+ ASIC3_GPIO_REGISTER(SleepConf, sleepconf, fn, FN) \
+ ASIC3_GPIO_REGISTER(Status, status, fn, FN)
+
+#if 0
+ ASIC3_GPIO_REGISTER(Mask, mask, fn, FN)
+ ASIC3_GPIO_REGISTER(TriggerType, trigtype, fn, FN)
+ ASIC3_GPIO_REGISTER(EdgeTrigger, rising, fn, FN)
+ ASIC3_GPIO_REGISTER(LevelTrigger, triglevel, fn, FN)
+ ASIC3_GPIO_REGISTER(IntStatus, intstatus, fn, FN)
+#endif
+
+ASIC3_GPIO_FUNCTIONS(a, A)
+ASIC3_GPIO_FUNCTIONS(b, B)
+ASIC3_GPIO_FUNCTIONS(c, C)
+ASIC3_GPIO_FUNCTIONS(d, D)
+
+int asic3_gpio_get_value(struct device *dev, unsigned gpio)
+{
+ u32 mask = ASIC3_GPIO_bit(gpio);
+ printk("%s(%d)\n", __FUNCTION__, gpio);
+ switch (gpio >> 4) {
+ case _IPAQ_ASIC3_GPIO_BANK_A:
+ return asic3_get_gpio_status_a(dev) & mask;
+ case _IPAQ_ASIC3_GPIO_BANK_B:
+ return asic3_get_gpio_status_b(dev) & mask;
+ case _IPAQ_ASIC3_GPIO_BANK_C:
+ return asic3_get_gpio_status_c(dev) & mask;
+ case _IPAQ_ASIC3_GPIO_BANK_D:
+ return asic3_get_gpio_status_d(dev) & mask;
+ }
+
+ printk(KERN_ERR "%s: invalid GPIO value 0x%x", __FUNCTION__, gpio);
+ return 0;
+}
+EXPORT_SYMBOL(asic3_gpio_get_value);
+
+void asic3_gpio_set_value(struct device *dev, unsigned gpio, int val)
+{
+ u32 mask = ASIC3_GPIO_bit(gpio);
+ u32 bitval = 0;
+ if (val) bitval = mask;
+ printk("%s(%d, %d)\n", __FUNCTION__, gpio, val);
+
+ switch (gpio >> 4) {
+ case _IPAQ_ASIC3_GPIO_BANK_A:
+ asic3_set_gpio_out_a(dev, mask, bitval);
+ return;
+ case _IPAQ_ASIC3_GPIO_BANK_B:
+ asic3_set_gpio_out_b(dev, mask, bitval);
+ return;
+ case _IPAQ_ASIC3_GPIO_BANK_C:
+ asic3_set_gpio_out_c(dev, mask, bitval);
+ return;
+ case _IPAQ_ASIC3_GPIO_BANK_D:
+ asic3_set_gpio_out_d(dev, mask, bitval);
+ return;
+ }
+
+ printk(KERN_ERR "%s: invalid GPIO value 0x%x", __FUNCTION__, gpio);
+}
+EXPORT_SYMBOL(asic3_gpio_set_value);
+
+int asic3_irq_base(struct device *dev)
+{
+ struct asic3_data *asic = dev->driver_data;
+
+ return asic->irq_base;
+}
+EXPORT_SYMBOL(asic3_irq_base);
+
+static int asic3_gpio_to_irq(struct device *dev, unsigned gpio)
+{
+ struct asic3_data *asic = dev->driver_data;
+ printk("%s(%d)\n", __FUNCTION__, gpio);
+
+ return asic->irq_base + gpio;
+}
+
+void asic3_set_led(struct device *dev, int led_num, int duty_time,
+ int cycle_time, int timebase)
+{
+ struct asic3_data *asic = dev->driver_data;
+ unsigned int led_base;
+
+ /* it's a macro thing: see #define _IPAQ_ASIC_LED_0_Base for why you
+ * can't substitute led_num in the macros below...
+ */
+
+ switch (led_num) {
+ case 0:
+ led_base = _IPAQ_ASIC3_LED_0_Base;
+ break;
+ case 1:
+ led_base = _IPAQ_ASIC3_LED_1_Base;
+ break;
+ case 2:
+ led_base = _IPAQ_ASIC3_LED_2_Base;
+ break;
+ default:
+ printk(KERN_ERR "%s: invalid led number %d", __FUNCTION__,
+ led_num);
+ return;
+ }
+
+ __asic3_write_register(asic, led_base + _IPAQ_ASIC3_LED_TimeBase,
+ timebase | LED_EN);
+ __asic3_write_register(asic, led_base + _IPAQ_ASIC3_LED_PeriodTime,
+ cycle_time);
+ __asic3_write_register(asic, led_base + _IPAQ_ASIC3_LED_DutyTime,
+ 0);
+ udelay(20); /* asic voodoo - possibly need a whole duty cycle? */
+ __asic3_write_register(asic, led_base + _IPAQ_ASIC3_LED_DutyTime,
+ duty_time);
+}
+EXPORT_SYMBOL(asic3_set_led);
+
+void asic3_set_clock_sel(struct device *dev, u32 bits, u32 val)
+{
+ struct asic3_data *asic = dev->driver_data;
+ unsigned long flags;
+ u32 v;
+
+ spin_lock_irqsave(&asic3_gpio_lock, flags);
+ v = __asic3_read_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, SEL));
+ v = (v & ~bits) | val;
+ __asic3_write_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, SEL), v);
+ spin_unlock_irqrestore(&asic3_gpio_lock, flags);
+}
+EXPORT_SYMBOL(asic3_set_clock_sel);
+
+void asic3_set_clock_cdex(struct device *dev, u32 bits, u32 val)
+{
+ struct asic3_data *asic = dev->driver_data;
+ unsigned long flags;
+ u32 v;
+
+ spin_lock_irqsave(&asic3_gpio_lock, flags);
+ v = __asic3_read_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, CDEX));
+ v = (v & ~bits) | val;
+ __asic3_write_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, CDEX), v);
+ spin_unlock_irqrestore(&asic3_gpio_lock, flags);
+}
+EXPORT_SYMBOL(asic3_set_clock_cdex);
+
+static void asic3_clock_cdex_enable(struct clk *clk)
+{
+ struct asic3_data *asic = (struct asic3_data *)clk->parent->ctrlbit;
+ unsigned long flags, val;
+
+ local_irq_save(flags);
+
+ val = __asic3_read_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, CDEX));
+ val |= clk->ctrlbit;
+ __asic3_write_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, CDEX), val);
+
+ local_irq_restore(flags);
+}
+
+static void asic3_clock_cdex_disable(struct clk *clk)
+{
+ struct asic3_data *asic = (struct asic3_data *)clk->parent->ctrlbit;
+ unsigned long flags, val;
+
+ local_irq_save(flags);
+
+ val = __asic3_read_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, CDEX));
+ val &= ~clk->ctrlbit;
+ __asic3_write_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, CDEX), val);
+
+ local_irq_restore(flags);
+}
+
+/* base clocks */
+
+static struct clk clk_g = {
+ .name = "gclk",
+ .rate = 0,
+ .parent = NULL,
+};
+
+/* clock definitions */
+
+static struct clk asic3_clocks[] = {
+ {
+ .name = "spi",
+ .id = -1,
+ .parent = &clk_g,
+ .enable = asic3_clock_cdex_enable,
+ .disable = asic3_clock_cdex_disable,
+ .ctrlbit = CLOCK_CDEX_SPI,
+ },
+#ifdef CONFIG_HTC_ASIC3_DS1WM
+ {
+ .name = "ds1wm",
+ .id = -1,
+ .rate = 5000000,
+ .parent = &clk_g,
+ .enable = asic3_clock_cdex_enable,
+ .disable = asic3_clock_cdex_disable,
+ .ctrlbit = CLOCK_CDEX_OWM,
+ },
+#endif
+ {
+ .name = "pwm0",
+ .id = -1,
+ .parent = &clk_g,
+ .enable = asic3_clock_cdex_enable,
+ .disable = asic3_clock_cdex_disable,
+ .ctrlbit = CLOCK_CDEX_PWM0,
+ },
+ {
+ .name = "pwm1",
+ .id = -1,
+ .parent = &clk_g,
+ .enable = asic3_clock_cdex_enable,
+ .disable = asic3_clock_cdex_disable,
+ .ctrlbit = CLOCK_CDEX_PWM1,
+ },
+ {
+ .name = "led0",
+ .id = -1,
+ .parent = &clk_g,
+ .enable = asic3_clock_cdex_enable,
+ .disable = asic3_clock_cdex_disable,
+ .ctrlbit = CLOCK_CDEX_LED0,
+ },
+ {
+ .name = "led1",
+ .id = -1,
+ .parent = &clk_g,
+ .enable = asic3_clock_cdex_enable,
+ .disable = asic3_clock_cdex_disable,
+ .ctrlbit = CLOCK_CDEX_LED1,
+ },
+ {
+ .name = "led2",
+ .id = -1,
+ .parent = &clk_g,
+ .enable = asic3_clock_cdex_enable,
+ .disable = asic3_clock_cdex_disable,
+ .ctrlbit = CLOCK_CDEX_LED2,
+ },
+ {
+ .name = "smbus",
+ .id = -1,
+ .parent = &clk_g,
+ .enable = asic3_clock_cdex_enable,
+ .disable = asic3_clock_cdex_disable,
+ .ctrlbit = CLOCK_CDEX_SMBUS,
+ },
+ {
+ .name = "ex0",
+ .id = -1,
+ .parent = &clk_g,
+ .enable = asic3_clock_cdex_enable,
+ .disable = asic3_clock_cdex_disable,
+ .ctrlbit = CLOCK_CDEX_EX0,
+ },
+ {
+ .name = "ex1",
+ .id = -1,
+ .parent = &clk_g,
+ .enable = asic3_clock_cdex_enable,
+ .disable = asic3_clock_cdex_disable,
+ .ctrlbit = CLOCK_CDEX_EX1,
+ },
+};
+
+void asic3_set_extcf_select(struct device *dev, u32 bits, u32 val)
+{
+ struct asic3_data *asic = dev->driver_data;
+ unsigned long flags;
+ u32 v;
+
+ spin_lock_irqsave(&asic3_gpio_lock, flags);
+ v = __asic3_read_register(asic, IPAQ_ASIC3_OFFSET(EXTCF, Select));
+ v = (v & ~bits) | val;
+ __asic3_write_register(asic, IPAQ_ASIC3_OFFSET(EXTCF, Select), v);
+ spin_unlock_irqrestore(&asic3_gpio_lock, flags);
+}
+EXPORT_SYMBOL(asic3_set_extcf_select);
+
+void asic3_set_extcf_reset(struct device *dev, u32 bits, u32 val)
+{
+ struct asic3_data *asic = dev->driver_data;
+ unsigned long flags;
+ u32 v;
+
+ spin_lock_irqsave(&asic3_gpio_lock, flags);
+ v = __asic3_read_register(asic, IPAQ_ASIC3_OFFSET(EXTCF, Reset));
+ v = (v & ~bits) | val;
+ __asic3_write_register(asic, IPAQ_ASIC3_OFFSET(EXTCF, Reset), v);
+ spin_unlock_irqrestore(&asic3_gpio_lock, flags);
+}
+EXPORT_SYMBOL(asic3_set_extcf_reset);
+
+void asic3_set_sdhwctrl(struct device *dev, u32 bits, u32 val)
+{
+ struct asic3_data *asic = dev->driver_data;
+ unsigned long flags;
+ u32 v;
+
+ spin_lock_irqsave (&asic3_gpio_lock, flags);
+ v = __asic3_read_register(asic, IPAQ_ASIC3_OFFSET(SDHWCTRL, SDConf));
+ v = (v & ~bits) | val;
+ __asic3_write_register(asic, IPAQ_ASIC3_OFFSET(SDHWCTRL, SDConf), v);
+ spin_unlock_irqrestore(&asic3_gpio_lock, flags);
+}
+EXPORT_SYMBOL(asic3_set_sdhwctrl);
+
+
+#define MAX_ASIC_ISR_LOOPS 20
+#define _IPAQ_ASIC3_GPIO_Base_INCR \
+ (_IPAQ_ASIC3_GPIO_B_Base - _IPAQ_ASIC3_GPIO_A_Base)
+
+static inline void asic3_irq_flip_edge(struct asic3_data *asic,
+ u32 base, int bit)
+{
+ u16 edge = __asic3_read_register(asic,
+ base + _IPAQ_ASIC3_GPIO_EdgeTrigger);
+ edge ^= bit;
+ __asic3_write_register(asic,
+ base + _IPAQ_ASIC3_GPIO_EdgeTrigger, edge);
+}
+
+static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc)
+{
+ int iter;
+ struct asic3_data *asic;
+
+ /* Acknowledge the parrent (i.e. CPU's) IRQ */
+ desc->chip->ack(irq);
+
+ asic = desc->handler_data;
+
+ /* printk( KERN_NOTICE "asic3_irq_demux: irq=%d\n", irq ); */
+ for (iter = 0 ; iter < MAX_ASIC_ISR_LOOPS; iter++) {
+ u32 status;
+ int bank;
+
+ status = __asic3_read_register(asic,
+ IPAQ_ASIC3_OFFSET(INTR, PIntStat));
+ /* Check all ten register bits */
+ if ((status & 0x3ff) == 0)
+ break;
+
+ /* Handle GPIO IRQs */
+ for (bank = 0; bank < 4; bank++) {
+ if (status & (1 << bank)) {
+ unsigned long base, i, istat;
+
+ base = _IPAQ_ASIC3_GPIO_A_Base
+ + bank * _IPAQ_ASIC3_GPIO_Base_INCR;
+ istat = __asic3_read_register(asic,
+ base + _IPAQ_ASIC3_GPIO_IntStatus);
+ /* IntStatus is write 0 to clear */
+ /* XXX could miss interrupts! */
+ __asic3_write_register(asic,
+ base + _IPAQ_ASIC3_GPIO_IntStatus, 0);
+
+ for (i = 0; i < 16; i++) {
+ int bit = (1 << i);
+ unsigned int irqnr;
+ if (!(istat & bit))
+ continue;
+
+ irqnr = asic->irq_base
+ + (16 * bank) + i;
+ desc = irq_desc + irqnr;
+ desc->handle_irq(irqnr, desc);
+ if (asic->irq_bothedge[bank] & bit) {
+ asic3_irq_flip_edge(asic, base,
+ bit);
+ }
+ }
+ }
+ }
+
+ /* Handle remaining IRQs in the status register */
+ {
+ int i;
+
+ for (i = ASIC3_LED0_IRQ; i <= ASIC3_OWM_IRQ; i++) {
+ /* They start at bit 4 and go up */
+ if (status & (1 << (i - ASIC3_LED0_IRQ + 4))) {
+ desc = irq_desc + asic->irq_base + i;
+ desc->handle_irq(asic->irq_base + i,
+ desc);
+ }
+ }
+ }
+
+ }
+
+ if (iter >= MAX_ASIC_ISR_LOOPS)
+ printk(KERN_ERR "%s: interrupt processing overrun\n",
+ __FUNCTION__);
+}
+
+static inline int asic3_irq_to_bank(struct asic3_data *asic, int irq)
+{
+ int n;
+
+ n = (irq - asic->irq_base) >> 4;
+
+ return (n * (_IPAQ_ASIC3_GPIO_B_Base - _IPAQ_ASIC3_GPIO_A_Base));
+}
+
+static inline int asic3_irq_to_index(struct asic3_data *asic, int irq)
+{
+ return (irq - asic->irq_base) & 15;
+}
+
+static void asic3_mask_gpio_irq(unsigned int irq)
+{
+ struct asic3_data *asic = get_irq_chip_data(irq);
+ u32 val, bank, index;
+ unsigned long flags;
+
+ bank = asic3_irq_to_bank(asic, irq);
+ index = asic3_irq_to_index(asic, irq);
+
+ spin_lock_irqsave(&asic3_gpio_lock, flags);
+ val = __asic3_read_register(asic, bank + _IPAQ_ASIC3_GPIO_Mask);
+ val |= 1 << index;
+ __asic3_write_register(asic, bank + _IPAQ_ASIC3_GPIO_Mask, val);
+ spin_unlock_irqrestore(&asic3_gpio_lock, flags);
+}
+
+static void asic3_mask_irq(unsigned int irq)
+{
+ struct asic3_data *asic = get_irq_chip_data(irq);
+ int regval;
+
+ if (irq < ASIC3_NR_GPIO_IRQS) {
+ printk(KERN_ERR "asic3_base: gpio mask attempt, irq %d\n",
+ irq);
+ return;
+ }
+
+ regval = __asic3_read_register(asic,
+ _IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask);
+
+ switch (irq - asic->irq_base) {
+ case ASIC3_LED0_IRQ:
+ __asic3_write_register(asic,
+ _IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+ regval & ~ASIC3_INTMASK_MASK0);
+ break;
+ case ASIC3_LED1_IRQ:
+ __asic3_write_register(asic,
+ _IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+ regval & ~ASIC3_INTMASK_MASK1);
+ break;
+ case ASIC3_LED2_IRQ:
+ __asic3_write_register(asic,
+ _IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+ regval & ~ASIC3_INTMASK_MASK2);
+ break;
+ case ASIC3_SPI_IRQ:
+ __asic3_write_register(asic,
+ _IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+ regval & ~ASIC3_INTMASK_MASK3);
+ break;
+ case ASIC3_SMBUS_IRQ:
+ __asic3_write_register(asic,
+ _IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+ regval & ~ASIC3_INTMASK_MASK4);
+ break;
+ case ASIC3_OWM_IRQ:
+ __asic3_write_register(asic,
+ _IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+ regval & ~ASIC3_INTMASK_MASK5);
+ break;
+ default:
+ printk(KERN_ERR "asic3_base: bad non-gpio irq %d\n", irq);
+ break;
+ }
+}
+
+static void asic3_unmask_gpio_irq(unsigned int irq)
+{
+ struct asic3_data *asic = get_irq_chip_data(irq);
+ u32 val, bank, index;
+ unsigned long flags;
+
+ bank = asic3_irq_to_bank(asic, irq);
+ index = asic3_irq_to_index(asic, irq);
+
+ spin_lock_irqsave(&asic3_gpio_lock, flags);
+ val = __asic3_read_register(asic, bank + _IPAQ_ASIC3_GPIO_Mask);
+ val &= ~(1 << index);
+ __asic3_write_register(asic, bank + _IPAQ_ASIC3_GPIO_Mask, val);
+ spin_unlock_irqrestore(&asic3_gpio_lock, flags);
+}
+
+static void asic3_unmask_irq(unsigned int irq)
+{
+ struct asic3_data *asic = get_irq_chip_data(irq);
+ int regval;
+
+ if (irq < ASIC3_NR_GPIO_IRQS) {
+ printk(KERN_ERR "asic3_base: gpio unmask attempt, irq %d\n",
+ irq);
+ return;
+ }
+
+ regval = __asic3_read_register(asic,
+ _IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask);
+
+ switch (irq - asic->irq_base) {
+ case ASIC3_LED0_IRQ:
+ __asic3_write_register(asic,
+ _IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+ regval | ASIC3_INTMASK_MASK0);
+ break;
+ case ASIC3_LED1_IRQ:
+ __asic3_write_register(asic,
+ _IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+ regval | ASIC3_INTMASK_MASK1);
+ break;
+ case ASIC3_LED2_IRQ:
+ __asic3_write_register(asic,
+ _IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+ regval | ASIC3_INTMASK_MASK2);
+ break;
+ case ASIC3_SPI_IRQ:
+ __asic3_write_register(asic,
+ _IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+ regval | ASIC3_INTMASK_MASK3);
+ break;
+ case ASIC3_SMBUS_IRQ:
+ __asic3_write_register(asic,
+ _IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+ regval | ASIC3_INTMASK_MASK4);
+ break;
+ case ASIC3_OWM_IRQ:
+ __asic3_write_register(asic,
+ _IPAQ_ASIC3_INTR_Base + _IPAQ_ASIC3_INTR_IntMask,
+ regval | ASIC3_INTMASK_MASK5);
+ break;
+ default:
+ printk(KERN_ERR "asic3_base: bad non-gpio irq %d\n", irq);
+ break;
+ }
+}
+
+static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
+{
+ struct asic3_data *asic = get_irq_chip_data(irq);
+ u32 bank, index;
+ unsigned long flags;
+ u16 trigger, level, edge, bit;
+
+ bank = asic3_irq_to_bank(asic, irq);
+ index = asic3_irq_to_index(asic, irq);
+ bit = 1<<index;
+
+ spin_lock_irqsave(&asic3_gpio_lock, flags);
+ level = __asic3_read_register(asic,
+ bank + _IPAQ_ASIC3_GPIO_LevelTrigger);
+ edge = __asic3_read_register(asic,
+ bank + _IPAQ_ASIC3_GPIO_EdgeTrigger);
+ trigger = __asic3_read_register(asic,
+ bank + _IPAQ_ASIC3_GPIO_TriggerType);
+ asic->irq_bothedge[(irq - asic->irq_base) >> 4] &= ~bit;
+
+ if (type == IRQT_RISING) {
+ trigger |= bit;
+ edge |= bit;
+ } else if (type == IRQT_FALLING) {
+ trigger |= bit;
+ edge &= ~bit;
+ } else if (type == IRQT_BOTHEDGE) {
+ trigger |= bit;
+ if (asic3_gpio_get_value(asic->dev, irq - asic->irq_base))
+ edge &= ~bit;
+ else
+ edge |= bit;
+ asic->irq_bothedge[(irq - asic->irq_base) >> 4] |= bit;
+ } else if (type == IRQT_LOW) {
+ trigger &= ~bit;
+ level &= ~bit;
+ } else if (type == IRQT_HIGH) {
+ trigger &= ~bit;
+ level |= bit;
+ } else {
+ /*
+ * if type == IRQT_NOEDGE, we should mask interrupts, but
+ * be careful to not unmask them if mask was also called.
+ * Probably need internal state for mask.
+ */
+ printk(KERN_NOTICE "asic3: irq type not changed.\n");
+ }
+ __asic3_write_register(asic, bank + _IPAQ_ASIC3_GPIO_LevelTrigger,
+ level);
+ __asic3_write_register(asic, bank + _IPAQ_ASIC3_GPIO_EdgeTrigger,
+ edge);
+ __asic3_write_register(asic, bank + _IPAQ_ASIC3_GPIO_TriggerType,
+ trigger);
+ spin_unlock_irqrestore(&asic3_gpio_lock, flags);
+ return 0;
+}
+
+static struct irq_chip asic3_gpio_irq_chip = {
+ .name = "ASIC3-GPIO",
+ .ack = asic3_mask_gpio_irq,
+ .mask = asic3_mask_gpio_irq,
+ .unmask = asic3_unmask_gpio_irq,
+ .set_type = asic3_gpio_irq_type,
+};
+
+static struct irq_chip asic3_irq_chip = {
+ .name = "ASIC3",
+ .ack = asic3_mask_irq,
+ .mask = asic3_mask_irq,
+ .unmask = asic3_unmask_irq,
+};
+
+static void asic3_release(struct device *dev)
+{
+ struct platform_device *sdev = to_platform_device(dev);
+
+ kfree(sdev->resource);
+ kfree(sdev);
+}
+
+int asic3_register_mmc(struct device *dev)
+{
+ struct platform_device *sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
+ struct tmio_mmc_hwconfig *mmc_config = kmalloc(sizeof(*mmc_config),
+ GFP_KERNEL);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct asic3_data *asic = dev->driver_data;
+ struct asic3_platform_data *asic3_pdata = dev->platform_data;
+ struct resource *res;
+ int rc;
+
+ if (sdev == NULL || mmc_config == NULL)
+ return -ENOMEM;
+
+ if (asic3_pdata->tmio_mmc_hwconfig) {
+ memcpy(mmc_config, asic3_pdata->tmio_mmc_hwconfig,
+ sizeof(*mmc_config));
+ } else {
+ memset(mmc_config, 0, sizeof(*mmc_config));
+ }
+ mmc_config->address_shift = asic->bus_shift;
+
+ sdev->id = -1;
+ sdev->name = "asic3_mmc";
+ sdev->dev.parent = dev;
+ sdev->num_resources = 2;
+ sdev->dev.platform_data = mmc_config;
+ sdev->dev.release = asic3_release;
+
+ res = kzalloc(sdev->num_resources * sizeof(struct resource),
+ GFP_KERNEL);
+ if (res == NULL) {
+ kfree(sdev);
+ kfree(mmc_config);
+ return -ENOMEM;
+ }
+ sdev->resource = res;
+
+ res[0].start = pdev->resource[2].start;
+ res[0].end = pdev->resource[2].end;
+ res[0].flags = IORESOURCE_MEM;
+ res[1].start = res[1].end = pdev->resource[3].start;
+ res[1].flags = IORESOURCE_IRQ;
+
+ rc = platform_device_register(sdev);
+ if (rc) {
+ printk(KERN_ERR "asic3_base: "
+ "Could not register asic3_mmc device\n");
+ kfree(res);
+ kfree(sdev);
+ return rc;
+ }
+
+ asic->mmc_dev = sdev;
+
+ return 0;
+}
+EXPORT_SYMBOL(asic3_register_mmc);
+
+int asic3_unregister_mmc(struct device *dev)
+{
+ struct asic3_data *asic = dev->driver_data;
+ platform_device_unregister(asic->mmc_dev);
+ asic->mmc_dev = 0;
+
+ return 0;
+}
+EXPORT_SYMBOL(asic3_unregister_mmc);
+
+#ifdef CONFIG_HTC_ASIC3_DS1WM
+/*
+ * DS1WM subdevice
+ */
+
+static void asic3_ds1wm_enable(struct platform_device *ds1wm_dev)
+{
+ struct device *dev = ds1wm_dev->dev.parent;
+
+ /* Turn on external clocks and the OWM clock */
+ asic3_set_clock_cdex(dev,
+ CLOCK_CDEX_EX0 | CLOCK_CDEX_EX1 | CLOCK_CDEX_OWM,
+ CLOCK_CDEX_EX0 | CLOCK_CDEX_EX1 | CLOCK_CDEX_OWM);
+
+ mdelay(1);
+
+ asic3_set_extcf_reset(dev, ASIC3_EXTCF_OWM_RESET,
+ ASIC3_EXTCF_OWM_RESET);
+ mdelay(1);
+ asic3_set_extcf_reset(dev, ASIC3_EXTCF_OWM_RESET, 0);
+ mdelay(1);
+
+ /* Clear OWM_SMB, set OWM_EN */
+ asic3_set_extcf_select(dev,
+ ASIC3_EXTCF_OWM_SMB | ASIC3_EXTCF_OWM_EN,
+ 0 | ASIC3_EXTCF_OWM_EN);
+
+ mdelay(1);
+}
+
+static void asic3_ds1wm_disable(struct platform_device *ds1wm_dev)
+{
+ struct device *dev = ds1wm_dev->dev.parent;
+
+ asic3_set_extcf_select(dev,
+ ASIC3_EXTCF_OWM_SMB | ASIC3_EXTCF_OWM_EN,
+ 0 | 0);
+
+ asic3_set_clock_cdex(dev,
+ CLOCK_CDEX_EX0 | CLOCK_CDEX_EX1 | CLOCK_CDEX_OWM,
+ CLOCK_CDEX_EX0 | CLOCK_CDEX_EX1 | 0);
+}
+
+
+static struct resource asic3_ds1wm_resources[] = {
+ {
+ .start = _IPAQ_ASIC3_OWM_Base,
+ .end = _IPAQ_ASIC3_OWM_Base + 0x14 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = ASIC3_OWM_IRQ,
+ .end = ASIC3_OWM_IRQ,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE |
+ IORESOURCE_IRQ_SOC_SUBDEVICE,
+ },
+};
+
+static struct ds1wm_platform_data ds1wm_pd = {
+ .enable = asic3_ds1wm_enable,
+ .disable = asic3_ds1wm_disable,
+};
+#endif
+
+static struct soc_device_data asic3_blocks[] = {
+#ifdef CONFIG_HTC_ASIC3_DS1WM
+ {
+ .name = "ds1wm",
+ .res = asic3_ds1wm_resources,
+ .num_resources = ARRAY_SIZE(asic3_ds1wm_resources),
+ .hwconfig = &ds1wm_pd,
+ },
+#endif
+};
+
+static int asic3_probe(struct platform_device *pdev)
+{
+ struct asic3_platform_data *pdata = pdev->dev.platform_data;
+ struct asic3_data *asic;
+ struct device *dev = &pdev->dev;
+ unsigned long clksel;
+ int i, rc;
+
+ asic = kzalloc(sizeof(struct asic3_data), GFP_KERNEL);
+ if (!asic)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, asic);
+ asic->dev = &pdev->dev;
+
+ asic->mapping = ioremap(pdev->resource[0].start, IPAQ_ASIC3_MAP_SIZE);
+ if (!asic->mapping) {
+ printk(KERN_ERR "asic3: couldn't ioremap ASIC3\n");
+ kfree (asic);
+ return -ENOMEM;
+ }
+
+ if (pdata && pdata->bus_shift)
+ asic->bus_shift = pdata->bus_shift;
+ else
+ asic->bus_shift = 2;
+
+ /* XXX: should get correct SD clock values from pdata struct */
+ clksel = 0;
+ __asic3_write_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, SEL), clksel);
+
+ /* Register ASIC3's clocks. */
+ clk_g.ctrlbit = (int)asic;
+
+ if (clk_register(&clk_g) < 0)
+ printk(KERN_ERR "asic3: failed to register ASIC3 gclk\n");
+
+ for (i = 0; i < ARRAY_SIZE(asic3_clocks); i++) {
+ rc = clk_register(&asic3_clocks[i]);
+ if (rc < 0)
+ printk(KERN_ERR "asic3: "
+ "failed to register clock %s (%d)\n",
+ asic3_clocks[i].name, rc);
+ }
+
+ __asic3_write_register(asic, IPAQ_ASIC3_GPIO_OFFSET(A, Mask), 0xffff);
+ __asic3_write_register(asic, IPAQ_ASIC3_GPIO_OFFSET(B, Mask), 0xffff);
+ __asic3_write_register(asic, IPAQ_ASIC3_GPIO_OFFSET(C, Mask), 0xffff);
+ __asic3_write_register(asic, IPAQ_ASIC3_GPIO_OFFSET(D, Mask), 0xffff);
+
+ asic3_set_gpio_sleepmask_a(dev, 0xffff, 0xffff);
+ asic3_set_gpio_sleepmask_b(dev, 0xffff, 0xffff);
+ asic3_set_gpio_sleepmask_c(dev, 0xffff, 0xffff);
+ asic3_set_gpio_sleepmask_d(dev, 0xffff, 0xffff);
+
+ if (pdata) {
+ asic3_set_gpio_out_a(dev, 0xffff, pdata->gpio_a.init);
+ asic3_set_gpio_out_b(dev, 0xffff, pdata->gpio_b.init);
+ asic3_set_gpio_out_c(dev, 0xffff, pdata->gpio_c.init);
+ asic3_set_gpio_out_d(dev, 0xffff, pdata->gpio_d.init);
+
+ asic3_set_gpio_dir_a(dev, 0xffff, pdata->gpio_a.dir);
+ asic3_set_gpio_dir_b(dev, 0xffff, pdata->gpio_b.dir);
+ asic3_set_gpio_dir_c(dev, 0xffff, pdata->gpio_c.dir);
+ asic3_set_gpio_dir_d(dev, 0xffff, pdata->gpio_d.dir);
+
+ asic3_set_gpio_sleepmask_a(dev, 0xffff,
+ pdata->gpio_a.sleep_mask);
+ asic3_set_gpio_sleepmask_b(dev, 0xffff,
+ pdata->gpio_b.sleep_mask);
+ asic3_set_gpio_sleepmask_c(dev, 0xffff,
+ pdata->gpio_c.sleep_mask);
+ asic3_set_gpio_sleepmask_d(dev, 0xffff,
+ pdata->gpio_d.sleep_mask);
+
+ asic3_set_gpio_sleepout_a(dev, 0xffff,
+ pdata->gpio_a.sleep_out);
+ asic3_set_gpio_sleepout_b(dev, 0xffff,
+ pdata->gpio_b.sleep_out);
+ asic3_set_gpio_sleepout_c(dev, 0xffff,
+ pdata->gpio_c.sleep_out);
+ asic3_set_gpio_sleepout_d(dev, 0xffff,
+ pdata->gpio_d.sleep_out);
+
+ asic3_set_gpio_battfaultout_a(dev, 0xffff,
+ pdata->gpio_a.batt_fault_out);
+ asic3_set_gpio_battfaultout_b(dev, 0xffff,
+ pdata->gpio_b.batt_fault_out);
+ asic3_set_gpio_battfaultout_c(dev, 0xffff,
+ pdata->gpio_c.batt_fault_out);
+ asic3_set_gpio_battfaultout_d(dev, 0xffff,
+ pdata->gpio_d.batt_fault_out);
+
+ asic3_set_gpio_sleepconf_a(dev, 0xffff,
+ pdata->gpio_a.sleep_conf);
+ asic3_set_gpio_sleepconf_b(dev, 0xffff,
+ pdata->gpio_b.sleep_conf);
+ asic3_set_gpio_sleepconf_c(dev, 0xffff,
+ pdata->gpio_c.sleep_conf);
+ asic3_set_gpio_sleepconf_d(dev, 0xffff,
+ pdata->gpio_d.sleep_conf);
+
+ asic3_set_gpio_alt_fn_a(dev, 0xffff,
+ pdata->gpio_a.alt_function);
+ asic3_set_gpio_alt_fn_b(dev, 0xffff,
+ pdata->gpio_b.alt_function);
+ asic3_set_gpio_alt_fn_c(dev, 0xffff,
+ pdata->gpio_c.alt_function);
+ asic3_set_gpio_alt_fn_d(dev, 0xffff,
+ pdata->gpio_d.alt_function);
+ }
+
+ asic->irq_nr = -1;
+ asic->irq_base = -1;
+
+ if (pdev->num_resources > 1)
+ asic->irq_nr = pdev->resource[1].start;
+
+ if (asic->irq_nr != -1) {
+ unsigned int i;
+
+ if (!pdata->irq_base) {
+ printk(KERN_ERR "asic3: IRQ base not specified\n");
+ asic3_remove(pdev);
+ return -EINVAL;
+ }
+
+ asic->irq_base = pdata->irq_base;
+
+ /* turn on clock to IRQ controller */
+ clksel |= CLOCK_SEL_CX;
+ __asic3_write_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, SEL),
+ clksel);
+
+ printk(KERN_INFO "asic3: using irq %d-%d on irq %d\n",
+ asic->irq_base, asic->irq_base + ASIC3_NR_IRQS - 1,
+ asic->irq_nr);
+
+ for (i = 0 ; i < ASIC3_NR_IRQS ; i++) {
+ int irq = i + asic->irq_base;
+ if (i < ASIC3_NR_GPIO_IRQS) {
+ set_irq_chip(irq, &asic3_gpio_irq_chip);
+ set_irq_chip_data(irq, asic);
+ set_irq_handler(irq, handle_level_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ } else {
+ /* The remaining IRQs are not GPIO */
+ set_irq_chip(irq, &asic3_irq_chip);
+ set_irq_chip_data(irq, asic);
+ set_irq_handler(irq, handle_level_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ }
+ }
+
+ __asic3_write_register(asic, IPAQ_ASIC3_OFFSET(INTR, IntMask),
+ ASIC3_INTMASK_GINTMASK);
+
+ set_irq_chained_handler(asic->irq_nr, asic3_irq_demux);
+ set_irq_type(asic->irq_nr, IRQT_RISING);
+ set_irq_data(asic->irq_nr, asic);
+ }
+
+#ifdef CONFIG_HTC_ASIC3_DS1WM
+ ds1wm_pd.bus_shift = asic->bus_shift;
+#endif
+
+ pdata->gpiodev_ops.get = asic3_gpio_get_value;
+ pdata->gpiodev_ops.set = asic3_gpio_set_value;
+ pdata->gpiodev_ops.to_irq = asic3_gpio_to_irq;
+
+ soc_add_devices(pdev, asic3_blocks, ARRAY_SIZE(asic3_blocks),
+ &pdev->resource[0],
+ asic->bus_shift - ASIC3_DEFAULT_ADDR_SHIFT,
+ asic->irq_base);
+
+ if (pdev->num_resources > 2) {
+ int rc;
+ rc = asic3_register_mmc(dev);
+ if (rc) {
+ asic3_remove(pdev);
+ return rc;
+ }
+ }
+
+ if (pdata && pdata->num_child_platform_devs != 0)
+ platform_add_devices(pdata->child_platform_devs,
+ pdata->num_child_platform_devs);
+
+ return 0;
+}
+
+static int asic3_remove(struct platform_device *pdev)
+{
+ struct asic3_platform_data *pdata = pdev->dev.platform_data;
+ struct asic3_data *asic = platform_get_drvdata(pdev);
+ int i;
+
+ if (pdata && pdata->num_child_platform_devs != 0) {
+ for (i = 0; i < pdata->num_child_platform_devs; i++) {
+ platform_device_unregister(
+ pdata->child_platform_devs[i]);
+ }
+ }
+
+ if (asic->irq_nr != -1) {
+ unsigned int i;
+
+ for (i = 0 ; i < ASIC3_NR_IRQS ; i++) {
+ int irq = i + asic->irq_base;
+ set_irq_flags(irq, 0);
+ set_irq_handler (irq, NULL);
+ set_irq_chip (irq, NULL);
+ set_irq_chip_data(irq, NULL);
+ }
+
+ set_irq_chained_handler(asic->irq_nr, NULL);
+ }
+
+ if (asic->mmc_dev)
+ asic3_unregister_mmc(&pdev->dev);
+
+ for (i = 0; i < ARRAY_SIZE(asic3_clocks); i++)
+ clk_unregister(&asic3_clocks[i]);
+ clk_unregister(&clk_g);
+
+ __asic3_write_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, SEL), 0);
+ __asic3_write_register(asic, IPAQ_ASIC3_OFFSET(INTR, IntMask), 0);
+
+ iounmap(asic->mapping);
+
+ kfree(asic);
+
+ return 0;
+}
+
+static void asic3_shutdown(struct platform_device *pdev)
+{
+}
+
+#define ASIC3_SUSPEND_CDEX_MASK \
+ (CLOCK_CDEX_LED0 | CLOCK_CDEX_LED1 | CLOCK_CDEX_LED2)
+static unsigned short suspend_cdex;
+
+static int asic3_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct asic3_data *asic = platform_get_drvdata(pdev);
+ suspend_cdex = __asic3_read_register(asic,
+ _IPAQ_ASIC3_CLOCK_Base + _IPAQ_ASIC3_CLOCK_CDEX);
+ /* The LEDs are still active during suspend */
+ __asic3_write_register(asic,
+ _IPAQ_ASIC3_CLOCK_Base + _IPAQ_ASIC3_CLOCK_CDEX,
+ suspend_cdex & ASIC3_SUSPEND_CDEX_MASK);
+ return 0;
+}
+
+static int asic3_resume(struct platform_device *pdev)
+{
+ struct asic3_data *asic = platform_get_drvdata(pdev);
+ unsigned short intmask;
+
+ __asic3_write_register(asic, IPAQ_ASIC3_OFFSET(CLOCK, CDEX),
+ suspend_cdex);
+
+ if (asic->irq_nr != -1) {
+ /* Toggle the interrupt mask to try to get ASIC3 to show
+ * the CPU an interrupt edge. For more details see the
+ * kernel-discuss thread around 13 June 2005 with the
+ * subject "asic3 suspend / resume". */
+ intmask = __asic3_read_register(asic,
+ IPAQ_ASIC3_OFFSET(INTR, IntMask));
+ __asic3_write_register(asic, IPAQ_ASIC3_OFFSET(INTR, IntMask),
+ intmask & ~ASIC3_INTMASK_GINTMASK);
+ mdelay(1);
+ __asic3_write_register(asic, IPAQ_ASIC3_OFFSET(INTR, IntMask),
+ intmask | ASIC3_INTMASK_GINTMASK);
+ }
+
+ return 0;
+}
+
+static struct platform_driver asic3_device_driver = {
+ .driver = {
+ .name = "asic3",
+ },
+ .probe = asic3_probe,
+ .remove = asic3_remove,
+ .suspend = asic3_suspend,
+ .resume = asic3_resume,
+ .shutdown = asic3_shutdown,
+};
+
+static int __init asic3_base_init(void)
+{
+ int retval = 0;
+ retval = platform_driver_register(&asic3_device_driver);
+ return retval;
+}
+
+static void __exit asic3_base_exit(void)
+{
+ platform_driver_unregister(&asic3_device_driver);
+}
+
+#ifdef MODULE
+module_init(asic3_base_init);
+#else /* start early for dependencies */
+subsys_initcall(asic3_base_init);
+#endif
+module_exit(asic3_base_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");
+MODULE_DESCRIPTION("Core driver for HTC ASIC3");
+MODULE_SUPPORTED_DEVICE("asic3");
Index: linux-2.6.22/drivers/mfd/soc-core.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/drivers/mfd/soc-core.c 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,106 @@
+/*
+ * drivers/soc/soc-core.c
+ *
+ * core SoC support
+ * Copyright (c) 2006 Ian Molton
+ *
+ * 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.
+ *
+ * This file contains functionality used by many SoC type devices.
+ *
+ * Created: 2006-11-28
+ *
+ */
+
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include "soc-core.h"
+
+void soc_free_devices(struct platform_device *devices, int nr_devs)
+{
+ struct platform_device *dev = devices;
+ int i;
+
+ for (i = 0; i < nr_devs; i++) {
+ struct resource *res = dev->resource;
+ platform_device_unregister(dev++);
+ kfree(res);
+ }
+ kfree(devices);
+}
+EXPORT_SYMBOL_GPL(soc_free_devices);
+
+#define SIGNED_SHIFT(val, shift) ((shift) >= 0 ? ((val) << (shift)) : ((val) >> -(shift)))
+
+struct platform_device *soc_add_devices(struct platform_device *dev,
+ struct soc_device_data *soc, int nr_devs,
+ struct resource *mem,
+ int relative_addr_shift, int irq_base)
+{
+ struct platform_device *devices;
+ int i, r, base;
+
+ devices = kzalloc(nr_devs * sizeof(struct platform_device), GFP_KERNEL);
+ if (!devices)
+ return NULL;
+
+ for (i = 0; i < nr_devs; i++) {
+ struct platform_device *sdev = &devices[i];
+ struct soc_device_data *blk = &soc[i];
+ struct resource *res;
+
+ sdev->id = -1;
+ sdev->name = blk->name;
+
+ sdev->dev.parent = &dev->dev;
+ sdev->dev.platform_data = (void *)blk->hwconfig;
+ sdev->num_resources = blk->num_resources;
+
+ /* Allocate space for the subdevice resources */
+ res = kzalloc (blk->num_resources * sizeof (struct resource), GFP_KERNEL);
+ if (!res)
+ goto fail;
+
+ for (r = 0 ; r < blk->num_resources ; r++) {
+ res[r].name = blk->res[r].name; // Fixme - should copy
+
+ /* Find out base to use */
+ base = 0;
+ if (blk->res[r].flags & IORESOURCE_MEM) {
+ base = mem->start;
+ } else if ((blk->res[r].flags & IORESOURCE_IRQ) &&
+ (blk->res[r].flags & IORESOURCE_IRQ_SOC_SUBDEVICE)) {
+ base = irq_base;
+ }
+
+ /* Adjust resource */
+ if (blk->res[r].flags & IORESOURCE_MEM) {
+ res[r].parent = mem;
+ res[r].start = base + SIGNED_SHIFT(blk->res[r].start, relative_addr_shift);
+ res[r].end = base + SIGNED_SHIFT(blk->res[r].end, relative_addr_shift);
+ } else {
+ res[r].start = base + blk->res[r].start;
+ res[r].end = base + blk->res[r].end;
+ }
+ res[r].flags = blk->res[r].flags;
+ }
+
+ sdev->resource = res;
+ if (platform_device_register(sdev)) {
+ kfree(res);
+ goto fail;
+ }
+
+ printk(KERN_INFO "SoC: registering %s\n", blk->name);
+ }
+ return devices;
+
+fail:
+ soc_free_devices(devices, i + 1);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(soc_add_devices);
Index: linux-2.6.22/drivers/mfd/soc-core.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/drivers/mfd/soc-core.h 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,30 @@
+/*
+ * drivers/soc/soc-core.h
+ *
+ * core SoC support
+ * Copyright (c) 2006 Ian Molton
+ *
+ * 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.
+ *
+ * This file contains prototypes for the functions in soc-core.c
+ *
+ * Created: 2006-11-28
+ *
+ */
+
+struct soc_device_data {
+ char *name;
+ struct resource *res;
+ int num_resources;
+ void *hwconfig; /* platform_data to pass to the subdevice */
+};
+
+struct platform_device *soc_add_devices(struct platform_device *dev,
+ struct soc_device_data *soc, int n_devs,
+ struct resource *mem,
+ int relative_addr_shift, int irq_base);
+
+void soc_free_devices(struct platform_device *devices, int nr_devs);
+
Index: linux-2.6.22/include/asm-arm/arch-pxa/clock.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/include/asm-arm/arch-pxa/clock.h 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,27 @@
+/*
+ * linux/include/asm-arm/arch-pxa/clock.h
+ *
+ * Copyright (C) 2006 Erik Hovland
+ *
+ * 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.
+ */
+
+struct clk {
+ struct list_head node;
+ struct module *owner;
+ struct clk *parent;
+ const char *name;
+ int id;
+ unsigned int enabled;
+ unsigned long rate;
+ unsigned long ctrlbit;
+
+ void (*enable)(struct clk *);
+ void (*disable)(struct clk *);
+};
+
+
+extern int clk_register(struct clk *clk);
+extern void clk_unregister(struct clk *clk);
Index: linux-2.6.22/include/asm-arm/arch-pxa/htcuniversal-asic.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/include/asm-arm/arch-pxa/htcuniversal-asic.h 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,213 @@
+/*
+ * include/asm/arm/arch-pxa/htcuniversal-asic.h
+ *
+ * Authors: Giuseppe Zompatori <giuseppe_zompatori@yahoo.it>
+ *
+ * based on previews work, see below:
+ *
+ * include/asm/arm/arch-pxa/hx4700-asic.h
+ * Copyright (c) 2004 SDG Systems, LLC
+ *
+ */
+
+#ifndef _HTCUNIVERSAL_ASIC_H_
+#define _HTCUNIVERSAL_ASIC_H_
+
+#include <asm/hardware/ipaq-asic3.h>
+
+/* ASIC3 */
+
+#define HTCUNIVERSAL_ASIC3_GPIO_PHYS PXA_CS4_PHYS
+#define HTCUNIVERSAL_ASIC3_MMC_PHYS PXA_CS3_PHYS
+
+/* TODO: some information is missing here */
+
+/* ASIC3 GPIO A bank */
+
+#define GPIOA_I2C_EN 0 /* Output */
+#define GPIOA_SPK_PWR1_ON 1 /* Output */
+#define GPIOA_AUDIO_PWR_ON 2 /* Output */
+#define GPIOA_EARPHONE_PWR_ON 3 /* Output */
+
+#define GPIOA_UNKNOWN4 4 /* Output */
+#define GPIOA_BUTTON_BACKLIGHT_N 5 /* Input */
+#define GPIOA_SPK_PWR2_ON 6 /* Output */
+#define GPIOA_BUTTON_RECORD_N 7 /* Input */
+
+#define GPIOA_BUTTON_CAMERA_N 8 /* Input */
+#define GPIOA_UNKNOWN9 9 /* Output */
+#define GPIOA_FLASHLIGHT 10 /* Output */
+#define GPIOA_COVER_ROTATE_N 11 /* Input */
+
+#define GPIOA_TOUCHSCREEN_N 12 /* Input */
+#define GPIOA_VOL_UP_N 13 /* Input */
+#define GPIOA_VOL_DOWN_N 14 /* Input */
+#define GPIOA_LCD_PWR5_ON 15 /* Output */
+
+/* ASIC3 GPIO B bank */
+
+#define GPIOB_BB_READY 0 /* Input */
+#define GPIOB_CODEC_PDN 1 /* Output */
+#define GPIOB_UNKNOWN2 2 /* Input */
+#define GPIOB_BB_UNKNOWN3 3 /* Input */
+
+#define GPIOB_BT_IRQ 4 /* Input */
+#define GPIOB_CLAMSHELL_N 5 /* Input */
+#define GPIOB_LCD_PWR3_ON 6 /* Output */
+#define GPIOB_BB_ALERT 7 /* Input */
+
+#define GPIOB_BB_RESET2 8 /* Output */
+#define GPIOB_EARPHONE_N 9 /* Input */
+#define GPIOB_MICRECORD_N 10 /* Input */
+#define GPIOB_NIGHT_SENSOR 11 /* Input */
+
+#define GPIOB_UMTS_DCD 12 /* Input */
+#define GPIOB_UNKNOWN13 13 /* Input */
+#define GPIOB_CHARGE_EN 14 /* Output */
+#define GPIOB_USB_PUEN 15 /* Output */
+
+/* ASIC3 GPIO C bank */
+
+#define GPIOC_LED_BTWIFI 0 /* Output */
+#define GPIOC_LED_RED 1 /* Output */
+#define GPIOC_LED_GREEN 2 /* Output */
+#define GPIOC_BOARDID3 3 /* Input */
+
+#define GPIOC_WIFI_IRQ_N 4 /* Input */
+#define GPIOC_WIFI_RESET 5 /* Output */
+#define GPIOC_WIFI_PWR1_ON 6 /* Output */
+#define GPIOC_BT_RESET 7 /* Output */
+
+#define GPIOC_UNKNOWN8 8 /* Output */
+#define GPIOC_LCD_PWR1_ON 9 /* Output */
+#define GPIOC_LCD_PWR2_ON 10 /* Output */
+#define GPIOC_BOARDID2 11 /* Input */
+
+#define GPIOC_BOARDID1 12 /* Input */
+#define GPIOC_BOARDID0 13 /* Input */
+#define GPIOC_BT_PWR_ON 14 /* Output */
+#define GPIOC_CHARGE_ON 15 /* Output */
+
+/* ASIC3 GPIO D bank */
+
+#define GPIOD_KEY_OK_N 0 /* Input */
+#define GPIOD_KEY_RIGHT_N 1 /* Input */
+#define GPIOD_KEY_LEFT_N 2 /* Input */
+#define GPIOD_KEY_DOWN_N 3 /* Input */
+
+#define GPIOD_KEY_UP_N 4 /* Input */
+#define GPIOD_SDIO_DET 5 /* Input */
+#define GPIOD_WIFI_PWR2_ON 6 /* Output */
+#define GPIOD_HW_REBOOT 7 /* Output */
+
+#define GPIOD_BB_RESET1 8 /* Output */
+#define GPIOD_UNKNOWN9 9 /* Output */
+#define GPIOD_VIBRA_PWR_ON 10 /* Output */
+#define GPIOD_WIFI_PWR3_ON 11 /* Output */
+
+#define GPIOD_FL_PWR_ON 12 /* Output */
+#define GPIOD_LCD_PWR4_ON 13 /* Output */
+#define GPIOD_BL_KEYP_PWR_ON 14 /* Output */
+#define GPIOD_BL_KEYB_PWR_ON 15 /* Output */
+
+extern struct platform_device htcuniversal_asic3;
+
+/* ASIC3 GPIO A bank */
+
+#define GPIO_I2C_EN 0*16+GPIOA_I2C_EN
+#define GPIO_SPK_PWR1_ON 0*16+GPIOA_SPK_PWR1_ON
+#define GPIO_AUDIO_PWR_ON 0*16+GPIOA_AUDIO_PWR_ON
+#define GPIO_EARPHONE_PWR_ON 0*16+GPIOA_EARPHONE_PWR_ON
+
+#define GPIO_UNKNOWNA4 0*16+GPIOA_UNKNOWN4
+#define GPIO_BUTTON_BACKLIGHT_N 0*16+GPIOA_BUTTON_BACKLIGHT_N
+#define GPIO_SPK_PWR2_ON 0*16+GPIOA_SPK_PWR2_ON
+#define GPIO_BUTTON_RECORD_N 0*16+GPIOA_BUTTON_RECORD_N
+
+#define GPIO_BUTTON_CAMERA_N 0*16+GPIOA_BUTTON_CAMERA_N
+#define GPIO_UNKNOWNA9 0*16+GPIOA_UNKNOWN9
+#define GPIO_FLASHLIGHT 0*16+GPIOA_FLASHLIGHT
+#define GPIO_COVER_ROTATE_N 0*16+GPIOA_COVER_ROTATE_N
+
+#define GPIO_TOUCHSCREEN_N 0*16+GPIOA_TOUCHSCREEN_N
+#define GPIO_VOL_UP_N 0*16+GPIOA_VOL_UP_N
+#define GPIO_VOL_DOWN_N 0*16+GPIOA_VOL_DOWN_N
+#define GPIO_LCD_PWR5_ON 0*16+GPIOA_LCD_PWR5_ON
+
+/* ASIC3 GPIO B bank */
+
+#define GPIO_BB_READY 1*16+GPIOB_BB_READY
+#define GPIO_CODEC_PDN 1*16+GPIOB_CODEC_PDN
+#define GPIO_UNKNOWNB2 1*16+GPIOB_UNKNOWN2
+#define GPIO_BB_UNKNOWN3 1*16+GPIOB_BB_UNKNOWN3
+
+#define GPIO_BT_IRQ 1*16+GPIOB_BT_IRQ
+#define GPIO_CLAMSHELL_N 1*16+GPIOB_CLAMSHELL_N
+#define GPIO_LCD_PWR3_ON 1*16+GPIOB_LCD_PWR3_ON
+#define GPIO_BB_ALERT 1*16+GPIOB_BB_ALERT
+
+#define GPIO_BB_RESET2 1*16+GPIOB_BB_RESET2
+#define GPIO_EARPHONE_N 1*16+GPIOB_EARPHONE_N
+#define GPIO_MICRECORD_N 1*16+GPIOB_MICRECORD_N
+#define GPIO_NIGHT_SENSOR 1*16+GPIOB_NIGHT_SENSOR
+
+#define GPIO_UMTS_DCD 1*16+GPIOB_UMTS_DCD
+#define GPIO_UNKNOWNB13 1*16+GPIOB_UNKNOWN13
+#define GPIO_CHARGE_EN 1*16+GPIOB_CHARGE_EN
+#define GPIO_USB_PUEN 1*16+GPIOB_USB_PUEN
+
+/* ASIC3 GPIO C bank */
+
+#define GPIO_LED_BTWIFI 2*16+GPIOC_LED_BTWIFI
+#define GPIO_LED_RED 2*16+GPIOC_LED_RED
+#define GPIO_LED_GREEN 2*16+GPIOC_LED_GREEN
+#define GPIO_BOARDID3 2*16+GPIOC_BOARDID3
+
+#define GPIO_WIFI_IRQ_N 2*16+GPIOC_WIFI_IRQ_N
+#define GPIO_WIFI_RESET 2*16+GPIOC_WIFI_RESET
+#define GPIO_WIFI_PWR1_ON 2*16+GPIOC_WIFI_PWR1_ON
+#define GPIO_BT_RESET 2*16+GPIOC_BT_RESET
+
+#define GPIO_UNKNOWNC8 2*16+GPIOC_UNKNOWN8
+#define GPIO_LCD_PWR1_ON 2*16+GPIOC_LCD_PWR1_ON
+#define GPIO_LCD_PWR2_ON 2*16+GPIOC_LCD_PWR2_ON
+#define GPIO_BOARDID2 2*16+GPIOC_BOARDID2
+
+#define GPIO_BOARDID1 2*16+GPIOC_BOARDID1
+#define GPIO_BOARDID0 2*16+GPIOC_BOARDID0
+#define GPIO_BT_PWR_ON 2*16+GPIOC_BT_PWR_ON
+#define GPIO_CHARGE_ON 2*16+GPIOC_CHARGE_ON
+
+/* ASIC3 GPIO D bank */
+
+#define GPIO_KEY_OK_N 3*16+GPIOD_KEY_OK_N
+#define GPIO_KEY_RIGHT_N 3*16+GPIOD_KEY_RIGHT_N
+#define GPIO_KEY_LEFT_N 3*16+GPIOD_KEY_LEFT_N
+#define GPIO_KEY_DOWN_N 3*16+GPIOD_KEY_DOWN_N
+
+#define GPIO_KEY_UP_N 3*16+GPIOD_KEY_UP_N
+#define GPIO_SDIO_DET 3*16+GPIOD_SDIO_DET
+#define GPIO_WIFI_PWR2_ON 3*16+GPIOD_WIFI_PWR2_ON
+#define GPIO_HW_REBOOT 3*16+GPIOD_HW_REBOOT
+
+#define GPIO_BB_RESET1 3*16+GPIOD_BB_RESET1
+#define GPIO_UNKNOWND9 3*16+GPIOD_UNKNOWN9
+#define GPIO_VIBRA_PWR_ON 3*16+GPIOD_VIBRA_PWR_ON
+#define GPIO_WIFI_PWR3_ON 3*16+GPIOD_WIFI_PWR3_ON
+
+#define GPIO_FL_PWR_ON 3*16+GPIOD_FL_PWR_ON
+#define GPIO_LCD_PWR4_ON 3*16+GPIOD_LCD_PWR4_ON
+#define GPIO_BL_KEYP_PWR_ON 3*16+GPIOD_BL_KEYP_PWR_ON
+#define GPIO_BL_KEYB_PWR_ON 3*16+GPIOD_BL_KEYB_PWR_ON
+
+#define HTCUNIVERSAL_EGPIO_BASE PXA_CS2_PHYS+0x02000000
+
+#define EGPIO4_ON 4 /* something */
+#define EGPIO5_BT_3V3_ON 5 /* Bluetooth related */
+#define EGPIO6_WIFI_ON 6 /* WLAN related*/
+
+extern void htcuniversal_egpio_enable( u_int16_t bits );
+extern void htcuniversal_egpio_disable( u_int16_t bits );
+
+#endif /* _HTCUNIVERSAL_ASIC_H_ */
+
Index: linux-2.6.22/include/asm-arm/arch-pxa/htcuniversal-gpio.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/include/asm-arm/arch-pxa/htcuniversal-gpio.h 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,220 @@
+/*
+ * include/asm-arm/arch-pxa/htcuniversal-gpio.h
+ * History:
+ *
+ * 2004-12-10 Michael Opdenacker. Wrote down GPIO settings as identified by Jamey Hicks.
+ * Reused the h2200-gpio.h file as a template.
+ */
+
+#ifndef _HTCUNIVERSAL_GPIO_H_
+#define _HTCUNIVERSAL_GPIO_H_
+
+#include <asm/arch/pxa-regs.h>
+
+#define GET_HTCUNIVERSAL_GPIO(gpio) \
+ (GPLR(GPIO_NR_HTCUNIVERSAL_ ## gpio) & GPIO_bit(GPIO_NR_HTCUNIVERSAL_ ## gpio))
+
+#define SET_HTCUNIVERSAL_GPIO(gpio, setp) \
+do { \
+if (setp) \
+ GPSR(GPIO_NR_HTCUNIVERSAL_ ## gpio) = GPIO_bit(GPIO_NR_HTCUNIVERSAL_ ## gpio); \
+else \
+ GPCR(GPIO_NR_HTCUNIVERSAL_ ## gpio) = GPIO_bit(GPIO_NR_HTCUNIVERSAL_ ## gpio); \
+} while (0)
+
+#define SET_HTCUNIVERSAL_GPIO_N(gpio, setp) \
+do { \
+if (setp) \
+ GPCR(GPIO_NR_HTCUNIVERSAL_ ## gpio ## _N) = GPIO_bit(GPIO_NR_HTCUNIVERSAL_ ## gpio ## _N); \
+else \
+ GPSR(GPIO_NR_HTCUNIVERSAL_ ## gpio ## _N) = GPIO_bit(GPIO_NR_HTCUNIVERSAL_ ## gpio ## _N); \
+} while (0)
+
+#define HTCUNIVERSAL_IRQ(gpio) \
+ IRQ_GPIO(GPIO_NR_HTCUNIVERSAL_ ## gpio)
+
+#define GPIO_NR_HTCUNIVERSAL_KEY_ON_N 0
+#define GPIO_NR_HTCUNIVERSAL_GP_RST_N 1
+
+#define GPIO_NR_HTCUNIVERSAL_USB_DET 9
+#define GPIO_NR_HTCUNIVERSAL_POWER_DET 10
+
+#define GPIO_NR_HTCUNIVERSAL_CIF_DD7 12
+#define GPIO_NR_HTCUNIVERSAL_ASIC3_SDIO_INT_N 13
+#define GPIO_NR_HTCUNIVERSAL_ASIC3_EXT_INT 14
+#define GPIO_NR_HTCUNIVERSAL_CS1_N 15
+
+#define GPIO_NR_HTCUNIVERSAL_CIF_DD6 17
+#define GPIO_NR_HTCUNIVERSAL_RDY 18
+
+#define GPIO_NR_HTCUNIVERSAL_PHONE_START 19
+
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT7 22
+#define GPIO_NR_HTCUNIVERSAL_SPI_CLK 23
+#define GPIO_NR_HTCUNIVERSAL_SPI_FRM 24
+#define GPIO_NR_HTCUNIVERSAL_SPI_DO 25
+#define GPIO_NR_HTCUNIVERSAL_SPI_DI 26
+
+#define GPIO_NR_HTCUNIVERSAL_CODEC_ON 27
+#define GPIO_NR_HTCUNIVERSAL_I2S_BCK 28
+#define GPIO_NR_HTCUNIVERSAL_I2S_DIN 29
+#define GPIO_NR_HTCUNIVERSAL_I2S_DOUT 30
+#define GPIO_NR_HTCUNIVERSAL_I2S_SYNC 31
+
+#define GPIO_NR_HTCUNIVERSAL_RS232_ON 32
+#define GPIO_NR_HTCUNIVERSAL_CS5_N 33
+
+#define GPIO_NR_HTCUNIVERSAL_PHONE_RXD 34
+#define GPIO_NR_HTCUNIVERSAL_PHONE_UART_CTS 35
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN7 36
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN3 37
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN4 38
+#define GPIO_NR_HTCUNIVERSAL_PHONE_TXD 39
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT6 40
+#define GPIO_NR_HTCUNIVERSAL_PHONE_UART_RTS 41
+#define GPIO_NR_HTCUNIVERSAL_BT_RXD 42
+#define GPIO_NR_HTCUNIVERSAL_BT_TXD 43
+#define GPIO_NR_HTCUNIVERSAL_BT_UART_CTS 44
+#define GPIO_NR_HTCUNIVERSAL_BT_UART_RTS 45
+
+#define GPIO_NR_HTCUNIVERSAL_SIR_RXD 42
+#define GPIO_NR_HTCUNIVERSAL_SIR_TXD 43
+
+#define GPIO_NR_HTCUNIVERSAL_POE_N 48
+#define GPIO_NR_HTCUNIVERSAL_PWE_N 49
+#define GPIO_NR_HTCUNIVERSAL_CIF_DD3 50
+#define GPIO_NR_HTCUNIVERSAL_CIF_DD2 51
+#define GPIO_NR_HTCUNIVERSAL_CIF_DD4 52
+
+#define GPIO_NR_HTCUNIVERSAL_CIF_MCLK 53
+#define GPIO_NR_HTCUNIVERSAL_CIF_PCLK 54
+#define GPIO_NR_HTCUNIVERSAL_CIF_DD1 55
+
+#define GPIO_NR_HTCUNIVERSAL_LDD0 58
+#define GPIO_NR_HTCUNIVERSAL_LDD1 59
+#define GPIO_NR_HTCUNIVERSAL_LDD2 60
+#define GPIO_NR_HTCUNIVERSAL_LDD3 61
+#define GPIO_NR_HTCUNIVERSAL_LDD4 62
+#define GPIO_NR_HTCUNIVERSAL_LDD5 63
+#define GPIO_NR_HTCUNIVERSAL_LDD6 64
+#define GPIO_NR_HTCUNIVERSAL_LDD7 65
+#define GPIO_NR_HTCUNIVERSAL_LDD8 66
+#define GPIO_NR_HTCUNIVERSAL_LDD9 67
+#define GPIO_NR_HTCUNIVERSAL_LDD10 68
+#define GPIO_NR_HTCUNIVERSAL_LDD11 69
+#define GPIO_NR_HTCUNIVERSAL_LDD12 70
+#define GPIO_NR_HTCUNIVERSAL_LDD13 71
+#define GPIO_NR_HTCUNIVERSAL_LDD14 72
+#define GPIO_NR_HTCUNIVERSAL_LDD15 73
+
+#define GPIO_NR_HTCUNIVERSAL_LFCLK_RD 74
+#define GPIO_NR_HTCUNIVERSAL_LFCLK_A0 75
+#define GPIO_NR_HTCUNIVERSAL_LFCLK_WR 76
+#define GPIO_NR_HTCUNIVERSAL_LBIAS 77
+
+#define GPIO_NR_HTCUNIVERSAL_CS2_N 78
+#define GPIO_NR_HTCUNIVERSAL_CS3_N 79
+#define GPIO_NR_HTCUNIVERSAL_CS4_N 80
+#define GPIO_NR_HTCUNIVERSAL_CIF_DD0 81
+#define GPIO_NR_HTCUNIVERSAL_CIF_DD5 82
+
+#define GPIO_NR_HTCUNIVERSAL_CIF_LV 84
+#define GPIO_NR_HTCUNIVERSAL_CIF_FV 85
+
+#define GPIO_NR_HTCUNIVERSAL_LCD1 86
+#define GPIO_NR_HTCUNIVERSAL_LCD2 87
+
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN5 90
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN6 91
+
+#define GPIO_NR_HTCUNIVERSAL_DREQ1 97
+
+#define GPIO_NR_HTCUNIVERSAL_PHONE_RESET 98
+
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN0 100
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN1 101
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN2 102
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT0 103
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT1 104
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT2 105
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT3 106
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT4 107
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT5 108
+
+#define GPIO_NR_HTCUNIVERSAL_PHONE_UNKNOWN 109
+#define GPIO_NR_HTCUNIVERSAL_PHONE_OFF 110
+
+#define GPIO_NR_HTCUNIVERSAL_USB_PUEN 112
+#define GPIO_NR_HTCUNIVERSAL_I2S_SYSCLK 113
+
+#define GPIO_NR_HTCUNIVERSAL_PWM_OUT1 115
+
+#define GPIO_NR_HTCUNIVERSAL_I2C_SCL 117
+#define GPIO_NR_HTCUNIVERSAL_I2C_SDA 118
+
+#if 0
+#define GPIO_NR_HTCUNIVERSAL_CPU_BATT_FAULT_N
+#define GPIO_NR_HTCUNIVERSAL_ASIC3_RESET_N
+#define GPIO_NR_HTCUNIVERSAL_CHARGE_EN_N
+#define GPIO_NR_HTCUNIVERSAL_FLASH_VPEN
+#define GPIO_NR_HTCUNIVERSAL_BATT_OFF
+#define GPIO_NR_HTCUNIVERSAL_USB_CHARGE_RATE
+#define GPIO_NR_HTCUNIVERSAL_BL_DETECT_N
+#define GPIO_NR_HTCUNIVERSAL_CPU_HW_RESET_N
+#endif
+
+
+#define GPIO_NR_HTCUNIVERSAL_TOUCHSCREEN_SPI_CLK_MD (23 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_TOUCHSCREEN_SPI_FRM_MD (24 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_TOUCHSCREEN_SPI_DO_MD (25 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_TOUCHSCREEN_SPI_DI_MD (26 | GPIO_ALT_FN_1_IN)
+
+#define GPIO_NR_HTCUNIVERSAL_I2S_BCK_MD (28 | GPIO_ALT_FN_1_OUT)
+#define GPIO_NR_HTCUNIVERSAL_I2S_DIN_MD (29 | GPIO_ALT_FN_2_IN)
+#define GPIO_NR_HTCUNIVERSAL_I2S_DOUT_MD (30 | GPIO_ALT_FN_1_OUT)
+#define GPIO_NR_HTCUNIVERSAL_I2S_SYNC_MD (31 | GPIO_ALT_FN_1_OUT)
+
+#define GPIO_NR_HTCUNIVERSAL_PHONE_RXD_MD (34 | GPIO_ALT_FN_1_IN)
+#define GPIO_NR_HTCUNIVERSAL_PHONE_UART_CTS_MD (35 | GPIO_ALT_FN_1_IN)
+
+#define GPIO_NR_HTCUNIVERSAL_PHONE_TXD_MD (39 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_PHONE_UART_RTS_MD (41 | GPIO_ALT_FN_2_OUT)
+
+#define GPIO_NR_HTCUNIVERSAL_BT_RXD_MD (42 | GPIO_ALT_FN_1_IN)
+#define GPIO_NR_HTCUNIVERSAL_BT_TXD_MD (43 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_BT_UART_CTS_MD (44 | GPIO_ALT_FN_1_IN)
+#define GPIO_NR_HTCUNIVERSAL_BT_UART_RTS_MD (45 | GPIO_ALT_FN_2_OUT)
+
+#define GPIO_NR_HTCUNIVERSAL_SIR_RXD_MD (46 | GPIO_ALT_FN_2_IN)
+#define GPIO_NR_HTCUNIVERSAL_SIR_TXD_MD (47 | GPIO_ALT_FN_1_OUT)
+
+#define GPIO_NR_HTCUNIVERSAL_POE_N_MD (48 | GPIO_ALT_FN_2_OUT | GPIO_DFLT_HIGH)
+#define GPIO_NR_HTCUNIVERSAL_PWE_N_MD (49 | GPIO_ALT_FN_2_OUT | GPIO_DFLT_HIGH)
+
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN0_MD (GPIO_NR_HTCUNIVERSAL_KP_MKIN0 | GPIO_ALT_FN_1_IN)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN1_MD (GPIO_NR_HTCUNIVERSAL_KP_MKIN1 | GPIO_ALT_FN_1_IN)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN2_MD (GPIO_NR_HTCUNIVERSAL_KP_MKIN2 | GPIO_ALT_FN_1_IN)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN3_MD (GPIO_NR_HTCUNIVERSAL_KP_MKIN3 | GPIO_ALT_FN_3_IN)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN4_MD (GPIO_NR_HTCUNIVERSAL_KP_MKIN4 | GPIO_ALT_FN_2_IN)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN5_MD (GPIO_NR_HTCUNIVERSAL_KP_MKIN5 | GPIO_ALT_FN_1_IN)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN6_MD (GPIO_NR_HTCUNIVERSAL_KP_MKIN6 | GPIO_ALT_FN_1_IN)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKIN7_MD (GPIO_NR_HTCUNIVERSAL_KP_MKIN7 | GPIO_ALT_FN_3_IN)
+
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT0_MD (GPIO_NR_HTCUNIVERSAL_KP_MKOUT0 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT1_MD (GPIO_NR_HTCUNIVERSAL_KP_MKOUT1 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT2_MD (GPIO_NR_HTCUNIVERSAL_KP_MKOUT2 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT3_MD (GPIO_NR_HTCUNIVERSAL_KP_MKOUT3 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT4_MD (GPIO_NR_HTCUNIVERSAL_KP_MKOUT4 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT5_MD (GPIO_NR_HTCUNIVERSAL_KP_MKOUT5 | GPIO_ALT_FN_2_OUT)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT6_MD (GPIO_NR_HTCUNIVERSAL_KP_MKOUT6 | GPIO_ALT_FN_1_OUT)
+#define GPIO_NR_HTCUNIVERSAL_KP_MKOUT7_MD (GPIO_NR_HTCUNIVERSAL_KP_MKOUT7 | GPIO_ALT_FN_1_OUT)
+
+
+#define GPIO_NR_HTCUNIVERSAL_I2S_SYSCLK_MD (113 | GPIO_ALT_FN_1_OUT)
+
+#define GPIO_NR_HTCUNIVERSAL_PWM1OUT_MD (115 | GPIO_ALT_FN_3_OUT)
+
+#define GPIO_NR_HTCUNIVERSAL_I2C_SCL_MD (117 | GPIO_ALT_FN_1_OUT)
+#define GPIO_NR_HTCUNIVERSAL_I2C_SDA_MD (118 | GPIO_ALT_FN_1_OUT)
+
+#endif /* _HTCUNIVERSAL_GPIO_H */
Index: linux-2.6.22/include/asm-arm/arch-pxa/htcuniversal-init.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/include/asm-arm/arch-pxa/htcuniversal-init.h 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,14 @@
+/*
+ * include/asm/arm/arch-pxa/htcuniversal-init.h
+ * Copyright (c) 2004 SDG Systems, LLC
+ */
+
+#ifndef _HTCUNIVERSAL_INIT_H_
+#define _HTCUNIVERSAL_INIT_H_
+
+/* htcuniversal initialization data should be found here
+ * See -init.h files from other devices for details
+ */
+
+#endif /* _HTCUNIVERSAL_INIT_H_ */
+
Index: linux-2.6.22/include/asm-arm/arch-pxa/htcuniversal.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/include/asm-arm/arch-pxa/htcuniversal.h 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,3 @@
+#include <asm/arch/irqs.h>
+
+#define HTCUNIVERSAL_ASIC3_IRQ_BASE IRQ_BOARD_START
Index: linux-2.6.22/include/asm-arm/arch-pxa/pxa-pm_ll.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/include/asm-arm/arch-pxa/pxa-pm_ll.h 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,6 @@
+struct pxa_ll_pm_ops {
+ void (*suspend)(unsigned long);
+ void (*resume)(void);
+};
+
+extern struct pxa_ll_pm_ops *pxa_pm_set_ll_ops(struct pxa_ll_pm_ops *new_ops);
Index: linux-2.6.22/include/asm-arm/arch-pxa/sharpsl.h
===================================================================
--- linux-2.6.22.orig/include/asm-arm/arch-pxa/sharpsl.h 2007-07-09 01:32:17.000000000 +0200
+++ linux-2.6.22/include/asm-arm/arch-pxa/sharpsl.h 2007-09-11 12:53:37.000000000 +0200
@@ -25,12 +25,6 @@
/*
* SharpSL Backlight
*/
-struct corgibl_machinfo {
- int max_intensity;
- int default_intensity;
- int limit_mask;
- void (*set_bl_intensity)(int intensity);
-};
extern void corgibl_limit_intensity(int limit);
Index: linux-2.6.22/include/asm-arm/hardware/asic3_keys.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/include/asm-arm/hardware/asic3_keys.h 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,18 @@
+#include <linux/input.h>
+
+struct asic3_keys_button {
+ /* Configuration parameters */
+ int keycode;
+ int gpio;
+ int active_low;
+ char *desc;
+ int type;
+ /* Internal state vars - add below */
+};
+
+struct asic3_keys_platform_data {
+ struct asic3_keys_button *buttons;
+ int nbuttons;
+ struct input_dev *input;
+ struct device *asic3_dev;
+};
Index: linux-2.6.22/include/asm-arm/hardware/asic3_leds.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/include/asm-arm/hardware/asic3_leds.h 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,34 @@
+/*
+ * LEDs support for HTC ASIC3 devices.
+ *
+ * Copyright (c) 2006 Anton Vorontsov <cbou@mail.ru>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+
+struct asic3_leds_machinfo;
+
+struct asic3_led {
+ struct led_classdev led_cdev;
+ int hw_num; /* Number of "hardware-accelerated" led */
+ int gpio_num; /* Number of GPIO if hw_num == -1 */
+ struct asic3_leds_machinfo *machinfo;
+};
+
+struct asic3_leds_machinfo {
+ int num_leds;
+ struct asic3_led *leds;
+ struct platform_device *asic3_pdev;
+};
+
+extern int asic3_leds_register(void);
+extern void asic3_leds_unregister(void);
+
Index: linux-2.6.22/include/asm-arm/hardware/ipaq-asic3.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/include/asm-arm/hardware/ipaq-asic3.h 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,602 @@
+/*
+ *
+ * Definitions for the HTC ASIC3 chip found in several handheld devices
+ *
+ * Copyright 2001 Compaq Computer Corporation.
+ *
+ * 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.
+ *
+ * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Author: Andrew Christian
+ *
+ */
+
+#ifndef IPAQ_ASIC3_H
+#define IPAQ_ASIC3_H
+
+/****************************************************/
+/* IPAQ, ASIC #3, replaces ASIC #1 */
+
+#define IPAQ_ASIC3_OFFSET(x,y) (_IPAQ_ASIC3_ ## x ## _Base + _IPAQ_ASIC3_ ## x ## _ ## y)
+#define IPAQ_ASIC3_GPIO_OFFSET(x,y) (_IPAQ_ASIC3_GPIO_ ## x ## _Base + _IPAQ_ASIC3_GPIO_ ## y)
+
+
+/* All offsets below are specified with the following address bus shift */
+#define ASIC3_DEFAULT_ADDR_SHIFT 2
+
+#define _IPAQ_ASIC3_GPIO_A_Base 0x0000
+#define _IPAQ_ASIC3_GPIO_B_Base 0x0100
+#define _IPAQ_ASIC3_GPIO_C_Base 0x0200
+#define _IPAQ_ASIC3_GPIO_D_Base 0x0300
+
+#define _IPAQ_ASIC3_GPIO_Mask 0x00 /* R/W 0:don't mask, 1:mask interrupt */
+#define _IPAQ_ASIC3_GPIO_Direction 0x04 /* R/W 0:input, 1:output */
+#define _IPAQ_ASIC3_GPIO_Out 0x08 /* R/W 0:output low, 1:output high */
+#define _IPAQ_ASIC3_GPIO_TriggerType 0x0c /* R/W 0:level, 1:edge */
+#define _IPAQ_ASIC3_GPIO_EdgeTrigger 0x10 /* R/W 0:falling, 1:rising */
+#define _IPAQ_ASIC3_GPIO_LevelTrigger 0x14 /* R/W 0:low, 1:high level detect */
+#define _IPAQ_ASIC3_GPIO_SleepMask 0x18 /* R/W 0:don't mask, 1:mask trigger in sleep mode */
+#define _IPAQ_ASIC3_GPIO_SleepOut 0x1c /* R/W level 0:low, 1:high in sleep mode */
+#define _IPAQ_ASIC3_GPIO_BattFaultOut 0x20 /* R/W level 0:low, 1:high in batt_fault */
+#define _IPAQ_ASIC3_GPIO_IntStatus 0x24 /* R/W 0:none, 1:detect */
+#define _IPAQ_ASIC3_GPIO_AltFunction 0x28 /* R/W 0:normal control 1:LED register control */
+#define _IPAQ_ASIC3_GPIO_SleepConf 0x2c /* R/W bit 1: autosleep 0: disable gposlpout in normal mode, enable gposlpout in sleep mode */
+#define _IPAQ_ASIC3_GPIO_Status 0x30 /* R Pin status */
+
+#define IPAQ_ASIC3_GPIO_A_MASK(_b) IPAQ_ASIC3_GPIO( _b, u16, A, Mask )
+#define IPAQ_ASIC3_GPIO_A_DIR(_b) IPAQ_ASIC3_GPIO( _b, u16, A, Direction )
+#define IPAQ_ASIC3_GPIO_A_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, A, Out )
+#define IPAQ_ASIC3_GPIO_A_LEVELTRI(_b) IPAQ_ASIC3_GPIO( _b, u16, A, TriggerType )
+#define IPAQ_ASIC3_GPIO_A_RISING(_b) IPAQ_ASIC3_GPIO( _b, u16, A, EdgeTrigger )
+#define IPAQ_ASIC3_GPIO_A_LEVEL(_b) IPAQ_ASIC3_GPIO( _b, u16, A, LevelTrigger )
+#define IPAQ_ASIC3_GPIO_A_SLEEP_MASK(_b) IPAQ_ASIC3_GPIO( _b, u16, A, SleepMask )
+#define IPAQ_ASIC3_GPIO_A_SLEEP_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, A, SleepOut )
+#define IPAQ_ASIC3_GPIO_A_BATT_FAULT_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, A, BattFaultOut )
+#define IPAQ_ASIC3_GPIO_A_INT_STATUS(_b) IPAQ_ASIC3_GPIO( _b, u16, A, IntStatus )
+#define IPAQ_ASIC3_GPIO_A_ALT_FUNCTION(_b) IPAQ_ASIC3_GPIO( _b, u16, A, AltFunction )
+#define IPAQ_ASIC3_GPIO_A_SLEEP_CONF(_b) IPAQ_ASIC3_GPIO( _b, u16, A, SleepConf )
+#define IPAQ_ASIC3_GPIO_A_STATUS(_b) IPAQ_ASIC3_GPIO( _b, u16, A, Status )
+
+#define IPAQ_ASIC3_GPIO_B_MASK(_b) IPAQ_ASIC3_GPIO( _b, u16, B, Mask )
+#define IPAQ_ASIC3_GPIO_B_DIR(_b) IPAQ_ASIC3_GPIO( _b, u16, B, Direction )
+#define IPAQ_ASIC3_GPIO_B_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, B, Out )
+#define IPAQ_ASIC3_GPIO_B_LEVELTRI(_b) IPAQ_ASIC3_GPIO( _b, u16, B, TriggerType )
+#define IPAQ_ASIC3_GPIO_B_RISING(_b) IPAQ_ASIC3_GPIO( _b, u16, B, EdgeTrigger )
+#define IPAQ_ASIC3_GPIO_B_LEVEL(_b) IPAQ_ASIC3_GPIO( _b, u16, B, LevelTrigger )
+#define IPAQ_ASIC3_GPIO_B_SLEEP_MASK(_b) IPAQ_ASIC3_GPIO( _b, u16, B, SleepMask )
+#define IPAQ_ASIC3_GPIO_B_SLEEP_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, B, SleepOut )
+#define IPAQ_ASIC3_GPIO_B_BATT_FAULT_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, B, BattFaultOut )
+#define IPAQ_ASIC3_GPIO_B_INT_STATUS(_b) IPAQ_ASIC3_GPIO( _b, u16, B, IntStatus )
+#define IPAQ_ASIC3_GPIO_B_ALT_FUNCTION(_b) IPAQ_ASIC3_GPIO( _b, u16, B, AltFunction )
+#define IPAQ_ASIC3_GPIO_B_SLEEP_CONF(_b) IPAQ_ASIC3_GPIO( _b, u16, B, SleepConf )
+#define IPAQ_ASIC3_GPIO_B_STATUS(_b) IPAQ_ASIC3_GPIO( _b, u16, B, Status )
+
+#define IPAQ_ASIC3_GPIO_C_MASK(_b) IPAQ_ASIC3_GPIO( _b, u16, C, Mask )
+#define IPAQ_ASIC3_GPIO_C_DIR(_b) IPAQ_ASIC3_GPIO( _b, u16, C, Direction )
+#define IPAQ_ASIC3_GPIO_C_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, C, Out )
+#define IPAQ_ASIC3_GPIO_C_LEVELTRI(_b) IPAQ_ASIC3_GPIO( _b, u16, C, TriggerType )
+#define IPAQ_ASIC3_GPIO_C_RISING(_b) IPAQ_ASIC3_GPIO( _b, u16, C, EdgeTrigger )
+#define IPAQ_ASIC3_GPIO_C_LEVEL(_b) IPAQ_ASIC3_GPIO( _b, u16, C, LevelTrigger )
+#define IPAQ_ASIC3_GPIO_C_SLEEP_MASK(_b) IPAQ_ASIC3_GPIO( _b, u16, C, SleepMask )
+#define IPAQ_ASIC3_GPIO_C_SLEEP_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, C, SleepOut )
+#define IPAQ_ASIC3_GPIO_C_BATT_FAULT_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, C, BattFaultOut )
+#define IPAQ_ASIC3_GPIO_C_INT_STATUS(_b) IPAQ_ASIC3_GPIO( _b, u16, C, IntStatus )
+#define IPAQ_ASIC3_GPIO_C_ALT_FUNCTION(_b) IPAQ_ASIC3_GPIO( _b, u16, C, AltFunction )
+#define IPAQ_ASIC3_GPIO_C_SLEEP_CONF(_b) IPAQ_ASIC3_GPIO( _b, u16, C, SleepConf )
+#define IPAQ_ASIC3_GPIO_C_STATUS(_b) IPAQ_ASIC3_GPIO( _b, u16, C, Status )
+
+#define IPAQ_ASIC3_GPIO_D_MASK(_b) IPAQ_ASIC3_GPIO( _b, u16, D, Mask )
+#define IPAQ_ASIC3_GPIO_D_DIR(_b) IPAQ_ASIC3_GPIO( _b, u16, D, Direction )
+#define IPAQ_ASIC3_GPIO_D_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, D, Out )
+#define IPAQ_ASIC3_GPIO_D_LEVELTRI(_b) IPAQ_ASIC3_GPIO( _b, u16, D, TriggerType )
+#define IPAQ_ASIC3_GPIO_D_RISING(_b) IPAQ_ASIC3_GPIO( _b, u16, D, EdgeTrigger )
+#define IPAQ_ASIC3_GPIO_D_LEVEL(_b) IPAQ_ASIC3_GPIO( _b, u16, D, LevelTrigger )
+#define IPAQ_ASIC3_GPIO_D_SLEEP_MASK(_b) IPAQ_ASIC3_GPIO( _b, u16, D, SleepMask )
+#define IPAQ_ASIC3_GPIO_D_SLEEP_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, D, SleepOut )
+#define IPAQ_ASIC3_GPIO_D_BATT_FAULT_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, D, BattFaultOut )
+#define IPAQ_ASIC3_GPIO_D_INT_STATUS(_b) IPAQ_ASIC3_GPIO( _b, u16, D, IntStatus )
+#define IPAQ_ASIC3_GPIO_D_ALT_FUNCTION(_b) IPAQ_ASIC3_GPIO( _b, u16, D, AltFunction )
+#define IPAQ_ASIC3_GPIO_D_SLEEP_CONF(_b) IPAQ_ASIC3_GPIO( _b, u16, D, SleepConf )
+#define IPAQ_ASIC3_GPIO_D_STATUS(_b) IPAQ_ASIC3_GPIO( _b, u16, D, Status )
+
+#define _IPAQ_ASIC3_SPI_Base 0x0400
+#define _IPAQ_ASIC3_SPI_Control 0x0000
+#define _IPAQ_ASIC3_SPI_TxData 0x0004
+#define _IPAQ_ASIC3_SPI_RxData 0x0008
+#define _IPAQ_ASIC3_SPI_Int 0x000c
+#define _IPAQ_ASIC3_SPI_Status 0x0010
+
+#define IPAQ_ASIC3_SPI_Control(_b) IPAQ_ASIC3( _b, u16, SPI, Control )
+#define IPAQ_ASIC3_SPI_TxData(_b) IPAQ_ASIC3( _b, u16, SPI, TxData )
+#define IPAQ_ASIC3_SPI_RxData(_b) IPAQ_ASIC3( _b, u16, SPI, RxData )
+#define IPAQ_ASIC3_SPI_Int(_b) IPAQ_ASIC3( _b, u16, SPI, Int )
+#define IPAQ_ASIC3_SPI_Status(_b) IPAQ_ASIC3( _b, u16, SPI, Status )
+
+#define SPI_CONTROL_SPR(clk) ((clk) & 0x0f) /* Clock rate */
+
+#define _IPAQ_ASIC3_PWM_0_Base 0x0500
+#define _IPAQ_ASIC3_PWM_1_Base 0x0600
+#define _IPAQ_ASIC3_PWM_TimeBase 0x0000
+#define _IPAQ_ASIC3_PWM_PeriodTime 0x0004
+#define _IPAQ_ASIC3_PWM_DutyTime 0x0008
+
+#define IPAQ_ASIC3_PWM_TimeBase(_b, x) IPAQ_ASIC3_N( _b, u16, PWM, x, TimeBase )
+#define IPAQ_ASIC3_PWM_PeriodTime(_b, x) IPAQ_ASIC3_N( _b, u16, PWM, x, PeriodTime )
+#define IPAQ_ASIC3_PWM_DutyTime(_b, x) IPAQ_ASIC3_N( _b, u16, PWM, x, DutyTime )
+
+#define PWM_TIMEBASE_VALUE(x) ((x)&0xf) /* Low 4 bits sets time base */
+#define PWM_TIMEBASE_ENABLE (1 << 4) /* Enable clock */
+
+#define _IPAQ_ASIC3_LED_0_Base 0x0700
+#define _IPAQ_ASIC3_LED_1_Base 0x0800
+#define _IPAQ_ASIC3_LED_2_Base 0x0900
+#define _IPAQ_ASIC3_LED_TimeBase 0x0000 /* R/W 7 bits */
+#define _IPAQ_ASIC3_LED_PeriodTime 0x0004 /* R/W 12 bits */
+#define _IPAQ_ASIC3_LED_DutyTime 0x0008 /* R/W 12 bits */
+#define _IPAQ_ASIC3_LED_AutoStopCount 0x000c /* R/W 16 bits */
+
+#define IPAQ_ASIC3_LED_TimeBase(_b, x) IPAQ_ASIC3_N( _b, u8, LED, x, TimeBase )
+#define IPAQ_ASIC3_LED_PeriodTime(_b, x) IPAQ_ASIC3_N( _b, u16, LED, x, PeriodTime )
+#define IPAQ_ASIC3_LED_DutyTime(_b, x) IPAQ_ASIC3_N( _b, u16, LED, x, DutyTime )
+#define IPAQ_ASIC3_LED_AutoStopCount(_b, x) IPAQ_ASIC3_N( _b, u16, LED, x, AutoStopCount )
+
+/* LED TimeBase bits - match ASIC2 */
+#define LED_TBS 0x0f /* Low 4 bits sets time base, max = 13 */
+ /* Note: max = 5 on hx4700 */
+ /* 0: maximum time base */
+ /* 1: maximum time base / 2 */
+ /* n: maximum time base / 2^n */
+
+#define LED_EN (1 << 4) /* LED ON/OFF 0:off, 1:on */
+#define LED_AUTOSTOP (1 << 5) /* LED ON/OFF auto stop set 0:disable, 1:enable */
+#define LED_ALWAYS (1 << 6) /* LED Interrupt Mask 0:No mask, 1:mask */
+
+#define _IPAQ_ASIC3_CLOCK_Base 0x0A00
+#define _IPAQ_ASIC3_CLOCK_CDEX 0x00
+#define _IPAQ_ASIC3_CLOCK_SEL 0x04
+
+#define IPAQ_ASIC3_CLOCK_CDEX(_b) IPAQ_ASIC3( _b, u16, CLOCK, CDEX )
+#define IPAQ_ASIC3_CLOCK_SEL(_b) IPAQ_ASIC3( _b, u16, CLOCK, SEL )
+
+#define CLOCK_CDEX_SOURCE (1 << 0) /* 2 bits */
+#define CLOCK_CDEX_SOURCE0 (1 << 0)
+#define CLOCK_CDEX_SOURCE1 (1 << 1)
+#define CLOCK_CDEX_SPI (1 << 2)
+#define CLOCK_CDEX_OWM (1 << 3)
+#define CLOCK_CDEX_PWM0 (1 << 4)
+#define CLOCK_CDEX_PWM1 (1 << 5)
+#define CLOCK_CDEX_LED0 (1 << 6)
+#define CLOCK_CDEX_LED1 (1 << 7)
+#define CLOCK_CDEX_LED2 (1 << 8)
+
+#define CLOCK_CDEX_SD_HOST (1 << 9) /* R/W: SD host clock source 24.576M/12.288M */
+#define CLOCK_CDEX_SD_BUS (1 << 10) /* R/W: SD bus clock source control 24.576M/12.288M */
+#define CLOCK_CDEX_SMBUS (1 << 11)
+#define CLOCK_CDEX_CONTROL_CX (1 << 12)
+
+#define CLOCK_CDEX_EX0 (1 << 13) /* R/W: 32.768 kHz crystal */
+#define CLOCK_CDEX_EX1 (1 << 14) /* R/W: 24.576 MHz crystal */
+
+#define CLOCK_SEL_SD_HCLK_SEL (1 << 0) /* R/W: SDIO host clock select - 1: 24.576 Mhz, 0: 12.288 MHz */
+#define CLOCK_SEL_SD_BCLK_SEL (1 << 1) /* R/W: SDIO bus clock select - 1: 24.576 MHz, 0: 12.288 MHz */
+#define CLOCK_SEL_CX (1 << 2) /* R/W: INT clock source control (32.768 kHz) */
+
+
+#define _IPAQ_ASIC3_INTR_Base 0x0B00
+
+#define _IPAQ_ASIC3_INTR_IntMask 0x00 /* Interrupt mask control */
+#define _IPAQ_ASIC3_INTR_PIntStat 0x04 /* Peripheral interrupt status */
+#define _IPAQ_ASIC3_INTR_IntCPS 0x08 /* Interrupt timer clock pre-scale */
+#define _IPAQ_ASIC3_INTR_IntTBS 0x0c /* Interrupt timer set */
+
+#define IPAQ_ASIC3_INTR_IntMask(_b) IPAQ_ASIC3( _b, u8, INTR, IntMask )
+#define IPAQ_ASIC3_INTR_PIntStat(_b) IPAQ_ASIC3( _b, u8, INTR, PIntStat )
+#define IPAQ_ASIC3_INTR_IntCPS(_b) IPAQ_ASIC3( _b, u8, INTR, IntCPS )
+#define IPAQ_ASIC3_INTR_IntTBS(_b) IPAQ_ASIC3( _b, u16, INTR, IntTBS )
+
+#define ASIC3_INTMASK_GINTMASK (1 << 0) /* Global interrupt mask 1:enable */
+#define ASIC3_INTMASK_GINTEL (1 << 1) /* 1: rising edge, 0: hi level */
+#define ASIC3_INTMASK_MASK0 (1 << 2)
+#define ASIC3_INTMASK_MASK1 (1 << 3)
+#define ASIC3_INTMASK_MASK2 (1 << 4)
+#define ASIC3_INTMASK_MASK3 (1 << 5)
+#define ASIC3_INTMASK_MASK4 (1 << 6)
+#define ASIC3_INTMASK_MASK5 (1 << 7)
+
+#define ASIC3_INTR_PERIPHERAL_A (1 << 0)
+#define ASIC3_INTR_PERIPHERAL_B (1 << 1)
+#define ASIC3_INTR_PERIPHERAL_C (1 << 2)
+#define ASIC3_INTR_PERIPHERAL_D (1 << 3)
+#define ASIC3_INTR_LED0 (1 << 4)
+#define ASIC3_INTR_LED1 (1 << 5)
+#define ASIC3_INTR_LED2 (1 << 6)
+#define ASIC3_INTR_SPI (1 << 7)
+#define ASIC3_INTR_SMBUS (1 << 8)
+#define ASIC3_INTR_OWM (1 << 9)
+
+#define ASIC3_INTR_CPS(x) ((x)&0x0f) /* 4 bits, max 14 */
+#define ASIC3_INTR_CPS_SET ( 1 << 4 ) /* Time base enable */
+
+
+/* Basic control of the SD ASIC */
+#define _IPAQ_ASIC3_SDHWCTRL_Base 0x0E00
+
+#define _IPAQ_ASIC3_SDHWCTRL_SDConf 0x00
+#define IPAQ_ASIC3_SDHWCTRL_SDConf(_b) IPAQ_ASIC3( _b, u8, SDHWCTRL, SDConf )
+
+#define ASIC3_SDHWCTRL_SUSPEND (1 << 0) /* 1=suspend all SD operations */
+#define ASIC3_SDHWCTRL_CLKSEL (1 << 1) /* 1=SDICK, 0=HCLK */
+#define ASIC3_SDHWCTRL_PCLR (1 << 2) /* All registers of SDIO cleared */
+#define ASIC3_SDHWCTRL_LEVCD (1 << 3) /* Level of SD card detection: 1:high, 0:low */
+#define ASIC3_SDHWCTRL_LEVWP (1 << 4) /* Level of SD card write protection: 1=low, 0=high */
+#define ASIC3_SDHWCTRL_SDLED (1 << 5) /* SD card LED signal 1=enable, 0=disable */
+#define ASIC3_SDHWCTRL_SDPWR (1 << 6) /* SD card power supply control 1=enable */
+
+
+/* This is a pointer to an array of 12 u32 values - but only the lower 2 bytes matter */
+/* Use it as "IPAQ_ASIC3_HWPROTECT_ARRAY[x]" */
+
+#define _IPAQ_ASIC3_HWPROTECT_Base 0x1000
+#define IPAQ_ASIC3_HWPROTECT_ARRAY ((volatile u32*)(_IPAQ_ASIC3_Base + _IPAQ_ASIC3_HWPROTECT_Base))
+#define HWPROTECT_ARRAY_LEN 12
+#define HWPROTECT_ARRAY_VALUES {0x4854,0x432d,0x5344,0x494f,0x2050,0x2f4e,0x3a33,0x3048,0x3830,0x3032,0x382d,0x3030}
+
+
+#define _IPAQ_ASIC3_EXTCF_Base 0x1100
+
+#define _IPAQ_ASIC3_EXTCF_Select 0x00
+#define _IPAQ_ASIC3_EXTCF_Reset 0x04
+
+#define IPAQ_ASIC3_EXTCF_Select(_b) IPAQ_ASIC3( _b, u16, EXTCF, Select )
+#define IPAQ_ASIC3_EXTCF_Reset(_b) IPAQ_ASIC3( _b, u16, EXTCF, Reset )
+
+#define ASIC3_EXTCF_SMOD0 (1 << 0) /* slot number of mode 0 */
+#define ASIC3_EXTCF_SMOD1 (1 << 1) /* slot number of mode 1 */
+#define ASIC3_EXTCF_SMOD2 (1 << 2) /* slot number of mode 2 */
+#define ASIC3_EXTCF_OWM_EN (1 << 4) /* enable onewire module */
+#define ASIC3_EXTCF_OWM_SMB (1 << 5) /* OWM bus selection */
+#define ASIC3_EXTCF_OWM_RESET (1 << 6) /* undocumented, used by OWM and CF */
+#define ASIC3_EXTCF_CF0_SLEEP_MODE (1 << 7) /* CF0 sleep state control */
+#define ASIC3_EXTCF_CF1_SLEEP_MODE (1 << 8) /* CF1 sleep state control */
+#define ASIC3_EXTCF_CF0_PWAIT_EN (1 << 10) /* CF0 PWAIT_n control */
+#define ASIC3_EXTCF_CF1_PWAIT_EN (1 << 11) /* CF1 PWAIT_n control */
+#define ASIC3_EXTCF_CF0_BUF_EN (1 << 12) /* CF0 buffer control */
+#define ASIC3_EXTCF_CF1_BUF_EN (1 << 13) /* CF1 buffer control */
+#define ASIC3_EXTCF_SD_MEM_ENABLE (1 << 14)
+#define ASIC3_EXTCF_CF_SLEEP (1 << 15) /* CF sleep mode control */
+
+/*****************************************************************************
+ * The Onewire interface registers
+ *
+ * OWM_CMD
+ * OWM_DAT
+ * OWM_INTR
+ * OWM_INTEN
+ * OWM_CLKDIV
+ *
+ *****************************************************************************/
+
+#define _IPAQ_ASIC3_OWM_Base 0xC00
+
+#define _IPAQ_ASIC3_OWM_CMD 0x00
+#define _IPAQ_ASIC3_OWM_DAT 0x04
+#define _IPAQ_ASIC3_OWM_INTR 0x08
+#define _IPAQ_ASIC3_OWM_INTEN 0x0C
+#define _IPAQ_ASIC3_OWM_CLKDIV 0x10
+
+#define ASIC3_OWM_CMD_ONEWR (1 << 0)
+#define ASIC3_OWM_CMD_SRA (1 << 1)
+#define ASIC3_OWM_CMD_DQO (1 << 2)
+#define ASIC3_OWM_CMD_DQI (1 << 3)
+
+#define ASIC3_OWM_INTR_PD (1 << 0)
+#define ASIC3_OWM_INTR_PDR (1 << 1)
+#define ASIC3_OWM_INTR_TBE (1 << 2)
+#define ASIC3_OWM_INTR_TEMP (1 << 3)
+#define ASIC3_OWM_INTR_RBF (1 << 4)
+
+#define ASIC3_OWM_INTEN_EPD (1 << 0)
+#define ASIC3_OWM_INTEN_IAS (1 << 1)
+#define ASIC3_OWM_INTEN_ETBE (1 << 2)
+#define ASIC3_OWM_INTEN_ETMT (1 << 3)
+#define ASIC3_OWM_INTEN_ERBF (1 << 4)
+
+#define ASIC3_OWM_CLKDIV_PRE (3 << 0) /* two bits wide at bit position 0 */
+#define ASIC3_OWM_CLKDIV_DIV (7 << 2) /* 3 bits wide at bit position 2 */
+
+
+/*****************************************************************************
+ * The SD configuration registers are at a completely different location
+ * in memory. They are divided into three sets of registers:
+ *
+ * SD_CONFIG Core configuration register
+ * SD_CTRL Control registers for SD operations
+ * SDIO_CTRL Control registers for SDIO operations
+ *
+ *****************************************************************************/
+
+#define IPAQ_ASIC3_SD_CONFIG(_b, s,x) \
+ (*((volatile s *) ((_b) + _IPAQ_ASIC3_SD_CONFIG_Base + (_IPAQ_ASIC3_SD_CONFIG_ ## x))))
+
+#define _IPAQ_ASIC3_SD_CONFIG_Base 0x0400 // Assumes 32 bit addressing
+
+#define _IPAQ_ASIC3_SD_CONFIG_Command 0x08 /* R/W: Command */
+#define _IPAQ_ASIC3_SD_CONFIG_Addr0 0x20 /* [9:31] SD Control Register Base Address */
+#define _IPAQ_ASIC3_SD_CONFIG_Addr1 0x24 /* [9:31] SD Control Register Base Address */
+#define _IPAQ_ASIC3_SD_CONFIG_IntPin 0x78 /* R/O: interrupt assigned to pin */
+#define _IPAQ_ASIC3_SD_CONFIG_ClkStop 0x80 /* Set to 0x1f to clock SD controller, 0 otherwise. */
+ /* at 0x82 - Gated Clock Control */
+#define _IPAQ_ASIC3_SD_CONFIG_ClockMode 0x84 /* Control clock of SD controller */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_PinStatus 0x88 /* R/0: read status of SD pins */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_Power1 0x90 /* Power1 - manual power control */
+ /* Power2 is at 0x92 - auto power up after card inserted */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_Power3 0x94 /* auto power down when card removed */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_CardDetect 0x98 /* */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_Slot 0xA0 /* R/O: define support slot number */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_ExtGateClk1 0x1E0 /* Could be used for gated clock (don't use) */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_ExtGateClk2 0x1E2 /* Could be used for gated clock (don't use) */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_GPIO_OutAndEnable 0x1E8 /* GPIO Output Reg. , at 0x1EA - GPIO Output Enable Reg. */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_GPIO_Status 0x1EC /* GPIO Status Reg. */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_ExtGateClk3 0x1F0 /* Bit 1: double buffer/single buffer */
+
+#define IPAQ_ASIC3_SD_CONFIG_Command(_b) IPAQ_ASIC3_SD_CONFIG(_b, u16, Command )
+#define IPAQ_ASIC3_SD_CONFIG_Addr0(_b) IPAQ_ASIC3_SD_CONFIG(_b, u16, Addr0 )
+#define IPAQ_ASIC3_SD_CONFIG_Addr1(_b) IPAQ_ASIC3_SD_CONFIG(_b, u16, Addr1 )
+#define IPAQ_ASIC3_SD_CONFIG_IntPin(_b) IPAQ_ASIC3_SD_CONFIG(_b, u8, IntPin )
+#define IPAQ_ASIC3_SD_CONFIG_ClkStop(_b) IPAQ_ASIC3_SD_CONFIG(_b, u8, ClkStop )
+#define IPAQ_ASIC3_SD_CONFIG_ClockMode(_b) IPAQ_ASIC3_SD_CONFIG(_b, u8, ClockMode )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_PinStatus(_b) IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_PinStatus )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_Power1(_b) IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_Power1 )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_Power3(_b) IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_Power3 )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_CardDetect(_b) IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_CardDetect )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_Slot(_b) IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_Slot )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_ExtGateClk1(_b) IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_ExtGateClk1 )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_ExtGateClk3(_b) IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_ExtGateClk3 )
+
+#define SD_CONFIG_
+
+#define SD_CONFIG_COMMAND_MAE (1<<1) /* Memory access enable (set to 1 to access SD Controller) */
+
+#define SD_CONFIG_CLK_ENABLE_ALL 0x1f
+
+#define SD_CONFIG_POWER1_PC_33V 0x0200 /* Set for 3.3 volts */
+#define SD_CONFIG_POWER1_PC_OFF 0x0000 /* Turn off power */
+
+#define SD_CONFIG_CARDDETECTMODE_CLK ((x)&0x3) /* two bits - number of cycles for card detection */
+
+
+#define _IPAQ_ASIC3_SD_CTRL_Base 0x1000
+
+#define IPAQ_ASIC3_SD(_b, s,x) \
+ (*((volatile s *) ((_b) + _IPAQ_ASIC3_SD_CTRL_Base + (_IPAQ_ASIC3_SD_CTRL_ ## x))))
+
+#define _IPAQ_ASIC3_SD_CTRL_Cmd 0x00
+#define _IPAQ_ASIC3_SD_CTRL_Arg0 0x08
+#define _IPAQ_ASIC3_SD_CTRL_Arg1 0x0C
+#define _IPAQ_ASIC3_SD_CTRL_StopInternal 0x10
+#define _IPAQ_ASIC3_SD_CTRL_TransferSectorCount 0x14
+#define _IPAQ_ASIC3_SD_CTRL_Response0 0x18
+#define _IPAQ_ASIC3_SD_CTRL_Response1 0x1C
+#define _IPAQ_ASIC3_SD_CTRL_Response2 0x20
+#define _IPAQ_ASIC3_SD_CTRL_Response3 0x24
+#define _IPAQ_ASIC3_SD_CTRL_Response4 0x28
+#define _IPAQ_ASIC3_SD_CTRL_Response5 0x2C
+#define _IPAQ_ASIC3_SD_CTRL_Response6 0x30
+#define _IPAQ_ASIC3_SD_CTRL_Response7 0x34
+#define _IPAQ_ASIC3_SD_CTRL_CardStatus 0x38
+#define _IPAQ_ASIC3_SD_CTRL_BufferCtrl 0x3C
+#define _IPAQ_ASIC3_SD_CTRL_IntMaskCard 0x40
+#define _IPAQ_ASIC3_SD_CTRL_IntMaskBuffer 0x44
+#define _IPAQ_ASIC3_SD_CTRL_CardClockCtrl 0x48
+#define _IPAQ_ASIC3_SD_CTRL_MemCardXferDataLen 0x4C
+#define _IPAQ_ASIC3_SD_CTRL_MemCardOptionSetup 0x50
+#define _IPAQ_ASIC3_SD_CTRL_ErrorStatus0 0x58
+#define _IPAQ_ASIC3_SD_CTRL_ErrorStatus1 0x5C
+#define _IPAQ_ASIC3_SD_CTRL_DataPort 0x60
+#define _IPAQ_ASIC3_SD_CTRL_TransactionCtrl 0x68
+#define _IPAQ_ASIC3_SD_CTRL_SoftwareReset 0x1C0
+
+#define IPAQ_ASIC3_SD_CTRL_Cmd(_b) IPAQ_ASIC3_SD( _b, u16, Cmd ) /* */
+#define IPAQ_ASIC3_SD_CTRL_Arg0(_b) IPAQ_ASIC3_SD( _b, u16, Arg0 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_Arg1(_b) IPAQ_ASIC3_SD( _b, u16, Arg1 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_StopInternal(_b) IPAQ_ASIC3_SD( _b, u16, StopInternal ) /* */
+#define IPAQ_ASIC3_SD_CTRL_TransferSectorCount(_b) IPAQ_ASIC3_SD( _b, u16, TransferSectorCount ) /* */
+#define IPAQ_ASIC3_SD_CTRL_Response0(_b) IPAQ_ASIC3_SD( _b, u16, Response0 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_Response1(_b) IPAQ_ASIC3_SD( _b, u16, Response1 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_Response2(_b) IPAQ_ASIC3_SD( _b, u16, Response2 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_Response3(_b) IPAQ_ASIC3_SD( _b, u16, Response3 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_Response4(_b) IPAQ_ASIC3_SD( _b, u16, Response4 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_Response5(_b) IPAQ_ASIC3_SD( _b, u16, Response5 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_Response6(_b) IPAQ_ASIC3_SD( _b, u16, Response6 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_Response7(_b) IPAQ_ASIC3_SD( _b, u16, Response7 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_CardStatus(_b) IPAQ_ASIC3_SD( _b, u16, CardStatus ) /* */
+#define IPAQ_ASIC3_SD_CTRL_BufferCtrl(_b) IPAQ_ASIC3_SD( _b, u16, BufferCtrl ) /* and error status*/
+#define IPAQ_ASIC3_SD_CTRL_IntMaskCard(_b) IPAQ_ASIC3_SD( _b, u16, IntMaskCard ) /* */
+#define IPAQ_ASIC3_SD_CTRL_IntMaskBuffer(_b) IPAQ_ASIC3_SD( _b, u16, IntMaskBuffer ) /* */
+#define IPAQ_ASIC3_SD_CTRL_CardClockCtrl(_b) IPAQ_ASIC3_SD( _b, u16, CardClockCtrl ) /* */
+#define IPAQ_ASIC3_SD_CTRL_MemCardXferDataLen(_b) IPAQ_ASIC3_SD( _b, u16, MemCardXferDataLen ) /* */
+#define IPAQ_ASIC3_SD_CTRL_MemCardOptionSetup(_b) IPAQ_ASIC3_SD( _b, u16, MemCardOptionSetup ) /* */
+#define IPAQ_ASIC3_SD_CTRL_ErrorStatus0(_b) IPAQ_ASIC3_SD( _b, u16, ErrorStatus0 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_ErrorStatus1(_b) IPAQ_ASIC3_SD( _b, u16, ErrorStatus1 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_DataPort(_b) IPAQ_ASIC3_SD( _b, u16, DataPort ) /* */
+#define IPAQ_ASIC3_SD_CTRL_TransactionCtrl(_b) IPAQ_ASIC3_SD( _b, u16, TransactionCtrl ) /* */
+#define IPAQ_ASIC3_SD_CTRL_SoftwareReset(_b) IPAQ_ASIC3_SD( _b, u16, SoftwareReset ) /* */
+
+#define SD_CTRL_SOFTWARE_RESET_CLEAR (1<<0)
+
+#define SD_CTRL_TRANSACTIONCONTROL_SET (1<<8) // 0x0100
+
+#define SD_CTRL_CARDCLOCKCONTROL_FOR_SD_CARD (1<<15)// 0x8000
+#define SD_CTRL_CARDCLOCKCONTROL_ENABLE_CLOCK (1<<8) // 0x0100
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_512 (1<<7) // 0x0080
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_256 (1<<6) // 0x0040
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_128 (1<<5) // 0x0020
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_64 (1<<4) // 0x0010
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_32 (1<<3) // 0x0008
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_16 (1<<2) // 0x0004
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_8 (1<<1) // 0x0002
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_4 (1<<0) // 0x0001
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_2 (0<<0) // 0x0000
+
+#define MEM_CARD_OPTION_REQUIRED 0x000e
+#define MEM_CARD_OPTION_DATA_RESPONSE_TIMEOUT(x) (((x)&0x0f)<<4) /* Four bits */
+#define MEM_CARD_OPTION_C2_MODULE_NOT_PRESENT (1<<14) // 0x4000
+#define MEM_CARD_OPTION_DATA_XFR_WIDTH_1 (1<<15) // 0x8000
+#define MEM_CARD_OPTION_DATA_XFR_WIDTH_4 (0<<15) //~0x8000
+
+#define SD_CTRL_COMMAND_INDEX(x) ((x)&0x3f) /* 0=CMD0, 1=CMD1, ..., 63=CMD63 */
+#define SD_CTRL_COMMAND_TYPE_CMD (0 << 6)
+#define SD_CTRL_COMMAND_TYPE_ACMD (1 << 6)
+#define SD_CTRL_COMMAND_TYPE_AUTHENTICATION (2 << 6)
+#define SD_CTRL_COMMAND_RESPONSE_TYPE_NORMAL (0 << 8)
+#define SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R1 (4 << 8)
+#define SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R1B (5 << 8)
+#define SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R2 (6 << 8)
+#define SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R3 (7 << 8)
+#define SD_CTRL_COMMAND_DATA_PRESENT (1 << 11)
+#define SD_CTRL_COMMAND_TRANSFER_READ (1 << 12)
+#define SD_CTRL_COMMAND_TRANSFER_WRITE (0 << 12)
+#define SD_CTRL_COMMAND_MULTI_BLOCK (1 << 13)
+#define SD_CTRL_COMMAND_SECURITY_CMD (1 << 14)
+
+#define SD_CTRL_STOP_INTERNAL_ISSSUE_CMD12 (1 << 0)
+#define SD_CTRL_STOP_INTERNAL_AUTO_ISSUE_CMD12 (1 << 8)
+
+#define SD_CTRL_CARDSTATUS_RESPONSE_END (1 << 0)
+#define SD_CTRL_CARDSTATUS_RW_END (1 << 2)
+#define SD_CTRL_CARDSTATUS_CARD_REMOVED_0 (1 << 3)
+#define SD_CTRL_CARDSTATUS_CARD_INSERTED_0 (1 << 4)
+#define SD_CTRL_CARDSTATUS_SIGNAL_STATE_PRESENT_0 (1 << 5)
+#define SD_CTRL_CARDSTATUS_WRITE_PROTECT (1 << 7)
+#define SD_CTRL_CARDSTATUS_CARD_REMOVED_3 (1 << 8)
+#define SD_CTRL_CARDSTATUS_CARD_INSERTED_3 (1 << 9)
+#define SD_CTRL_CARDSTATUS_SIGNAL_STATE_PRESENT_3 (1 << 10)
+
+#define SD_CTRL_BUFFERSTATUS_CMD_INDEX_ERROR (1 << 0) // 0x0001
+#define SD_CTRL_BUFFERSTATUS_CRC_ERROR (1 << 1) // 0x0002
+#define SD_CTRL_BUFFERSTATUS_STOP_BIT_END_ERROR (1 << 2) // 0x0004
+#define SD_CTRL_BUFFERSTATUS_DATA_TIMEOUT (1 << 3) // 0x0008
+#define SD_CTRL_BUFFERSTATUS_BUFFER_OVERFLOW (1 << 4) // 0x0010
+#define SD_CTRL_BUFFERSTATUS_BUFFER_UNDERFLOW (1 << 5) // 0x0020
+#define SD_CTRL_BUFFERSTATUS_CMD_TIMEOUT (1 << 6) // 0x0040
+#define SD_CTRL_BUFFERSTATUS_UNK7 (1 << 7) // 0x0080
+#define SD_CTRL_BUFFERSTATUS_BUFFER_READ_ENABLE (1 << 8) // 0x0100
+#define SD_CTRL_BUFFERSTATUS_BUFFER_WRITE_ENABLE (1 << 9) // 0x0200
+#define SD_CTRL_BUFFERSTATUS_ILLEGAL_FUNCTION (1 << 13)// 0x2000
+#define SD_CTRL_BUFFERSTATUS_CMD_BUSY (1 << 14)// 0x4000
+#define SD_CTRL_BUFFERSTATUS_ILLEGAL_ACCESS (1 << 15)// 0x8000
+
+#define SD_CTRL_INTMASKCARD_RESPONSE_END (1 << 0) // 0x0001
+#define SD_CTRL_INTMASKCARD_RW_END (1 << 2) // 0x0004
+#define SD_CTRL_INTMASKCARD_CARD_REMOVED_0 (1 << 3) // 0x0008
+#define SD_CTRL_INTMASKCARD_CARD_INSERTED_0 (1 << 4) // 0x0010
+#define SD_CTRL_INTMASKCARD_SIGNAL_STATE_PRESENT_0 (1 << 5) // 0x0020
+#define SD_CTRL_INTMASKCARD_UNK6 (1 << 6) // 0x0040
+#define SD_CTRL_INTMASKCARD_WRITE_PROTECT (1 << 7) // 0x0080
+#define SD_CTRL_INTMASKCARD_CARD_REMOVED_3 (1 << 8) // 0x0100
+#define SD_CTRL_INTMASKCARD_CARD_INSERTED_3 (1 << 9) // 0x0200
+#define SD_CTRL_INTMASKCARD_SIGNAL_STATE_PRESENT_3 (1 << 10)// 0x0400
+
+#define SD_CTRL_INTMASKBUFFER_CMD_INDEX_ERROR (1 << 0) // 0x0001
+#define SD_CTRL_INTMASKBUFFER_CRC_ERROR (1 << 1) // 0x0002
+#define SD_CTRL_INTMASKBUFFER_STOP_BIT_END_ERROR (1 << 2) // 0x0004
+#define SD_CTRL_INTMASKBUFFER_DATA_TIMEOUT (1 << 3) // 0x0008
+#define SD_CTRL_INTMASKBUFFER_BUFFER_OVERFLOW (1 << 4) // 0x0010
+#define SD_CTRL_INTMASKBUFFER_BUFFER_UNDERFLOW (1 << 5) // 0x0020
+#define SD_CTRL_INTMASKBUFFER_CMD_TIMEOUT (1 << 6) // 0x0040
+#define SD_CTRL_INTMASKBUFFER_UNK7 (1 << 7) // 0x0080
+#define SD_CTRL_INTMASKBUFFER_BUFFER_READ_ENABLE (1 << 8) // 0x0100
+#define SD_CTRL_INTMASKBUFFER_BUFFER_WRITE_ENABLE (1 << 9) // 0x0200
+#define SD_CTRL_INTMASKBUFFER_ILLEGAL_FUNCTION (1 << 13)// 0x2000
+#define SD_CTRL_INTMASKBUFFER_CMD_BUSY (1 << 14)// 0x4000
+#define SD_CTRL_INTMASKBUFFER_ILLEGAL_ACCESS (1 << 15)// 0x8000
+
+#define SD_CTRL_DETAIL0_RESPONSE_CMD_ERROR (1 << 0) // 0x0001
+#define SD_CTRL_DETAIL0_END_BIT_ERROR_FOR_RESPONSE_NON_CMD12 (1 << 2) // 0x0004
+#define SD_CTRL_DETAIL0_END_BIT_ERROR_FOR_RESPONSE_CMD12 (1 << 3) // 0x0008
+#define SD_CTRL_DETAIL0_END_BIT_ERROR_FOR_READ_DATA (1 << 4) // 0x0010
+#define SD_CTRL_DETAIL0_END_BIT_ERROR_FOR_WRITE_CRC_STATUS (1 << 5) // 0x0020
+#define SD_CTRL_DETAIL0_CRC_ERROR_FOR_RESPONSE_NON_CMD12 (1 << 8) // 0x0100
+#define SD_CTRL_DETAIL0_CRC_ERROR_FOR_RESPONSE_CMD12 (1 << 9) // 0x0200
+#define SD_CTRL_DETAIL0_CRC_ERROR_FOR_READ_DATA (1 << 10)// 0x0400
+#define SD_CTRL_DETAIL0_CRC_ERROR_FOR_WRITE_CMD (1 << 11)// 0x0800
+
+#define SD_CTRL_DETAIL1_NO_CMD_RESPONSE (1 << 0) // 0x0001
+#define SD_CTRL_DETAIL1_TIMEOUT_READ_DATA (1 << 4) // 0x0010
+#define SD_CTRL_DETAIL1_TIMEOUT_CRS_STATUS (1 << 5) // 0x0020
+#define SD_CTRL_DETAIL1_TIMEOUT_CRC_BUSY (1 << 6) // 0x0040
+
+#define _IPAQ_ASIC3_SDIO_CTRL_Base 0x1200
+
+#define IPAQ_ASIC3_SDIO(_b, s,x) \
+ (*((volatile s *) ((_b) + _IPAQ_ASIC3_SDIO_CTRL_Base + (_IPAQ_ASIC3_SDIO_CTRL_ ## x))))
+
+#define _IPAQ_ASIC3_SDIO_CTRL_Cmd 0x00
+#define _IPAQ_ASIC3_SDIO_CTRL_CardPortSel 0x04
+#define _IPAQ_ASIC3_SDIO_CTRL_Arg0 0x08
+#define _IPAQ_ASIC3_SDIO_CTRL_Arg1 0x0C
+#define _IPAQ_ASIC3_SDIO_CTRL_TransferBlockCount 0x14
+#define _IPAQ_ASIC3_SDIO_CTRL_Response0 0x18
+#define _IPAQ_ASIC3_SDIO_CTRL_Response1 0x1C
+#define _IPAQ_ASIC3_SDIO_CTRL_Response2 0x20
+#define _IPAQ_ASIC3_SDIO_CTRL_Response3 0x24
+#define _IPAQ_ASIC3_SDIO_CTRL_Response4 0x28
+#define _IPAQ_ASIC3_SDIO_CTRL_Response5 0x2C
+#define _IPAQ_ASIC3_SDIO_CTRL_Response6 0x30
+#define _IPAQ_ASIC3_SDIO_CTRL_Response7 0x34
+#define _IPAQ_ASIC3_SDIO_CTRL_CardStatus 0x38
+#define _IPAQ_ASIC3_SDIO_CTRL_BufferCtrl 0x3C
+#define _IPAQ_ASIC3_SDIO_CTRL_IntMaskCard 0x40
+#define _IPAQ_ASIC3_SDIO_CTRL_IntMaskBuffer 0x44
+#define _IPAQ_ASIC3_SDIO_CTRL_CardXferDataLen 0x4C
+#define _IPAQ_ASIC3_SDIO_CTRL_CardOptionSetup 0x50
+#define _IPAQ_ASIC3_SDIO_CTRL_ErrorStatus0 0x54
+#define _IPAQ_ASIC3_SDIO_CTRL_ErrorStatus1 0x58
+#define _IPAQ_ASIC3_SDIO_CTRL_DataPort 0x60
+#define _IPAQ_ASIC3_SDIO_CTRL_TransactionCtrl 0x68
+#define _IPAQ_ASIC3_SDIO_CTRL_CardIntCtrl 0x6C
+#define _IPAQ_ASIC3_SDIO_CTRL_ClocknWaitCtrl 0x70
+#define _IPAQ_ASIC3_SDIO_CTRL_HostInformation 0x74
+#define _IPAQ_ASIC3_SDIO_CTRL_ErrorCtrl 0x78
+#define _IPAQ_ASIC3_SDIO_CTRL_LEDCtrl 0x7C
+#define _IPAQ_ASIC3_SDIO_CTRL_SoftwareReset 0x1C0
+
+#define IPAQ_ASIC3_SDIO_CTRL_Cmd(_b) IPAQ_ASIC3_SDIO( _b, u16, Cmd ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_CardPortSel(_b) IPAQ_ASIC3_SDIO( _b, u16, CardPortSel ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Arg0(_b) IPAQ_ASIC3_SDIO( _b, u16, Arg0 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Arg1(_b) IPAQ_ASIC3_SDIO( _b, u16, Arg1 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_TransferBlockCount(_b) IPAQ_ASIC3_SDIO( _b, u16, TransferBlockCount ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response0(_b) IPAQ_ASIC3_SDIO( _b, u16, Response0 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response1(_b) IPAQ_ASIC3_SDIO( _b, u16, Response1 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response2(_b) IPAQ_ASIC3_SDIO( _b, u16, Response2 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response3(_b) IPAQ_ASIC3_SDIO( _b, u16, Response3 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response4(_b) IPAQ_ASIC3_SDIO( _b, u16, Response4 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response5(_b) IPAQ_ASIC3_SDIO( _b, u16, Response5 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response6(_b) IPAQ_ASIC3_SDIO( _b, u16, Response6 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response7(_b) IPAQ_ASIC3_SDIO( _b, u16, Response7 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_CardStatus(_b) IPAQ_ASIC3_SDIO( _b, u16, CardStatus ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_BufferCtrl(_b) IPAQ_ASIC3_SDIO( _b, u16, BufferCtrl ) /* and error status*/
+#define IPAQ_ASIC3_SDIO_CTRL_IntMaskCard(_b) IPAQ_ASIC3_SDIO( _b, u16, IntMaskCard ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_IntMaskBuffer(_b) IPAQ_ASIC3_SDIO( _b, u16, IntMaskBuffer ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_CardXferDataLen(_b) IPAQ_ASIC3_SDIO( _b, u16, CardXferDataLen ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_CardOptionSetup(_b) IPAQ_ASIC3_SDIO( _b, u16, CardOptionSetup ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_ErrorStatus0(_b) IPAQ_ASIC3_SDIO( _b, u16, ErrorStatus0 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_ErrorStatus1(_b) IPAQ_ASIC3_SDIO( _b, u16, ErrorStatus1 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_DataPort(_b) IPAQ_ASIC3_SDIO( _b, u16, DataPort ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_TransactionCtrl(_b) IPAQ_ASIC3_SDIO( _b, u16, TransactionCtrl ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_CardIntCtrl(_b) IPAQ_ASIC3_SDIO( _b, u16, CardIntCtrl ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_ClocknWaitCtrl(_b) IPAQ_ASIC3_SDIO( _b, u16, ClocknWaitCtrl ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_HostInformation(_b) IPAQ_ASIC3_SDIO( _b, u16, HostInformation ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_ErrorCtrl(_b) IPAQ_ASIC3_SDIO( _b, u16, ErrorCtrl ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_LEDCtrl(_b) IPAQ_ASIC3_SDIO( _b, u16, LEDCtrl ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_SoftwareReset(_b) IPAQ_ASIC3_SDIO( _b, u16, SoftwareReset ) /* */
+
+#define IPAQ_ASIC3_MAP_SIZE 0x2000
+
+#endif
Index: linux-2.6.22/include/linux/backlight.h
===================================================================
--- linux-2.6.22.orig/include/linux/backlight.h 2007-09-11 12:53:26.000000000 +0200
+++ linux-2.6.22/include/linux/backlight.h 2007-09-11 12:53:37.000000000 +0200
@@ -92,4 +92,11 @@
return dev_get_drvdata(&bl_dev->dev);
}
+struct generic_bl_info {
+ int max_intensity;
+ int default_intensity;
+ int limit_mask;
+ void (*set_bl_intensity)(int intensity);
+};
+
#endif
Index: linux-2.6.22/include/linux/gpiodev.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/include/linux/gpiodev.h 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,44 @@
+#ifndef __GPIODEV_H
+#define __GPIODEV_H
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/gpio.h>
+
+/* Interface */
+
+/* This structure must be first member of device platform_data structure
+ of a device which provides gpiodev interface. All method pointers
+ must be non-NULL, so stubs must be used for non-implemented ones. */
+struct gpiodev_ops {
+ int (*get)(struct device *this, unsigned gpio_no);
+ void (*set)(struct device *this, unsigned gpio_no, int val);
+ int (*to_irq)(struct device *this, unsigned gpio_no);
+};
+
+/* Generalized GPIO structure */
+
+struct gpio {
+ struct device *gpio_dev;
+ unsigned gpio_no;
+};
+
+/* API functions */
+
+static inline int gpiodev_get_value(struct gpio *gpio)
+{
+ struct gpiodev_ops *ops = gpio->gpio_dev->platform_data;
+ return ops->get(gpio->gpio_dev, gpio->gpio_no);
+}
+static inline void gpiodev_set_value(struct gpio *gpio, int val)
+{
+ struct gpiodev_ops *ops = gpio->gpio_dev->platform_data;
+ ops->set(gpio->gpio_dev, gpio->gpio_no, val);
+}
+static inline int gpiodev_to_irq(struct gpio *gpio)
+{
+ struct gpiodev_ops *ops = gpio->gpio_dev->platform_data;
+ return ops->to_irq(gpio->gpio_dev, gpio->gpio_no);
+}
+
+#endif /* __GPIODEV_H */
Index: linux-2.6.22/include/linux/input_pda.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/include/linux/input_pda.h 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,47 @@
+#ifndef _INPUT_PDA_H
+#define _INPUT_PDA_H
+
+/*
+ * This is temporary virtual button key codes map
+ * for keyboardless handheld computers.
+ * Its purpose is to provide map common to all devices
+ * and known to work with current software and its bugs
+ * and misfeatures. Once issues with the software are
+ * solved, codes from input.h will be used directly
+ * (missing key definitions will be added).
+ */
+
+/* Some directly usable keycodes:
+KEY_POWER - Power/suspend button
+KEY_ENTER - Enter/Action/Central button on joypad
+KEY_UP
+KEY_DOWN
+KEY_LEFT
+KEY_RIGHT
+*/
+
+/* XXX Instead of using any values in include/linux/input.h, we have to use
+ use values < 128 due to some munging that kdrive does to get keystrokes.
+ When kdrive gets its key events from evdev instead of the console,
+ we should be able to switch to using input.h values and get rid of
+ xmodmap. */
+
+#define _KEY_APP1 KEY_F9 // xmodmap sees 67 + 8 = 75
+#define _KEY_APP2 KEY_F10 // xmodmap 76
+#define _KEY_APP3 KEY_F11 // xmodmap 95
+#define _KEY_APP4 KEY_F12 // xmodmap 96
+
+#define _KEY_RECORD KEY_RO
+
+/* It is highly recommended to use exactly 4 codes above for
+ 4 buttons the device has. This will ensure that console and
+ framebuffer applications (e.g. games) will work ok on all
+ devices. If you'd like more distinguishable names, following
+ convenience defines are provided, suiting many devices. */
+
+#define _KEY_CALENDAR _KEY_APP1
+#define _KEY_CONTACTS _KEY_APP2
+#define _KEY_MAIL _KEY_APP3
+#define _KEY_HOMEPAGE _KEY_APP4
+
+#endif
Index: linux-2.6.22/include/linux/soc/asic3_base.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/include/linux/soc/asic3_base.h 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,104 @@
+#include <asm/types.h>
+#include <linux/gpiodev.h>
+
+/* Private API - for ASIC3 devices internal use only */
+#define HDR_IPAQ_ASIC3_ACTION(ACTION,action,fn,FN) \
+u32 asic3_get_gpio_ ## action ## _ ## fn (struct device *dev); \
+void asic3_set_gpio_ ## action ## _ ## fn (struct device *dev, u32 bits, u32 val);
+
+#define HDR_IPAQ_ASIC3_FN(fn,FN) \
+ HDR_IPAQ_ASIC3_ACTION ( MASK,mask,fn,FN) \
+ HDR_IPAQ_ASIC3_ACTION ( DIR, dir, fn, FN) \
+ HDR_IPAQ_ASIC3_ACTION ( OUT, out, fn, FN) \
+ HDR_IPAQ_ASIC3_ACTION ( LEVELTRI, trigtype, fn, FN) \
+ HDR_IPAQ_ASIC3_ACTION ( RISING, rising, fn, FN) \
+ HDR_IPAQ_ASIC3_ACTION ( LEVEL, triglevel, fn, FN) \
+ HDR_IPAQ_ASIC3_ACTION ( SLEEP_MASK, sleepmask, fn, FN) \
+ HDR_IPAQ_ASIC3_ACTION ( SLEEP_OUT, sleepout, fn, FN) \
+ HDR_IPAQ_ASIC3_ACTION ( BATT_FAULT_OUT, battfaultout, fn, FN) \
+ HDR_IPAQ_ASIC3_ACTION ( INT_STATUS, intstatus, fn, FN) \
+ HDR_IPAQ_ASIC3_ACTION ( ALT_FUNCTION, alt_fn, fn, FN) \
+ HDR_IPAQ_ASIC3_ACTION ( SLEEP_CONF, sleepconf, fn, FN) \
+ HDR_IPAQ_ASIC3_ACTION ( STATUS, status, fn, FN)
+
+/* Public API */
+
+#define ASIC3_GPIOA_IRQ_BASE 0
+#define ASIC3_GPIOB_IRQ_BASE 16
+#define ASIC3_GPIOC_IRQ_BASE 32
+#define ASIC3_GPIOD_IRQ_BASE 48
+#define ASIC3_LED0_IRQ 64
+#define ASIC3_LED1_IRQ 65
+#define ASIC3_LED2_IRQ 66
+#define ASIC3_SPI_IRQ 67
+#define ASIC3_SMBUS_IRQ 68
+#define ASIC3_OWM_IRQ 69
+
+#define ASIC3_NR_GPIO_IRQS 64 /* 16 bits each GPIO A...D banks */
+#define ASIC3_NR_IRQS (ASIC3_OWM_IRQ + 1)
+
+extern int asic3_irq_base(struct device *dev);
+
+extern void asic3_write_register(struct device *dev, unsigned int reg,
+ u32 value);
+extern u32 asic3_read_register(struct device *dev, unsigned int reg);
+
+/* old clock api */
+extern void asic3_set_clock_sel(struct device *dev, u32 bits, u32 val);
+extern u32 asic3_get_clock_cdex(struct device *dev);
+extern void asic3_set_clock_cdex(struct device *dev, u32 bits, u32 val);
+
+extern void asic3_set_extcf_select(struct device *dev, u32 bits, u32 val);
+extern void asic3_set_extcf_reset(struct device *dev, u32 bits, u32 val);
+extern void asic3_set_sdhwctrl(struct device *dev, u32 bits, u32 val);
+
+extern void asic3_set_led(struct device *dev, int led_num, int duty_time,
+ int cycle_time, int timebase);
+
+extern int asic3_register_mmc(struct device *dev);
+extern int asic3_unregister_mmc(struct device *dev);
+
+/* Accessors for GPIO banks */
+HDR_IPAQ_ASIC3_FN(a, A)
+HDR_IPAQ_ASIC3_FN(b, B)
+HDR_IPAQ_ASIC3_FN(c, C)
+HDR_IPAQ_ASIC3_FN(d, D)
+
+#define _IPAQ_ASIC3_GPIO_BANK_A 0
+#define _IPAQ_ASIC3_GPIO_BANK_B 1
+#define _IPAQ_ASIC3_GPIO_BANK_C 2
+#define _IPAQ_ASIC3_GPIO_BANK_D 3
+
+#define ASIC3_GPIO_bit(gpio) (1 << (gpio & 0xf))
+
+extern int asic3_get_gpio_bit(struct device *dev, int gpio);
+extern void asic3_set_gpio_bit(struct device *dev, int gpio, int val);
+extern int asic3_gpio_get_value(struct device *dev, unsigned gpio);
+extern void asic3_gpio_set_value(struct device *dev, unsigned gpio, int val);
+
+
+struct tmio_mmc_hwconfig;
+
+struct asic3_platform_data
+{
+ // Must be first member
+ struct gpiodev_ops gpiodev_ops;
+
+ struct {
+ u32 dir;
+ u32 init;
+ u32 sleep_mask;
+ u32 sleep_out;
+ u32 batt_fault_out;
+ u32 sleep_conf;
+ u32 alt_function;
+ } gpio_a, gpio_b, gpio_c, gpio_d;
+
+ int irq_base;
+ unsigned int bus_shift;
+
+ struct platform_device **child_platform_devs;
+ int num_child_platform_devs;
+
+ struct tmio_mmc_hwconfig *tmio_mmc_hwconfig;
+};
Index: linux-2.6.22/include/linux/soc/tmio_mmc.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/include/linux/soc/tmio_mmc.h 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,17 @@
+#include <linux/platform_device.h>
+
+#define MMC_CLOCK_DISABLED 0
+#define MMC_CLOCK_ENABLED 1
+
+#define TMIO_WP_ALWAYS_RW ((void*)-1)
+
+struct tmio_mmc_hwconfig {
+ void (*hwinit)(struct platform_device *sdev);
+ void (*set_mmc_clock)(struct platform_device *sdev, int state);
+
+ /* NULL - use ASIC3 signal,
+ TMIO_WP_ALWAYS_RW - assume always R/W (e.g. miniSD)
+ otherwise - machine-specific handler */
+ int (*mmc_get_ro)(struct platform_device *pdev);
+ short address_shift;
+};
Index: linux-2.6.22/include/asm-arm/arch-pxa/pxa-regs.h
===================================================================
--- linux-2.6.22.orig/include/asm-arm/arch-pxa/pxa-regs.h 2007-09-11 12:53:34.000000000 +0200
+++ linux-2.6.22/include/asm-arm/arch-pxa/pxa-regs.h 2007-09-11 12:53:37.000000000 +0200
@@ -2043,6 +2043,8 @@
#define LDCMD_SOFINT (1 << 22)
#define LDCMD_EOFINT (1 << 21)
+#define LCCR4_13M_PCD_EN (1<<25) /* 13M PCD enable */
+#define LCCR4_PCDDIV (1<<31) /* PCD selection */
#define LCCR5_SOFM1 (1<<0) /* Start Of Frame Mask for Overlay 1 (channel 1) */
#define LCCR5_SOFM2 (1<<1) /* Start Of Frame Mask for Overlay 2 (channel 2) */
Index: linux-2.6.22/drivers/mmc/host/Kconfig
===================================================================
--- linux-2.6.22.orig/drivers/mmc/host/Kconfig 2007-07-09 01:32:17.000000000 +0200
+++ linux-2.6.22/drivers/mmc/host/Kconfig 2007-09-11 12:53:37.000000000 +0200
@@ -100,3 +100,9 @@
To compile this driver as a module, choose M here: the
module will be called tifm_sd.
+config MMC_ASIC3
+ tristate "HTC ASIC3 SD/MMC support"
+ depends on MMC && HTC_ASIC3
+ help
+ This provides support for the ASIC3 SD/MMC controller, used
+ in the iPAQ hx4700 and others.
Index: linux-2.6.22/drivers/mmc/host/Makefile
===================================================================
--- linux-2.6.22.orig/drivers/mmc/host/Makefile 2007-07-09 01:32:17.000000000 +0200
+++ linux-2.6.22/drivers/mmc/host/Makefile 2007-09-11 12:53:37.000000000 +0200
@@ -15,4 +15,4 @@
obj-$(CONFIG_MMC_OMAP) += omap.o
obj-$(CONFIG_MMC_AT91) += at91_mci.o
obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
-
+obj-$(CONFIG_MMC_ASIC3) += asic3_mmc.o
Index: linux-2.6.22/drivers/mmc/host/asic3_mmc.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/drivers/mmc/host/asic3_mmc.c 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,900 @@
+/* Note that this driver can likely be merged into the tmio driver, so
+ * consider this code temporary. It works, though.
+ */
+/*
+ * linux/drivers/mmc/asic3_mmc.c
+ *
+ * Copyright (c) 2005 SDG Systems, LLC
+ *
+ * based on tmio_mmc.c
+ * Copyright (C) 2004 Ian Molton
+ *
+ * Refactored to support all ASIC3 devices, 2006 Paul Sokolovsky
+ *
+ * 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.
+ *
+ * Driver for the SD / SDIO cell found in:
+ *
+ * TC6393XB
+ *
+ * This driver draws mainly on scattered spec sheets, Reverse engineering
+ * of the toshiba e800 SD driver and some parts of the 2.4 ASIC3 driver (4 bit
+ * support).
+ *
+ * Supports MMC 1 bit transfers and SD 1 and 4 bit modes.
+ *
+ * TODO:
+ * Eliminate FIXMEs
+ * SDIO support
+ * Power management
+ * Handle MMC errors (at all)
+ *
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+//#include <linux/mmc/protocol.h>
+#include <linux/mmc/sd.h>
+#include <linux/scatterlist.h>
+//#include <linux/soc-old.h>
+#include <linux/soc/asic3_base.h>
+#include <linux/soc/tmio_mmc.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <linux/clk.h>
+#include <asm/mach-types.h>
+
+#include <asm/hardware/ipaq-asic3.h>
+#include "asic3_mmc.h"
+
+struct asic3_mmc_host {
+ void *ctl_base;
+ struct device *asic3_dev; /* asic3 device */
+ struct tmio_mmc_hwconfig *hwconfig; /* HW config data/handlers, guaranteed != NULL */
+ unsigned long bus_shift;
+ struct mmc_command *cmd;
+ struct mmc_request *mrq;
+ struct mmc_data *data;
+ struct mmc_host *mmc;
+ int irq;
+ unsigned short clock_for_sd;
+
+ /* I/O related stuff */
+ struct scatterlist *sg_ptr;
+ unsigned int sg_len;
+ unsigned int sg_off;
+};
+
+static void
+mmc_finish_request(struct asic3_mmc_host *host)
+{
+ struct mmc_request *mrq = host->mrq;
+
+ /* Write something to end the command */
+ host->mrq = NULL;
+ host->cmd = NULL;
+ host->data = NULL;
+
+ mmc_request_done(host->mmc, mrq);
+}
+
+
+#define ASIC3_MMC_REG(host, block, reg) (*((volatile u16 *) ((host->ctl_base) + ((_IPAQ_ASIC3_## block ## _Base + _IPAQ_ASIC3_ ## block ## _ ## reg) >> (2 - host->bus_shift))) ))
+
+static void
+mmc_start_command(struct asic3_mmc_host *host, struct mmc_command *cmd)
+{
+ struct mmc_data *data = host->data;
+ int c = cmd->opcode;
+
+ DBG("Opcode: %d, base: %p\n", cmd->opcode, host->ctl_base);
+
+ if(cmd->opcode == MMC_STOP_TRANSMISSION) {
+ ASIC3_MMC_REG(host, SD_CTRL, StopInternal) = SD_CTRL_STOP_INTERNAL_ISSSUE_CMD12;
+ cmd->resp[0] = cmd->opcode;
+ cmd->resp[1] = 0;
+ cmd->resp[2] = 0;
+ cmd->resp[3] = 0;
+ cmd->resp[4] = 0;
+ return;
+ }
+
+ switch(cmd->flags & 0x1f) {
+ case MMC_RSP_NONE: c |= SD_CTRL_COMMAND_RESPONSE_TYPE_NORMAL; break;
+ case MMC_RSP_R1: c |= SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R1; break;
+ case MMC_RSP_R1B: c |= SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R1B; break;
+ case MMC_RSP_R2: c |= SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R2; break;
+ case MMC_RSP_R3: c |= SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R3; break;
+ default:
+ DBG("Unknown response type %d\n", cmd->flags & 0x1f);
+ break;
+ }
+
+ host->cmd = cmd;
+
+ if(cmd->opcode == MMC_APP_CMD) {
+ c |= APP_CMD;
+ }
+ if (cmd->opcode == MMC_GO_IDLE_STATE) {
+ c |= (3 << 8); /* This was removed from ipaq-asic3.h for some reason */
+ }
+ if(data) {
+ c |= SD_CTRL_COMMAND_DATA_PRESENT;
+ if(data->blocks > 1) {
+ ASIC3_MMC_REG(host, SD_CTRL, StopInternal) = SD_CTRL_STOP_INTERNAL_AUTO_ISSUE_CMD12;
+ c |= SD_CTRL_COMMAND_MULTI_BLOCK;
+ }
+ if(data->flags & MMC_DATA_READ) {
+ c |= SD_CTRL_COMMAND_TRANSFER_READ;
+ }
+ /* MMC_DATA_WRITE does not require a bit to be set */
+ }
+
+ /* Enable the command and data interrupts */
+ ASIC3_MMC_REG(host, SD_CTRL, IntMaskCard) = ~(
+ SD_CTRL_INTMASKCARD_RESPONSE_END
+ | SD_CTRL_INTMASKCARD_RW_END
+ | SD_CTRL_INTMASKCARD_CARD_REMOVED_0
+ | SD_CTRL_INTMASKCARD_CARD_INSERTED_0
+#if 0
+ | SD_CTRL_INTMASKCARD_CARD_REMOVED_3
+ | SD_CTRL_INTMASKCARD_CARD_INSERTED_3
+#endif
+ );
+
+ ASIC3_MMC_REG(host, SD_CTRL, IntMaskBuffer) = ~(
+ SD_CTRL_INTMASKBUFFER_UNK7
+ | SD_CTRL_INTMASKBUFFER_CMD_BUSY
+#if 0
+ | SD_CTRL_INTMASKBUFFER_CMD_INDEX_ERROR
+ | SD_CTRL_INTMASKBUFFER_CRC_ERROR
+ | SD_CTRL_INTMASKBUFFER_STOP_BIT_END_ERROR
+ | SD_CTRL_INTMASKBUFFER_DATA_TIMEOUT
+ | SD_CTRL_INTMASKBUFFER_BUFFER_OVERFLOW
+ | SD_CTRL_INTMASKBUFFER_BUFFER_UNDERFLOW
+ | SD_CTRL_INTMASKBUFFER_CMD_TIMEOUT
+ | SD_CTRL_INTMASKBUFFER_BUFFER_READ_ENABLE
+ | SD_CTRL_INTMASKBUFFER_BUFFER_WRITE_ENABLE
+ | SD_CTRL_INTMASKBUFFER_ILLEGAL_ACCESS
+#endif
+ );
+
+ /* Send the command */
+ ASIC3_MMC_REG(host, SD_CTRL, Arg1) = cmd->arg >> 16;
+ ASIC3_MMC_REG(host, SD_CTRL, Arg0) = cmd->arg & 0xffff;
+ ASIC3_MMC_REG(host, SD_CTRL, Cmd) = c;
+}
+
+/* This chip always returns (at least?) as much data as you ask for. I'm
+ * unsure what happens if you ask for less than a block. This should be looked
+ * into to ensure that a funny length read doesnt mess up the controller data
+ * state machine.
+ *
+ * Aric: Statement above may not apply to ASIC3.
+ *
+ * FIXME - this chip cannot do 1 and 2 byte data requests in 4 bit mode
+ *
+ * Aric: Statement above may not apply to ASIC3.
+ */
+
+static struct tasklet_struct mmc_data_read_tasklet;
+
+static void
+mmc_data_transfer(unsigned long h)
+{
+ struct asic3_mmc_host *host = (struct asic3_mmc_host *)h;
+ struct mmc_data *data = host->data;
+ unsigned short *buf;
+ int count;
+ /* unsigned long flags; */
+
+ if(!data){
+ printk(KERN_WARNING DRIVER_NAME ": Spurious Data IRQ\n");
+ return;
+ }
+
+ /* local_irq_save(flags); */
+ /* buf = kmap_atomic(host->sg_ptr->page, KM_BIO_SRC_IRQ); */
+ buf = kmap(host->sg_ptr->page);
+ buf += host->sg_ptr->offset/2 + host->sg_off/2;
+
+ /*
+ * Ensure we dont read more than one block. The chip will interrupt us
+ * When the next block is available.
+ */
+ count = host->sg_ptr->length - host->sg_off;
+ if(count > data->blksz) {
+ count = data->blksz;
+ }
+
+ DBG("count: %08x, page: %p, offset: %08x flags %08x\n",
+ count, host->sg_ptr->page, host->sg_off, data->flags);
+
+ host->sg_off += count;
+
+ /* Transfer the data */
+ if(data->flags & MMC_DATA_READ) {
+ while(count > 0) {
+ /* Read two bytes from SD/MMC controller. */
+ *buf = ASIC3_MMC_REG(host, SD_CTRL, DataPort);
+ buf++;
+ count -= 2;
+ }
+ //flush_dcache_page(host->sg_ptr->page);
+ } else {
+ while(count > 0) {
+ /* Write two bytes to SD/MMC controller. */
+ ASIC3_MMC_REG(host, SD_CTRL, DataPort) = *buf;
+ buf++;
+ count -= 2;
+ }
+ }
+
+ /* kunmap_atomic(host->sg_ptr->page, KM_BIO_SRC_IRQ); */
+ kunmap(host->sg_ptr->page);
+ /* local_irq_restore(flags); */
+ if(host->sg_off == host->sg_ptr->length) {
+ host->sg_ptr++;
+ host->sg_off = 0;
+ --host->sg_len;
+ }
+
+ return;
+}
+
+static void
+mmc_data_end_irq(struct asic3_mmc_host *host)
+{
+ struct mmc_data *data = host->data;
+
+ host->data = NULL;
+
+ if(!data){
+ printk(KERN_WARNING DRIVER_NAME ": Spurious data end IRQ\n");
+ return;
+ }
+
+ if (data->error == MMC_ERR_NONE) {
+ data->bytes_xfered = data->blocks * data->blksz;
+ } else {
+ data->bytes_xfered = 0;
+ }
+
+ DBG("Completed data request\n");
+
+ ASIC3_MMC_REG(host, SD_CTRL, StopInternal) = 0;
+
+ /* Make sure read enable interrupt and write enable interrupt are disabled */
+ if(data->flags & MMC_DATA_READ) {
+ ASIC3_MMC_REG(host, SD_CTRL, IntMaskBuffer) |= SD_CTRL_INTMASKBUFFER_BUFFER_READ_ENABLE;
+ } else {
+ ASIC3_MMC_REG(host, SD_CTRL, IntMaskBuffer) |= SD_CTRL_INTMASKBUFFER_BUFFER_WRITE_ENABLE;
+ }
+
+ mmc_finish_request(host);
+}
+
+static void
+mmc_cmd_irq(struct asic3_mmc_host *host, unsigned int buffer_stat)
+{
+ struct mmc_command *cmd = host->cmd;
+ u8 *buf = (u8 *)cmd->resp;
+ u16 data;
+
+ if(!host->cmd) {
+ printk(KERN_WARNING DRIVER_NAME ": Spurious CMD irq\n");
+ return;
+ }
+
+ host->cmd = NULL;
+ if(cmd->flags & MMC_RSP_PRESENT && cmd->flags & MMC_RSP_136) {
+ /* R2 */
+ buf[12] = 0xff;
+ data = ASIC3_MMC_REG(host, SD_CTRL, Response0);
+ buf[13] = data & 0xff;
+ buf[14] = data >> 8;
+ data = ASIC3_MMC_REG(host, SD_CTRL, Response1);
+ buf[15] = data & 0xff;
+ buf[8] = data >> 8;
+ data = ASIC3_MMC_REG(host, SD_CTRL, Response2);
+ buf[9] = data & 0xff;
+ buf[10] = data >> 8;
+ data = ASIC3_MMC_REG(host, SD_CTRL, Response3);
+ buf[11] = data & 0xff;
+ buf[4] = data >> 8;
+ data = ASIC3_MMC_REG(host, SD_CTRL, Response4);
+ buf[5] = data & 0xff;
+ buf[6] = data >> 8;
+ data = ASIC3_MMC_REG(host, SD_CTRL, Response5);
+ buf[7] = data & 0xff;
+ buf[0] = data >> 8;
+ data = ASIC3_MMC_REG(host, SD_CTRL, Response6);
+ buf[1] = data & 0xff;
+ buf[2] = data >> 8;
+ data = ASIC3_MMC_REG(host, SD_CTRL, Response7);
+ buf[3] = data & 0xff;
+ } else if(cmd->flags & MMC_RSP_PRESENT) {
+ /* R1, R1B, R3 */
+ data = ASIC3_MMC_REG(host, SD_CTRL, Response0);
+ buf[0] = data & 0xff;
+ buf[1] = data >> 8;
+ data = ASIC3_MMC_REG(host, SD_CTRL, Response1);
+ buf[2] = data & 0xff;
+ buf[3] = data >> 8;
+ }
+ DBG("Response: %08x %08x %08x %08x\n", cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
+
+ if(buffer_stat & SD_CTRL_BUFFERSTATUS_CMD_TIMEOUT) {
+ cmd->error = MMC_ERR_TIMEOUT;
+ } else if((buffer_stat & SD_CTRL_BUFFERSTATUS_CRC_ERROR) && (cmd->flags & MMC_RSP_CRC)) {
+ cmd->error = MMC_ERR_BADCRC;
+ } else if(buffer_stat &
+ (
+ SD_CTRL_BUFFERSTATUS_ILLEGAL_ACCESS
+ | SD_CTRL_BUFFERSTATUS_CMD_INDEX_ERROR
+ | SD_CTRL_BUFFERSTATUS_STOP_BIT_END_ERROR
+ | SD_CTRL_BUFFERSTATUS_BUFFER_OVERFLOW
+ | SD_CTRL_BUFFERSTATUS_BUFFER_UNDERFLOW
+ | SD_CTRL_BUFFERSTATUS_DATA_TIMEOUT
+ )
+ ) {
+ DBG("Buffer status ERROR 0x%04x - inside check buffer\n", buffer_stat);
+ DBG("detail0 error status 0x%04x\n", ASIC3_MMC_REG(host, SD_CTRL, ErrorStatus0));
+ DBG("detail1 error status 0x%04x\n", ASIC3_MMC_REG(host, SD_CTRL, ErrorStatus1));
+ cmd->error = MMC_ERR_FAILED;
+ }
+
+ if(cmd->error == MMC_ERR_NONE) {
+ switch (cmd->opcode) {
+ case SD_APP_SET_BUS_WIDTH:
+ if(cmd->arg == SD_BUS_WIDTH_4) {
+ host->clock_for_sd = SD_CTRL_CARDCLOCKCONTROL_FOR_SD_CARD;
+ ASIC3_MMC_REG(host, SD_CTRL, MemCardOptionSetup) =
+ MEM_CARD_OPTION_REQUIRED
+ | MEM_CARD_OPTION_DATA_RESPONSE_TIMEOUT(14)
+ | MEM_CARD_OPTION_C2_MODULE_NOT_PRESENT
+ | MEM_CARD_OPTION_DATA_XFR_WIDTH_4;
+ } else {
+ host->clock_for_sd = 0;
+ ASIC3_MMC_REG(host, SD_CTRL, MemCardOptionSetup) =
+ MEM_CARD_OPTION_REQUIRED
+ | MEM_CARD_OPTION_DATA_RESPONSE_TIMEOUT(14)
+ | MEM_CARD_OPTION_C2_MODULE_NOT_PRESENT
+ | MEM_CARD_OPTION_DATA_XFR_WIDTH_1;
+ }
+ break;
+ case MMC_SELECT_CARD:
+ if((cmd->arg >> 16) == 0) {
+ /* We have been deselected. */
+ ASIC3_MMC_REG(host, SD_CTRL, MemCardOptionSetup) =
+ MEM_CARD_OPTION_REQUIRED
+ | MEM_CARD_OPTION_DATA_RESPONSE_TIMEOUT(14)
+ | MEM_CARD_OPTION_C2_MODULE_NOT_PRESENT
+ | MEM_CARD_OPTION_DATA_XFR_WIDTH_1;
+ }
+ }
+ }
+
+ /*
+ * If there is data to handle we enable data IRQs here, and we will
+ * ultimatley finish the request in the mmc_data_end_irq handler.
+ */
+ if(host->data && (cmd->error == MMC_ERR_NONE)){
+ if(host->data->flags & MMC_DATA_READ) {
+ /* Enable the read enable interrupt */
+ ASIC3_MMC_REG(host, SD_CTRL, IntMaskBuffer) &=
+ ~SD_CTRL_INTMASKBUFFER_BUFFER_READ_ENABLE;
+ } else {
+ /* Enable the write enable interrupt */
+ ASIC3_MMC_REG(host, SD_CTRL, IntMaskBuffer) &=
+ ~SD_CTRL_INTMASKBUFFER_BUFFER_WRITE_ENABLE;
+ }
+ } else {
+ /* There's no data, or we encountered an error, so finish now. */
+ mmc_finish_request(host);
+ }
+
+ return;
+}
+
+static void hwinit2_irqsafe(struct asic3_mmc_host *host);
+
+static irqreturn_t
+mmc_irq(int irq, void *irq_desc)
+{
+ struct asic3_mmc_host *host;
+ unsigned int breg, bmask, bstatus, creg, cmask, cstatus;
+
+ host = irq_desc;
+
+ /* asic3 bstatus has errors */
+ bstatus = ASIC3_MMC_REG(host, SD_CTRL, BufferCtrl);
+ bmask = ASIC3_MMC_REG(host, SD_CTRL, IntMaskBuffer);
+ cstatus = ASIC3_MMC_REG(host, SD_CTRL, CardStatus);
+ cmask = ASIC3_MMC_REG(host, SD_CTRL, IntMaskCard);
+ breg = bstatus & ~bmask & ~DONT_CARE_BUFFER_BITS;
+ creg = cstatus & ~cmask & ~DONT_CARE_CARD_BITS;
+
+ if (!breg && !creg) {
+ /* This occurs sometimes for no known reason. It doesn't hurt
+ * anything, so I don't print it. */
+ ASIC3_MMC_REG(host, SD_CTRL, IntMaskBuffer) &= ~breg;
+ ASIC3_MMC_REG(host, SD_CTRL, IntMaskCard) &= ~creg;
+ goto out;
+ }
+
+ while (breg || creg) {
+
+ /* XXX TODO: Need to handle errors in breg here. */
+
+ /*
+ * Card insert/remove. The mmc controlling code is stateless. That
+ * is, it doesn't care if it was an insert or a remove. It treats
+ * both the same.
+ */
+ /* XXX Asic3 has _3 versions of these status bits, too, for a second slot, perhaps? */
+ if (creg & (SD_CTRL_CARDSTATUS_CARD_INSERTED_0 | SD_CTRL_CARDSTATUS_CARD_REMOVED_0)) {
+ ASIC3_MMC_REG(host, SD_CTRL, CardStatus) &=
+ ~(SD_CTRL_CARDSTATUS_CARD_REMOVED_0 | SD_CTRL_CARDSTATUS_CARD_INSERTED_0);
+ if(creg & SD_CTRL_CARDSTATUS_CARD_INSERTED_0) {
+ hwinit2_irqsafe(host);
+ }
+ mmc_detect_change(host->mmc,1);
+ }
+
+ /* Command completion */
+ if (creg & SD_CTRL_CARDSTATUS_RESPONSE_END) {
+ ASIC3_MMC_REG(host, SD_CTRL, CardStatus) &=
+ ~(SD_CTRL_CARDSTATUS_RESPONSE_END);
+ mmc_cmd_irq(host, bstatus);
+ }
+
+ /* Data transfer */
+ if (breg & (SD_CTRL_BUFFERSTATUS_BUFFER_READ_ENABLE | SD_CTRL_BUFFERSTATUS_BUFFER_WRITE_ENABLE)) {
+ ASIC3_MMC_REG(host, SD_CTRL, BufferCtrl) &=
+ ~(SD_CTRL_BUFFERSTATUS_BUFFER_WRITE_ENABLE | SD_CTRL_BUFFERSTATUS_BUFFER_READ_ENABLE);
+ tasklet_schedule(&mmc_data_read_tasklet);
+ }
+
+ /* Data transfer completion */
+ if (creg & SD_CTRL_CARDSTATUS_RW_END) {
+ ASIC3_MMC_REG(host, SD_CTRL, CardStatus) &= ~(SD_CTRL_CARDSTATUS_RW_END);
+ mmc_data_end_irq(host);
+ }
+
+ /* Check status - keep going until we've handled it all */
+ bstatus = ASIC3_MMC_REG(host, SD_CTRL, BufferCtrl);
+ bmask = ASIC3_MMC_REG(host, SD_CTRL, IntMaskBuffer);
+ cstatus = ASIC3_MMC_REG(host, SD_CTRL, CardStatus);
+ cmask = ASIC3_MMC_REG(host, SD_CTRL, IntMaskCard);
+ breg = bstatus & ~bmask & ~DONT_CARE_BUFFER_BITS;
+ creg = cstatus & ~cmask & ~DONT_CARE_CARD_BITS;
+ }
+
+out:
+ /* Ensure all interrupt sources are cleared */
+ ASIC3_MMC_REG(host, SD_CTRL, BufferCtrl) = 0;
+ ASIC3_MMC_REG(host, SD_CTRL, CardStatus) = 0;
+ return IRQ_HANDLED;
+}
+
+static void
+mmc_start_data(struct asic3_mmc_host *host, struct mmc_data *data)
+{
+ DBG("setup data transfer: blocksize %08x nr_blocks %d, page: %08x, offset: %08x\n", data->blksz,
+ data->blocks, (int)data->sg->page, data->sg->offset);
+
+ host->sg_len = data->sg_len;
+ host->sg_ptr = data->sg;
+ host->sg_off = 0;
+ host->data = data;
+
+ /* Set transfer length and blocksize */
+ ASIC3_MMC_REG(host, SD_CTRL, TransferSectorCount) = data->blocks;
+ ASIC3_MMC_REG(host, SD_CTRL, MemCardXferDataLen) = data->blksz;
+}
+
+/* Process requests from the MMC layer */
+static void
+mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct asic3_mmc_host *host = mmc_priv(mmc);
+
+ WARN_ON(host->mrq != NULL);
+
+ host->mrq = mrq;
+
+ /* If we're performing a data request we need to setup some
+ extra information */
+ if(mrq->data) {
+ mmc_start_data(host, mrq->data);
+ }
+
+ mmc_start_command(host, mrq->cmd);
+}
+
+/* Set MMC clock / power.
+ * Note: This controller uses a simple divider scheme therefore it cannot run
+ * a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as MMC
+ * wont run that fast, it has to be clocked at 12MHz which is the next slowest
+ * setting. This is likely not an issue because we are doing single 16-bit
+ * writes for data I/O.
+ */
+static void
+mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct asic3_mmc_host *host = mmc_priv(mmc);
+ u32 clk = 0;
+
+ DBG("clock %uHz busmode %u powermode %u Vdd %u\n",
+ ios->clock, ios->bus_mode, ios->power_mode, ios->vdd);
+
+ if (ios->clock) {
+ clk = 0x80; /* slowest by default */
+ if(ios->clock >= 24000000 / 256) clk >>= 1;
+ if(ios->clock >= 24000000 / 128) clk >>= 1;
+ if(ios->clock >= 24000000 / 64) clk >>= 1;
+ if(ios->clock >= 24000000 / 32) clk >>= 1;
+ if(ios->clock >= 24000000 / 16) clk >>= 1;
+ if(ios->clock >= 24000000 / 8) clk >>= 1;
+ if(ios->clock >= 24000000 / 4) clk >>= 1;
+ if(ios->clock >= 24000000 / 2) clk >>= 1;
+ if(ios->clock >= 24000000 / 1) clk >>= 1;
+ if(clk == 0) { /* For fastest speed we disable the divider. */
+ ASIC3_MMC_REG(host, SD_CONFIG, ClockMode) = 0;
+ } else {
+ ASIC3_MMC_REG(host, SD_CONFIG, ClockMode) = 1;
+ }
+ ASIC3_MMC_REG(host, SD_CTRL, CardClockCtrl) = 0;
+ ASIC3_MMC_REG(host, SD_CTRL, CardClockCtrl) =
+ host->clock_for_sd
+ | SD_CTRL_CARDCLOCKCONTROL_ENABLE_CLOCK
+ | clk;
+ msleep(10);
+ } else {
+ ASIC3_MMC_REG(host, SD_CTRL, CardClockCtrl) = 0;
+ }
+
+ switch (ios->power_mode) {
+ case MMC_POWER_OFF:
+ ASIC3_MMC_REG(host, SD_CONFIG, SDHC_Power1) = 0;
+ msleep(1);
+ break;
+ case MMC_POWER_UP:
+ break;
+ case MMC_POWER_ON:
+ ASIC3_MMC_REG(host, SD_CONFIG, SDHC_Power1) = SD_CONFIG_POWER1_PC_33V;
+ msleep(20);
+ break;
+ }
+}
+
+static int
+mmc_get_ro(struct mmc_host *mmc)
+{
+ struct asic3_mmc_host *host = mmc_priv(mmc);
+
+ /* Call custom handler for RO status */
+ if(host->hwconfig->mmc_get_ro) {
+ /* Special case for cards w/o WP lock (like miniSD) */
+ if (host->hwconfig->mmc_get_ro == (void*)-1) {
+ return 0;
+ } else {
+ struct platform_device *pdev = to_platform_device(mmc_dev(mmc));
+ return host->hwconfig->mmc_get_ro(pdev);
+ }
+ }
+
+ /* WRITE_PROTECT is active low */
+ return (ASIC3_MMC_REG(host, SD_CTRL, CardStatus) & SD_CTRL_CARDSTATUS_WRITE_PROTECT)?0:1;
+}
+
+static struct mmc_host_ops mmc_ops = {
+ .request = mmc_request,
+ .set_ios = mmc_set_ios,
+ .get_ro = mmc_get_ro,
+};
+
+static void
+hwinit2_irqsafe(struct asic3_mmc_host *host)
+{
+ ASIC3_MMC_REG(host, SD_CONFIG, Addr1) = 0x0000;
+ ASIC3_MMC_REG(host, SD_CONFIG, Addr0) = 0x0800;
+
+ ASIC3_MMC_REG(host, SD_CONFIG, ClkStop) = SD_CONFIG_CLKSTOP_ENABLE_ALL;
+ ASIC3_MMC_REG(host, SD_CONFIG, SDHC_CardDetect) = 2;
+ ASIC3_MMC_REG(host, SD_CONFIG, Command) = SD_CONFIG_COMMAND_MAE;
+
+ ASIC3_MMC_REG(host, SD_CTRL, SoftwareReset) = 0; /* reset on */
+ mdelay(2);
+
+ ASIC3_MMC_REG(host, SD_CTRL, SoftwareReset) = 1; /* reset off */
+ mdelay(2);
+
+ ASIC3_MMC_REG(host, SD_CTRL, MemCardOptionSetup) =
+ MEM_CARD_OPTION_REQUIRED
+ | MEM_CARD_OPTION_DATA_RESPONSE_TIMEOUT(14)
+ | MEM_CARD_OPTION_C2_MODULE_NOT_PRESENT
+ | MEM_CARD_OPTION_DATA_XFR_WIDTH_1
+ ;
+ host->clock_for_sd = 0;
+
+ ASIC3_MMC_REG(host, SD_CTRL, CardClockCtrl) = 0;
+ ASIC3_MMC_REG(host, SD_CTRL, CardStatus) = 0;
+ ASIC3_MMC_REG(host, SD_CTRL, BufferCtrl) = 0;
+ ASIC3_MMC_REG(host, SD_CTRL, ErrorStatus0) = 0;
+ ASIC3_MMC_REG(host, SD_CTRL, ErrorStatus1) = 0;
+ ASIC3_MMC_REG(host, SD_CTRL, StopInternal) = 0;
+
+ ASIC3_MMC_REG(host, SDIO_CTRL, ClocknWaitCtrl) = 0x100;
+ /* *((unsigned short *)(((char *)host->ctl_base) + 0x938)) = 0x100; */
+
+ ASIC3_MMC_REG(host, SD_CONFIG, ClockMode) = 0;
+ ASIC3_MMC_REG(host, SD_CTRL, CardClockCtrl) = 0;
+
+ mdelay(1);
+
+
+ ASIC3_MMC_REG(host, SD_CTRL, IntMaskCard) = ~(
+ SD_CTRL_INTMASKCARD_RESPONSE_END
+ | SD_CTRL_INTMASKCARD_RW_END
+ | SD_CTRL_INTMASKCARD_CARD_REMOVED_0
+ | SD_CTRL_INTMASKCARD_CARD_INSERTED_0
+#if 0
+ | SD_CTRL_INTMASKCARD_CARD_REMOVED_3
+ | SD_CTRL_INTMASKCARD_CARD_INSERTED_3
+#endif
+ )
+ ; /* check */
+ ASIC3_MMC_REG(host, SD_CTRL, IntMaskBuffer) = 0xffff; /* IRQs off */
+
+ /*
+ * ASIC3_MMC_REG(host, SD_CTRL, TransactionCtrl) = SD_CTRL_TRANSACTIONCONTROL_SET;
+ * Wince has 0x1000
+ */
+ /* ASIC3_MMC_REG(host, SD_CTRL, TransactionCtrl) = 0x1000; */
+
+
+ asic3_set_sdhwctrl(host->asic3_dev, ASIC3_SDHWCTRL_SDPWR, ASIC3_SDHWCTRL_SDPWR); /* turn on power at controller(?) */
+
+}
+
+static void
+hwinit(struct asic3_mmc_host *host, struct platform_device *pdev)
+{
+ /* Call custom handler for enabling clock (if needed) */
+ if(host->hwconfig->set_mmc_clock)
+ host->hwconfig->set_mmc_clock(pdev, MMC_CLOCK_ENABLED);
+
+ /* Not sure if it must be done bit by bit, but leaving as-is */
+ asic3_set_sdhwctrl(host->asic3_dev, ASIC3_SDHWCTRL_LEVCD, ASIC3_SDHWCTRL_LEVCD);
+ asic3_set_sdhwctrl(host->asic3_dev, ASIC3_SDHWCTRL_LEVWP, ASIC3_SDHWCTRL_LEVWP);
+ asic3_set_sdhwctrl(host->asic3_dev, ASIC3_SDHWCTRL_SUSPEND, 0);
+ asic3_set_sdhwctrl(host->asic3_dev, ASIC3_SDHWCTRL_PCLR, 0);
+
+ asic3_set_clock_cdex (host->asic3_dev,
+ CLOCK_CDEX_EX1 | CLOCK_CDEX_EX0, CLOCK_CDEX_EX1 | CLOCK_CDEX_EX0);
+ msleep(1);
+
+ asic3_set_clock_sel (host->asic3_dev,
+ CLOCK_SEL_SD_HCLK_SEL | CLOCK_SEL_SD_BCLK_SEL,
+ CLOCK_SEL_SD_HCLK_SEL | 0); /* ? */
+
+ asic3_set_clock_cdex (host->asic3_dev,
+ CLOCK_CDEX_SD_HOST | CLOCK_CDEX_SD_BUS,
+ CLOCK_CDEX_SD_HOST | CLOCK_CDEX_SD_BUS);
+ msleep(1);
+
+ asic3_set_extcf_select(host->asic3_dev, ASIC3_EXTCF_SD_MEM_ENABLE, ASIC3_EXTCF_SD_MEM_ENABLE);
+
+ /* Long Delay */
+ if( !machine_is_h4700())
+ msleep(500);
+
+ hwinit2_irqsafe(host);
+}
+
+#ifdef CONFIG_PM
+static int
+mmc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct asic3_mmc_host *host = mmc_priv(mmc);
+ int ret;
+
+ ret = mmc_suspend_host(mmc, state);
+
+ if (ret) {
+ printk(KERN_ERR DRIVER_NAME ": Could not suspend MMC host, hardware not suspended");
+ return ret;
+ }
+
+ /* disable the card insert / remove interrupt while sleeping */
+ ASIC3_MMC_REG(host, SD_CTRL, IntMaskCard) = ~(
+ SD_CTRL_INTMASKCARD_RESPONSE_END
+ | SD_CTRL_INTMASKCARD_RW_END);
+
+ /* disable clock */
+ ASIC3_MMC_REG(host, SD_CTRL, CardClockCtrl) = 0;
+ ASIC3_MMC_REG(host, SD_CONFIG, ClkStop) = 0;
+
+ /* power down */
+ ASIC3_MMC_REG(host, SD_CONFIG, SDHC_Power1) = 0;
+
+ asic3_set_clock_cdex (host->asic3_dev,
+ CLOCK_CDEX_SD_HOST | CLOCK_CDEX_SD_BUS, 0);
+
+ /* disable core clock */
+ if(host->hwconfig->set_mmc_clock)
+ host->hwconfig->set_mmc_clock(pdev, MMC_CLOCK_DISABLED);
+
+ /* Put in suspend mode */
+ asic3_set_sdhwctrl(host->asic3_dev, ASIC3_SDHWCTRL_SUSPEND, ASIC3_SDHWCTRL_SUSPEND);
+ return 0;
+}
+
+static int
+mmc_resume(struct platform_device *pdev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct asic3_mmc_host *host = mmc_priv(mmc);
+
+ printk(KERN_INFO "%s: starting resume\n", DRIVER_NAME);
+
+ asic3_set_sdhwctrl(host->asic3_dev, ASIC3_SDHWCTRL_SUSPEND, 0);
+ hwinit(host, pdev);
+
+ /* re-enable card remove / insert interrupt */
+ ASIC3_MMC_REG(host, SD_CTRL, IntMaskCard) = ~(
+ SD_CTRL_INTMASKCARD_RESPONSE_END
+ | SD_CTRL_INTMASKCARD_RW_END
+ | SD_CTRL_INTMASKCARD_CARD_REMOVED_0
+ | SD_CTRL_INTMASKCARD_CARD_INSERTED_0 );
+
+ mmc_resume_host(mmc);
+
+ printk(KERN_INFO "%s: finished resume\n", DRIVER_NAME);
+ return 0;
+}
+#endif
+
+static int
+mmc_probe(struct platform_device *pdev)
+{
+ struct mmc_host *mmc;
+ struct asic3_mmc_host *host = NULL;
+ int retval = 0;
+ struct tmio_mmc_hwconfig *mmc_config = (struct tmio_mmc_hwconfig *)pdev->dev.platform_data;
+
+ /* bus_shift is mandatory */
+ if (!mmc_config) {
+ printk(KERN_ERR DRIVER_NAME ": Invalid configuration\n");
+ return -EINVAL;
+ }
+
+ mmc = mmc_alloc_host(sizeof(struct asic3_mmc_host) + 128, &pdev->dev);
+ if (!mmc) {
+ retval = -ENOMEM;
+ goto exceptional_return;
+ }
+
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+ platform_set_drvdata(pdev, mmc);
+
+ host->ctl_base = 0;
+ host->hwconfig = mmc_config;
+ host->bus_shift = mmc_config->address_shift;
+ host->asic3_dev = pdev->dev.parent;
+ host->clock_for_sd = 0;
+
+ tasklet_init(&mmc_data_read_tasklet, mmc_data_transfer, (unsigned long)host);
+
+ host->ctl_base = ioremap_nocache ((unsigned long)pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start);
+ if(!host->ctl_base){
+ printk(KERN_ERR DRIVER_NAME ": Could not map ASIC3 SD controller\n");
+ retval = -ENODEV;
+ goto exceptional_return;
+ }
+
+ printk(DRIVER_NAME ": ASIC3 MMC/SD Driver, controller at 0x%lx\n", (unsigned long)pdev->resource[0].start);
+
+ mmc->ops = &mmc_ops;
+ mmc->caps = MMC_CAP_4_BIT_DATA;
+ mmc->f_min = 46875; /* ARIC: not sure what these should be */
+ mmc->f_max = 24000000; /* ARIC: not sure what these should be */
+ mmc->ocr_avail = MMC_VDD_32_33;
+
+ hwinit(host, pdev);
+
+
+ host->irq = pdev->resource[1].start;
+
+ retval = request_irq(host->irq, mmc_irq, 0, DRIVER_NAME, host);
+ if(retval) {
+ printk(KERN_ERR DRIVER_NAME ": Unable to get interrupt\n");
+ retval = -ENODEV;
+ goto exceptional_return;
+ }
+ set_irq_type(host->irq, IRQT_FALLING);
+
+ mmc_add_host(mmc);
+
+#ifdef CONFIG_PM
+ // resume_timer.function = resume_timer_callback;
+ // resume_timer.data = 0;
+ // init_timer(&resume_timer);
+#endif
+
+ return 0;
+
+exceptional_return:
+ if (mmc) {
+ mmc_free_host(mmc);
+ }
+ if(host && host->ctl_base) iounmap(host->ctl_base);
+ return retval;
+}
+
+static int
+mmc_remove(struct platform_device *pdev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ if (mmc) {
+ struct asic3_mmc_host *host = mmc_priv(mmc);
+ mmc_remove_host(mmc);
+ free_irq(host->irq, host);
+ /* FIXME - we might want to consider stopping the chip here... */
+ iounmap(host->ctl_base);
+ mmc_free_host(mmc); /* FIXME - why does this call hang? */
+ }
+ return 0;
+}
+
+/* ------------------- device registration ----------------------- */
+
+static struct platform_driver mmc_asic3_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+ .probe = mmc_probe,
+ .remove = mmc_remove,
+#ifdef CONFIG_PM
+ .suspend = mmc_suspend,
+ .resume = mmc_resume,
+#endif
+};
+
+static int __init mmc_init(void)
+{
+ return platform_driver_register(&mmc_asic3_driver);
+}
+
+static void __exit mmc_exit(void)
+{
+ platform_driver_unregister(&mmc_asic3_driver);
+}
+
+late_initcall(mmc_init);
+module_exit(mmc_exit);
+
+MODULE_DESCRIPTION("HTC ASIC3 SD/MMC driver");
+MODULE_AUTHOR("Aric Blumer, SDG Systems, LLC");
+MODULE_LICENSE("GPL");
+
Index: linux-2.6.22/drivers/mmc/host/asic3_mmc.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/drivers/mmc/host/asic3_mmc.h 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,25 @@
+#ifndef __ASIC3_MMC_H
+#define __ASIC3_MMC_H
+
+#define DRIVER_NAME "asic3_mmc"
+
+#ifdef CONFIG_MMC_DEBUG
+#define DBG(x...) printk(DRIVER_NAME ": " x)
+#else
+#define DBG(x...) do { } while (0)
+#endif
+
+/* Response types */
+#define APP_CMD 0x0040
+
+#define SD_CONFIG_CLKSTOP_ENABLE_ALL 0x1f
+
+#define DONT_CARE_CARD_BITS ( \
+ SD_CTRL_INTMASKCARD_SIGNAL_STATE_PRESENT_3 \
+ | SD_CTRL_INTMASKCARD_WRITE_PROTECT \
+ | SD_CTRL_INTMASKCARD_UNK6 \
+ | SD_CTRL_INTMASKCARD_SIGNAL_STATE_PRESENT_0 \
+ )
+#define DONT_CARE_BUFFER_BITS ( SD_CTRL_INTMASKBUFFER_UNK7 | SD_CTRL_INTMASKBUFFER_CMD_BUSY )
+
+#endif // __ASIC3_MMC_H
Index: linux-2.6.22/drivers/input/keyboard/Makefile
===================================================================
--- linux-2.6.22.orig/drivers/input/keyboard/Makefile 2007-07-09 01:32:17.000000000 +0200
+++ linux-2.6.22/drivers/input/keyboard/Makefile 2007-09-11 12:53:37.000000000 +0200
@@ -21,4 +21,4 @@
obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keyboard.o
obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
-
+obj-$(CONFIG_KEYBOARD_ASIC3) += asic3_keys.o
Index: linux-2.6.22/drivers/input/keyboard/asic3_keys.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/drivers/input/keyboard/asic3_keys.c 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,131 @@
+/*
+ * Generic buttons driver for ASIC3 SoC.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Copyright (C) 2003 Joshua Wise
+ * Copyright (C) 2005 Pawel Kolodziejski
+ * Copyright (C) 2006 Paul Sokolovsky
+ *
+ */
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/soc/asic3_base.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/arch/irqs.h>
+#include <asm/hardware.h>
+#include <asm/hardware/ipaq-asic3.h>
+#include <asm/hardware/asic3_keys.h>
+
+static irqreturn_t asic3_keys_asic_handle(int irq, void *data)
+{
+ struct asic3_keys_platform_data *pdata = data;
+ int i, base_irq;
+
+ base_irq = asic3_irq_base(pdata->asic3_dev);
+ for (i = 0; i < pdata->nbuttons; i++) {
+ struct asic3_keys_button *b = &pdata->buttons[i];
+ if ((base_irq + b->gpio) == irq) {
+ int state = !!asic3_gpio_get_value(pdata->asic3_dev, b->gpio);
+
+ if (pdata->buttons[i].type == EV_SW)
+ input_report_switch(pdata->input, pdata->buttons[i].keycode, state ^ b->active_low);
+ else
+ input_report_key(pdata->input, b->keycode, state ^ b->active_low);
+ input_sync(pdata->input);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit asic3_keys_probe(struct platform_device *pdev)
+{
+ struct asic3_keys_platform_data *pdata = pdev->dev.platform_data;
+ int i, base_irq;
+ int j, ret;
+
+ pdata->input = input_allocate_device();
+
+ base_irq = asic3_irq_base(pdata->asic3_dev);
+
+ for (i = 0; i < pdata->nbuttons; i++) {
+ struct asic3_keys_button *b = &pdata->buttons[i];
+ set_bit(b->keycode, pdata->input->keybit);
+ ret=request_irq(base_irq + b->gpio, asic3_keys_asic_handle, SA_SAMPLE_RANDOM, b->desc, pdata);
+ if (ret)
+ {
+ printk(KERN_NOTICE "Failed to allocate asic3_keys irq=%d.\n",b->gpio);
+
+ for(j=0; j<i ; j++)
+ free_irq(base_irq + pdata->buttons[i].gpio, NULL);
+
+ input_unregister_device (pdata->input);
+
+ return -ENODEV;
+ }
+
+ set_irq_type(base_irq + b->gpio, IRQT_BOTHEDGE);
+ if (pdata->buttons[i].type == EV_SW) {
+ pdata->input->evbit[0] |= BIT(EV_SW);
+ set_bit(b->keycode, pdata->input->swbit);
+ } else {
+ pdata->input->evbit[0] |= BIT(EV_KEY);
+ set_bit(b->keycode, pdata->input->keybit);
+ }
+ }
+
+ pdata->input->name = pdev->name;
+ input_register_device(pdata->input);
+
+ return 0;
+}
+
+static int __devexit asic3_keys_remove(struct platform_device *pdev)
+{
+ struct asic3_keys_platform_data *pdata = pdev->dev.platform_data;
+ int i, base_irq;
+
+ base_irq = asic3_irq_base(pdata->asic3_dev);
+ for (i = 0; i < pdata->nbuttons; i++) {
+ free_irq(base_irq + pdata->buttons[i].gpio, NULL);
+ }
+
+ input_unregister_device(pdata->input);
+
+ return 0;
+}
+
+
+static struct platform_driver asic3_keys_driver = {
+ .probe = asic3_keys_probe,
+ .remove = __devexit_p(asic3_keys_remove),
+ .driver = {
+ .name = "asic3-keys",
+ },
+};
+
+static int __init asic3_keys_init(void)
+{
+ return platform_driver_register(&asic3_keys_driver);
+}
+
+static void __exit asic3_keys_exit(void)
+{
+ platform_driver_unregister(&asic3_keys_driver);
+}
+
+module_init(asic3_keys_init);
+module_exit(asic3_keys_exit);
+
+MODULE_AUTHOR("Joshua Wise, Pawel Kolodziejski, Paul Sokolovsky");
+MODULE_DESCRIPTION("Buttons driver for HTC ASIC3 SoC");
+MODULE_LICENSE("GPL");
Index: linux-2.6.22/include/asm-arm/arch-pxa/irqs.h
===================================================================
--- linux-2.6.22.orig/include/asm-arm/arch-pxa/irqs.h 2007-09-11 12:53:24.000000000 +0200
+++ linux-2.6.22/include/asm-arm/arch-pxa/irqs.h 2007-09-11 12:53:37.000000000 +0200
@@ -172,6 +172,8 @@
defined(CONFIG_MACH_LOGICPD_PXA270) || \
defined(CONFIG_MACH_MAINSTONE)
#define NR_IRQS (IRQ_BOARD_END)
+#elif defined(CONFIG_MACH_HTCUNIVERSAL)
+#define NR_IRQS (IRQ_BOARD_START + 96)
#else
#define NR_IRQS (IRQ_BOARD_START)
#endif
Index: linux-2.6.22/include/linux/ioport.h
===================================================================
--- linux-2.6.22.orig/include/linux/ioport.h 2007-07-09 01:32:17.000000000 +0200
+++ linux-2.6.22/include/linux/ioport.h 2007-09-11 12:53:37.000000000 +0200
@@ -56,6 +56,7 @@
#define IORESOURCE_IRQ_HIGHLEVEL (1<<2)
#define IORESOURCE_IRQ_LOWLEVEL (1<<3)
#define IORESOURCE_IRQ_SHAREABLE (1<<4)
+#define IORESOURCE_IRQ_SOC_SUBDEVICE (1<<5)
/* ISA PnP DMA specific bits (IORESOURCE_BITS) */
#define IORESOURCE_DMA_TYPE_MASK (3<<0)
Index: linux-2.6.22/drivers/video/backlight/Kconfig
===================================================================
--- linux-2.6.22.orig/drivers/video/backlight/Kconfig 2007-09-11 12:53:30.000000000 +0200
+++ linux-2.6.22/drivers/video/backlight/Kconfig 2007-09-11 12:53:37.000000000 +0200
@@ -40,7 +40,7 @@
config BACKLIGHT_CORGI
tristate "Sharp Corgi Backlight Driver (SL Series)"
- depends on BACKLIGHT_CLASS_DEVICE && PXA_SHARPSL
+ depends on BACKLIGHT_CLASS_DEVICE
default y
help
If you have a Sharp Zaurus SL-C7xx, SL-Cxx00 or SL-6000x say y to enable the
Index: linux-2.6.22/drivers/video/backlight/corgi_bl.c
===================================================================
--- linux-2.6.22.orig/drivers/video/backlight/corgi_bl.c 2007-07-09 01:32:17.000000000 +0200
+++ linux-2.6.22/drivers/video/backlight/corgi_bl.c 2007-09-11 12:53:37.000000000 +0200
@@ -24,7 +24,7 @@
static int corgibl_intensity;
static struct backlight_properties corgibl_data;
static struct backlight_device *corgi_backlight_device;
-static struct corgibl_machinfo *bl_machinfo;
+static struct generic_bl_info *bl_machinfo;
static unsigned long corgibl_flags;
#define CORGIBL_SUSPENDED 0x01
@@ -107,7 +107,7 @@
static int corgibl_probe(struct platform_device *pdev)
{
- struct corgibl_machinfo *machinfo = pdev->dev.platform_data;
+ struct generic_bl_info *machinfo = pdev->dev.platform_data;
bl_machinfo = machinfo;
if (!machinfo->limit_mask)
Index: linux-2.6.22/arch/arm/mach-pxa/corgi.c
===================================================================
--- linux-2.6.22.orig/arch/arm/mach-pxa/corgi.c 2007-09-11 12:53:32.000000000 +0200
+++ linux-2.6.22/arch/arm/mach-pxa/corgi.c 2007-09-11 12:53:37.000000000 +0200
@@ -20,6 +20,7 @@
#include <linux/interrupt.h>
#include <linux/mmc/host.h>
#include <linux/pm.h>
+#include <linux/backlight.h>
#include <asm/setup.h>
#include <asm/memory.h>
@@ -143,7 +144,7 @@
/*
* Corgi Backlight Device
*/
-static struct corgibl_machinfo corgi_bl_machinfo = {
+static struct generic_bl_info corgi_bl_machinfo = {
.max_intensity = 0x2f,
.default_intensity = 0x1f,
.limit_mask = 0x0b,
Index: linux-2.6.22/arch/arm/mach-pxa/spitz.c
===================================================================
--- linux-2.6.22.orig/arch/arm/mach-pxa/spitz.c 2007-09-11 12:53:33.000000000 +0200
+++ linux-2.6.22/arch/arm/mach-pxa/spitz.c 2007-09-11 12:53:37.000000000 +0200
@@ -222,7 +222,7 @@
/*
* Spitz Backlight Device
*/
-static struct corgibl_machinfo spitz_bl_machinfo = {
+static struct generic_bl_info spitz_bl_machinfo = {
.default_intensity = 0x1f,
.limit_mask = 0x0b,
.max_intensity = 0x2f,
Index: linux-2.6.22/include/asm-arm/arch-pxa/serial.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.22/include/asm-arm/arch-pxa/serial.h 2007-09-11 12:53:37.000000000 +0200
@@ -0,0 +1,78 @@
+/*
+ * linux/include/asm-arm/arch-pxa/serial.h
+ *
+ * Author: Nicolas Pitre
+ * Copyright: (C) 2001 MontaVista Software Inc.
+ *
+ * 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 <asm/arch/pxa-regs.h>
+
+#define BAUD_BASE 921600
+
+/* Standard COM flags */
+#define STD_COM_FLAGS (ASYNC_SKIP_TEST)
+
+#define STD_SERIAL_PORT_DEFNS \
+ { \
+ type: PORT_PXA, \
+ xmit_fifo_size: 64, \
+ baud_base: BAUD_BASE, \
+ iomem_base: &FFUART, \
+ iomem_reg_shift: 2, \
+ io_type: SERIAL_IO_MEM, \
+ irq: IRQ_FFUART, \
+ flags: STD_COM_FLAGS, \
+ }, { \
+ type: PORT_PXA, \
+ xmit_fifo_size: 64, \
+ baud_base: BAUD_BASE, \
+ iomem_base: &STUART, \
+ iomem_reg_shift: 2, \
+ io_type: SERIAL_IO_MEM, \
+ irq: IRQ_STUART, \
+ flags: STD_COM_FLAGS, \
+ }, { \
+ type: PORT_PXA, \
+ xmit_fifo_size: 64, \
+ baud_base: BAUD_BASE, \
+ iomem_base: &BTUART, \
+ iomem_reg_shift: 2, \
+ io_type: SERIAL_IO_MEM, \
+ irq: IRQ_BTUART, \
+ flags: STD_COM_FLAGS, \
+ }
+
+#define EXTRA_SERIAL_PORT_DEFNS
+
+struct platform_pxa_serial_funcs {
+
+ /* Initialize whatever is connected to this serial port. */
+ void (*configure)(int state);
+#define PXA_UART_CFG_PRE_STARTUP 0
+#define PXA_UART_CFG_POST_STARTUP 1
+#define PXA_UART_CFG_PRE_SHUTDOWN 2
+#define PXA_UART_CFG_POST_SHUTDOWN 3
+
+ /* 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)(int txrx);
+#define PXA_SERIAL_TX 1
+#define PXA_SERIAL_RX 2
+
+ /* Get the current state of tx/rx. */
+ int (*get_txrx)(void);
+
+ int (*suspend)(struct platform_device *dev, pm_message_t state);
+ int (*resume)(struct platform_device *dev);
+};
+
+void pxa_set_ffuart_info(struct platform_pxa_serial_funcs *ffuart_funcs);
+void pxa_set_btuart_info(struct platform_pxa_serial_funcs *btuart_funcs);
+void pxa_set_stuart_info(struct platform_pxa_serial_funcs *stuart_funcs);
+void pxa_set_hwuart_info(struct platform_pxa_serial_funcs *hwuart_funcs);
Index: linux-2.6.22/drivers/serial/pxa.c
===================================================================
--- linux-2.6.22.orig/drivers/serial/pxa.c 2007-07-09 01:32:17.000000000 +0200
+++ linux-2.6.22/drivers/serial/pxa.c 2007-09-11 12:53:37.000000000 +0200
@@ -46,6 +46,7 @@
#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/irq.h>
+#include <asm/arch/serial.h>
#include <asm/arch/pxa-regs.h>
@@ -59,6 +60,14 @@
char *name;
};
+
+#define IS_METHOD(dev, method) (dev && (dev)->platform_data && ((struct platform_pxa_serial_funcs *)(dev)->platform_data)->method)
+#define METHOD_CALL(dev, method) \
+ ((struct platform_pxa_serial_funcs *)(dev)->platform_data)->method()
+#define SAFE_METHOD_CALL(dev, method, args...) \
+ if (IS_METHOD(dev, method)) \
+ ((struct platform_pxa_serial_funcs *)(dev)->platform_data)->method(args)
+
static inline unsigned int serial_in(struct uart_pxa_port *up, int offset)
{
offset <<= 2;
@@ -346,6 +355,9 @@
unsigned long flags;
int retval;
+ /* Perform platform-specific port initialization, if needed. */
+ SAFE_METHOD_CALL(port->dev, configure, PXA_UART_CFG_PRE_STARTUP);
+
if (port->line == 3) /* HWUART */
up->mcr |= UART_MCR_AFE;
else
@@ -401,6 +413,12 @@
(void) serial_in(up, UART_IIR);
(void) serial_in(up, UART_MSR);
+ /*
+ * Perform platform-specific port initialization if needed
+ */
+ SAFE_METHOD_CALL(port->dev, configure, PXA_UART_CFG_POST_STARTUP);
+ SAFE_METHOD_CALL(port->dev, set_txrx, PXA_SERIAL_RX);
+
return 0;
}
@@ -409,6 +427,8 @@
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
unsigned long flags;
+ SAFE_METHOD_CALL(port->dev, configure, PXA_UART_CFG_PRE_SHUTDOWN);
+
free_irq(up->port.irq, up);
/*
@@ -430,6 +450,8 @@
UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT);
serial_out(up, UART_FCR, 0);
+
+ SAFE_METHOD_CALL(port->dev, configure, PXA_UART_CFG_POST_SHUTDOWN);
}
static void
Index: linux-2.6.22/arch/arm/mach-pxa/generic.c
===================================================================
--- linux-2.6.22.orig/arch/arm/mach-pxa/generic.c 2007-09-11 12:53:11.000000000 +0200
+++ linux-2.6.22/arch/arm/mach-pxa/generic.c 2007-09-11 12:53:37.000000000 +0200
@@ -42,6 +42,7 @@
#include <asm/arch/mmc.h>
#include <asm/arch/irda.h>
#include <asm/arch/i2c.h>
+#include <asm/arch/serial.h>
#include "devices.h"
#include "generic.h"
@@ -346,6 +347,18 @@
.id = 3,
};
+void __init pxa_set_ffuart_info(struct platform_pxa_serial_funcs *info)
+{
+ pxa_device_ffuart.dev.platform_data = info;
+}
+EXPORT_SYMBOL(pxa_set_ffuart_info);
+
+void __init pxa_set_btuart_info(struct platform_pxa_serial_funcs *info)
+{
+ pxa_device_btuart.dev.platform_data = info;
+}
+EXPORT_SYMBOL(pxa_set_btuart_info);
+
static struct resource pxai2c_resources[] = {
{
.start = 0x40301680,
Index: linux-2.6.22/drivers/leds/Makefile
===================================================================
--- linux-2.6.22.orig/drivers/leds/Makefile 2007-09-11 12:53:14.000000000 +0200
+++ linux-2.6.22/drivers/leds/Makefile 2007-09-11 12:53:37.000000000 +0200
@@ -16,6 +16,7 @@
obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
obj-$(CONFIG_LEDS_H1940) += leds-h1940.o
obj-$(CONFIG_LEDS_COBALT) += leds-cobalt.o
+obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o
obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
# LED Triggers
Index: linux-2.6.22/arch/arm/Kconfig
===================================================================
--- linux-2.6.22.orig/arch/arm/Kconfig 2007-09-11 12:53:32.000000000 +0200
+++ linux-2.6.22/arch/arm/Kconfig 2007-09-11 12:53:37.000000000 +0200
@@ -1032,6 +1032,8 @@
source "drivers/w1/Kconfig"
+source "drivers/power/Kconfig"
+
source "drivers/hwmon/Kconfig"
#source "drivers/l3/Kconfig"
Index: linux-2.6.22/drivers/input/keyboard/Kconfig
===================================================================
--- linux-2.6.22.orig/drivers/input/keyboard/Kconfig 2007-09-11 14:28:45.000000000 +0200
+++ linux-2.6.22/drivers/input/keyboard/Kconfig 2007-09-11 14:29:05.000000000 +0200
@@ -253,4 +253,11 @@
To compile this driver as a module, choose M here: the
module will be called gpio-keys.
+config KEYBOARD_ASIC3
+ tristate "Buttons on ASIC3 SoC GPIOs (iPaqs, etc.)"
+ depends on HTC_ASIC3
+ help
+ This enables support for the buttons attached to GPIOs of
+ HTC ASIC3 peripheral controller.
+
endif