Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/arch/arm/mach-msm/board-trout.h b/arch/arm/mach-msm/board-trout.h
- index 4f345a5..d1debc2 100644
- --- a/arch/arm/mach-msm/board-trout.h
- +++ b/arch/arm/mach-msm/board-trout.h
- @@ -1,5 +1,161 @@
- +/* linux/arch/arm/mach-msm/board-trout.h
- +** Author: Brian Swetland <swetland@google.com>
- +*/
- +#ifndef __ARCH_ARM_MACH_MSM_BOARD_TROUT_H
- +#define __ARCH_ARM_MACH_MSM_BOARD_TROUT_H
- +
- +#include <mach/board.h>
- +
- +#define MSM_SMI_BASE 0x00000000
- +#define MSM_SMI_SIZE 0x00800000
- +
- +#define MSM_EBI_BASE 0x10000000
- +#define MSM_EBI_SIZE 0x06e00000
- +
- +#define MSM_PMEM_GPU0_BASE 0x00000000
- +#define MSM_PMEM_GPU0_SIZE 0x00700000
- +
- +#define MSM_PMEM_MDP_BASE 0x02000000
- +#define MSM_PMEM_MDP_SIZE 0x00800000
- +
- +#define MSM_PMEM_ADSP_BASE 0x02800000
- +#define MSM_PMEM_ADSP_SIZE 0x00800000
- +
- +#define MSM_PMEM_CAMERA_BASE 0x03000000
- +#define MSM_PMEM_CAMERA_SIZE 0x00800000
- +
- +#define MSM_FB_BASE 0x03800000
- +#define MSM_FB_SIZE 0x00100000
- +
- +#define MSM_LINUX_BASE MSM_EBI_BASE
- +#define MSM_LINUX_SIZE 0x06500000
- +
- +#define MSM_PMEM_GPU1_SIZE 0x800000
- +#define MSM_PMEM_GPU1_BASE MSM_RAM_CONSOLE_BASE - MSM_PMEM_GPU1_SIZE
- +
- +#define MSM_RAM_CONSOLE_BASE MSM_EBI_BASE + 0x6d00000
- +#define MSM_RAM_CONSOLE_SIZE 128 * SZ_1K
- +
- +#if (MSM_FB_BASE + MSM_FB_SIZE) >= (MSM_PMEM_GPU1_BASE)
- +#error invalid memory map
- +#endif
- +
- +#define DECLARE_MSM_IOMAP
- +#include <mach/msm_iomap.h>
- +
- +#define TROUT_4_BALL_UP_0 1
- +#define TROUT_4_BALL_LEFT_0 18
- +#define TROUT_4_BALL_DOWN_0 57
- +#define TROUT_4_BALL_RIGHT_0 91
- +
- +#define TROUT_5_BALL_UP_0 94
- +#define TROUT_5_BALL_LEFT_0 18
- +#define TROUT_5_BALL_DOWN_0 90
- +#define TROUT_5_BALL_RIGHT_0 19
- +
- +#define TROUT_POWER_KEY 20
- +
- +#define TROUT_4_TP_LS_EN 19
- +#define TROUT_5_TP_LS_EN 1
- #define TROUT_CPLD_BASE 0xE8100000
- #define TROUT_CPLD_START 0x98000000
- #define TROUT_CPLD_SIZE SZ_4K
- +#define TROUT_GPIO_CABLE_IN1 (83)
- +#define TROUT_GPIO_CABLE_IN2 (49)
- +
- +#define TROUT_GPIO_START (128)
- +
- +#define TROUT_GPIO_INT_MASK0_REG (0x0c)
- +#define TROUT_GPIO_INT_STAT0_REG (0x0e)
- +#define TROUT_GPIO_INT_MASK1_REG (0x14)
- +#define TROUT_GPIO_INT_STAT1_REG (0x10)
- +
- +#define TROUT_GPIO_HAPTIC_PWM (28)
- +#define TROUT_GPIO_PS_HOLD (25)
- +
- +#define TROUT_GPIO_MISC2_BASE (TROUT_GPIO_START + 0x00)
- +#define TROUT_GPIO_MISC3_BASE (TROUT_GPIO_START + 0x08)
- +#define TROUT_GPIO_MISC4_BASE (TROUT_GPIO_START + 0x10)
- +#define TROUT_GPIO_MISC5_BASE (TROUT_GPIO_START + 0x18)
- +#define TROUT_GPIO_INT2_BASE (TROUT_GPIO_START + 0x20)
- +#define TROUT_GPIO_MISC1_BASE (TROUT_GPIO_START + 0x28)
- +#define TROUT_GPIO_VIRTUAL_BASE (TROUT_GPIO_START + 0x30)
- +#define TROUT_GPIO_INT5_BASE (TROUT_GPIO_START + 0x48)
- +
- +#define TROUT_GPIO_CHARGER_EN (TROUT_GPIO_MISC2_BASE + 0)
- +#define TROUT_GPIO_ISET (TROUT_GPIO_MISC2_BASE + 1)
- +#define TROUT_GPIO_H2W_DAT_DIR (TROUT_GPIO_MISC2_BASE + 2)
- +#define TROUT_GPIO_H2W_CLK_DIR (TROUT_GPIO_MISC2_BASE + 3)
- +#define TROUT_GPIO_H2W_DAT_GPO (TROUT_GPIO_MISC2_BASE + 4)
- +#define TROUT_GPIO_H2W_CLK_GPO (TROUT_GPIO_MISC2_BASE + 5)
- +#define TROUT_GPIO_H2W_SEL0 (TROUT_GPIO_MISC2_BASE + 6)
- +#define TROUT_GPIO_H2W_SEL1 (TROUT_GPIO_MISC2_BASE + 7)
- +
- +#define TROUT_GPIO_FLASH_EN (TROUT_GPIO_MISC3_BASE + 1)
- +#define TROUT_GPIO_I2C_PULL (TROUT_GPIO_MISC3_BASE + 2)
- +#define TROUT_GPIO_TP_I2C_PULL (TROUT_GPIO_MISC3_BASE + 3)
- +#define TROUT_GPIO_TP_EN (TROUT_GPIO_MISC3_BASE + 4)
- +#define TROUT_GPIO_JOG_EN (TROUT_GPIO_MISC3_BASE + 5)
- +#define TROUT_GPIO_UI_LED_EN (TROUT_GPIO_MISC3_BASE + 6)
- +#define TROUT_GPIO_QTKEY_LED_EN (TROUT_GPIO_MISC3_BASE + 7)
- +
- +#define TROUT_GPIO_VCM_PWDN (TROUT_GPIO_MISC4_BASE + 0)
- +#define TROUT_GPIO_USB_H2W_SW (TROUT_GPIO_MISC4_BASE + 1)
- +#define TROUT_GPIO_COMPASS_RST_N (TROUT_GPIO_MISC4_BASE + 2)
- +#define TROUT_GPIO_HAPTIC_EN_UP (TROUT_GPIO_MISC4_BASE + 3)
- +#define TROUT_GPIO_HAPTIC_EN_MAIN (TROUT_GPIO_MISC4_BASE + 4)
- +#define TROUT_GPIO_USB_PHY_RST_N (TROUT_GPIO_MISC4_BASE + 5)
- +#define TROUT_GPIO_WIFI_PA_RESETX (TROUT_GPIO_MISC4_BASE + 6)
- +#define TROUT_GPIO_WIFI_EN (TROUT_GPIO_MISC4_BASE + 7)
- +
- +#define TROUT_GPIO_BT_32K_EN (TROUT_GPIO_MISC5_BASE + 0)
- +#define TROUT_GPIO_MAC_32K_EN (TROUT_GPIO_MISC5_BASE + 1)
- +#define TROUT_GPIO_MDDI_32K_EN (TROUT_GPIO_MISC5_BASE + 2)
- +#define TROUT_GPIO_COMPASS_32K_EN (TROUT_GPIO_MISC5_BASE + 3)
- +
- +#define TROUT_GPIO_NAVI_ACT_N (TROUT_GPIO_INT2_BASE + 0)
- +#define TROUT_GPIO_COMPASS_IRQ (TROUT_GPIO_INT2_BASE + 1)
- +#define TROUT_GPIO_SLIDING_DET (TROUT_GPIO_INT2_BASE + 2)
- +#define TROUT_GPIO_AUD_HSMIC_DET_N (TROUT_GPIO_INT2_BASE + 3)
- +#define TROUT_GPIO_SD_DOOR_N (TROUT_GPIO_INT2_BASE + 4)
- +#define TROUT_GPIO_CAM_BTN_STEP1_N (TROUT_GPIO_INT2_BASE + 5)
- +#define TROUT_GPIO_CAM_BTN_STEP2_N (TROUT_GPIO_INT2_BASE + 6)
- +#define TROUT_GPIO_TP_ATT_N (TROUT_GPIO_INT2_BASE + 7)
- +#define TROUT_GPIO_BANK0_FIRST_INT_SOURCE (TROUT_GPIO_NAVI_ACT_N)
- +#define TROUT_GPIO_BANK0_LAST_INT_SOURCE (TROUT_GPIO_TP_ATT_N)
- +
- +#define TROUT_GPIO_H2W_DAT_GPI (TROUT_GPIO_MISC1_BASE + 0)
- +#define TROUT_GPIO_H2W_CLK_GPI (TROUT_GPIO_MISC1_BASE + 1)
- +#define TROUT_GPIO_CPLD128_VER_0 (TROUT_GPIO_MISC1_BASE + 4)
- +#define TROUT_GPIO_CPLD128_VER_1 (TROUT_GPIO_MISC1_BASE + 5)
- +#define TROUT_GPIO_CPLD128_VER_2 (TROUT_GPIO_MISC1_BASE + 6)
- +#define TROUT_GPIO_CPLD128_VER_3 (TROUT_GPIO_MISC1_BASE + 7)
- +
- +#define TROUT_GPIO_SDMC_CD_N (TROUT_GPIO_VIRTUAL_BASE + 0)
- +#define TROUT_GPIO_END (TROUT_GPIO_SDMC_CD_N)
- +#define TROUT_GPIO_BANK1_FIRST_INT_SOURCE (TROUT_GPIO_SDMC_CD_N)
- +#define TROUT_GPIO_BANK1_LAST_INT_SOURCE (TROUT_GPIO_SDMC_CD_N)
- +
- +#define TROUT_GPIO_VIRTUAL_TO_REAL_OFFSET \
- + (TROUT_GPIO_INT5_BASE - TROUT_GPIO_VIRTUAL_BASE)
- +
- +#define TROUT_INT_START (NR_MSM_IRQS + NR_GPIO_IRQS)
- +#define TROUT_INT_BANK0_COUNT (8)
- +#define TROUT_INT_BANK1_START (TROUT_INT_START + TROUT_INT_BANK0_COUNT)
- +#define TROUT_INT_BANK1_COUNT (1)
- +#define TROUT_INT_END (TROUT_INT_START + TROUT_INT_BANK0_COUNT + \
- + TROUT_INT_BANK1_COUNT - 1)
- +#define TROUT_GPIO_TO_INT(n) (((n) <= TROUT_GPIO_BANK0_LAST_INT_SOURCE) ? \
- + (TROUT_INT_START - TROUT_GPIO_BANK0_FIRST_INT_SOURCE + (n)) : \
- + (TROUT_INT_BANK1_START - TROUT_GPIO_BANK1_FIRST_INT_SOURCE + (n)))
- +
- +#define TROUT_INT_TO_BANK(n) ((n - TROUT_INT_START) / TROUT_INT_BANK0_COUNT)
- +#define TROUT_INT_TO_MASK(n) (1U << ((n - TROUT_INT_START) & 7))
- +#define TROUT_BANK_TO_MASK_REG(bank) \
- + (bank ? TROUT_GPIO_INT_MASK1_REG : TROUT_GPIO_INT_MASK0_REG)
- +#define TROUT_BANK_TO_STAT_REG(bank) \
- + (bank ? TROUT_GPIO_INT_STAT1_REG : TROUT_GPIO_INT_STAT0_REG)
- +
- +#endif /* GUARD */
- diff --git a/arch/arm/mach-msm/devices-msm7x00.c b/arch/arm/mach-msm/devices-msm7x00.c
- index fde9d8f..e9991f3 100644
- --- a/arch/arm/mach-msm/devices-msm7x00.c
- +++ b/arch/arm/mach-msm/devices-msm7x00.c
- @@ -322,6 +322,74 @@ static struct platform_device *msm_sdcc_devices[] __initdata = {
- &msm_device_sdc4,
- };
- +static struct resource resources_mddi0[] = {
- + {
- + .start = MSM_PMDH_PHYS,
- + .end = MSM_PMDH_PHYS + MSM_PMDH_SIZE - 1,
- + .flags = IORESOURCE_MEM,
- + },
- + {
- + .start = INT_MDDI_PRI,
- + .end = INT_MDDI_PRI,
- + .flags = IORESOURCE_IRQ,
- + },
- +};
- +
- +static struct resource resources_mddi1[] = {
- + {
- + .start = MSM_EMDH_PHYS,
- + .end = MSM_EMDH_PHYS + MSM_EMDH_SIZE - 1,
- + .flags = IORESOURCE_MEM,
- + },
- + {
- + .start = INT_MDDI_EXT,
- + .end = INT_MDDI_EXT,
- + .flags = IORESOURCE_IRQ,
- + },
- +};
- +
- +struct platform_device msm_device_mddi0 = {
- + .name = "msm_mddi",
- + .id = 0,
- + .num_resources = ARRAY_SIZE(resources_mddi0),
- + .resource = resources_mddi0,
- + .dev = {
- + .coherent_dma_mask = 0xffffffff,
- + },
- +};
- +
- +struct platform_device msm_device_mddi1 = {
- + .name = "msm_mddi",
- + .id = 1,
- + .num_resources = ARRAY_SIZE(resources_mddi1),
- + .resource = resources_mddi1,
- + .dev = {
- + .coherent_dma_mask = 0xffffffff,
- + },
- +};
- +
- +
- +static struct resource resources_mdp[] = {
- + {
- + .start = MSM_MDP_PHYS,
- + .end = MSM_MDP_PHYS + MSM_MDP_SIZE - 1,
- + .name = "mdp",
- + .flags = IORESOURCE_MEM
- + },
- + {
- + .start = INT_MDP,
- + .end = INT_MDP,
- + .flags = IORESOURCE_IRQ,
- + },
- +};
- +
- +struct platform_device msm_device_mdp = {
- + .name = "msm_mdp",
- + .id = 0,
- + .num_resources = ARRAY_SIZE(resources_mdp),
- + .resource = resources_mdp,
- +};
- +
- int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat,
- unsigned int stat_irq, unsigned long stat_irq_flags)
- {
- diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
- index 568443e..b238197 100644
- --- a/arch/arm/mach-msm/devices.h
- +++ b/arch/arm/mach-msm/devices.h
- @@ -34,6 +34,9 @@ extern struct platform_device msm_device_i2c;
- extern struct platform_device msm_device_smd;
- extern struct platform_device msm_device_nand;
- +extern struct platform_device msm_device_mddi0;
- +extern struct platform_device msm_device_mddi1;
- +extern struct platform_device msm_device_mdp;
- extern struct clk msm_clocks_7x01a[];
- extern unsigned msm_num_clocks_7x01a;
- diff --git a/arch/arm/mach-msm/include/mach/earlysuspend.h b/arch/arm/mach-msm/include/mach/earlysuspend.h
- new file mode 100755
- index 0000000..8343b81
- --- /dev/null
- +++ b/arch/arm/mach-msm/include/mach/earlysuspend.h
- @@ -0,0 +1,56 @@
- +/* include/linux/earlysuspend.h
- + *
- + * Copyright (C) 2007-2008 Google, Inc.
- + *
- + * This software is licensed under the terms of the GNU General Public
- + * License version 2, as published by the Free Software Foundation, and
- + * may be copied, distributed, and modified under those terms.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + */
- +
- +#ifndef _LINUX_EARLYSUSPEND_H
- +#define _LINUX_EARLYSUSPEND_H
- +
- +#ifdef CONFIG_HAS_EARLYSUSPEND
- +#include <linux/list.h>
- +#endif
- +
- +/* The early_suspend structure defines suspend and resume hooks to be called
- + * when the user visible sleep state of the system changes, and a level to
- + * control the order. They can be used to turn off the screen and input
- + * devices that are not used for wakeup.
- + * Suspend handlers are called in low to high level order, resume handlers are
- + * called in the opposite order. If, when calling register_early_suspend,
- + * the suspend handlers have already been called without a matching call to the
- + * resume handlers, the suspend handler will be called directly from
- + * register_early_suspend. This direct call can violate the normal level order.
- + */
- +enum {
- + EARLY_SUSPEND_LEVEL_BLANK_SCREEN = 50,
- + EARLY_SUSPEND_LEVEL_STOP_DRAWING = 100,
- + EARLY_SUSPEND_LEVEL_DISABLE_FB = 150,
- +};
- +struct early_suspend {
- +#ifdef CONFIG_HAS_EARLYSUSPEND
- + struct list_head link;
- + int level;
- + void (*suspend)(struct early_suspend *h);
- + void (*resume)(struct early_suspend *h);
- +#endif
- +};
- +
- +#ifdef CONFIG_HAS_EARLYSUSPEND
- +void register_early_suspend(struct early_suspend *handler);
- +void unregister_early_suspend(struct early_suspend *handler);
- +#else
- +#define register_early_suspend(handler) do { } while (0)
- +#define unregister_early_suspend(handler) do { } while (0)
- +#endif
- +
- +#endif
- +
- diff --git a/arch/arm/mach-msm/include/mach/htc_pwrsink.h b/arch/arm/mach-msm/include/mach/htc_pwrsink.h
- new file mode 100644
- index 0000000..0c3b70a
- --- /dev/null
- +++ b/arch/arm/mach-msm/include/mach/htc_pwrsink.h
- @@ -0,0 +1,87 @@
- +/* include/asm/mach-msm/htc_pwrsink.h
- + *
- + * Copyright (C) 2007 Google, Inc.
- + * Copyright (C) 2008 HTC Corporation.
- + *
- + * This software is licensed under the terms of the GNU General Public
- + * License version 2, as published by the Free Software Foundation, and
- + * may be copied, distributed, and modified under those terms.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + */
- +#ifndef _ARCH_ARM_MACH_MSM_HTC_PWRSINK_H_
- +#define _ARCH_ARM_MACH_MSM_HTC_PWRSINK_H_
- +
- +#include <linux/platform_device.h>
- +#include <mach/earlysuspend.h>
- +
- +typedef enum {
- + PWRSINK_AUDIO_PCM = 0,
- + PWRSINK_AUDIO_MP3,
- + PWRSINK_AUDIO_AAC,
- +
- + PWRSINK_AUDIO_LAST = PWRSINK_AUDIO_AAC,
- + PWRSINK_AUDIO_INVALID
- +} pwrsink_audio_id_type;
- +
- +struct pwr_sink_audio {
- + unsigned volume;
- + unsigned percent;
- +};
- +
- +typedef enum {
- + PWRSINK_SYSTEM_LOAD = 0,
- + PWRSINK_AUDIO,
- + PWRSINK_BACKLIGHT,
- + PWRSINK_LED_BUTTON,
- + PWRSINK_LED_KEYBOARD,
- + PWRSINK_GP_CLK,
- + PWRSINK_BLUETOOTH,
- + PWRSINK_CAMERA,
- + PWRSINK_SDCARD,
- + PWRSINK_VIDEO,
- + PWRSINK_WIFI,
- +
- + PWRSINK_LAST = PWRSINK_WIFI,
- + PWRSINK_INVALID
- +} pwrsink_id_type;
- +
- +struct pwr_sink {
- + pwrsink_id_type id;
- + unsigned ua_max;
- + unsigned percent_util;
- +};
- +
- +struct pwr_sink_platform_data {
- + unsigned num_sinks;
- + struct pwr_sink *sinks;
- + int (*suspend_late)(struct platform_device *, pm_message_t state);
- + int (*resume_early)(struct platform_device *);
- + void (*suspend_early)(struct early_suspend *);
- + void (*resume_late)(struct early_suspend *);
- +};
- +
- +#ifndef CONFIG_HTC_PWRSINK
- +static inline int htc_pwrsink_set(pwrsink_id_type id, unsigned percent)
- +{
- + return 0;
- +}
- +static inline int htc_pwrsink_audio_set(pwrsink_audio_id_type id,
- + unsigned percent_utilized) { return 0; }
- +static inline int htc_pwrsink_audio_volume_set(
- + pwrsink_audio_id_type id, unsigned volume) { return 0; }
- +static inline int htc_pwrsink_audio_path_set(unsigned path) { return 0; }
- +#else
- +extern int htc_pwrsink_set(pwrsink_id_type id, unsigned percent);
- +extern int htc_pwrsink_audio_set(pwrsink_audio_id_type id,
- + unsigned percent_utilized);
- +extern int htc_pwrsink_audio_volume_set(pwrsink_audio_id_type id,
- + unsigned volume);
- +extern int htc_pwrsink_audio_path_set(unsigned path);
- +#endif
- +
- +#endif
- diff --git a/arch/arm/mach-msm/include/mach/msm_hsusb.h b/arch/arm/mach-msm/include/mach/msm_hsusb.h
- new file mode 100644
- index 0000000..2d49b0f
- --- /dev/null
- +++ b/arch/arm/mach-msm/include/mach/msm_hsusb.h
- @@ -0,0 +1,74 @@
- +/* linux/include/asm-arm/arch-msm/hsusb.h
- + *
- + * Copyright (C) 2008 Google, Inc.
- + * Author: Brian Swetland <swetland@google.com>
- + *
- + * This software is licensed under the terms of the GNU General Public
- + * License version 2, as published by the Free Software Foundation, and
- + * may be copied, distributed, and modified under those terms.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + */
- +
- +#ifndef __ASM_ARCH_MSM_HSUSB_H
- +#define __ASM_ARCH_MSM_HSUSB_H
- +
- +#include <linux/types.h>
- +
- +/* platform device data for msm_hsusb driver */
- +
- +#ifdef CONFIG_USB_FUNCTION
- +/* matches a product ID to a list of enabled functions */
- +struct msm_hsusb_product {
- + /* product ID for usb_device_descriptor.idProduct */
- + __u16 product_id;
- +
- + /* bit mask of enabled usb_functions, matching ordering
- + ** in msm_hsusb_platform_data.functions
- + */
- + __u32 functions;
- +};
- +#endif
- +
- +struct msm_hsusb_platform_data {
- + /* hard reset the ULPI PHY */
- + void (*phy_reset)(void);
- +
- + /* for notification when USB is connected or disconnected */
- + void (*usb_connected)(int);
- +
- + /* val, reg pairs terminated by -1 */
- + int *phy_init_seq;
- +
- +#ifdef CONFIG_USB_FUNCTION
- + /* USB device descriptor fields */
- + __u16 vendor_id;
- +
- + /* Default product ID.
- + ** This can be overridden dynamically based on the disabled
- + ** state of the functions using the product_table.
- + */
- + __u16 product_id;
- +
- + __u16 version;
- + char *serial_number;
- + char *product_name;
- + char *manufacturer_name;
- +
- + /* list of function drivers to bind to this configuration */
- + int num_functions;
- + char **functions;
- +
- + /* if num_products is zero, then the default value in product_id
- + ** is used for the configuration descriptor.
- + */
- + int num_products;
- + struct msm_hsusb_product *products;
- +#endif
- +};
- +
- +#endif
- diff --git a/arch/arm/mach-msm/include/mach/msm_hsusb_hw.h b/arch/arm/mach-msm/include/mach/msm_hsusb_hw.h
- new file mode 100644
- index 0000000..8042b31
- --- /dev/null
- +++ b/arch/arm/mach-msm/include/mach/msm_hsusb_hw.h
- @@ -0,0 +1,204 @@
- +/*
- + * Copyright (C) 2007 Google, Inc.
- + * Author: Brian Swetland <swetland@google.com>
- + *
- + * This software is licensed under the terms of the GNU General Public
- + * License version 2, as published by the Free Software Foundation, and
- + * may be copied, distributed, and modified under those terms.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + */
- +
- +#ifndef __LINUX_USB_GADGET_MSM72K_UDC_H__
- +#define __LINUX_USB_GADGET_MSM72K_UDC_H__
- +
- +/*-------------------------------------------------------------------------*/
- +
- +#define xprintk(level, fmt, args...) \
- + printk(level "%s: " fmt , driver_name , ## args)
- +
- +#ifdef DEBUG
- +#undef DEBUG
- +#define DEBUG(fmt, args...) \
- + xprintk(KERN_DEBUG , fmt , ## args)
- +#else
- +#define DEBUG(fmt,args...) \
- + do { } while (0)
- +#endif /* DEBUG */
- +
- +#ifdef VERBOSE
- +#define VDEBUG DEBUG
- +#else
- +#define VDEBUG(fmt,args...) \
- + do { } while (0)
- +#endif /* VERBOSE */
- +
- +#define ERROR(fmt,args...) \
- + xprintk(KERN_ERR , fmt , ## args)
- +#define INFO(fmt,args...) \
- + xprintk(KERN_INFO , fmt , ## args)
- +
- +/*-------------------------------------------------------------------------*/
- +
- +
- +#define USB_ID (MSM_USB_BASE + 0x0000)
- +#define USB_HWGENERAL (MSM_USB_BASE + 0x0004)
- +#define USB_HWHOST (MSM_USB_BASE + 0x0008)
- +#define USB_HWDEVICE (MSM_USB_BASE + 0x000C)
- +#define USB_HWTXBUF (MSM_USB_BASE + 0x0010)
- +#define USB_HWRXBUF (MSM_USB_BASE + 0x0014)
- +#define USB_SBUSCFG (MSM_USB_BASE + 0x0090)
- +
- +#define USB_CAPLENGTH (MSM_USB_BASE + 0x0100) /* 8 bit */
- +#define USB_HCIVERSION (MSM_USB_BASE + 0x0102) /* 16 bit */
- +#define USB_HCSPARAMS (MSM_USB_BASE + 0x0104)
- +#define USB_HCCPARAMS (MSM_USB_BASE + 0x0108)
- +#define USB_DCIVERSION (MSM_USB_BASE + 0x0120) /* 16 bit */
- +#define USB_USBCMD (MSM_USB_BASE + 0x0140)
- +#define USB_USBSTS (MSM_USB_BASE + 0x0144)
- +#define USB_USBINTR (MSM_USB_BASE + 0x0148)
- +#define USB_FRINDEX (MSM_USB_BASE + 0x014C)
- +#define USB_DEVICEADDR (MSM_USB_BASE + 0x0154)
- +#define USB_ENDPOINTLISTADDR (MSM_USB_BASE + 0x0158)
- +#define USB_BURSTSIZE (MSM_USB_BASE + 0x0160)
- +#define USB_TXFILLTUNING (MSM_USB_BASE + 0x0164)
- +#define USB_ULPI_VIEWPORT (MSM_USB_BASE + 0x0170)
- +#define USB_ENDPTNAK (MSM_USB_BASE + 0x0178)
- +#define USB_ENDPTNAKEN (MSM_USB_BASE + 0x017C)
- +#define USB_PORTSC (MSM_USB_BASE + 0x0184)
- +#define USB_OTGSC (MSM_USB_BASE + 0x01A4)
- +#define USB_USBMODE (MSM_USB_BASE + 0x01A8)
- +#define USB_ENDPTSETUPSTAT (MSM_USB_BASE + 0x01AC)
- +#define USB_ENDPTPRIME (MSM_USB_BASE + 0x01B0)
- +#define USB_ENDPTFLUSH (MSM_USB_BASE + 0x01B4)
- +#define USB_ENDPTSTAT (MSM_USB_BASE + 0x01B8)
- +#define USB_ENDPTCOMPLETE (MSM_USB_BASE + 0x01BC)
- +#define USB_ENDPTCTRL(n) (MSM_USB_BASE + 0x01C0 + (4 * (n)))
- +
- +
- +#define USBCMD_RESET 2
- +#define USBCMD_ATTACH 1
- +#define USBCMD_ATDTW (1 << 14)
- +
- +#define USBMODE_DEVICE 2
- +#define USBMODE_HOST 3
- +
- +struct ept_queue_head {
- + unsigned config;
- + unsigned active; /* read-only */
- +
- + unsigned next;
- + unsigned info;
- + unsigned page0;
- + unsigned page1;
- + unsigned page2;
- + unsigned page3;
- + unsigned page4;
- + unsigned reserved_0;
- +
- + unsigned char setup_data[8];
- +
- + unsigned reserved_1;
- + unsigned reserved_2;
- + unsigned reserved_3;
- + unsigned reserved_4;
- +};
- +
- +#define CONFIG_MAX_PKT(n) ((n) << 16)
- +#define CONFIG_ZLT (1 << 29) /* stop on zero-len xfer */
- +#define CONFIG_IOS (1 << 15) /* IRQ on setup */
- +
- +struct ept_queue_item {
- + unsigned next;
- + unsigned info;
- + unsigned page0;
- + unsigned page1;
- + unsigned page2;
- + unsigned page3;
- + unsigned page4;
- + unsigned reserved;
- +};
- +
- +#define TERMINATE 1
- +
- +#define INFO_BYTES(n) ((n) << 16)
- +#define INFO_IOC (1 << 15)
- +#define INFO_ACTIVE (1 << 7)
- +#define INFO_HALTED (1 << 6)
- +#define INFO_BUFFER_ERROR (1 << 5)
- +#define INFO_TXN_ERROR (1 << 3)
- +
- +
- +#define STS_NAKI (1 << 16) /* */
- +#define STS_SLI (1 << 8) /* R/WC - suspend state entered */
- +#define STS_SRI (1 << 7) /* R/WC - SOF recv'd */
- +#define STS_URI (1 << 6) /* R/WC - RESET recv'd - write to clear */
- +#define STS_FRI (1 << 3) /* R/WC - Frame List Rollover */
- +#define STS_PCI (1 << 2) /* R/WC - Port Change Detect */
- +#define STS_UEI (1 << 1) /* R/WC - USB Error */
- +#define STS_UI (1 << 0) /* R/WC - USB Transaction Complete */
- +
- +
- +/* bits used in all the endpoint status registers */
- +#define EPT_TX(n) (1 << ((n) + 16))
- +#define EPT_RX(n) (1 << (n))
- +
- +
- +#define CTRL_TXE (1 << 23)
- +#define CTRL_TXR (1 << 22)
- +#define CTRL_TXI (1 << 21)
- +#define CTRL_TXD (1 << 17)
- +#define CTRL_TXS (1 << 16)
- +#define CTRL_RXE (1 << 7)
- +#define CTRL_RXR (1 << 6)
- +#define CTRL_RXI (1 << 5)
- +#define CTRL_RXD (1 << 1)
- +#define CTRL_RXS (1 << 0)
- +
- +#define CTRL_TXT_MASK (3 << 18)
- +#define CTRL_TXT_CTRL (0 << 18)
- +#define CTRL_TXT_ISOCH (1 << 18)
- +#define CTRL_TXT_BULK (2 << 18)
- +#define CTRL_TXT_INT (3 << 18)
- +#define CTRL_TXT_EP_TYPE_SHIFT 18
- +
- +#define CTRL_RXT_MASK (3 << 2)
- +#define CTRL_RXT_CTRL (0 << 2)
- +#define CTRL_RXT_ISOCH (1 << 2)
- +#define CTRL_RXT_BULK (2 << 2)
- +#define CTRL_RXT_INT (3 << 2)
- +#define CTRL_RXT_EP_TYPE_SHIFT 2
- +
- +#define ULPI_WAKEUP (1 << 31)
- +#define ULPI_RUN (1 << 30)
- +#define ULPI_WRITE (1 << 29)
- +#define ULPI_READ (0 << 29)
- +#define ULPI_STATE_NORMAL (1 << 27)
- +#define ULPI_ADDR(n) (((n) & 255) << 16)
- +#define ULPI_DATA(n) ((n) & 255)
- +#define ULPI_DATA_READ(n) (((n) >> 8) & 255)
- +
- +/* USB_PORTSC bits for determining port speed */
- +#define PORTSC_PSPD_FS (0 << 26)
- +#define PORTSC_PSPD_LS (1 << 26)
- +#define PORTSC_PSPD_HS (2 << 26)
- +#define PORTSC_PSPD_MASK (3 << 26)
- +/* suspend and remote wakeup */
- +#define PORTSC_FPR (1 << 6)
- +#define PORTSC_SUSP (1 << 7)
- +
- +/* test mode support */
- +#define J_TEST (0x0100)
- +#define K_TEST (0x0200)
- +#define SE0_NAK_TEST (0x0300)
- +#define TST_PKT_TEST (0x0400)
- +#define PORTSC_PTC (0xf << 16)
- +#define PORTSC_PTC_J_STATE (0x01 << 16)
- +#define PORTSC_PTC_K_STATE (0x02 << 16)
- +#define PORTSC_PTC_SE0_NAK (0x03 << 16)
- +#define PORTSC_PTC_TST_PKT (0x04 << 16)
- +#endif /* __LINUX_USB_GADGET_MSM72K_UDC_H__ */
- diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
- index 591ae9f..79717e4 100644
- --- a/drivers/usb/gadget/Kconfig
- +++ b/drivers/usb/gadget/Kconfig
- @@ -509,6 +509,24 @@ config USB_LANGWELL
- #
- # LAST -- dummy/emulated controller
- #
- +config USB_GADGET_MSM_72K
- + boolean "MSM 72K Device Controller"
- + depends on ARCH_MSM
- + select USB_GADGET_SELECTED
- + select USB_GADGET_DUALSPEED
- + help
- + USB gadget driver for Qualcomm MSM 72K architecture.
- +
- + Say "y" to link the driver statically, or "m" to build a
- + dynamically linked module called "msm72k" and force all
- + gadget drivers to also be dynamically linked.
- +
- +config USB_MSM_72K
- + tristate
- + depends on USB_GADGET_MSM_72K
- + default USB_GADGET
- + select USB_GADGET_SELECTED
- +
- config USB_GADGET_DUMMY_HCD
- boolean "Dummy HCD (DEVELOPMENT)"
- diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
- index 9bcde11..48ea27a 100644
- --- a/drivers/usb/gadget/Makefile
- +++ b/drivers/usb/gadget/Makefile
- @@ -28,6 +28,7 @@ obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
- obj-$(CONFIG_USB_CI13XXX) += ci13xxx_udc.o
- obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o
- obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o
- +obj-$(CONFIG_USB_MSM_72K) += msm72k_udc.o
- #
- # USB gadget drivers
- diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
- index e511fec..a8314ba 100644
- --- a/drivers/usb/gadget/gadget_chips.h
- +++ b/drivers/usb/gadget/gadget_chips.h
- @@ -126,6 +126,12 @@
- #define gadget_is_ci13xxx(g) 0
- #endif
- +#ifdef CONFIG_USB_GADGET_MSM_72K
- +#define gadget_is_msm72k(g) !strcmp("msm72k_udc", (g)->name)
- +#else
- +#define gadget_is_msm72k(g) 0
- +#endif
- +
- // CONFIG_USB_GADGET_SX2
- // CONFIG_USB_GADGET_AU1X00
- // ...
- diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
- new file mode 100644
- index 0000000..1630cf8
- --- /dev/null
- +++ b/drivers/usb/gadget/msm72k_udc.c
- @@ -0,0 +1,1738 @@
- +/*
- + * Driver for HighSpeed USB Client Controller in MSM7K
- + *
- + * Copyright (C) 2008 Google, Inc.
- + * Author: Mike Lockwood <lockwood@android.com>
- + * Brian Swetland <swetland@google.com>
- + *
- + * This software is licensed under the terms of the GNU General Public
- + * License version 2, as published by the Free Software Foundation, and
- + * may be copied, distributed, and modified under those terms.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + */
- +
- +#include <linux/init.h>
- +#include <linux/module.h>
- +#include <linux/kernel.h>
- +#include <linux/list.h>
- +
- +#include <linux/delay.h>
- +#include <linux/interrupt.h>
- +#include <linux/dma-mapping.h>
- +#include <linux/dmapool.h>
- +#include <linux/platform_device.h>
- +#include <linux/debugfs.h>
- +#include <linux/workqueue.h>
- +#include <linux/clk.h>
- +
- +#include <linux/usb/ch9.h>
- +#include <linux/usb/gadget.h>
- +#include <linux/io.h>
- +
- +#include <asm/mach-types.h>
- +
- +#include <mach/board.h>
- +#include <mach/msm_hsusb.h>
- +#include <linux/device.h>
- +#include <mach/msm_hsusb_hw.h>
- +
- +static const char driver_name[] = "msm72k_udc";
- +
- +/* #define DEBUG */
- +/* #define VERBOSE */
- +
- +#define MSM_USB_BASE ((unsigned) ui->addr)
- +
- +#define DRIVER_DESC "MSM 72K USB Peripheral Controller"
- +
- +#define EPT_FLAG_IN 0x0001
- +
- +#define SETUP_BUF_SIZE 4096
- +
- +
- +static const char *const ep_name[] = {
- + "ep0out", "ep1out", "ep2out", "ep3out",
- + "ep4out", "ep5out", "ep6out", "ep7out",
- + "ep8out", "ep9out", "ep10out", "ep11out",
- + "ep12out", "ep13out", "ep14out", "ep15out",
- + "ep0in", "ep1in", "ep2in", "ep3in",
- + "ep4in", "ep5in", "ep6in", "ep7in",
- + "ep8in", "ep9in", "ep10in", "ep11in",
- + "ep12in", "ep13in", "ep14in", "ep15in"
- +};
- +
- +/* current state of VBUS */
- +static int vbus;
- +
- +struct msm_request {
- + struct usb_request req;
- +
- + /* saved copy of req.complete */
- + void (*gadget_complete)(struct usb_ep *ep,
- + struct usb_request *req);
- +
- +
- + struct usb_info *ui;
- + struct msm_request *next;
- +
- + unsigned busy:1;
- + unsigned live:1;
- + unsigned alloced:1;
- + unsigned dead:1;
- +
- + dma_addr_t dma;
- + dma_addr_t item_dma;
- +
- + struct ept_queue_item *item;
- +};
- +
- +#define to_msm_request(r) container_of(r, struct msm_request, req)
- +#define to_msm_endpoint(r) container_of(r, struct msm_endpoint, ep)
- +
- +struct msm_endpoint {
- + struct usb_ep ep;
- + struct usb_info *ui;
- + struct msm_request *req; /* head of pending requests */
- + struct msm_request *last;
- + unsigned flags;
- +
- + /* bit number (0-31) in various status registers
- + ** as well as the index into the usb_info's array
- + ** of all endpoints
- + */
- + unsigned char bit;
- + unsigned char num;
- +
- + /* pointers to DMA transfer list area */
- + /* these are allocated from the usb_info dma space */
- + struct ept_queue_head *head;
- +};
- +
- +static void usb_do_work(struct work_struct *w);
- +
- +
- +#define USB_STATE_IDLE 0
- +#define USB_STATE_ONLINE 1
- +#define USB_STATE_OFFLINE 2
- +
- +#define USB_FLAG_START 0x0001
- +#define USB_FLAG_VBUS_ONLINE 0x0002
- +#define USB_FLAG_VBUS_OFFLINE 0x0004
- +#define USB_FLAG_RESET 0x0008
- +
- +struct usb_info {
- + /* lock for register/queue/device state changes */
- + spinlock_t lock;
- +
- + /* single request used for handling setup transactions */
- + struct usb_request *setup_req;
- +
- + struct platform_device *pdev;
- + int irq;
- + void *addr;
- +
- + unsigned state;
- + unsigned flags;
- +
- + unsigned online:1;
- + unsigned running:1;
- +
- + struct dma_pool *pool;
- +
- + /* dma page to back the queue heads and items */
- + unsigned char *buf;
- + dma_addr_t dma;
- +
- + struct ept_queue_head *head;
- +
- + /* used for allocation */
- + unsigned next_item;
- + unsigned next_ifc_num;
- +
- + /* endpoints are ordered based on their status bits,
- + ** so they are OUT0, OUT1, ... OUT15, IN0, IN1, ... IN15
- + */
- + struct msm_endpoint ept[32];
- +
- + int *phy_init_seq;
- + void (*phy_reset)(void);
- +
- + /* for notification when USB is connected or disconnected */
- + void (*usb_connected)(int);
- +
- + struct work_struct work;
- + unsigned phy_status;
- + unsigned phy_fail_count;
- +
- + struct usb_gadget gadget;
- + struct usb_gadget_driver *driver;
- +
- +#define ep0out ept[0]
- +#define ep0in ept[16]
- +
- + struct clk *clk;
- + struct clk *pclk;
- +
- + unsigned int ep0_dir;
- + u16 test_mode;
- +
- + u8 remote_wakeup;
- +};
- +
- +static const struct usb_ep_ops msm72k_ep_ops;
- +
- +
- +static int msm72k_pullup(struct usb_gadget *_gadget, int is_active);
- +static int msm72k_set_halt(struct usb_ep *_ep, int value);
- +static void flush_endpoint(struct msm_endpoint *ept);
- +
- +static int usb_ep_get_stall(struct msm_endpoint *ept)
- +{
- + unsigned int n;
- + struct usb_info *ui = ept->ui;
- +
- + n = readl(USB_ENDPTCTRL(ept->num));
- + if (ept->flags & EPT_FLAG_IN)
- + return (CTRL_TXS & n) ? 1 : 0;
- + else
- + return (CTRL_RXS & n) ? 1 : 0;
- +}
- +
- +#if 0
- +static unsigned ulpi_read(struct usb_info *ui, unsigned reg)
- +{
- + unsigned timeout = 100000;
- +
- + /* initiate read operation */
- + writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
- + USB_ULPI_VIEWPORT);
- +
- + /* wait for completion */
- + while ((readl(USB_ULPI_VIEWPORT) & ULPI_RUN) && (--timeout))
- + ;
- +
- + if (timeout == 0) {
- + ERROR("ulpi_read: timeout %08x\n", readl(USB_ULPI_VIEWPORT));
- + return 0xffffffff;
- + }
- + return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
- +}
- +#endif
- +
- +static void ulpi_write(struct usb_info *ui, unsigned val, unsigned reg)
- +{
- + unsigned timeout = 10000;
- +
- + /* initiate write operation */
- + writel(ULPI_RUN | ULPI_WRITE |
- + ULPI_ADDR(reg) | ULPI_DATA(val),
- + USB_ULPI_VIEWPORT);
- +
- + /* wait for completion */
- + while ((readl(USB_ULPI_VIEWPORT) & ULPI_RUN) && (--timeout))
- + ;
- +
- + if (timeout == 0)
- + ERROR("ulpi_write: timeout\n");
- +}
- +
- +static void ulpi_init(struct usb_info *ui)
- +{
- + int *seq = ui->phy_init_seq;
- +
- + if (!seq)
- + return;
- +
- + while (seq[0] >= 0) {
- + INFO("ulpi: write 0x%02x to 0x%02x\n", seq[0], seq[1]);
- + ulpi_write(ui, seq[0], seq[1]);
- + seq += 2;
- + }
- +}
- +
- +static void init_endpoints(struct usb_info *ui)
- +{
- + unsigned n;
- +
- + for (n = 0; n < 32; n++) {
- + struct msm_endpoint *ept = ui->ept + n;
- +
- + ept->ui = ui;
- + ept->bit = n;
- + ept->num = n & 15;
- + ept->ep.name = ep_name[n];
- + ept->ep.ops = &msm72k_ep_ops;
- +
- + if (ept->bit > 15) {
- + /* IN endpoint */
- + ept->head = ui->head + (ept->num << 1) + 1;
- + ept->flags = EPT_FLAG_IN;
- + } else {
- + /* OUT endpoint */
- + ept->head = ui->head + (ept->num << 1);
- + ept->flags = 0;
- + }
- +
- + }
- +}
- +
- +static void config_ept(struct msm_endpoint *ept)
- +{
- + unsigned cfg = CONFIG_MAX_PKT(ept->ep.maxpacket) | CONFIG_ZLT;
- +
- + if (ept->bit == 0)
- + /* ep0 out needs interrupt-on-setup */
- + cfg |= CONFIG_IOS;
- +
- + ept->head->config = cfg;
- + ept->head->next = TERMINATE;
- +
- + if (ept->ep.maxpacket)
- + INFO("ept #%d %s max:%d head:%p bit:%d\n",
- + ept->num, (ept->flags & EPT_FLAG_IN) ? "in" : "out",
- + ept->ep.maxpacket, ept->head, ept->bit);
- +}
- +
- +static void configure_endpoints(struct usb_info *ui)
- +{
- + unsigned n;
- +
- + for (n = 0; n < 32; n++)
- + config_ept(ui->ept + n);
- +}
- +
- +struct usb_request *usb_ept_alloc_req(struct msm_endpoint *ept,
- + unsigned bufsize, gfp_t gfp_flags)
- +{
- + struct usb_info *ui = ept->ui;
- + struct msm_request *req;
- +
- + req = kzalloc(sizeof(*req), gfp_flags);
- + if (!req)
- + goto fail1;
- +
- + req->item = dma_pool_alloc(ui->pool, gfp_flags, &req->item_dma);
- + if (!req->item)
- + goto fail2;
- +
- + if (bufsize) {
- + req->req.buf = kmalloc(bufsize, gfp_flags);
- + if (!req->req.buf)
- + goto fail3;
- + req->alloced = 1;
- + }
- +
- + return &req->req;
- +
- +fail3:
- + dma_pool_free(ui->pool, req->item, req->item_dma);
- +fail2:
- + kfree(req);
- +fail1:
- + return 0;
- +}
- +
- +static void do_free_req(struct usb_info *ui, struct msm_request *req)
- +{
- + if (req->alloced)
- + kfree(req->req.buf);
- +
- + dma_pool_free(ui->pool, req->item, req->item_dma);
- + kfree(req);
- +}
- +
- +
- +static void usb_ept_enable(struct msm_endpoint *ept, int yes,
- + unsigned char ep_type)
- +{
- + struct usb_info *ui = ept->ui;
- + int in = ept->flags & EPT_FLAG_IN;
- + unsigned n;
- +
- + n = readl(USB_ENDPTCTRL(ept->num));
- +
- + if (in) {
- + if (yes) {
- + n = (n & (~CTRL_TXT_MASK)) |
- + (ep_type << CTRL_TXT_EP_TYPE_SHIFT);
- + n |= CTRL_TXE | CTRL_TXR;
- + } else
- + n &= (~CTRL_TXE);
- + } else {
- + if (yes) {
- + n = (n & (~CTRL_RXT_MASK)) |
- + (ep_type << CTRL_RXT_EP_TYPE_SHIFT);
- + n |= CTRL_RXE | CTRL_RXR;
- + } else
- + n &= ~(CTRL_RXE);
- + }
- + writel(n, USB_ENDPTCTRL(ept->num));
- +
- +#if 1
- + INFO("ept %d %s %s\n",
- + ept->num, in ? "in" : "out", yes ? "enabled" : "disabled");
- +#endif
- +}
- +
- +static void usb_ept_start(struct msm_endpoint *ept)
- +{
- + struct usb_info *ui = ept->ui;
- + struct msm_request *req = ept->req;
- +
- + BUG_ON(req->live);
- +
- + /* link the hw queue head to the request's transaction item */
- + ept->head->next = req->item_dma;
- + ept->head->info = 0;
- +
- + /* start the endpoint */
- + writel(1 << ept->bit, USB_ENDPTPRIME);
- +
- + /* mark this chain of requests as live */
- + while (req) {
- + req->live = 1;
- + req = req->next;
- + }
- +}
- +
- +int usb_ept_queue_xfer(struct msm_endpoint *ept, struct usb_request *_req)
- +{
- + unsigned long flags;
- + struct msm_request *req = to_msm_request(_req);
- + struct msm_request *last;
- + struct usb_info *ui = ept->ui;
- + struct ept_queue_item *item = req->item;
- + unsigned length = req->req.length;
- +
- + if (length > 0x4000)
- + return -EMSGSIZE;
- +
- + spin_lock_irqsave(&ui->lock, flags);
- +
- + if (req->busy) {
- + req->req.status = -EBUSY;
- + spin_unlock_irqrestore(&ui->lock, flags);
- + INFO("usb_ept_queue_xfer() tried to queue busy request\n");
- + return -EBUSY;
- + }
- +
- + if (!ui->online && (ept->num != 0)) {
- + req->req.status = -ESHUTDOWN;
- + spin_unlock_irqrestore(&ui->lock, flags);
- + INFO("usb_ept_queue_xfer() called while offline\n");
- + return -ESHUTDOWN;
- + }
- +
- + req->busy = 1;
- + req->live = 0;
- + req->next = 0;
- + req->req.status = -EBUSY;
- +
- + req->dma = dma_map_single(NULL, req->req.buf, length,
- + (ept->flags & EPT_FLAG_IN) ?
- + DMA_TO_DEVICE : DMA_FROM_DEVICE);
- +
- + /* prepare the transaction descriptor item for the hardware */
- + item->next = TERMINATE;
- + item->info = INFO_BYTES(length) | INFO_IOC | INFO_ACTIVE;
- + item->page0 = req->dma;
- + item->page1 = (req->dma + 0x1000) & 0xfffff000;
- + item->page2 = (req->dma + 0x2000) & 0xfffff000;
- + item->page3 = (req->dma + 0x3000) & 0xfffff000;
- +
- + /* Add the new request to the end of the queue */
- + last = ept->last;
- + if (last) {
- + /* Already requests in the queue. add us to the
- + * end, but let the completion interrupt actually
- + * start things going, to avoid hw issues
- + */
- + last->next = req;
- +
- + /* only modify the hw transaction next pointer if
- + * that request is not live
- + */
- + if (!last->live)
- + last->item->next = req->item_dma;
- + } else {
- + /* queue was empty -- kick the hardware */
- + ept->req = req;
- + usb_ept_start(ept);
- + }
- + ept->last = req;
- +
- + spin_unlock_irqrestore(&ui->lock, flags);
- + return 0;
- +}
- +
- +/* --- endpoint 0 handling --- */
- +
- +static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
- +{
- + struct msm_request *r = to_msm_request(req);
- + struct msm_endpoint *ept = to_msm_endpoint(ep);
- + struct usb_info *ui = ept->ui;
- +
- + req->complete = r->gadget_complete;
- + r->gadget_complete = 0;
- + if (req->complete)
- + req->complete(&ui->ep0in.ep, req);
- +}
- +
- +static void ep0_queue_ack_complete(struct usb_ep *ep, struct usb_request *req)
- +{
- + struct msm_endpoint *ept = to_msm_endpoint(ep);
- +
- + /* queue up the receive of the ACK response from the host */
- + if (req->status == 0) {
- + struct usb_info *ui = ept->ui;
- + req->length = 0;
- + req->complete = ep0_complete;
- + if (ui->ep0_dir == USB_DIR_IN)
- + usb_ept_queue_xfer(&ui->ep0out, req);
- + else
- + usb_ept_queue_xfer(&ui->ep0in, req);
- + } else
- + ep0_complete(ep, req);
- +}
- +
- +static void ep0_setup_ack_complete(struct usb_ep *ep, struct usb_request *req)
- +{
- + struct msm_endpoint *ept = to_msm_endpoint(ep);
- + struct usb_info *ui = ept->ui;
- + unsigned int temp;
- +
- + if (!ui->test_mode)
- + return;
- +
- + switch (ui->test_mode) {
- + case J_TEST:
- + pr_info("usb electrical test mode: (J)\n");
- + temp = readl(USB_PORTSC) & (~PORTSC_PTC);
- + writel(temp | PORTSC_PTC_J_STATE, USB_PORTSC);
- + break;
- +
- + case K_TEST:
- + pr_info("usb electrical test mode: (K)\n");
- + temp = readl(USB_PORTSC) & (~PORTSC_PTC);
- + writel(temp | PORTSC_PTC_K_STATE, USB_PORTSC);
- + break;
- +
- + case SE0_NAK_TEST:
- + pr_info("usb electrical test mode: (SE0-NAK)\n");
- + temp = readl(USB_PORTSC) & (~PORTSC_PTC);
- + writel(temp | PORTSC_PTC_SE0_NAK, USB_PORTSC);
- + break;
- +
- + case TST_PKT_TEST:
- + pr_info("usb electrical test mode: (TEST_PKT)\n");
- + temp = readl(USB_PORTSC) & (~PORTSC_PTC);
- + writel(temp | PORTSC_PTC_TST_PKT, USB_PORTSC);
- + break;
- + }
- +}
- +
- +static void ep0_setup_ack(struct usb_info *ui)
- +{
- + struct usb_request *req = ui->setup_req;
- + req->length = 0;
- + req->complete = ep0_setup_ack_complete;
- + usb_ept_queue_xfer(&ui->ep0in, req);
- +}
- +
- +static void ep0_setup_stall(struct usb_info *ui)
- +{
- + writel((1<<16) | (1<<0), USB_ENDPTCTRL(0));
- +}
- +
- +static void ep0_setup_send(struct usb_info *ui, unsigned length)
- +{
- + struct usb_request *req = ui->setup_req;
- + struct msm_request *r = to_msm_request(req);
- + struct msm_endpoint *ept = &ui->ep0in;
- +
- + req->length = length;
- + req->complete = ep0_queue_ack_complete;
- + r->gadget_complete = 0;
- + usb_ept_queue_xfer(ept, req);
- +}
- +
- +static void handle_setup(struct usb_info *ui)
- +{
- + struct usb_ctrlrequest ctl;
- + struct usb_request *req = ui->setup_req;
- + int ret;
- +
- + memcpy(&ctl, ui->ep0out.head->setup_data, sizeof(ctl));
- + writel(EPT_RX(0), USB_ENDPTSETUPSTAT);
- +
- + if (ctl.bRequestType & USB_DIR_IN)
- + ui->ep0_dir = USB_DIR_IN;
- + else
- + ui->ep0_dir = USB_DIR_OUT;
- +
- + /* any pending ep0 transactions must be canceled */
- + flush_endpoint(&ui->ep0out);
- + flush_endpoint(&ui->ep0in);
- +
- + INFO("setup: type=%02x req=%02x val=%04x idx=%04x len=%04x\n",
- + ctl.bRequestType, ctl.bRequest, ctl.wValue,
- + ctl.wIndex, ctl.wLength);
- +
- + if ((ctl.bRequestType & (USB_DIR_IN | USB_TYPE_MASK)) ==
- + (USB_DIR_IN | USB_TYPE_STANDARD)) {
- + if (ctl.bRequest == USB_REQ_GET_STATUS) {
- + if (ctl.wLength != 2)
- + goto stall;
- + switch (ctl.bRequestType & USB_RECIP_MASK) {
- + case USB_RECIP_ENDPOINT:
- + {
- + struct msm_endpoint *ept;
- + unsigned num =
- + ctl.wIndex & USB_ENDPOINT_NUMBER_MASK;
- + u16 temp = 0;
- +
- + if (num == 0) {
- + memset(req->buf, 0, 2);
- + break;
- + }
- + if (ctl.wIndex & USB_ENDPOINT_DIR_MASK)
- + num += 16;
- + ept = &ui->ep0out + num;
- + temp = usb_ep_get_stall(ept);
- + temp = temp << USB_ENDPOINT_HALT;
- + memcpy(req->buf, &temp, 2);
- + break;
- + }
- + case USB_RECIP_DEVICE:
- + {
- + u16 temp = 0;
- +
- + temp = 1 << USB_DEVICE_SELF_POWERED;
- + temp |= (ui->remote_wakeup <<
- + USB_DEVICE_REMOTE_WAKEUP);
- + memcpy(req->buf, &temp, 2);
- + break;
- + }
- + case USB_RECIP_INTERFACE:
- + memset(req->buf, 0, 2);
- + break;
- + default:
- + goto stall;
- + }
- + ep0_setup_send(ui, 2);
- + return;
- + }
- + }
- + if (ctl.bRequestType ==
- + (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)) {
- + if ((ctl.bRequest == USB_REQ_CLEAR_FEATURE) ||
- + (ctl.bRequest == USB_REQ_SET_FEATURE)) {
- + if ((ctl.wValue == 0) && (ctl.wLength == 0)) {
- + unsigned num = ctl.wIndex & 0x0f;
- +
- + if (num != 0) {
- + struct msm_endpoint *ept;
- +
- + if (ctl.wIndex & 0x80)
- + num += 16;
- + ept = &ui->ep0out + num;
- +
- + if (ctl.bRequest == USB_REQ_SET_FEATURE)
- + msm72k_set_halt(&ept->ep, 1);
- + else
- + msm72k_set_halt(&ept->ep, 0);
- + }
- + goto ack;
- + }
- + }
- + }
- + if (ctl.bRequestType == (USB_DIR_OUT | USB_TYPE_STANDARD)) {
- + if (ctl.bRequest == USB_REQ_SET_CONFIGURATION)
- + ui->online = !!ctl.wValue;
- + else if (ctl.bRequest == USB_REQ_SET_ADDRESS) {
- + /* write address delayed (will take effect
- + ** after the next IN txn)
- + */
- + writel((ctl.wValue << 25) | (1 << 24), USB_DEVICEADDR);
- + goto ack;
- + } else if (ctl.bRequest == USB_REQ_SET_FEATURE) {
- + switch (ctl.wValue) {
- + case USB_DEVICE_TEST_MODE:
- + switch (ctl.wIndex) {
- + case J_TEST:
- + case K_TEST:
- + case SE0_NAK_TEST:
- + case TST_PKT_TEST:
- + ui->test_mode = ctl.wIndex;
- + goto ack;
- + }
- + goto stall;
- + case USB_DEVICE_REMOTE_WAKEUP:
- + ui->remote_wakeup = 1;
- + goto ack;
- + }
- + } else if ((ctl.bRequest == USB_REQ_CLEAR_FEATURE) &&
- + (ctl.wValue == USB_DEVICE_REMOTE_WAKEUP)) {
- + ui->remote_wakeup = 0;
- + goto ack;
- + }
- + }
- +
- + /* delegate if we get here */
- + if (ui->driver) {
- + ret = ui->driver->setup(&ui->gadget, &ctl);
- + if (ret >= 0)
- + return;
- + }
- +
- +stall:
- + /* stall ep0 on error */
- + ep0_setup_stall(ui);
- + return;
- +
- +ack:
- + ep0_setup_ack(ui);
- +}
- +
- +static void handle_endpoint(struct usb_info *ui, unsigned bit)
- +{
- + struct msm_endpoint *ept = ui->ept + bit;
- + struct msm_request *req;
- + unsigned long flags;
- + unsigned info;
- +
- + /*
- + INFO("handle_endpoint() %d %s req=%p(%08x)\n",
- + ept->num, (ept->flags & EPT_FLAG_IN) ? "in" : "out",
- + ept->req, ept->req ? ept->req->item_dma : 0);
- + */
- +
- + /* expire all requests that are no longer active */
- + spin_lock_irqsave(&ui->lock, flags);
- + while ((req = ept->req)) {
- + info = req->item->info;
- +
- + /* if we've processed all live requests, time to
- + * restart the hardware on the next non-live request
- + */
- + if (!req->live) {
- + usb_ept_start(ept);
- + break;
- + }
- +
- + /* if the transaction is still in-flight, stop here */
- + if (info & INFO_ACTIVE)
- + break;
- +
- + /* advance ept queue to the next request */
- + ept->req = req->next;
- + if (ept->req == 0)
- + ept->last = 0;
- +
- + dma_unmap_single(NULL, req->dma, req->req.length,
- + (ept->flags & EPT_FLAG_IN) ?
- + DMA_TO_DEVICE : DMA_FROM_DEVICE);
- +
- + if (info & (INFO_HALTED | INFO_BUFFER_ERROR | INFO_TXN_ERROR)) {
- + /* XXX pass on more specific error code */
- + req->req.status = -EIO;
- + req->req.actual = 0;
- + INFO("msm72k_udc: ept %d %s error. info=%08x\n",
- + ept->num,
- + (ept->flags & EPT_FLAG_IN) ? "in" : "out",
- + info);
- + } else {
- + req->req.status = 0;
- + req->req.actual =
- + req->req.length - ((info >> 16) & 0x7FFF);
- + }
- + req->busy = 0;
- + req->live = 0;
- + if (req->dead)
- + do_free_req(ui, req);
- +
- + if (req->req.complete) {
- + spin_unlock_irqrestore(&ui->lock, flags);
- + req->req.complete(&ept->ep, &req->req);
- + spin_lock_irqsave(&ui->lock, flags);
- + }
- + }
- + spin_unlock_irqrestore(&ui->lock, flags);
- +}
- +
- +static void flush_endpoint_hw(struct usb_info *ui, unsigned bits)
- +{
- + /* flush endpoint, canceling transactions
- + ** - this can take a "large amount of time" (per databook)
- + ** - the flush can fail in some cases, thus we check STAT
- + ** and repeat if we're still operating
- + ** (does the fact that this doesn't use the tripwire matter?!)
- + */
- + do {
- + writel(bits, USB_ENDPTFLUSH);
- + while (readl(USB_ENDPTFLUSH) & bits)
- + udelay(100);
- + } while (readl(USB_ENDPTSTAT) & bits);
- +}
- +
- +static void flush_endpoint_sw(struct msm_endpoint *ept)
- +{
- + struct usb_info *ui = ept->ui;
- + struct msm_request *req;
- + unsigned long flags;
- +
- + /* inactive endpoints have nothing to do here */
- + if (ept->ep.maxpacket == 0)
- + return;
- +
- + /* put the queue head in a sane state */
- + ept->head->info = 0;
- + ept->head->next = TERMINATE;
- +
- + /* cancel any pending requests */
- + spin_lock_irqsave(&ui->lock, flags);
- + req = ept->req;
- + ept->req = 0;
- + ept->last = 0;
- + while (req != 0) {
- + req->busy = 0;
- + req->live = 0;
- + req->req.status = -ECONNRESET;
- + req->req.actual = 0;
- + if (req->req.complete) {
- + spin_unlock_irqrestore(&ui->lock, flags);
- + req->req.complete(&ept->ep, &req->req);
- + spin_lock_irqsave(&ui->lock, flags);
- + }
- + if (req->dead)
- + do_free_req(ui, req);
- + req = req->next;
- + }
- + spin_unlock_irqrestore(&ui->lock, flags);
- +}
- +
- +static void flush_endpoint(struct msm_endpoint *ept)
- +{
- + flush_endpoint_hw(ept->ui, (1 << ept->bit));
- + flush_endpoint_sw(ept);
- +}
- +
- +static void flush_all_endpoints(struct usb_info *ui)
- +{
- + unsigned n;
- +
- + flush_endpoint_hw(ui, 0xffffffff);
- +
- + for (n = 0; n < 32; n++)
- + flush_endpoint_sw(ui->ept + n);
- +}
- +
- +
- +static irqreturn_t usb_interrupt(int irq, void *data)
- +{
- + struct usb_info *ui = data;
- + unsigned n;
- +
- + n = readl(USB_USBSTS);
- + writel(n, USB_USBSTS);
- +
- + /* somehow we got an IRQ while in the reset sequence: ignore it */
- + if (ui->running == 0)
- + return IRQ_HANDLED;
- +
- + if (n & STS_PCI) {
- + switch (readl(USB_PORTSC) & PORTSC_PSPD_MASK) {
- + case PORTSC_PSPD_FS:
- + INFO("msm72k_udc: portchange USB_SPEED_FULL\n");
- + ui->gadget.speed = USB_SPEED_FULL;
- + break;
- + case PORTSC_PSPD_LS:
- + INFO("msm72k_udc: portchange USB_SPEED_LOW\n");
- + ui->gadget.speed = USB_SPEED_LOW;
- + break;
- + case PORTSC_PSPD_HS:
- + INFO("msm72k_udc: portchange USB_SPEED_HIGH\n");
- + ui->gadget.speed = USB_SPEED_HIGH;
- + break;
- + }
- + }
- +
- + if (n & STS_URI) {
- + INFO("msm72k_udc: reset\n");
- +
- + writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT);
- + writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE);
- + writel(0xffffffff, USB_ENDPTFLUSH);
- + writel(0, USB_ENDPTCTRL(1));
- +
- + if (ui->online != 0) {
- + /* marking us offline will cause ept queue attempts
- + ** to fail
- + */
- + ui->online = 0;
- +
- + flush_all_endpoints(ui);
- +
- + /* XXX: we can't seem to detect going offline,
- + * XXX: so deconfigure on reset for the time being
- + */
- + if (ui->driver) {
- + printk(KERN_INFO "usb: notify offline\n");
- + ui->driver->disconnect(&ui->gadget);
- + }
- + }
- + }
- +
- + if (n & STS_SLI)
- + INFO("msm72k_udc: suspend\n");
- +
- + if (n & STS_UI) {
- + n = readl(USB_ENDPTSETUPSTAT);
- + if (n & EPT_RX(0))
- + handle_setup(ui);
- +
- + n = readl(USB_ENDPTCOMPLETE);
- + writel(n, USB_ENDPTCOMPLETE);
- + while (n) {
- + unsigned bit = __ffs(n);
- + handle_endpoint(ui, bit);
- + n = n & (~(1 << bit));
- + }
- + }
- + return IRQ_HANDLED;
- +}
- +
- +static void usb_prepare(struct usb_info *ui)
- +{
- + spin_lock_init(&ui->lock);
- +
- + memset(ui->buf, 0, 4096);
- + ui->head = (void *) (ui->buf + 0);
- +
- + /* only important for reset/reinit */
- + memset(ui->ept, 0, sizeof(ui->ept));
- + ui->next_item = 0;
- + ui->next_ifc_num = 0;
- +
- + init_endpoints(ui);
- +
- + ui->ep0in.ep.maxpacket = 64;
- + ui->ep0out.ep.maxpacket = 64;
- +
- + ui->setup_req =
- + usb_ept_alloc_req(&ui->ep0in, SETUP_BUF_SIZE, GFP_KERNEL);
- +
- + INIT_WORK(&ui->work, usb_do_work);
- +}
- +
- +static void usb_suspend_phy(struct usb_info *ui)
- +{
- + /* clear VBusValid and SessionEnd rising interrupts */
- + ulpi_write(ui, (1 << 1) | (1 << 3), 0x0f);
- + /* clear VBusValid and SessionEnd falling interrupts */
- + ulpi_write(ui, (1 << 1) | (1 << 3), 0x12);
- + /* disable interface protect circuit to drop current consumption */
- + ulpi_write(ui, (1 << 7), 0x08);
- +}
- +
- +static void usb_reset(struct usb_info *ui)
- +{
- + unsigned long flags;
- + unsigned otgsc;
- +
- + INFO("msm72k_udc: reset controller\n");
- +
- + spin_lock_irqsave(&ui->lock, flags);
- + ui->running = 0;
- + spin_unlock_irqrestore(&ui->lock, flags);
- +
- +#if 0
- + /* we should flush and shutdown cleanly if already running */
- + writel(0xffffffff, USB_ENDPTFLUSH);
- + msleep(2);
- +#endif
- +
- + otgsc = readl(USB_OTGSC);
- +
- + /* RESET */
- + writel(2, USB_USBCMD);
- + msleep(10);
- +
- + if (ui->phy_reset)
- + ui->phy_reset();
- +
- + /* INCR4 BURST mode */
- + writel(0x01, USB_SBUSCFG);
- +
- + /* select DEVICE mode */
- + writel(0x12, USB_USBMODE);
- + msleep(1);
- +
- + /* select ULPI phy */
- + writel(0x80000000, USB_PORTSC);
- +
- + ulpi_init(ui);
- +
- + writel(ui->dma, USB_ENDPOINTLISTADDR);
- +
- + configure_endpoints(ui);
- +
- + /* marking us offline will cause ept queue attempts to fail */
- + ui->online = 0;
- +
- + /* terminate any pending transactions */
- + flush_all_endpoints(ui);
- +
- + if (ui->driver) {
- + printk(KERN_INFO "usb: notify offline\n");
- + ui->driver->disconnect(&ui->gadget);
- + }
- +
- + /* enable interrupts */
- + writel(otgsc, USB_OTGSC);
- + writel(STS_URI | STS_SLI | STS_UI | STS_PCI, USB_USBINTR);
- +
- + /* go to RUN mode (D+ pullup enable) */
- + msm72k_pullup(&ui->gadget, 1);
- +
- + spin_lock_irqsave(&ui->lock, flags);
- + ui->running = 1;
- + spin_unlock_irqrestore(&ui->lock, flags);
- +}
- +
- +static void usb_start(struct usb_info *ui)
- +{
- + unsigned long flags;
- +
- + spin_lock_irqsave(&ui->lock, flags);
- + ui->flags |= USB_FLAG_START;
- + schedule_work(&ui->work);
- + spin_unlock_irqrestore(&ui->lock, flags);
- +}
- +
- +static struct usb_info *the_usb_info;
- +
- +static int usb_free(struct usb_info *ui, int ret)
- +{
- + INFO("usb_free(%d)\n", ret);
- +
- + if (ui->irq)
- + free_irq(ui->irq, 0);
- + if (ui->pool)
- + dma_pool_destroy(ui->pool);
- + if (ui->dma)
- + dma_free_coherent(&ui->pdev->dev, 4096, ui->buf, ui->dma);
- + if (ui->addr)
- + iounmap(ui->addr);
- + if (ui->clk)
- + clk_put(ui->clk);
- + if (ui->pclk)
- + clk_put(ui->pclk);
- + kfree(ui);
- + return ret;
- +}
- +
- +static void usb_do_work_check_vbus(struct usb_info *ui)
- +{
- + unsigned long iflags;
- +
- + spin_lock_irqsave(&ui->lock, iflags);
- + if (vbus)
- + ui->flags |= USB_FLAG_VBUS_ONLINE;
- + else
- + ui->flags |= USB_FLAG_VBUS_OFFLINE;
- + spin_unlock_irqrestore(&ui->lock, iflags);
- +}
- +
- +static void usb_do_work(struct work_struct *w)
- +{
- + struct usb_info *ui = container_of(w, struct usb_info, work);
- + unsigned long iflags;
- + unsigned flags, _vbus;
- +
- + for (;;) {
- + spin_lock_irqsave(&ui->lock, iflags);
- + flags = ui->flags;
- + ui->flags = 0;
- + _vbus = vbus;
- + spin_unlock_irqrestore(&ui->lock, iflags);
- +
- + /* give up if we have nothing to do */
- + if (flags == 0)
- + break;
- +
- + switch (ui->state) {
- + case USB_STATE_IDLE:
- + if (flags & USB_FLAG_START) {
- + pr_info("msm72k_udc: IDLE -> ONLINE\n");
- + clk_enable(ui->clk);
- + clk_enable(ui->pclk);
- + usb_reset(ui);
- +
- + ui->state = USB_STATE_ONLINE;
- + usb_do_work_check_vbus(ui);
- + }
- + break;
- + case USB_STATE_ONLINE:
- + /* If at any point when we were online, we received
- + * the signal to go offline, we must honor it
- + */
- + if (flags & USB_FLAG_VBUS_OFFLINE) {
- + pr_info("msm72k_udc: ONLINE -> OFFLINE\n");
- +
- + /* synchronize with irq context */
- + spin_lock_irqsave(&ui->lock, iflags);
- + ui->running = 0;
- + ui->online = 0;
- + msm72k_pullup(&ui->gadget, 0);
- + spin_unlock_irqrestore(&ui->lock, iflags);
- +
- + if (ui->usb_connected)
- + ui->usb_connected(0);
- +
- + /* terminate any transactions, etc */
- + flush_all_endpoints(ui);
- +
- + if (ui->driver) {
- + printk(KERN_INFO "usb: notify offline\n");
- + ui->driver->disconnect(&ui->gadget);
- + }
- +
- + /* power down phy, clock down usb */
- + spin_lock_irqsave(&ui->lock, iflags);
- + usb_suspend_phy(ui);
- + clk_disable(ui->pclk);
- + clk_disable(ui->clk);
- + spin_unlock_irqrestore(&ui->lock, iflags);
- +
- + ui->state = USB_STATE_OFFLINE;
- + usb_do_work_check_vbus(ui);
- + break;
- + }
- + if (flags & USB_FLAG_RESET) {
- + pr_info("msm72k_udc: ONLINE -> RESET\n");
- + usb_reset(ui);
- + pr_info("msm72k_udc: RESET -> ONLINE\n");
- + break;
- + }
- + break;
- + case USB_STATE_OFFLINE:
- + /* If we were signaled to go online and vbus is still
- + * present when we received the signal, go online.
- + */
- + if ((flags & USB_FLAG_VBUS_ONLINE) && _vbus) {
- + pr_info("msm72k_udc: OFFLINE -> ONLINE\n");
- + clk_enable(ui->clk);
- + clk_enable(ui->pclk);
- + usb_reset(ui);
- +
- + if (ui->usb_connected)
- + ui->usb_connected(1);
- +
- + ui->state = USB_STATE_ONLINE;
- + usb_do_work_check_vbus(ui);
- + }
- + break;
- + }
- + }
- +}
- +
- +/* FIXME - the callers of this function should use a gadget API instead.
- + * This is called from htc_battery.c and board-halibut.c
- + * WARNING - this can get called before this driver is initialized.
- + */
- +#if !defined(MODULE)
- +void msm_hsusb_set_vbus_state(int online)
- +#else
- +static void msm_hsusb_set_vbus_state_new(int online)
- +#endif
- +{
- + unsigned long flags;
- + struct usb_info *ui = the_usb_info;
- +
- + if (ui) {
- + spin_lock_irqsave(&ui->lock, flags);
- + if (vbus != online) {
- + vbus = online;
- + if (online)
- + ui->flags |= USB_FLAG_VBUS_ONLINE;
- + else
- + ui->flags |= USB_FLAG_VBUS_OFFLINE;
- + schedule_work(&ui->work);
- + }
- + spin_unlock_irqrestore(&ui->lock, flags);
- + } else {
- + printk(KERN_ERR "msm_hsusb_set_vbus_state called before driver initialized\n");
- + vbus = online;
- + }
- +}
- +
- +
- +#if defined(CONFIG_DEBUG_FS)
- +
- +void usb_function_reenumerate(void)
- +{
- + struct usb_info *ui = the_usb_info;
- +
- + /* disable and re-enable the D+ pullup */
- + INFO("msm72k_udc: disable pullup\n");
- + writel(0x00080000, USB_USBCMD);
- +
- + msleep(10);
- +
- + INFO("msm72k_udc: enable pullup\n");
- + writel(0x00080001, USB_USBCMD);
- +}
- +
- +static char debug_buffer[PAGE_SIZE];
- +
- +static ssize_t debug_read_status(struct file *file, char __user *ubuf,
- + size_t count, loff_t *ppos)
- +{
- + struct usb_info *ui = file->private_data;
- + char *buf = debug_buffer;
- + unsigned long flags;
- + struct msm_endpoint *ept;
- + struct msm_request *req;
- + int n;
- + int i = 0;
- +
- + spin_lock_irqsave(&ui->lock, flags);
- +
- + i += scnprintf(buf + i, PAGE_SIZE - i,
- + "regs: setup=%08x prime=%08x stat=%08x done=%08x\n",
- + readl(USB_ENDPTSETUPSTAT),
- + readl(USB_ENDPTPRIME),
- + readl(USB_ENDPTSTAT),
- + readl(USB_ENDPTCOMPLETE));
- + i += scnprintf(buf + i, PAGE_SIZE - i,
- + "regs: cmd=%08x sts=%08x intr=%08x port=%08x\n\n",
- + readl(USB_USBCMD),
- + readl(USB_USBSTS),
- + readl(USB_USBINTR),
- + readl(USB_PORTSC));
- +
- +
- + for (n = 0; n < 32; n++) {
- + ept = ui->ept + n;
- + if (ept->ep.maxpacket == 0)
- + continue;
- +
- + i += scnprintf(buf + i, PAGE_SIZE - i,
- + "ept%d %s cfg=%08x active=%08x next=%08x info=%08x\n",
- + ept->num, (ept->flags & EPT_FLAG_IN) ? "in " : "out",
- + ept->head->config, ept->head->active,
- + ept->head->next, ept->head->info);
- +
- + for (req = ept->req; req; req = req->next)
- + i += scnprintf(buf + i, PAGE_SIZE - i,
- + " req @%08x next=%08x info=%08x page0=%08x %c %c\n",
- + req->item_dma, req->item->next,
- + req->item->info, req->item->page0,
- + req->busy ? 'B' : ' ',
- + req->live ? 'L' : ' ');
- + }
- +
- + i += scnprintf(buf + i, PAGE_SIZE - i,
- + "phy failure count: %d\n", ui->phy_fail_count);
- +
- + spin_unlock_irqrestore(&ui->lock, flags);
- +
- + return simple_read_from_buffer(ubuf, count, ppos, buf, i);
- +}
- +
- +static ssize_t debug_write_reset(struct file *file, const char __user *buf,
- + size_t count, loff_t *ppos)
- +{
- + struct usb_info *ui = file->private_data;
- + unsigned long flags;
- +
- + spin_lock_irqsave(&ui->lock, flags);
- + ui->flags |= USB_FLAG_RESET;
- + schedule_work(&ui->work);
- + spin_unlock_irqrestore(&ui->lock, flags);
- +
- + return count;
- +}
- +
- +static ssize_t debug_write_cycle(struct file *file, const char __user *buf,
- + size_t count, loff_t *ppos)
- +{
- + usb_function_reenumerate();
- + return count;
- +}
- +
- +static int debug_open(struct inode *inode, struct file *file)
- +{
- + file->private_data = inode->i_private;
- + return 0;
- +}
- +
- +const struct file_operations debug_stat_ops = {
- + .open = debug_open,
- + .read = debug_read_status,
- +};
- +
- +const struct file_operations debug_reset_ops = {
- + .open = debug_open,
- + .write = debug_write_reset,
- +};
- +
- +const struct file_operations debug_cycle_ops = {
- + .open = debug_open,
- + .write = debug_write_cycle,
- +};
- +
- +static void usb_debugfs_init(struct usb_info *ui)
- +{
- + struct dentry *dent;
- + dent = debugfs_create_dir("usb", 0);
- + if (IS_ERR(dent))
- + return;
- +
- + debugfs_create_file("status", 0444, dent, ui, &debug_stat_ops);
- + debugfs_create_file("reset", 0222, dent, ui, &debug_reset_ops);
- + debugfs_create_file("cycle", 0222, dent, ui, &debug_cycle_ops);
- +}
- +#else
- +static void usb_debugfs_init(struct usb_info *ui) {}
- +#endif
- +
- +static int
- +msm72k_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
- +{
- + struct msm_endpoint *ept = to_msm_endpoint(_ep);
- + unsigned char ep_type =
- + desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
- +
- + _ep->maxpacket = le16_to_cpu(desc->wMaxPacketSize);
- + config_ept(ept);
- + usb_ept_enable(ept, 1, ep_type);
- + return 0;
- +}
- +
- +static int msm72k_disable(struct usb_ep *_ep)
- +{
- + struct msm_endpoint *ept = to_msm_endpoint(_ep);
- +
- + usb_ept_enable(ept, 0, 0);
- + return 0;
- +}
- +
- +static struct usb_request *
- +msm72k_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
- +{
- + return usb_ept_alloc_req(to_msm_endpoint(_ep), 0, gfp_flags);
- +}
- +
- +static void
- +msm72k_free_request(struct usb_ep *_ep, struct usb_request *_req)
- +{
- + struct msm_request *req = to_msm_request(_req);
- + struct msm_endpoint *ept = to_msm_endpoint(_ep);
- + struct usb_info *ui = ept->ui;
- + unsigned long flags;
- + int dead = 0;
- +
- + spin_lock_irqsave(&ui->lock, flags);
- + /* defer freeing resources if request is still busy */
- + if (req->busy)
- + dead = req->dead = 1;
- + spin_unlock_irqrestore(&ui->lock, flags);
- +
- + /* if req->dead, then we will clean up when the request finishes */
- + if (!dead)
- + do_free_req(ui, req);
- +}
- +
- +static int
- +msm72k_queue(struct usb_ep *_ep, struct usb_request *req, gfp_t gfp_flags)
- +{
- + struct msm_endpoint *ep = to_msm_endpoint(_ep);
- + struct usb_info *ui = ep->ui;
- +
- + if (ep == &ui->ep0in) {
- + struct msm_request *r = to_msm_request(req);
- + if (!req->length)
- + goto ep_queue_done;
- + r->gadget_complete = req->complete;
- + /* ep0_queue_ack_complete queue a receive for ACK before
- + ** calling req->complete
- + */
- + req->complete = ep0_queue_ack_complete;
- + if (ui->ep0_dir == USB_DIR_OUT)
- + ep = &ui->ep0out;
- + }
- +ep_queue_done:
- + return usb_ept_queue_xfer(ep, req);
- +}
- +
- +static int msm72k_dequeue(struct usb_ep *_ep, struct usb_request *_req)
- +{
- + struct msm_endpoint *ep = to_msm_endpoint(_ep);
- + struct msm_request *req = to_msm_request(_req);
- + struct usb_info *ui = ep->ui;
- +
- + struct msm_request *cur, *prev;
- + unsigned long flags;
- +
- + if (!_ep || !_req)
- + return -EINVAL;
- +
- + spin_lock_irqsave(&ui->lock, flags);
- + cur = ep->req;
- + prev = NULL;
- +
- + while (cur != 0) {
- + if (cur == req) {
- + req->busy = 0;
- + req->live = 0;
- + req->req.status = -ECONNRESET;
- + req->req.actual = 0;
- + if (req->req.complete) {
- + spin_unlock_irqrestore(&ui->lock, flags);
- + req->req.complete(&ep->ep, &req->req);
- + spin_lock_irqsave(&ui->lock, flags);
- + }
- + if (req->dead)
- + do_free_req(ui, req);
- + /* remove from linked list */
- + if (prev)
- + prev->next = cur->next;
- + else
- + ep->req = cur->next;
- + prev = cur;
- + /* break from loop */
- + cur = NULL;
- + } else
- + cur = cur->next;
- + }
- + spin_unlock_irqrestore(&ui->lock, flags);
- +
- + return 0;
- +}
- +
- +static int
- +msm72k_set_halt(struct usb_ep *_ep, int value)
- +{
- + struct msm_endpoint *ept = to_msm_endpoint(_ep);
- + struct usb_info *ui = ept->ui;
- + unsigned int in = ept->flags & EPT_FLAG_IN;
- + unsigned int n;
- + unsigned long flags;
- +
- + spin_lock_irqsave(&ui->lock, flags);
- + n = readl(USB_ENDPTCTRL(ept->num));
- +
- + if (in) {
- + if (value)
- + n |= CTRL_TXS;
- + else {
- + n &= ~CTRL_TXS;
- + n |= CTRL_TXR;
- + }
- + } else {
- + if (value)
- + n |= CTRL_RXS;
- + else {
- + n &= ~CTRL_RXS;
- + n |= CTRL_RXR;
- + }
- + }
- + writel(n, USB_ENDPTCTRL(ept->num));
- + spin_unlock_irqrestore(&ui->lock, flags);
- +
- + return 0;
- +}
- +
- +static int
- +msm72k_fifo_status(struct usb_ep *_ep)
- +{
- + return -EOPNOTSUPP;
- +}
- +
- +static void
- +msm72k_fifo_flush(struct usb_ep *_ep)
- +{
- + flush_endpoint(to_msm_endpoint(_ep));
- +}
- +
- +static const struct usb_ep_ops msm72k_ep_ops = {
- + .enable = msm72k_enable,
- + .disable = msm72k_disable,
- +
- + .alloc_request = msm72k_alloc_request,
- + .free_request = msm72k_free_request,
- +
- + .queue = msm72k_queue,
- + .dequeue = msm72k_dequeue,
- +
- + .set_halt = msm72k_set_halt,
- + .fifo_status = msm72k_fifo_status,
- + .fifo_flush = msm72k_fifo_flush,
- +};
- +
- +static int msm72k_get_frame(struct usb_gadget *_gadget)
- +{
- + struct usb_info *ui = container_of(_gadget, struct usb_info, gadget);
- +
- + /* frame number is in bits 13:3 */
- + return (readl(USB_FRINDEX) >> 3) & 0x000007FF;
- +}
- +
- +/* VBUS reporting logically comes from a transceiver */
- +static int msm72k_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
- +{
- + msm_hsusb_set_vbus_state(is_active);
- + return 0;
- +}
- +
- +/* drivers may have software control over D+ pullup */
- +static int msm72k_pullup(struct usb_gadget *_gadget, int is_active)
- +{
- + struct usb_info *ui = container_of(_gadget, struct usb_info, gadget);
- +
- + if (is_active) {
- + if (vbus && ui->driver)
- + writel(0x00080001, USB_USBCMD);
- + } else
- + writel(0x00080000, USB_USBCMD);
- +
- + return 0;
- +}
- +
- +static int msm72k_wakeup(struct usb_gadget *_gadget)
- +{
- + struct usb_info *ui = container_of(_gadget, struct usb_info, gadget);
- + unsigned long flags;
- +
- + if (!ui->remote_wakeup) {
- + pr_err("%s: remote wakeup not supported\n", __func__);
- + return -ENOTSUPP;
- + }
- +
- + if (!ui->online) {
- + pr_err("%s: device is not configured\n", __func__);
- + return -ENODEV;
- + }
- +
- + spin_lock_irqsave(&ui->lock, flags);
- + if ((readl(USB_PORTSC) & PORTSC_SUSP) == PORTSC_SUSP) {
- + pr_info("%s: enabling force resume\n", __func__);
- + writel(readl(USB_PORTSC) | PORTSC_FPR, USB_PORTSC);
- + }
- + spin_unlock_irqrestore(&ui->lock, flags);
- +
- + return 0;
- +}
- +
- +static const struct usb_gadget_ops msm72k_ops = {
- + .get_frame = msm72k_get_frame,
- + .vbus_session = msm72k_udc_vbus_session,
- + .pullup = msm72k_pullup,
- + .wakeup = msm72k_wakeup,
- +};
- +
- +static ssize_t usb_remote_wakeup(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + struct usb_info *ui = the_usb_info;
- +
- + msm72k_wakeup(&ui->gadget);
- +
- + return count;
- +}
- +static DEVICE_ATTR(wakeup, S_IWUSR, 0, usb_remote_wakeup);
- +
- +static int msm72k_probe(struct platform_device *pdev)
- +{
- + struct resource *res;
- + struct usb_info *ui;
- + int irq;
- + int ret;
- +
- + INFO("msm72k_probe\n");
- + ui = kzalloc(sizeof(struct usb_info), GFP_KERNEL);
- + if (!ui)
- + return -ENOMEM;
- +
- + ui->pdev = pdev;
- +
- + if (pdev->dev.platform_data) {
- + struct msm_hsusb_platform_data *pdata = pdev->dev.platform_data;
- + ui->phy_reset = pdata->phy_reset;
- + ui->phy_init_seq = pdata->phy_init_seq;
- + ui->usb_connected = pdata->usb_connected;
- + }
- +
- + irq = platform_get_irq(pdev, 0);
- + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- + if (!res || (irq < 0))
- + return usb_free(ui, -ENODEV);
- +
- + ui->addr = ioremap(res->start, 4096);
- + if (!ui->addr)
- + return usb_free(ui, -ENOMEM);
- +
- + ui->buf = dma_alloc_coherent(&pdev->dev, 4096, &ui->dma, GFP_KERNEL);
- + if (!ui->buf)
- + return usb_free(ui, -ENOMEM);
- +
- + ui->pool = dma_pool_create("msm72k_udc", NULL, 32, 32, 0);
- + if (!ui->pool)
- + return usb_free(ui, -ENOMEM);
- +
- + INFO("msm72k_probe() io=%p, irq=%d, dma=%p(%x)\n",
- + ui->addr, irq, ui->buf, ui->dma);
- +
- + ui->clk = clk_get(&pdev->dev, "usb_hs_clk");
- + if (IS_ERR(ui->clk))
- + return usb_free(ui, PTR_ERR(ui->clk));
- +
- + ui->pclk = clk_get(&pdev->dev, "usb_hs_pclk");
- + if (IS_ERR(ui->pclk))
- + return usb_free(ui, PTR_ERR(ui->pclk));
- +
- + ret = request_irq(irq, usb_interrupt, 0, pdev->name, ui);
- + if (ret)
- + return usb_free(ui, ret);
- + enable_irq_wake(irq);
- + ui->irq = irq;
- +
- + ui->gadget.ops = &msm72k_ops;
- + ui->gadget.is_dualspeed = 1;
- + device_initialize(&ui->gadget.dev);
- + ui->gadget.dev.init_name="gadget";
- + ui->gadget.dev.parent = &pdev->dev;
- + ui->gadget.dev.dma_mask = pdev->dev.dma_mask;
- +
- + the_usb_info = ui;
- +
- + usb_debugfs_init(ui);
- +
- + usb_prepare(ui);
- +
- + return 0;
- +}
- +
- +int usb_gadget_register_driver(struct usb_gadget_driver *driver)
- +{
- + struct usb_info *ui = the_usb_info;
- + int retval, n;
- +
- + if (!driver
- + || driver->speed < USB_SPEED_FULL
- + || !driver->bind
- + || !driver->disconnect
- + || !driver->setup)
- + return -EINVAL;
- + if (!ui)
- + return -ENODEV;
- + if (ui->driver)
- + return -EBUSY;
- +
- + /* first hook up the driver ... */
- + ui->driver = driver;
- + ui->gadget.dev.driver = &driver->driver;
- + ui->gadget.name = driver_name;
- + INIT_LIST_HEAD(&ui->gadget.ep_list);
- + ui->gadget.ep0 = &ui->ep0in.ep;
- + INIT_LIST_HEAD(&ui->gadget.ep0->ep_list);
- + ui->gadget.speed = USB_SPEED_UNKNOWN;
- +
- + for (n = 1; n < 16; n++) {
- + struct msm_endpoint *ept = ui->ept + n;
- + list_add_tail(&ept->ep.ep_list, &ui->gadget.ep_list);
- + ept->ep.maxpacket = 512;
- + }
- + for (n = 17; n < 32; n++) {
- + struct msm_endpoint *ept = ui->ept + n;
- + list_add_tail(&ept->ep.ep_list, &ui->gadget.ep_list);
- + ept->ep.maxpacket = 512;
- + }
- +
- + retval = device_add(&ui->gadget.dev);
- + if (retval)
- + goto fail;
- +
- + retval = driver->bind(&ui->gadget);
- + if (retval) {
- + INFO("bind to driver %s --> error %d\n",
- + driver->driver.name, retval);
- + device_del(&ui->gadget.dev);
- + goto fail;
- + }
- +
- + /* create sysfs node for remote wakeup */
- + retval = device_create_file(&ui->gadget.dev, &dev_attr_wakeup);
- + if (retval != 0)
- + INFO("failed to create sysfs entry: (wakeup) error: (%d)\n",
- + retval);
- + INFO("msm72k_udc: registered gadget driver '%s'\n",
- + driver->driver.name);
- + usb_start(ui);
- +
- + return 0;
- +
- +fail:
- + ui->driver = NULL;
- + ui->gadget.dev.driver = NULL;
- + return retval;
- +}
- +EXPORT_SYMBOL(usb_gadget_register_driver);
- +
- +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
- +{
- + struct usb_info *dev = the_usb_info;
- +
- + if (!dev)
- + return -ENODEV;
- + if (!driver || driver != dev->driver || !driver->unbind)
- + return -EINVAL;
- +
- + device_remove_file(&dev->gadget.dev, &dev_attr_wakeup);
- + driver->unbind(&dev->gadget);
- + dev->gadget.dev.driver = NULL;
- + dev->driver = NULL;
- +
- + device_del(&dev->gadget.dev);
- +
- + VDEBUG("unregistered gadget driver '%s'\n", driver->driver.name);
- + return 0;
- +}
- +EXPORT_SYMBOL(usb_gadget_unregister_driver);
- +
- +
- +static struct platform_driver usb_driver = {
- + .probe = msm72k_probe,
- + .driver = { .name = "msm_hsusb", },
- +};
- +
- +#if defined(MODULE)
- +extern void (*msm_hsusb_set_vbus_state)(int online);
- +#endif
- +
- +static int __init init(void)
- +{
- + #if defined(MODULE)
- + msm_hsusb_set_vbus_state = &msm_hsusb_set_vbus_state_new;
- + #endif
- + return platform_driver_register(&usb_driver);
- +}
- +module_init(init);
- +
- +static void __exit cleanup(void)
- +{
- + platform_driver_unregister(&usb_driver);
- +}
- +module_exit(cleanup);
- +
- +MODULE_DESCRIPTION(DRIVER_DESC);
- +MODULE_AUTHOR("Mike Lockwood, Brian Swetland");
- +MODULE_LICENSE("GPL");
- diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
- index e54a337..430a086 100644
- --- a/drivers/video/backlight/Kconfig
- +++ b/drivers/video/backlight/Kconfig
- @@ -185,6 +185,15 @@ config BACKLIGHT_OMAP1
- the PWL module of OMAP1 processors. Say Y if your board
- uses this hardware.
- +config BACKLIGHT_TROUT
- + tristate "Backlight driver for the MSM trout board (e.g. htcdream)"
- + depends on MACH_TROUT
- + default y
- + help
- + This driver controls the LCD backlight level and power for
- + the PWL module of the armv6 processors. Say Y if your board
- + uses this hardware.
- +
- config BACKLIGHT_HP680
- tristate "HP Jornada 680 Backlight Driver"
- depends on SH_HP6XX
- diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
- index 44c0f81..1d962ed 100644
- --- a/drivers/video/backlight/Makefile
- +++ b/drivers/video/backlight/Makefile
- @@ -35,4 +35,5 @@ obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o
- obj-$(CONFIG_BACKLIGHT_ADP8860) += adp8860_bl.o
- obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o
- obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o
- +obj-$(CONFIG_BACKLIGHT_TROUT) += trout_bl.o
- diff --git a/drivers/video/backlight/trout_bl.c b/drivers/video/backlight/trout_bl.c
- new file mode 100644
- index 0000000..4539324
- --- /dev/null
- +++ b/drivers/video/backlight/trout_bl.c
- @@ -0,0 +1,661 @@
- +/* linux/arch/arm/mach-msm/board-trout-mddi.c
- +** Author: Brian Swetland <swetland@google.com>
- +*/
- +
- +#include <linux/kernel.h>
- +#include <linux/init.h>
- +#include <linux/platform_device.h>
- +#include <linux/delay.h>
- +#include <linux/backlight.h>
- +#include <linux/clk.h>
- +#include <linux/err.h>
- +#include <linux/gpio.h>
- +
- +#include <asm/io.h>
- +#include <asm/gpio.h>
- +#include <asm/mach-types.h>
- +
- +#include <mach/msm_fb.h>
- +#include <mach/vreg.h>
- +#include <mach/htc_pwrsink.h>
- +
- +#include <../board-trout.h>
- +#include <../proc_comm.h>
- +#include <../devices.h>
- +
- +#define TROUT_DEFAULT_BACKLIGHT_BRIGHTNESS 127
- +
- +static struct clk *gp_clk;
- +static int trout_backlight_off;
- +static int trout_backlight_resume_level = TROUT_DEFAULT_BACKLIGHT_BRIGHTNESS;
- +static int trout_new_backlight = 1;
- +static uint8_t trout_backlight_last_level = 33;
- +static DEFINE_MUTEX(trout_backlight_lock);
- +
- +static void trout_set_backlight_level(uint8_t level)
- +{
- + unsigned percent = ((int)level * 100) / 255;
- +
- + if (trout_new_backlight) {
- + unsigned long flags;
- + int i = 0;
- + level = (int)level * 34 / 256;
- +
- + if (trout_backlight_last_level == level)
- + return;
- +
- + if (level == 0) {
- + gpio_set_value(27, 0);
- + msleep(2);
- + } else {
- + local_irq_save(flags);
- + if (trout_backlight_last_level == 0) {
- + gpio_set_value(27, 1);
- + udelay(40);
- + trout_backlight_last_level = 33;
- + }
- + i = (trout_backlight_last_level - level + 33) % 33;
- + while (i-- > 0) {
- + gpio_set_value(27, 0);
- + udelay(1);
- + gpio_set_value(27, 1);
- + udelay(1);
- + }
- + local_irq_restore(flags);
- + }
- + trout_backlight_last_level = level;
- + }
- + else {
- + if(level) {
- + clk_enable(gp_clk);
- + writel((1U << 16) | (~level & 0xffff),
- + MSM_CLK_CTL_BASE + 0x58);
- + /* Going directly to a 100% duty cycle does not
- + * seem to work */
- + if(level == 255) {
- + writel((~127 << 16) | 0xb20,
- + MSM_CLK_CTL_BASE + 0x5c);
- + udelay(1);
- + }
- + writel((~127 << 16) | 0xb58, MSM_CLK_CTL_BASE + 0x5c);
- + }
- + else {
- + writel(0x0, MSM_CLK_CTL_BASE + 0x5c);
- + clk_disable(gp_clk);
- + }
- + }
- + htc_pwrsink_set(PWRSINK_BACKLIGHT, percent);
- +}
- +
- +#define MDDI_CLIENT_CORE_BASE 0x108000
- +#define LCD_CONTROL_BLOCK_BASE 0x110000
- +#define SPI_BLOCK_BASE 0x120000
- +#define I2C_BLOCK_BASE 0x130000
- +#define PWM_BLOCK_BASE 0x140000
- +#define GPIO_BLOCK_BASE 0x150000
- +#define SYSTEM_BLOCK1_BASE 0x160000
- +#define SYSTEM_BLOCK2_BASE 0x170000
- +
- +
- +#define DPSUS (MDDI_CLIENT_CORE_BASE|0x24)
- +#define SYSCLKENA (MDDI_CLIENT_CORE_BASE|0x2C)
- +#define PWM0OFF (PWM_BLOCK_BASE|0x1C)
- +
- +#define V_VDDE2E_VDD2_GPIO 0
- +#define MDDI_RST_N 82
- +
- +#define MDDICAP0 (MDDI_CLIENT_CORE_BASE|0x00)
- +#define MDDICAP1 (MDDI_CLIENT_CORE_BASE|0x04)
- +#define MDDICAP2 (MDDI_CLIENT_CORE_BASE|0x08)
- +#define MDDICAP3 (MDDI_CLIENT_CORE_BASE|0x0C)
- +#define MDCAPCHG (MDDI_CLIENT_CORE_BASE|0x10)
- +#define MDCRCERC (MDDI_CLIENT_CORE_BASE|0x14)
- +#define TTBUSSEL (MDDI_CLIENT_CORE_BASE|0x18)
- +#define DPSET0 (MDDI_CLIENT_CORE_BASE|0x1C)
- +#define DPSET1 (MDDI_CLIENT_CORE_BASE|0x20)
- +#define DPSUS (MDDI_CLIENT_CORE_BASE|0x24)
- +#define DPRUN (MDDI_CLIENT_CORE_BASE|0x28)
- +#define SYSCKENA (MDDI_CLIENT_CORE_BASE|0x2C)
- +#define TESTMODE (MDDI_CLIENT_CORE_BASE|0x30)
- +#define FIFOMONI (MDDI_CLIENT_CORE_BASE|0x34)
- +#define INTMONI (MDDI_CLIENT_CORE_BASE|0x38)
- +#define MDIOBIST (MDDI_CLIENT_CORE_BASE|0x3C)
- +#define MDIOPSET (MDDI_CLIENT_CORE_BASE|0x40)
- +#define BITMAP0 (MDDI_CLIENT_CORE_BASE|0x44)
- +#define BITMAP1 (MDDI_CLIENT_CORE_BASE|0x48)
- +#define BITMAP2 (MDDI_CLIENT_CORE_BASE|0x4C)
- +#define BITMAP3 (MDDI_CLIENT_CORE_BASE|0x50)
- +#define BITMAP4 (MDDI_CLIENT_CORE_BASE|0x54)
- +
- +#define SRST (LCD_CONTROL_BLOCK_BASE|0x00)
- +#define PORT_ENB (LCD_CONTROL_BLOCK_BASE|0x04)
- +#define START (LCD_CONTROL_BLOCK_BASE|0x08)
- +#define PORT (LCD_CONTROL_BLOCK_BASE|0x0C)
- +#define CMN (LCD_CONTROL_BLOCK_BASE|0x10)
- +#define GAMMA (LCD_CONTROL_BLOCK_BASE|0x14)
- +#define INTFLG (LCD_CONTROL_BLOCK_BASE|0x18)
- +#define INTMSK (LCD_CONTROL_BLOCK_BASE|0x1C)
- +#define MPLFBUF (LCD_CONTROL_BLOCK_BASE|0x20)
- +#define HDE_LEFT (LCD_CONTROL_BLOCK_BASE|0x24)
- +#define VDE_TOP (LCD_CONTROL_BLOCK_BASE|0x28)
- +#define PXL (LCD_CONTROL_BLOCK_BASE|0x30)
- +#define HCYCLE (LCD_CONTROL_BLOCK_BASE|0x34)
- +#define HSW (LCD_CONTROL_BLOCK_BASE|0x38)
- +#define HDE_START (LCD_CONTROL_BLOCK_BASE|0x3C)
- +#define HDE_SIZE (LCD_CONTROL_BLOCK_BASE|0x40)
- +#define VCYCLE (LCD_CONTROL_BLOCK_BASE|0x44)
- +#define VSW (LCD_CONTROL_BLOCK_BASE|0x48)
- +#define VDE_START (LCD_CONTROL_BLOCK_BASE|0x4C)
- +#define VDE_SIZE (LCD_CONTROL_BLOCK_BASE|0x50)
- +#define WAKEUP (LCD_CONTROL_BLOCK_BASE|0x54)
- +#define WSYN_DLY (LCD_CONTROL_BLOCK_BASE|0x58)
- +#define REGENB (LCD_CONTROL_BLOCK_BASE|0x5C)
- +#define VSYNIF (LCD_CONTROL_BLOCK_BASE|0x60)
- +#define WRSTB (LCD_CONTROL_BLOCK_BASE|0x64)
- +#define RDSTB (LCD_CONTROL_BLOCK_BASE|0x68)
- +#define ASY_DATA (LCD_CONTROL_BLOCK_BASE|0x6C)
- +#define ASY_DATB (LCD_CONTROL_BLOCK_BASE|0x70)
- +#define ASY_DATC (LCD_CONTROL_BLOCK_BASE|0x74)
- +#define ASY_DATD (LCD_CONTROL_BLOCK_BASE|0x78)
- +#define ASY_DATE (LCD_CONTROL_BLOCK_BASE|0x7C)
- +#define ASY_DATF (LCD_CONTROL_BLOCK_BASE|0x80)
- +#define ASY_DATG (LCD_CONTROL_BLOCK_BASE|0x84)
- +#define ASY_DATH (LCD_CONTROL_BLOCK_BASE|0x88)
- +#define ASY_CMDSET (LCD_CONTROL_BLOCK_BASE|0x8C)
- +
- +#define SSICTL (SPI_BLOCK_BASE|0x00)
- +#define SSITIME (SPI_BLOCK_BASE|0x04)
- +#define SSITX (SPI_BLOCK_BASE|0x08)
- +#define SSIRX (SPI_BLOCK_BASE|0x0C)
- +#define SSIINTC (SPI_BLOCK_BASE|0x10)
- +#define SSIINTS (SPI_BLOCK_BASE|0x14)
- +#define SSIDBG1 (SPI_BLOCK_BASE|0x18)
- +#define SSIDBG2 (SPI_BLOCK_BASE|0x1C)
- +#define SSIID (SPI_BLOCK_BASE|0x20)
- +
- +#define WKREQ (SYSTEM_BLOCK1_BASE|0x00)
- +#define CLKENB (SYSTEM_BLOCK1_BASE|0x04)
- +#define DRAMPWR (SYSTEM_BLOCK1_BASE|0x08)
- +#define INTMASK (SYSTEM_BLOCK1_BASE|0x0C)
- +#define GPIOSEL (SYSTEM_BLOCK2_BASE|0x00)
- +
- +#define GPIODATA (GPIO_BLOCK_BASE|0x00)
- +#define GPIODIR (GPIO_BLOCK_BASE|0x04)
- +#define GPIOIS (GPIO_BLOCK_BASE|0x08)
- +#define GPIOIBE (GPIO_BLOCK_BASE|0x0C)
- +#define GPIOIEV (GPIO_BLOCK_BASE|0x10)
- +#define GPIOIE (GPIO_BLOCK_BASE|0x14)
- +#define GPIORIS (GPIO_BLOCK_BASE|0x18)
- +#define GPIOMIS (GPIO_BLOCK_BASE|0x1C)
- +#define GPIOIC (GPIO_BLOCK_BASE|0x20)
- +#define GPIOOMS (GPIO_BLOCK_BASE|0x24)
- +#define GPIOPC (GPIO_BLOCK_BASE|0x28)
- +#define GPIOID (GPIO_BLOCK_BASE|0x30)
- +
- +#define SPI_WRITE(reg, val) \
- + { SSITX, 0x00010000 | (((reg) & 0xff) << 8) | ((val) & 0xff) }, \
- + { 0, 5 },
- +
- +#define SPI_WRITE1(reg) \
- + { SSITX, (reg) & 0xff }, \
- + { 0, 5 },
- +
- +struct mddi_table {
- + uint32_t reg;
- + uint32_t value;
- +};
- +static struct mddi_table mddi_toshiba_init_table[] = {
- + { DPSET0, 0x09e90046 },
- + { DPSET1, 0x00000118 },
- + { DPSUS, 0x00000000 },
- + { DPRUN, 0x00000001 },
- + { 1, 14 }, /* msleep 14 */
- + { SYSCKENA, 0x00000001 },
- + //{ CLKENB, 0x000000EF },
- + { CLKENB, 0x0000A1EF }, /* # SYS.CLKENB # Enable clocks for each module (without DCLK , i2cCLK) */
- + //{ CLKENB, 0x000025CB }, /* Clock enable register */
- +
- + { GPIODATA, 0x02000200 }, /* # GPI .GPIODATA # GPIO2(RESET_LCD_N) set to 0 , GPIO3(eDRAM_Power) set to 0 */
- + { GPIODIR, 0x000030D }, /* 24D # GPI .GPIODIR # Select direction of GPIO port (0,2,3,6,9 output) */
- + { GPIOSEL, 0/*0x00000173*/}, /* # SYS.GPIOSEL # GPIO port multiplexing control */
- + { GPIOPC, 0x03C300C0 }, /* # GPI .GPIOPC # GPIO2,3 PD cut */
- + { WKREQ, 0x00000000 }, /* # SYS.WKREQ # Wake-up request event is VSYNC alignment */
- +
- + { GPIOIBE, 0x000003FF },
- + { GPIOIS, 0x00000000 },
- + { GPIOIC, 0x000003FF },
- + { GPIOIE, 0x00000000 },
- +
- + { GPIODATA, 0x00040004 }, /* # GPI .GPIODATA # eDRAM VD supply */
- + { 1, 1 }, /* msleep 1 */
- + { GPIODATA, 0x02040004 }, /* # GPI .GPIODATA # eDRAM VD supply */
- + { DRAMPWR, 0x00000001 }, /* eDRAM power */
- +};
- +
- +static struct mddi_table mddi_toshiba_panel_init_table[] = {
- + { SRST, 0x00000003 }, /* FIFO/LCDC not reset */
- + { PORT_ENB, 0x00000001 }, /* Enable sync. Port */
- + { START, 0x00000000 }, /* To stop operation */
- + //{ START, 0x00000001 }, /* To start operation */
- + { PORT, 0x00000004 }, /* Polarity of VS/HS/DE. */
- + { CMN, 0x00000000 },
- + { GAMMA, 0x00000000 }, /* No Gamma correction */
- + { INTFLG, 0x00000000 }, /* VSYNC interrupt flag clear/status */
- + { INTMSK, 0x00000000 }, /* VSYNC interrupt mask is off. */
- + { MPLFBUF, 0x00000000 }, /* Select frame buffer's base address. */
- + { HDE_LEFT, 0x00000000 }, /* The value of HDE_LEFT. */
- + { VDE_TOP, 0x00000000 }, /* The value of VDE_TPO. */
- + { PXL, 0x00000001 }, /* 1. RGB666 */
- + /* 2. Data is valid from 1st frame of beginning. */
- + { HDE_START, 0x00000006 }, /* HDE_START= 14 PCLK */
- + { HDE_SIZE, 0x0000009F }, /* HDE_SIZE=320 PCLK */
- + { HSW, 0x00000004 }, /* HSW= 10 PCLK */
- + { VSW, 0x00000001 }, /* VSW=2 HCYCLE */
- + { VDE_START, 0x00000003 }, /* VDE_START=4 HCYCLE */
- + { VDE_SIZE, 0x000001DF }, /* VDE_SIZE=480 HCYCLE */
- + { WAKEUP, 0x000001e2 }, /* Wakeup position in VSYNC mode. */
- + { WSYN_DLY, 0x00000000 }, /* Wakeup position in VSIN mode. */
- + { REGENB, 0x00000001 }, /* Set 1 to enable to change the value of registers. */
- + { CLKENB, 0x000025CB }, /* Clock enable register */
- +
- + { SSICTL, 0x00000170 }, /* SSI control register */
- + { SSITIME, 0x00000250 }, /* SSI timing control register */
- + { SSICTL, 0x00000172 }, /* SSI control register */
- +};
- +
- +
- +static struct mddi_table mddi_sharp_init_table[] = {
- + { VCYCLE, 0x000001eb },
- + { HCYCLE, 0x000000ae },
- + { REGENB, 0x00000001 }, /* Set 1 to enable to change the value of registers. */
- + { GPIODATA, 0x00040000 }, /* GPIO2 low */
- + { GPIODIR, 0x00000004 }, /* GPIO2 out */
- + { 1, 1 }, /* msleep 1 */
- + { GPIODATA, 0x00040004 }, /* GPIO2 high */
- + { 1, 10 }, /* msleep 10 */
- + SPI_WRITE(0x5f, 0x01)
- + SPI_WRITE1(0x11)
- + { 1, 200 }, /* msleep 200 */
- + SPI_WRITE1(0x29)
- + SPI_WRITE1(0xde)
- + { START, 0x00000001 }, /* To start operation */
- +};
- +
- +static struct mddi_table mddi_sharp_deinit_table[] = {
- + { 1, 200 }, /* msleep 200 */
- + SPI_WRITE(0x10, 0x1)
- + { 1, 100 }, /* msleep 100 */
- + { GPIODATA, 0x00040004 }, /* GPIO2 high */
- + { GPIODIR, 0x00000004 }, /* GPIO2 out */
- + { GPIODATA, 0x00040000 }, /* GPIO2 low */
- + { 1, 10 }, /* msleep 10 */
- +};
- +
- +static struct mddi_table mddi_tpo_init_table[] = {
- + { VCYCLE, 0x000001e5 },
- + { HCYCLE, 0x000000ac },
- + { REGENB, 0x00000001 }, /* Set 1 to enable to change the value of registers. */
- + { 0, 20 }, /* udelay 20 */
- + { GPIODATA, 0x00000004 }, /* GPIO2 high */
- + { GPIODIR, 0x00000004 }, /* GPIO2 out */
- + { 0, 20 }, /* udelay 20 */
- +
- + SPI_WRITE(0x08, 0x01)
- + { 0, 500 }, /* udelay 500 */
- + SPI_WRITE(0x08, 0x00)
- + SPI_WRITE(0x02, 0x00)
- + SPI_WRITE(0x03, 0x04)
- + SPI_WRITE(0x04, 0x0e)
- + SPI_WRITE(0x09, 0x02)
- + SPI_WRITE(0x0b, 0x08)
- + SPI_WRITE(0x0c, 0x53)
- + SPI_WRITE(0x0d, 0x01)
- + SPI_WRITE(0x0e, 0xe0)
- + SPI_WRITE(0x0f, 0x01)
- + SPI_WRITE(0x10, 0x58)
- + SPI_WRITE(0x20, 0x1e)
- + SPI_WRITE(0x21, 0x0a)
- + SPI_WRITE(0x22, 0x0a)
- + SPI_WRITE(0x23, 0x1e)
- + SPI_WRITE(0x25, 0x32)
- + SPI_WRITE(0x26, 0x00)
- + SPI_WRITE(0x27, 0xac)
- + SPI_WRITE(0x29, 0x06)
- + SPI_WRITE(0x2a, 0xa4)
- + SPI_WRITE(0x2b, 0x45)
- + SPI_WRITE(0x2c, 0x45)
- + SPI_WRITE(0x2d, 0x15)
- + SPI_WRITE(0x2e, 0x5a)
- + SPI_WRITE(0x2f, 0xff)
- + SPI_WRITE(0x30, 0x6b)
- + SPI_WRITE(0x31, 0x0d)
- + SPI_WRITE(0x32, 0x48)
- + SPI_WRITE(0x33, 0x82)
- + SPI_WRITE(0x34, 0xbd)
- + SPI_WRITE(0x35, 0xe7)
- + SPI_WRITE(0x36, 0x18)
- + SPI_WRITE(0x37, 0x94)
- + SPI_WRITE(0x38, 0x01)
- + SPI_WRITE(0x39, 0x5d)
- + SPI_WRITE(0x3a, 0xae)
- + SPI_WRITE(0x3b, 0xff)
- + SPI_WRITE(0x07, 0x09)
- + { 0, 10 }, /* udelay 10 */
- + { START, 0x00000001 }, /* To start operation */
- +};
- +
- +static struct mddi_table mddi_tpo_deinit_table[] = {
- + SPI_WRITE(0x07, 0x19)
- + { START, 0x00000000 }, /* To stop operation */
- + { GPIODATA, 0x00040004 }, /* GPIO2 high */
- + { GPIODIR, 0x00000004 }, /* GPIO2 out */
- + { GPIODATA, 0x00040000 }, /* GPIO2 low */
- + { 0, 5 }, /* usleep 5 */
- +};
- +
- +
- +#define GPIOSEL_VWAKEINT (1U << 0)
- +#define INTMASK_VWAKEOUT (1U << 0)
- +
- +static void trout_process_mddi_table(struct msm_mddi_client_data *client_data,
- + struct mddi_table *table, size_t count)
- +{
- + int i;
- + for(i = 0; i < count; i++) {
- + uint32_t reg = table[i].reg;
- + uint32_t value = table[i].value;
- +
- + if (reg == 0)
- + udelay(value);
- + else if (reg == 1)
- + msleep(value);
- + else
- + client_data->remote_write(client_data, value, reg);
- + }
- +}
- +
- +static struct vreg *vreg_mddi_1v5;
- +static struct vreg *vreg_lcm_2v85;
- +
- +static void trout_mddi_power_client(struct msm_mddi_client_data *client_data,
- + int on)
- +{
- + unsigned id, on_off;
- + if(on) {
- + on_off = 0;
- + id = PM_VREG_PDOWN_MDDI_ID;
- + msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
- + vreg_enable(vreg_mddi_1v5);
- + mdelay(5); // delay time >5ms and <10ms
- + gpio_set_value(V_VDDE2E_VDD2_GPIO, 1);
- + gpio_set_value(TROUT_GPIO_MDDI_32K_EN, 1);
- + msleep(3);
- + id = PM_VREG_PDOWN_AUX_ID;
- + msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
- + vreg_enable(vreg_lcm_2v85);
- + msleep(3);
- + gpio_set_value(MDDI_RST_N, 1);
- + msleep(10);
- + } else {
- + gpio_set_value(TROUT_GPIO_MDDI_32K_EN, 0);
- + gpio_set_value(MDDI_RST_N, 0);
- + msleep(10);
- + vreg_disable(vreg_lcm_2v85);
- + on_off = 1;
- + id = PM_VREG_PDOWN_AUX_ID;
- + msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
- + msleep(5);
- + gpio_set_value(V_VDDE2E_VDD2_GPIO, 0);
- + msleep(200);
- + vreg_disable(vreg_mddi_1v5);
- + id = PM_VREG_PDOWN_MDDI_ID;
- + msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
- + }
- +}
- +
- +static int trout_mddi_toshiba_client_init(
- + struct msm_mddi_bridge_platform_data *bridge_data,
- + struct msm_mddi_client_data *client_data)
- +{
- + int panel_id;
- +
- + client_data->auto_hibernate(client_data, 0);
- + trout_process_mddi_table(client_data, mddi_toshiba_init_table,
- + ARRAY_SIZE(mddi_toshiba_init_table));
- + client_data->auto_hibernate(client_data, 1);
- + panel_id = (client_data->remote_read(client_data, GPIODATA) >> 4) & 3;
- + if (panel_id > 1) {
- + printk("unknown panel id at mddi_enable\n");
- + return -1;
- + }
- + return 0;
- +}
- +
- +static int trout_mddi_toshiba_client_uninit(
- + struct msm_mddi_bridge_platform_data *bridge_data,
- + struct msm_mddi_client_data *client_data)
- +{
- + return 0;
- +}
- +
- +static int trout_mddi_panel_unblank(
- + struct msm_mddi_bridge_platform_data *bridge_data,
- + struct msm_mddi_client_data *client_data)
- +{
- +
- + int panel_id, ret = 0;
- +
- + trout_set_backlight_level(0);
- + client_data->auto_hibernate(client_data, 0);
- + trout_process_mddi_table(client_data, mddi_toshiba_panel_init_table,
- + ARRAY_SIZE(mddi_toshiba_panel_init_table));
- + panel_id = (client_data->remote_read(client_data, GPIODATA) >> 4) & 3;
- + switch(panel_id) {
- + case 0:
- + printk("init sharp panel\n");
- + trout_process_mddi_table(client_data,
- + mddi_sharp_init_table,
- + ARRAY_SIZE(mddi_sharp_init_table));
- + break;
- + case 1:
- + printk("init tpo panel\n");
- + trout_process_mddi_table(client_data,
- + mddi_tpo_init_table,
- + ARRAY_SIZE(mddi_tpo_init_table));
- + break;
- + default:
- + printk("unknown panel_id: %d\n", panel_id);
- + ret = -1;
- + };
- + mutex_lock(&trout_backlight_lock);
- + trout_set_backlight_level(trout_backlight_resume_level);
- + trout_backlight_off = 0;
- + mutex_unlock(&trout_backlight_lock);
- + client_data->auto_hibernate(client_data, 1);
- + client_data->remote_write(client_data, GPIOSEL_VWAKEINT, GPIOSEL);
- + client_data->remote_write(client_data, INTMASK_VWAKEOUT, INTMASK);
- + return ret;
- +
- +}
- +
- +static int trout_mddi_panel_blank(
- + struct msm_mddi_bridge_platform_data *bridge_data,
- + struct msm_mddi_client_data *client_data)
- +{
- + int panel_id, ret = 0;
- +
- + panel_id = (client_data->remote_read(client_data, GPIODATA) >> 4) & 3;
- + client_data->auto_hibernate(client_data, 0);
- + switch(panel_id) {
- + case 0:
- + printk("deinit sharp panel\n");
- + trout_process_mddi_table(client_data,
- + mddi_sharp_deinit_table,
- + ARRAY_SIZE(mddi_sharp_deinit_table));
- + break;
- + case 1:
- + printk("deinit tpo panel\n");
- + trout_process_mddi_table(client_data,
- + mddi_tpo_deinit_table,
- + ARRAY_SIZE(mddi_tpo_deinit_table));
- + break;
- + default:
- + printk("unknown panel_id: %d\n", panel_id);
- + ret = -1;
- + };
- + client_data->auto_hibernate(client_data, 1);
- + mutex_lock(&trout_backlight_lock);
- + trout_set_backlight_level(0);
- + trout_backlight_off = 1;
- + mutex_unlock(&trout_backlight_lock);
- + client_data->remote_write(client_data, 0, SYSCLKENA);
- + client_data->remote_write(client_data, 1, DPSUS);
- + return ret;
- +}
- +
- +static int trout_brightness_set(struct backlight_device *bd)
- +{
- + int intensity;
- + mutex_lock(&trout_backlight_lock);
- + intensity = bd->props.brightness;
- +
- + /* remember last backlight level as requested by user */
- + trout_backlight_resume_level = intensity;
- +
- + if(!trout_backlight_off)
- + trout_set_backlight_level(intensity);
- + mutex_unlock(&trout_backlight_lock);
- + return 0;
- +}
- +
- +static int trout_backlight_get_brightness(struct backlight_device *bd){
- + return bd->props.brightness;
- +}
- +
- +static struct backlight_ops trout_backlight_ops = {
- + .options = BL_CORE_SUSPENDRESUME,
- + .update_status = trout_brightness_set,
- + .get_brightness = trout_backlight_get_brightness,
- +};
- +
- +static int trout_backlight_probe(struct platform_device *pdev)
- +{
- + struct backlight_device *bd;
- + struct backlight_properties props;
- + memset(&props, 0, sizeof(struct backlight_properties));
- + props.max_brightness = TROUT_DEFAULT_BACKLIGHT_BRIGHTNESS;
- + bd = backlight_device_register("trout-backlight", &pdev->dev, NULL, &trout_backlight_ops, &props);
- + bd->props.max_brightness = TROUT_DEFAULT_BACKLIGHT_BRIGHTNESS;
- + bd->props.brightness = TROUT_DEFAULT_BACKLIGHT_BRIGHTNESS;
- + trout_brightness_set(bd);
- + return 0;
- +}
- +
- +static int trout_backlight_remove(struct platform_device *pdev)
- +{
- + struct backlight_device *bl = platform_get_drvdata(pdev);
- + backlight_device_unregister(bl);
- + return 0;
- +}
- +
- +static struct platform_driver trout_backlight_driver = {
- + .probe = trout_backlight_probe,
- + .remove = trout_backlight_remove,
- + .driver = {
- + .name = "trout-backlight",
- + .owner = THIS_MODULE,
- + },
- +};
- +
- +static struct resource resources_msm_fb[] = {
- + {
- + .start = MSM_FB_BASE,
- + .end = MSM_FB_BASE + MSM_FB_SIZE,
- + .flags = IORESOURCE_MEM,
- + },
- +};
- +
- +struct msm_mddi_bridge_platform_data toshiba_client_data = {
- + .init = trout_mddi_toshiba_client_init,
- + .uninit = trout_mddi_toshiba_client_uninit,
- + .blank = trout_mddi_panel_blank,
- + .unblank = trout_mddi_panel_unblank,
- + .fb_data = {
- + .xres = 320,
- + .yres = 480,
- + .width = 45,
- + .height = 67,
- + .output_format = 0,
- + },
- +};
- +
- +static struct msm_mddi_platform_data mddi_pdata = {
- + .clk_rate = 122880000,
- + .power_client = trout_mddi_power_client,
- + .fb_resource = resources_msm_fb,
- + .num_clients = 1,
- + .client_platform_data = {
- + {
- + .product_id = (0xd263 << 16 | 0),
- + .name = "mddi_c_d263_0000",
- + //.name = "mddi_c_dummy",
- + .id = 0,
- + .client_data = &toshiba_client_data,
- + //.client_data = &toshiba_client_data.fb_data,
- + .clk_rate = 0,
- + },
- + },
- +};
- +
- +static struct platform_device trout_backlight = {
- + .name = "trout-backlight",
- +};
- +
- +int __init trout_init_panel(void)
- +{
- + int rc;
- +
- + if (!machine_is_trout())
- + return 0;
- + vreg_mddi_1v5 = vreg_get(0, "gp2");
- + if (IS_ERR(vreg_mddi_1v5))
- + return PTR_ERR(vreg_mddi_1v5);
- + vreg_lcm_2v85 = vreg_get(0, "gp4");
- + if (IS_ERR(vreg_lcm_2v85))
- + return PTR_ERR(vreg_lcm_2v85);
- +
- + trout_new_backlight = system_rev >= 5;
- + if (trout_new_backlight) {
- + uint32_t config = PCOM_GPIO_CFG(27, 0, GPIO_OUTPUT,
- + GPIO_NO_PULL, GPIO_8MA);
- + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, 0);
- + }
- + else {
- + uint32_t config = PCOM_GPIO_CFG(27, 1, GPIO_OUTPUT,
- + GPIO_NO_PULL, GPIO_8MA);
- + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, 0);
- +
- + gp_clk = clk_get(NULL, "gp_clk");
- + if (IS_ERR(gp_clk)) {
- + printk(KERN_ERR "trout_init_panel: could not get gp"
- + "clock\n");
- + gp_clk = NULL;
- + }
- + rc = clk_set_rate(gp_clk, 19200000);
- + if (rc)
- + printk(KERN_ERR "trout_init_panel: set clock rate "
- + "failed\n");
- + }
- +
- + rc = platform_device_register(&msm_device_mdp);
- + if (rc)
- + return rc;
- + msm_device_mddi0.dev.platform_data = &mddi_pdata;
- + rc = platform_device_register(&msm_device_mddi0);
- + if (rc)
- + return rc;
- + platform_device_register(&trout_backlight);
- + return platform_driver_register(&trout_backlight_driver);
- +}
- +
- +device_initcall(trout_init_panel);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement