47a464d97b
git-svn-id: https://svn.o-hand.com/repos/poky/trunk@4570 311d38ba-8fff-0310-9ca6-ca027cbcb966
7921 lines
251 KiB
Diff
7921 lines
251 KiB
Diff
---
|
||
arch/arm/Kconfig | 2
|
||
arch/arm/mach-pxa/Kconfig | 89 +
|
||
arch/arm/mach-pxa/Makefile | 1
|
||
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
|
||
drivers/input/keyboard/Kconfig | 7
|
||
drivers/input/keyboard/Makefile | 1
|
||
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 | 1
|
||
drivers/mmc/host/asic3_mmc.c | 900 +++++++++++
|
||
drivers/mmc/host/asic3_mmc.h | 25
|
||
drivers/serial/pxa.c | 22
|
||
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/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
|
||
56 files changed, 7469 insertions(+), 1 deletion(-)
|
||
|
||
Index: linux-2.6.24/arch/arm/mach-pxa/htcuniversal/Makefile
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/Makefile 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/arch/arm/mach-pxa/htcuniversal/htcuniversal.c
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal.c 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_ak4641.c
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_ak4641.c 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_ak4641.h
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_ak4641.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_asic3_leds.c
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_asic3_leds.c 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_bl.c
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_bl.c 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_bt.c
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_bt.c 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_bt.h
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_bt.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_buttons.c
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_buttons.c 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_core.c
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_core.c 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_lcd.c
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_lcd.c 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_phone.c
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_phone.c 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_phone.h
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_phone.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_pm.c
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_pm.c 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_power2.c
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_power2.c 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_ts2.c
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_ts2.c 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_udc.c
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/htcuniversal_udc.c 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/arch/arm/mach-pxa/htcuniversal/tsc2046_ts.h
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/htcuniversal/tsc2046_ts.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/arch/arm/mach-pxa/Kconfig
|
||
===================================================================
|
||
--- linux-2.6.24.orig/arch/arm/mach-pxa/Kconfig 2008-03-10 16:08:01.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/Kconfig 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -92,6 +92,14 @@
|
||
bool "Sharp PXA270 models (SL-Cxx00)"
|
||
select PXA27x
|
||
|
||
+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
|
||
|
||
endif
|
||
@@ -111,6 +119,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
|
||
@@ -196,4 +284,3 @@
|
||
depends on (PXA25x || PXA27x) && INPUT
|
||
|
||
endif
|
||
-
|
||
Index: linux-2.6.24/arch/arm/mach-pxa/Makefile
|
||
===================================================================
|
||
--- linux-2.6.24.orig/arch/arm/mach-pxa/Makefile 2008-03-10 16:08:01.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/Makefile 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -23,6 +23,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/
|
||
|
||
ifeq ($(CONFIG_MACH_ZYLONITE),y)
|
||
obj-y += zylonite.o
|
||
Index: linux-2.6.24/drivers/leds/Kconfig
|
||
===================================================================
|
||
--- linux-2.6.24.orig/drivers/leds/Kconfig 2008-01-24 22:58:37.000000000 +0000
|
||
+++ linux-2.6.24/drivers/leds/Kconfig 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -114,6 +114,13 @@
|
||
help
|
||
This option enables support for the CM-X270 LEDs.
|
||
|
||
+config LEDS_ASIC3
|
||
+ tristate "LED Support for the HTC ASIC3 chip"
|
||
+ depends on 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.24/drivers/leds/leds-asic3.c
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/drivers/leds/leds-asic3.c 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/drivers/mfd/Kconfig
|
||
===================================================================
|
||
--- linux-2.6.24.orig/drivers/mfd/Kconfig 2008-03-10 16:07:51.000000000 +0000
|
||
+++ linux-2.6.24/drivers/mfd/Kconfig 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -21,6 +21,16 @@
|
||
help
|
||
Support for TI TSC2101 Touchscreen and Audio Codec
|
||
|
||
+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.24/drivers/mfd/Makefile
|
||
===================================================================
|
||
--- linux-2.6.24.orig/drivers/mfd/Makefile 2008-03-10 16:07:51.000000000 +0000
|
||
+++ linux-2.6.24/drivers/mfd/Makefile 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/drivers/mfd/asic3_base.c
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/drivers/mfd/asic3_base.c 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/drivers/mfd/soc-core.c
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/drivers/mfd/soc-core.c 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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_MFD_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.24/drivers/mfd/soc-core.h
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/drivers/mfd/soc-core.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/include/asm-arm/arch-pxa/clock.h
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/include/asm-arm/arch-pxa/clock.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/include/asm-arm/arch-pxa/htcuniversal-asic.h
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/include/asm-arm/arch-pxa/htcuniversal-asic.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/include/asm-arm/arch-pxa/htcuniversal-gpio.h
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/include/asm-arm/arch-pxa/htcuniversal-gpio.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/include/asm-arm/arch-pxa/htcuniversal-init.h
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/include/asm-arm/arch-pxa/htcuniversal-init.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/include/asm-arm/arch-pxa/htcuniversal.h
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/include/asm-arm/arch-pxa/htcuniversal.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -0,0 +1,3 @@
|
||
+#include <asm/arch/irqs.h>
|
||
+
|
||
+#define HTCUNIVERSAL_ASIC3_IRQ_BASE IRQ_BOARD_START
|
||
Index: linux-2.6.24/include/asm-arm/arch-pxa/pxa-pm_ll.h
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/include/asm-arm/arch-pxa/pxa-pm_ll.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/include/asm-arm/hardware/asic3_keys.h
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/include/asm-arm/hardware/asic3_keys.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/include/asm-arm/hardware/asic3_leds.h
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/include/asm-arm/hardware/asic3_leds.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/include/asm-arm/hardware/ipaq-asic3.h
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/include/asm-arm/hardware/ipaq-asic3.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/include/linux/gpiodev.h
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/include/linux/gpiodev.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/include/linux/input_pda.h
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/include/linux/input_pda.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/include/linux/soc/asic3_base.h
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/include/linux/soc/asic3_base.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/include/linux/soc/tmio_mmc.h
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/include/linux/soc/tmio_mmc.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/include/asm-arm/arch-pxa/pxa-regs.h
|
||
===================================================================
|
||
--- linux-2.6.24.orig/include/asm-arm/arch-pxa/pxa-regs.h 2008-03-10 16:07:59.000000000 +0000
|
||
+++ linux-2.6.24/include/asm-arm/arch-pxa/pxa-regs.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -2058,6 +2058,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.24/drivers/mmc/host/Makefile
|
||
===================================================================
|
||
--- linux-2.6.24.orig/drivers/mmc/host/Makefile 2008-01-24 22:58:37.000000000 +0000
|
||
+++ linux-2.6.24/drivers/mmc/host/Makefile 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -13,6 +13,7 @@
|
||
obj-$(CONFIG_MMC_RICOH_MMC) += ricoh_mmc.o
|
||
obj-$(CONFIG_MMC_WBSD) += wbsd.o
|
||
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
|
||
+obj-$(CONFIG_MMC_ASIC3) += asic3_mmc.o
|
||
obj-$(CONFIG_MMC_OMAP) += omap.o
|
||
obj-$(CONFIG_MMC_AT91) += at91_mci.o
|
||
obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
|
||
Index: linux-2.6.24/drivers/mmc/host/asic3_mmc.c
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/drivers/mmc/host/asic3_mmc.c 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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("[1;33mOpcode: %d[0m, 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.24/drivers/mmc/host/asic3_mmc.h
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/drivers/mmc/host/asic3_mmc.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/drivers/input/keyboard/asic3_keys.c
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/drivers/input/keyboard/asic3_keys.c 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/include/asm-arm/arch-pxa/irqs.h
|
||
===================================================================
|
||
--- linux-2.6.24.orig/include/asm-arm/arch-pxa/irqs.h 2008-01-24 22:58:37.000000000 +0000
|
||
+++ linux-2.6.24/include/asm-arm/arch-pxa/irqs.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -182,6 +182,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.24/include/asm-arm/arch-pxa/serial.h
|
||
===================================================================
|
||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
+++ linux-2.6.24/include/asm-arm/arch-pxa/serial.h 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -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.24/drivers/serial/pxa.c
|
||
===================================================================
|
||
--- linux-2.6.24.orig/drivers/serial/pxa.c 2008-01-24 22:58:37.000000000 +0000
|
||
+++ linux-2.6.24/drivers/serial/pxa.c 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -47,6 +47,7 @@
|
||
#include <asm/io.h>
|
||
#include <asm/hardware.h>
|
||
#include <asm/irq.h>
|
||
+#include <asm/arch/serial.h>
|
||
#include <asm/arch/pxa-regs.h>
|
||
|
||
|
||
@@ -60,6 +61,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;
|
||
@@ -347,6 +356,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
|
||
@@ -404,6 +416,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;
|
||
}
|
||
|
||
@@ -412,6 +430,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);
|
||
|
||
/*
|
||
@@ -433,6 +453,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.24/arch/arm/mach-pxa/generic.c
|
||
===================================================================
|
||
--- linux-2.6.24.orig/arch/arm/mach-pxa/generic.c 2008-01-24 22:58:37.000000000 +0000
|
||
+++ linux-2.6.24/arch/arm/mach-pxa/generic.c 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -38,6 +38,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"
|
||
@@ -412,6 +413,18 @@
|
||
.num_resources = ARRAY_SIZE(pxa_resource_hwuart),
|
||
};
|
||
|
||
+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.24/drivers/leds/Makefile
|
||
===================================================================
|
||
--- linux-2.6.24.orig/drivers/leds/Makefile 2008-01-24 22:58:37.000000000 +0000
|
||
+++ linux-2.6.24/drivers/leds/Makefile 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -15,6 +15,7 @@
|
||
obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
|
||
obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
|
||
obj-$(CONFIG_LEDS_H1940) += leds-h1940.o
|
||
+obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o
|
||
obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o
|
||
obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o
|
||
obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
|
||
Index: linux-2.6.24/drivers/input/keyboard/Kconfig
|
||
===================================================================
|
||
--- linux-2.6.24.orig/drivers/input/keyboard/Kconfig 2008-01-24 22:58:37.000000000 +0000
|
||
+++ linux-2.6.24/drivers/input/keyboard/Kconfig 2008-03-10 16:09:23.000000000 +0000
|
||
@@ -293,4 +293,11 @@
|
||
To compile this driver as a module, choose M here: the
|
||
module will be called bf54x-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
|
||
Index: linux-2.6.24/drivers/mmc/host/Kconfig
|
||
===================================================================
|
||
--- linux-2.6.24.orig/drivers/mmc/host/Kconfig 2008-01-24 22:58:37.000000000 +0000
|
||
+++ linux-2.6.24/drivers/mmc/host/Kconfig 2008-03-10 16:09:59.000000000 +0000
|
||
@@ -24,6 +24,13 @@
|
||
|
||
If unsure, say N.
|
||
|
||
+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.
|
||
+
|
||
config MMC_SDHCI
|
||
tristate "Secure Digital Host Controller Interface support (EXPERIMENTAL)"
|
||
depends on PCI && EXPERIMENTAL
|
||
Index: linux-2.6.24/drivers/input/keyboard/Makefile
|
||
===================================================================
|
||
--- linux-2.6.24.orig/drivers/input/keyboard/Makefile 2008-01-24 22:58:37.000000000 +0000
|
||
+++ linux-2.6.24/drivers/input/keyboard/Makefile 2008-03-10 16:10:28.000000000 +0000
|
||
@@ -6,6 +6,7 @@
|
||
|
||
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
|
||
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
|
||
+obj-$(CONFIG_KEYBOARD_ASIC3) += asic3_keys.o
|
||
obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o
|
||
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
|
||
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
|