diff options
Diffstat (limited to 'arch')
40 files changed, 5817 insertions, 4069 deletions
diff --git a/arch/arm/configs/tegra3_android_defconfig b/arch/arm/configs/tegra3_android_defconfig index ba20b0ee943f..2b4aee13812b 100644 --- a/arch/arm/configs/tegra3_android_defconfig +++ b/arch/arm/configs/tegra3_android_defconfig @@ -340,6 +340,7 @@ CONFIG_VIDEO_AR0832=y CONFIG_TORCH_SSL3250A=y CONFIG_TORCH_TPS61050=y CONFIG_VIDEO_SH532U=y +CONFIG_VIDEO_AD5816=y CONFIG_USB_VIDEO_CLASS=y # CONFIG_USB_GSPCA is not set # CONFIG_RADIO_ADAPTERS is not set diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 1aa448c44fcd..82306bc4aff5 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -22,6 +22,7 @@ config ARCH_TEGRA_2x_SOC select PCI_MSI if TEGRA_PCI select CPA select ARM_ERRATA_716044 + select ARM_ERRATA_764369 if SMP select ARCH_HAS_SUSPEND_PAGETABLE help Support for NVIDIA Tegra AP20 and T20 processors, based on the @@ -46,6 +47,7 @@ config ARCH_TEGRA_3x_SOC select ARCH_SUPPORTS_MSI if TEGRA_PCI select PCI_MSI if TEGRA_PCI select ARM_ERRATA_754322 + select ARM_ERRATA_764369 if SMP select TEGRA_LP2_ARM_TWD if HAVE_ARM_TWD && !TEGRA_RAIL_OFF_MULTIPLE_CPUS select CPA select ARCH_HAS_SUSPEND_PAGETABLE @@ -259,6 +261,13 @@ config TEGRA_CARDHU_DSI help Support for DSI Panel on Nvidia Cardhu +config TEGRA_CARDHU_DUAL_DSI_PANEL + bool "Support Dual DSI panel on Cardhu" + default n + depends on TEGRA_CARDHU_DSI + help + Support for Dual DSI Panel on Nvidia Cardhu + config TEGRA_EMC_SCALING_ENABLE bool "Enable scaling the memory frequency" depends on TEGRA_SILICON_PLATFORM diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 6b1c4c52c713..3153203c6efc 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -44,6 +44,8 @@ obj-y += i2c_error_recovery.o obj-y += mc.o obj-$(CONFIG_TEGRA_STAT_MON) += tegra2_statmon.o obj-$(CONFIG_USB_SUPPORT) += usb_phy.o +obj-$(CONFIG_USB_SUPPORT) += tegra3_usb_phy.o +obj-$(CONFIG_USB_SUPPORT) += tegra2_usb_phy.o obj-$(CONFIG_FIQ) += fiq.o obj-$(CONFIG_TEGRA_FIQ_DEBUGGER) += tegra_fiq_debugger.o obj-$(CONFIG_TEGRA_PWM) += pwm.o diff --git a/arch/arm/mach-tegra/baseband-xmm-power.c b/arch/arm/mach-tegra/baseband-xmm-power.c index 20f8d306f901..4da5d412cf41 100644 --- a/arch/arm/mach-tegra/baseband-xmm-power.c +++ b/arch/arm/mach-tegra/baseband-xmm-power.c @@ -33,6 +33,7 @@ #include <linux/suspend.h> #include <linux/pm_qos_params.h> #include <mach/usb_phy.h> +#include <linux/regulator/consumer.h> #include "board.h" #include "board-enterprise.h" #include "devices.h" diff --git a/arch/arm/mach-tegra/board-cardhu-kbc.c b/arch/arm/mach-tegra/board-cardhu-kbc.c index 16e83bbb03f8..c3971403148f 100644 --- a/arch/arm/mach-tegra/board-cardhu-kbc.c +++ b/arch/arm/mach-tegra/board-cardhu-kbc.c @@ -196,8 +196,8 @@ static struct gpio_keys_button cardhu_int_keys[] = { }; static struct gpio_keys_button cardhu_pm298_int_keys[] = { - [0] = GPIO_IKEY(KEY_POWER, MAX77663_IRQ_BASE + MAX77663_IRQ_ONOFF_EN0_FALLING, 1, 100), - [1] = GPIO_IKEY(KEY_POWER, MAX77663_IRQ_BASE + MAX77663_IRQ_ONOFF_EN0_1SEC, 1, 3000), + [0] = GPIO_IKEY(KEY_POWER, MAX77663_IRQ_BASE + MAX77663_IRQ_ONOFF_EN0_FALLING, 0, 100), + [1] = GPIO_IKEY(KEY_POWER, MAX77663_IRQ_BASE + MAX77663_IRQ_ONOFF_EN0_1SEC, 0, 3000), }; static struct gpio_keys_button cardhu_pm299_int_keys[] = { @@ -252,8 +252,6 @@ int __init cardhu_keys_init(void) if (get_tegra_image_type() == rck_image) cardhu_keys_e1291_pdata.buttons[i].code = KEY_ENTER; - } else { - tegra_gpio_enable(gpio_nr); } } @@ -265,8 +263,6 @@ int __init cardhu_keys_init(void) if (gpio_nr < 0) { if (get_tegra_image_type() == rck_image) cardhu_keys_e1198[i].code = KEY_ENTER; - } else { - tegra_gpio_enable(gpio_nr); } } diff --git a/arch/arm/mach-tegra/board-cardhu-panel.c b/arch/arm/mach-tegra/board-cardhu-panel.c index 4899dee38042..a62171060b84 100644 --- a/arch/arm/mach-tegra/board-cardhu-panel.c +++ b/arch/arm/mach-tegra/board-cardhu-panel.c @@ -144,8 +144,6 @@ static int cardhu_backlight_init(struct device *dev) pr_err("bl_output array does not have 256 elements\n"); #ifndef CONFIG_TEGRA_CARDHU_DSI - tegra_gpio_disable(cardhu_bl_pwm); - ret = gpio_request(cardhu_bl_enb, "backlight_enb"); if (ret < 0) return ret; @@ -153,8 +151,6 @@ static int cardhu_backlight_init(struct device *dev) ret = gpio_direction_output(cardhu_bl_enb, 1); if (ret < 0) gpio_free(cardhu_bl_enb); - else - tegra_gpio_enable(cardhu_bl_enb); return ret; #endif @@ -168,8 +164,6 @@ static int cardhu_backlight_init(struct device *dev) ret = gpio_direction_output(cardhu_dsia_bl_enb, 1); if (ret < 0) gpio_free(cardhu_dsia_bl_enb); - else - tegra_gpio_enable(cardhu_dsia_bl_enb); /* Enable back light for DSIb panel */ ret = gpio_request(cardhu_dsib_bl_enb, "dsib_bl_enable"); @@ -179,8 +173,6 @@ static int cardhu_backlight_init(struct device *dev) ret = gpio_direction_output(cardhu_dsib_bl_enb, 1); if (ret < 0) gpio_free(cardhu_dsib_bl_enb); - else - tegra_gpio_enable(cardhu_dsib_bl_enb); #endif #if DSI_PANEL_219 @@ -192,8 +184,6 @@ static int cardhu_backlight_init(struct device *dev) ret = gpio_direction_output(cardhu_dsia_bl_enb, 1); if (ret < 0) gpio_free(cardhu_dsia_bl_enb); - else - tegra_gpio_enable(cardhu_dsia_bl_enb); #endif return ret; @@ -206,7 +196,6 @@ static void cardhu_backlight_exit(struct device *dev) /*ret = gpio_request(cardhu_bl_enb, "backlight_enb");*/ gpio_set_value(cardhu_bl_enb, 0); gpio_free(cardhu_bl_enb); - tegra_gpio_disable(cardhu_bl_enb); return; #endif @@ -214,12 +203,11 @@ static void cardhu_backlight_exit(struct device *dev) /* Disable back light for DSIa panel */ gpio_set_value(cardhu_dsia_bl_enb, 0); gpio_free(cardhu_dsia_bl_enb); - tegra_gpio_disable(cardhu_dsia_bl_enb); + /* Disable back light for DSIb panel */ gpio_set_value(cardhu_dsib_bl_enb, 0); gpio_free(cardhu_dsib_bl_enb); - tegra_gpio_disable(cardhu_dsib_bl_enb); gpio_set_value(cardhu_lvds_shutdown, 1); mdelay(20); @@ -229,7 +217,7 @@ static void cardhu_backlight_exit(struct device *dev) /* Disable back light for DSIa panel */ gpio_set_value(cardhu_dsia_bl_enb, 0); gpio_free(cardhu_dsia_bl_enb); - tegra_gpio_disable(cardhu_dsia_bl_enb); + gpio_set_value(cardhu_lvds_shutdown, 1); mdelay(20); @@ -762,8 +750,6 @@ static int cardhu_dsi_panel_enable(void) ret = gpio_direction_output(AVDD_LCD, 1); if (ret < 0) gpio_free(AVDD_LCD); - else - tegra_gpio_enable(AVDD_LCD); #if DSI_PANEL_219 @@ -774,8 +760,7 @@ static int cardhu_dsi_panel_enable(void) if (ret < 0) { gpio_free(cardhu_bl_pwm); return ret; - } else - tegra_gpio_enable(cardhu_bl_pwm); + } ret = gpio_request(cardhu_bl_enb, "bl_enb"); if (ret < 0) @@ -784,8 +769,7 @@ static int cardhu_dsi_panel_enable(void) if (ret < 0) { gpio_free(cardhu_bl_enb); return ret; - } else - tegra_gpio_enable(cardhu_bl_enb); + } gpio_set_value(cardhu_lvds_shutdown, 1); mdelay(20); @@ -805,8 +789,7 @@ static int cardhu_dsi_panel_enable(void) if (ret < 0) { gpio_free(cardhu_dsi_218_panel_reset); return ret; - } else - tegra_gpio_enable(cardhu_dsi_218_panel_reset); + } gpio_set_value(cardhu_dsi_218_panel_reset, 1); gpio_set_value(cardhu_dsi_218_panel_reset, 0); @@ -823,8 +806,7 @@ static int cardhu_dsi_panel_enable(void) if (ret < 0) { gpio_free(cardhu_dsi_219_panel_reset); return ret; - } else - tegra_gpio_enable(cardhu_dsi_219_panel_reset); + } gpio_set_value(cardhu_dsi_219_panel_reset, 0); gpio_set_value(cardhu_dsi_219_panel_reset, 1); @@ -847,18 +829,13 @@ static int cardhu_dsi_panel_disable(void) printk(KERN_INFO "DSI panel disable\n"); #if DSI_PANEL_219 - tegra_gpio_disable(cardhu_dsi_219_panel_reset); gpio_free(cardhu_dsi_219_panel_reset); - tegra_gpio_disable(cardhu_bl_enb); gpio_free(cardhu_bl_enb); - tegra_gpio_disable(cardhu_bl_pwm); gpio_free(cardhu_bl_pwm); - tegra_gpio_disable(cardhu_lvds_shutdown); gpio_free(cardhu_lvds_shutdown); #endif #if DSI_PANEL_218 - tegra_gpio_disable(cardhu_dsi_218_panel_reset); gpio_free(cardhu_dsi_218_panel_reset); #endif @@ -882,7 +859,6 @@ static int cardhu_dsi_panel_postsuspend(void) } #if DSI_PANEL_218 - tegra_gpio_disable(AVDD_LCD); gpio_free(AVDD_LCD); #endif @@ -1222,28 +1198,22 @@ int __init cardhu_panel_init(void) /* lvds configuration */ err = gpio_request(pm313_R_FDE, "R_FDE"); err |= gpio_direction_output(pm313_R_FDE, 1); - tegra_gpio_enable(pm313_R_FDE); err |= gpio_request(pm313_R_FB, "R_FB"); err |= gpio_direction_output(pm313_R_FB, 1); - tegra_gpio_enable(pm313_R_FB); err |= gpio_request(pm313_MODE0, "MODE0"); err |= gpio_direction_output(pm313_MODE0, 1); - tegra_gpio_enable(pm313_MODE0); err |= gpio_request(pm313_MODE1, "MODE1"); err |= gpio_direction_output(pm313_MODE1, 0); - tegra_gpio_enable(pm313_MODE1); err |= gpio_request(pm313_BPP, "BPP"); err |= gpio_direction_output(pm313_BPP, PM313_LVDS_PANEL_BPP); - tegra_gpio_enable(pm313_BPP); err = gpio_request(pm313_lvds_shutdown, "lvds_shutdown"); /* free ride provided by bootloader */ err |= gpio_direction_output(pm313_lvds_shutdown, 1); - tegra_gpio_enable(pm313_lvds_shutdown); if (err) printk(KERN_ERR "ERROR(s) in LVDS configuration\n"); @@ -1254,15 +1224,12 @@ int __init cardhu_panel_init(void) (board_info.board_id == BOARD_PM311)) { gpio_request(e1247_pm269_lvds_shutdown, "lvds_shutdown"); gpio_direction_output(e1247_pm269_lvds_shutdown, 1); - tegra_gpio_enable(e1247_pm269_lvds_shutdown); } else { gpio_request(cardhu_lvds_shutdown, "lvds_shutdown"); gpio_direction_output(cardhu_lvds_shutdown, 1); - tegra_gpio_enable(cardhu_lvds_shutdown); } #endif - tegra_gpio_enable(cardhu_hdmi_hpd); gpio_request(cardhu_hdmi_hpd, "hdmi_hpd"); gpio_direction_input(cardhu_hdmi_hpd); diff --git a/arch/arm/mach-tegra/board-cardhu-pinmux.c b/arch/arm/mach-tegra/board-cardhu-pinmux.c index fd0a6ae34ffc..05e2179682b1 100644 --- a/arch/arm/mach-tegra/board-cardhu-pinmux.c +++ b/arch/arm/mach-tegra/board-cardhu-pinmux.c @@ -472,7 +472,6 @@ static __initdata struct tegra_pingroup_config cardhu_pinmux_cardhu_a03[] = { static __initdata struct tegra_pingroup_config cardhu_pinmux_e1291_a04[] = { DEFAULT_PINMUX(GMI_AD15, NAND, PULL_DOWN, NORMAL, OUTPUT), - DEFAULT_PINMUX(ULPI_DATA5, UARTA, PULL_UP, NORMAL, INPUT), DEFAULT_PINMUX(ULPI_DATA6, UARTA, NORMAL, NORMAL, OUTPUT), DEFAULT_PINMUX(SPI2_MOSI, SPI6, NORMAL, NORMAL, INPUT), DEFAULT_PINMUX(DAP3_SCLK, RSVD1, NORMAL, NORMAL, OUTPUT), @@ -544,11 +543,8 @@ static __initdata struct tegra_pingroup_config gmi_pins_269[] = { static void __init cardhu_pinmux_audio_init(void) { - tegra_gpio_enable(TEGRA_GPIO_CDC_IRQ); gpio_request(TEGRA_GPIO_CDC_IRQ, "wm8903"); gpio_direction_input(TEGRA_GPIO_CDC_IRQ); - - tegra_gpio_enable(TEGRA_GPIO_HP_DET); } #define GPIO_INIT_PIN_MODE(_gpio, _is_input, _value) \ @@ -755,7 +751,6 @@ static void set_unused_pin_gpio(struct gpio_init_pin_info *lpm_pin_info, gpio_free(pin_info->gpio_nr); continue; } - tegra_gpio_enable(pin_info->gpio_nr); } } diff --git a/arch/arm/mach-tegra/board-cardhu-pm298-power-rails.c b/arch/arm/mach-tegra/board-cardhu-pm298-power-rails.c index 0305ee702cbd..f0dc8afa56fe 100644 --- a/arch/arm/mach-tegra/board-cardhu-pm298-power-rails.c +++ b/arch/arm/mach-tegra/board-cardhu-pm298-power-rails.c @@ -698,12 +698,5 @@ int __init cardhu_pm298_gpio_switch_regulator_init(void) break; } - for (i = 0; i < nfixreg_devs; ++i) { - struct fixed_voltage_config *fixed_reg_pdata = - fixed_reg_devs[i]->dev.platform_data; - int gpio_nr = fixed_reg_pdata->gpio; - if (gpio_nr < TEGRA_NR_GPIOS) - tegra_gpio_enable(gpio_nr); - } return platform_add_devices(fixed_reg_devs, nfixreg_devs); } diff --git a/arch/arm/mach-tegra/board-cardhu-pm299-power-rails.c b/arch/arm/mach-tegra/board-cardhu-pm299-power-rails.c index 0c55aa49acc0..6d4db73b6ecd 100644 --- a/arch/arm/mach-tegra/board-cardhu-pm299-power-rails.c +++ b/arch/arm/mach-tegra/board-cardhu-pm299-power-rails.c @@ -688,12 +688,5 @@ int __init cardhu_pm299_gpio_switch_regulator_init(void) break; } - for (i = 0; i < nfixreg_devs; ++i) { - struct fixed_voltage_config *fixed_reg_pdata = - fixed_reg_devs[i]->dev.platform_data; - int gpio_nr = fixed_reg_pdata->gpio; - if (gpio_nr < TEGRA_NR_GPIOS) - tegra_gpio_enable(gpio_nr); - } return platform_add_devices(fixed_reg_devs, nfixreg_devs); } diff --git a/arch/arm/mach-tegra/board-cardhu-power.c b/arch/arm/mach-tegra/board-cardhu-power.c index 79d8d6116edc..61b5a15ed5c7 100644 --- a/arch/arm/mach-tegra/board-cardhu-power.c +++ b/arch/arm/mach-tegra/board-cardhu-power.c @@ -1,7 +1,7 @@ /* * arch/arm/mach-tegra/board-cardhu-power.c * - * Copyright (C) 2011 NVIDIA, Inc. + * Copyright (C) 2011-2012 NVIDIA, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -604,6 +604,7 @@ static struct regulator_consumer_supply fixed_reg_en_vdd_pnl1_supply[] = { static struct regulator_consumer_supply fixed_reg_cam1_ldo_en_supply[] = { REGULATOR_SUPPLY("vdd_2v8_cam1", NULL), REGULATOR_SUPPLY("avdd", "6-0072"), + REGULATOR_SUPPLY("vdd", "6-000e"), }; /* CAM2_LDO_EN from AP GPIO KB_ROW7 R07*/ @@ -649,6 +650,7 @@ static struct regulator_consumer_supply fixed_reg_en_1v8_cam_supply[] = { REGULATOR_SUPPLY("vdd_1v8_cam3", NULL), REGULATOR_SUPPLY("dvdd", "6-0072"), REGULATOR_SUPPLY("dvdd", "7-0072"), + REGULATOR_SUPPLY("vdd_i2c", "6-000e"), REGULATOR_SUPPLY("vdd_i2c", "2-0033"), }; @@ -1072,13 +1074,6 @@ int __init cardhu_fixed_regulator_init(void) break; } - for (i = 0; i < nfixreg_devs; ++i) { - struct fixed_voltage_config *fixed_reg_pdata = - fixed_reg_devs[i]->dev.platform_data; - int gpio_nr = fixed_reg_pdata->gpio; - if (gpio_nr < TEGRA_NR_GPIOS) - tegra_gpio_enable(gpio_nr); - } return platform_add_devices(fixed_reg_devs, nfixreg_devs); } subsys_initcall_sync(cardhu_fixed_regulator_init); diff --git a/arch/arm/mach-tegra/board-cardhu-sdhci.c b/arch/arm/mach-tegra/board-cardhu-sdhci.c index c4e631ddc108..cb0684bcc742 100644 --- a/arch/arm/mach-tegra/board-cardhu-sdhci.c +++ b/arch/arm/mach-tegra/board-cardhu-sdhci.c @@ -280,10 +280,6 @@ static int __init cardhu_wifi_init(void) if (rc) pr_err("WLAN_WOW gpio request failed:%d\n", rc); - tegra_gpio_enable(CARDHU_WLAN_PWR); - tegra_gpio_enable(CARDHU_WLAN_RST); - tegra_gpio_enable(CARDHU_WLAN_WOW); - rc = gpio_direction_output(CARDHU_WLAN_PWR, 0); if (rc) pr_err("WLAN_PWR gpio direction configuration failed:%d\n", rc); diff --git a/arch/arm/mach-tegra/board-cardhu-sensors.c b/arch/arm/mach-tegra/board-cardhu-sensors.c index 66b3c9dc8ef3..042f740c2935 100644 --- a/arch/arm/mach-tegra/board-cardhu-sensors.c +++ b/arch/arm/mach-tegra/board-cardhu-sensors.c @@ -49,6 +49,7 @@ #include "board.h" #include <linux/mpu.h> #include <media/sh532u.h> +#include <media/ad5816.h> #include <linux/bq27x00.h> #include <mach/gpio.h> #include <mach/edp.h> @@ -87,24 +88,20 @@ static int cardhu_camera_init(void) * and donot have TCA6416 exp for camera */ if ((board_info.board_id == BOARD_E1198) || (board_info.board_id == BOARD_E1291)) { - tegra_gpio_enable(CAM1_POWER_DWN_GPIO); ret = gpio_request(CAM1_POWER_DWN_GPIO, "camera_power_en"); if (ret < 0) pr_err("%s: gpio_request failed for gpio %s\n", __func__, "CAM1_POWER_DWN_GPIO"); - tegra_gpio_enable(CAM3_POWER_DWN_GPIO); ret = gpio_request(CAM3_POWER_DWN_GPIO, "cam3_power_en"); if (ret < 0) pr_err("%s: gpio_request failed for gpio %s\n", __func__, "CAM3_POWER_DWN_GPIO"); - tegra_gpio_enable(CAM2_POWER_DWN_GPIO); ret = gpio_request(CAM2_POWER_DWN_GPIO, "camera2_power_en"); if (ret < 0) pr_err("%s: gpio_request failed for gpio %s\n", __func__, "CAM2_POWER_DWN_GPIO"); - tegra_gpio_enable(OV5650_RESETN_GPIO); ret = gpio_request(OV5650_RESETN_GPIO, "camera_reset"); if (ret < 0) pr_err("%s: gpio_request failed for gpio %s\n", @@ -124,7 +121,6 @@ static int cardhu_camera_init(void) } /* To select the CSIB MUX either for cam2 or cam3 */ - tegra_gpio_enable(CAMERA_CSI_MUX_SEL_GPIO); ret = gpio_request(CAMERA_CSI_MUX_SEL_GPIO, "camera_csi_sel"); if (ret < 0) pr_err("%s: gpio_request failed for gpio %s\n", @@ -601,6 +597,54 @@ static struct sh532u_platform_data pm269_sh532u_right_pdata = { .gpio = pm269_sh532u_right_gpio_pdata, }; +static struct nvc_gpio_pdata ad5816_gpio_pdata[] = { + { AD5816_GPIO_RESET, TEGRA_GPIO_PBB0, false, 0, }, +}; + +static struct ad5816_platform_data ad5816_left_pdata = { + .cfg = NVC_CFG_NODEV, + .num = 1, + .sync = 2, + .dev_name = "focuser", + .gpio_count = ARRAY_SIZE(ad5816_gpio_pdata), + .gpio = ad5816_gpio_pdata, +}; + +static struct ad5816_platform_data ad5816_right_pdata = { + .cfg = NVC_CFG_NODEV, + .num = 2, + .sync = 1, + .dev_name = "focuser", + .gpio_count = ARRAY_SIZE(ad5816_gpio_pdata), + .gpio = ad5816_gpio_pdata, +}; + +static struct nvc_gpio_pdata pm269_ad5816_left_gpio_pdata[] = { + { AD5816_GPIO_RESET, CAM1_RST_L_GPIO, false, 0, }, +}; + +static struct ad5816_platform_data pm269_ad5816_left_pdata = { + .cfg = 0, + .num = 1, + .sync = 2, + .dev_name = "focuser", + .gpio_count = ARRAY_SIZE(pm269_ad5816_left_gpio_pdata), + .gpio = pm269_ad5816_left_gpio_pdata, +}; + +static struct nvc_gpio_pdata pm269_ad5816_right_gpio_pdata[] = { + { AD5816_GPIO_RESET, CAM2_RST_L_GPIO, false, 0, }, +}; + +static struct ad5816_platform_data pm269_ad5816_right_pdata = { + .cfg = 0, + .num = 2, + .sync = 1, + .dev_name = "focuser", + .gpio_count = ARRAY_SIZE(pm269_ad5816_right_gpio_pdata), + .gpio = pm269_ad5816_right_gpio_pdata, +}; + static struct nvc_torch_pin_state cardhu_tps61050_pinstate = { .mask = 0x0008, /*VGP3*/ @@ -628,6 +672,10 @@ static struct i2c_board_info cardhu_i2c6_board_info[] = { I2C_BOARD_INFO("sh532u", 0x72), .platform_data = &sh532u_left_pdata, }, + { + I2C_BOARD_INFO("ad5816", 0x0E), + .platform_data = &ad5816_left_pdata, + }, }; static struct i2c_board_info cardhu_i2c7_board_info[] = { @@ -639,6 +687,10 @@ static struct i2c_board_info cardhu_i2c7_board_info[] = { I2C_BOARD_INFO("sh532u", 0x72), .platform_data = &sh532u_right_pdata, }, + { + I2C_BOARD_INFO("ad5816", 0x0E), + .platform_data = &ad5816_right_pdata, + }, }; static struct i2c_board_info pm269_i2c6_board_info[] = { @@ -650,6 +702,10 @@ static struct i2c_board_info pm269_i2c6_board_info[] = { I2C_BOARD_INFO("sh532u", 0x72), .platform_data = &pm269_sh532u_left_pdata, }, + { + I2C_BOARD_INFO("ad5816", 0x0E), + .platform_data = &pm269_ad5816_left_pdata, + }, }; static struct i2c_board_info pm269_i2c7_board_info[] = { @@ -661,6 +717,10 @@ static struct i2c_board_info pm269_i2c7_board_info[] = { I2C_BOARD_INFO("sh532u", 0x72), .platform_data = &pm269_sh532u_right_pdata, }, + { + I2C_BOARD_INFO("ad5816", 0x0E), + .platform_data = &pm269_ad5816_right_pdata, + }, }; static struct i2c_board_info cardhu_i2c8_board_info[] = { @@ -785,8 +845,6 @@ static int cardhu_nct1008_init(void) ret = gpio_direction_input(nct1008_port); if (ret < 0) gpio_free(nct1008_port); - else - tegra_gpio_enable(nct1008_port); } return ret; @@ -916,7 +974,6 @@ static void mpuirq_init(void) #if (MPU_GYRO_TYPE == MPU_TYPE_MPU3050) #if MPU_ACCEL_IRQ_GPIO /* ACCEL-IRQ assignment */ - tegra_gpio_enable(MPU_ACCEL_IRQ_GPIO); ret = gpio_request(MPU_ACCEL_IRQ_GPIO, MPU_ACCEL_NAME); if (ret < 0) { pr_err("%s: gpio_request failed %d\n", __func__, ret); @@ -933,7 +990,6 @@ static void mpuirq_init(void) #endif /* MPU-IRQ assignment */ - tegra_gpio_enable(MPU_GYRO_IRQ_GPIO); ret = gpio_request(MPU_GYRO_IRQ_GPIO, MPU_GYRO_NAME); if (ret < 0) { pr_err("%s: gpio_request failed %d\n", __func__, ret); diff --git a/arch/arm/mach-tegra/board-cardhu.c b/arch/arm/mach-tegra/board-cardhu.c index 9083828b8352..4480ab3ef47b 100644 --- a/arch/arm/mach-tegra/board-cardhu.c +++ b/arch/arm/mach-tegra/board-cardhu.c @@ -86,43 +86,6 @@ static struct tegra_thermal_data thermal_data = { #endif }; -/* !!!TODO: Change for cardhu (Taken from Ventana) */ -static struct tegra_utmip_config utmi_phy_config[] = { - [0] = { - .hssync_start_delay = 0, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 15, - .xcvr_setup_offset = 0, - .xcvr_use_fuses = 1, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, - [1] = { - .hssync_start_delay = 0, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 15, - .xcvr_setup_offset = 0, - .xcvr_use_fuses = 1, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, - [2] = { - .hssync_start_delay = 0, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 8, - .xcvr_setup_offset = 0, - .xcvr_use_fuses = 1, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, -}; - static struct resource cardhu_bcm4329_rfkill_resources[] = { { .name = "bcm4329_nshutdown_gpio", @@ -170,8 +133,6 @@ static struct platform_device cardhu_bluesleep_device = { static noinline void __init cardhu_setup_bluesleep(void) { platform_device_register(&cardhu_bluesleep_device); - tegra_gpio_enable(TEGRA_GPIO_PU6); - tegra_gpio_enable(TEGRA_GPIO_PU1); return; } @@ -845,9 +806,6 @@ static int __init cardhu_touch_init(void) touch_init_raydium(TEGRA_GPIO_PH4, TEGRA_GPIO_PH6, 2); } else { - tegra_gpio_enable(TEGRA_GPIO_PH4); - tegra_gpio_enable(TEGRA_GPIO_PH6); - gpio_request(TEGRA_GPIO_PH4, "atmel-irq"); gpio_direction_input(TEGRA_GPIO_PH4); @@ -869,135 +827,287 @@ static int __init cardhu_touch_init(void) return 0; } -static struct tegra_uhsic_config uhsic_phy_config = { - .enable_gpio = EN_HSIC_GPIO, - .reset_gpio = -1, - .sync_start_delay = 9, - .idle_wait_delay = 17, - .term_range_adj = 0, - .elastic_underrun_limit = 16, - .elastic_overrun_limit = 16, -}; - -static struct tegra_ehci_platform_data tegra_ehci_uhsic_pdata = { - .phy_type = TEGRA_USB_PHY_TYPE_HSIC, - .phy_config = &uhsic_phy_config, - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .default_enable = true, -}; - -static struct tegra_ehci_platform_data tegra_ehci_pdata[] = { - [0] = { - .phy_config = &utmi_phy_config[0], - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .default_enable = true, - }, - [1] = { - .phy_config = &utmi_phy_config[1], - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .default_enable = true, - }, - [2] = { - .phy_config = &utmi_phy_config[2], - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .hotplug = 1, - .default_enable = true, - }, -}; - -static struct tegra_otg_platform_data tegra_otg_pdata = { - .ehci_device = &tegra_ehci1_device, - .ehci_pdata = &tegra_ehci_pdata[0], -}; - -#ifdef CONFIG_USB_SUPPORT -static struct usb_phy_plat_data tegra_usb_phy_pdata[] = { - [0] = { - .instance = 0, - .vbus_gpio = -1, - .vbus_reg_supply = "vdd_vbus_micro_usb", - }, - [1] = { - .instance = 1, - .vbus_gpio = -1, - }, - [2] = { - .instance = 2, - .vbus_gpio = -1, - .vbus_reg_supply = "vdd_vbus_typea_usb", - }, -}; - -static int cardhu_usb_hsic_postsupend(void) +static void cardu_usb_hsic_postsupend(void) { #ifdef CONFIG_TEGRA_BB_XMM_POWER baseband_xmm_set_power_status(BBXMM_PS_L2); #endif - return 0; } -static int cardhu_usb_hsic_preresume(void) +static void cardu_usb_hsic_preresume(void) { #ifdef CONFIG_TEGRA_BB_XMM_POWER baseband_xmm_set_power_status(BBXMM_PS_L2TOL0); #endif - return 0; } -static int cardhu_usb_hsic_phy_ready(void) +static void cardu_usb_hsic_phy_ready(void) { #ifdef CONFIG_TEGRA_BB_XMM_POWER baseband_xmm_set_power_status(BBXMM_PS_L0); #endif - return 0; } -static int cardhu_usb_hsic_phy_off(void) +static void cardu_usb_hsic_phy_off(void) { #ifdef CONFIG_TEGRA_BB_XMM_POWER baseband_xmm_set_power_status(BBXMM_PS_L3); #endif - return 0; } +static struct tegra_usb_phy_platform_ops hsic_xmm_plat_ops = { + .post_suspend = cardu_usb_hsic_postsupend, + .pre_resume = cardu_usb_hsic_preresume, + .port_power = cardu_usb_hsic_phy_ready, + .post_phy_off = cardu_usb_hsic_phy_off, +}; + +static struct tegra_usb_platform_data tegra_ehci2_hsic_xmm_pdata = { + .port_otg = false, + .has_hostpc = true, + .phy_intf = TEGRA_USB_PHY_INTF_HSIC, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = -1, + .hot_plug = false, + .remote_wakeup_supported = false, + .power_off_on_suspend = false, + }, + .u_cfg.hsic = { + .sync_start_delay = 9, + .idle_wait_delay = 17, + .term_range_adj = 0, + .elastic_underrun_limit = 16, + .elastic_overrun_limit = 16, + }, + .ops = &hsic_xmm_plat_ops, +}; + + +static int hsic_enable_gpio = -1; +static int hsic_reset_gpio = -1; + +void hsic_platform_open(void) +{ + int reset_gpio = 0, enable_gpio = 0; + + if (hsic_enable_gpio != -1) + enable_gpio = gpio_request(hsic_enable_gpio, "uhsic_enable"); + if (hsic_reset_gpio != -1) + reset_gpio = gpio_request(hsic_reset_gpio, "uhsic_reset"); + /* hsic enable signal deasserted, hsic reset asserted */ + if (!enable_gpio) + gpio_direction_output(hsic_enable_gpio, 0 /* deasserted */); + if (!reset_gpio) + gpio_direction_output(hsic_reset_gpio, 0 /* asserted */); + if (!enable_gpio) + tegra_gpio_enable(hsic_enable_gpio); + if (!reset_gpio) + tegra_gpio_enable(hsic_reset_gpio); + /* keep hsic reset asserted for 1 ms */ + udelay(1000); + /* enable (power on) hsic */ + if (!enable_gpio) + gpio_set_value_cansleep(hsic_enable_gpio, 1); + udelay(1000); + /* deassert reset */ + if (!reset_gpio) + gpio_set_value_cansleep(hsic_reset_gpio, 1); + +} + +void hsic_platform_close(void) +{ + if (hsic_enable_gpio != -1) { + gpio_set_value(hsic_enable_gpio, 0); + gpio_free(hsic_enable_gpio); + } + if (hsic_reset_gpio != -1) { + gpio_set_value(hsic_reset_gpio, 0); + gpio_free(hsic_reset_gpio); + } +} + +void hsic_power_on(void) +{ + if (hsic_enable_gpio != -1) { + gpio_set_value_cansleep(hsic_enable_gpio, 1); + udelay(1000); + } +} + +void hsic_power_off(void) +{ + if (hsic_enable_gpio != -1) { + gpio_set_value_cansleep(hsic_enable_gpio, 0); + udelay(1000); + } +} + +static struct tegra_usb_phy_platform_ops hsic_plat_ops = { + .open = hsic_platform_open, + .close = hsic_platform_close, + .pre_phy_on = hsic_power_on, + .post_phy_off = hsic_power_off, +}; + +static struct tegra_usb_platform_data tegra_ehci2_hsic_pdata = { + .port_otg = false, + .has_hostpc = true, + .phy_intf = TEGRA_USB_PHY_INTF_HSIC, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = -1, + .hot_plug = false, + .remote_wakeup_supported = false, + .power_off_on_suspend = false, + }, + .u_cfg.hsic = { + .sync_start_delay = 9, + .idle_wait_delay = 17, + .term_range_adj = 0, + .elastic_underrun_limit = 16, + .elastic_overrun_limit = 16, + }, + .ops = &hsic_plat_ops, +}; + +static struct tegra_usb_platform_data tegra_udc_pdata = { + .port_otg = true, + .has_hostpc = true, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_DEVICE, + .u_data.dev = { + .vbus_pmu_irq = 0, + .vbus_gpio = -1, + .charging_supported = false, + .remote_wakeup_supported = false, + }, + .u_cfg.utmi = { + .hssync_start_delay = 0, + .elastic_limit = 16, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_setup = 8, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, + }, +}; + +static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = { + .port_otg = true, + .has_hostpc = true, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = -1, + .vbus_reg = "vdd_vbus_micro_usb", + .hot_plug = true, + .remote_wakeup_supported = true, + .power_off_on_suspend = true, + }, + .u_cfg.utmi = { + .hssync_start_delay = 0, + .elastic_limit = 16, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_setup = 15, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, + }, +}; + +static struct tegra_usb_platform_data tegra_ehci2_utmi_pdata = { + .port_otg = false, + .has_hostpc = true, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = -1, + .hot_plug = false, + .remote_wakeup_supported = true, + .power_off_on_suspend = true, + }, + .u_cfg.utmi = { + .hssync_start_delay = 0, + .elastic_limit = 16, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_setup = 15, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, + }, +}; + +static struct tegra_usb_platform_data tegra_ehci3_utmi_pdata = { + .port_otg = false, + .has_hostpc = true, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = -1, + .vbus_reg = "vdd_vbus_typea_usb", + .hot_plug = true, + .remote_wakeup_supported = true, + .power_off_on_suspend = true, + }, + .u_cfg.utmi = { + .hssync_start_delay = 0, + .elastic_limit = 16, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_setup = 8, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, + }, +}; + +static struct tegra_usb_otg_data tegra_otg_pdata = { + .ehci_device = &tegra_ehci1_device, + .ehci_pdata = &tegra_ehci1_utmi_pdata, +}; + +#if CONFIG_USB_SUPPORT static void cardhu_usb_init(void) { struct board_info bi; tegra_get_board_info(&bi); - tegra_usb_phy_init(tegra_usb_phy_pdata, - ARRAY_SIZE(tegra_usb_phy_pdata)); - + /* OTG should be the first to be registered */ tegra_otg_device.dev.platform_data = &tegra_otg_pdata; platform_device_register(&tegra_otg_device); + + /* setup the udc platform data */ + tegra_udc_device.dev.platform_data = &tegra_udc_pdata; + if (bi.board_id == BOARD_PM267) { - uhsic_phy_config.reset_gpio = - PM267_SMSC4640_HSIC_HUB_RESET_GPIO; - tegra_ehci2_device.dev.platform_data = &tegra_ehci_uhsic_pdata; + hsic_enable_gpio = EN_HSIC_GPIO; + hsic_reset_gpio = PM267_SMSC4640_HSIC_HUB_RESET_GPIO; + tegra_ehci2_device.dev.platform_data = &tegra_ehci2_hsic_pdata; platform_device_register(&tegra_ehci2_device); } else if (bi.board_id == BOARD_E1256) { - tegra_ehci2_device.dev.platform_data = &tegra_ehci_uhsic_pdata; + hsic_enable_gpio = EN_HSIC_GPIO; + tegra_ehci2_device.dev.platform_data = &tegra_ehci2_hsic_pdata; platform_device_register(&tegra_ehci2_device); } else if (bi.board_id == BOARD_E1186) { - /* for baseband devices do not switch off phy during suspend */ - tegra_ehci_uhsic_pdata.power_down_on_bus_suspend = 0; - uhsic_phy_config.postsuspend = cardhu_usb_hsic_postsupend; - uhsic_phy_config.preresume = cardhu_usb_hsic_preresume; - uhsic_phy_config.usb_phy_ready = cardhu_usb_hsic_phy_ready; - uhsic_phy_config.post_phy_off = cardhu_usb_hsic_phy_off; - tegra_ehci2_device.dev.platform_data = &tegra_ehci_uhsic_pdata; - /* baseband registration happens in baseband-xmm-power */ + tegra_ehci2_device.dev.platform_data = + &tegra_ehci2_hsic_xmm_pdata; + /* ehci2 registration happens in baseband-xmm-power */ } else { - tegra_ehci2_device.dev.platform_data = &tegra_ehci_pdata[1]; + tegra_ehci2_device.dev.platform_data = &tegra_ehci2_utmi_pdata; platform_device_register(&tegra_ehci2_device); } - tegra_ehci3_device.dev.platform_data = &tegra_ehci_pdata[2]; + tegra_ehci3_device.dev.platform_data = &tegra_ehci3_utmi_pdata; platform_device_register(&tegra_ehci3_device); } @@ -1005,19 +1115,6 @@ static void cardhu_usb_init(void) static void cardhu_usb_init(void) { } #endif -static void cardhu_gps_init(void) -{ - tegra_gpio_enable(TEGRA_GPIO_PU2); - tegra_gpio_enable(TEGRA_GPIO_PU3); -} - -static void cardhu_nfc_init(void) -{ - tegra_gpio_enable(TEGRA_GPIO_PX0); - tegra_gpio_enable(TEGRA_GPIO_PP3); - tegra_gpio_enable(TEGRA_GPIO_PO7); -} - static struct baseband_power_platform_data tegra_baseband_power_data = { .baseband_type = BASEBAND_XMM, .modem = { @@ -1095,7 +1192,7 @@ static void cardhu_modem_init(void) } else { w_disable_gpio = TEGRA_GPIO_PDD5; } - tegra_gpio_enable(w_disable_gpio); + ret = gpio_request(w_disable_gpio, "w_disable_gpio"); if (ret < 0) pr_err("%s: gpio_request failed for gpio %d\n", @@ -1115,22 +1212,9 @@ static void cardhu_modem_init(void) break; } gpio_direction_output(TEGRA_GPIO_PH7, 1); - tegra_gpio_enable(TEGRA_GPIO_PH7); } break; case BOARD_E1186: - tegra_gpio_enable( - tegra_baseband_power_data.modem.xmm.bb_rst); - tegra_gpio_enable( - tegra_baseband_power_data.modem.xmm.bb_on); - tegra_gpio_enable( - tegra_baseband_power_data.modem.xmm.ipc_bb_wake); - tegra_gpio_enable( - tegra_baseband_power_data.modem.xmm.ipc_ap_wake); - tegra_gpio_enable( - tegra_baseband_power_data.modem.xmm.ipc_hsic_active); - tegra_gpio_enable( - tegra_baseband_power_data.modem.xmm.ipc_hsic_sus_req); platform_device_register(&tegra_baseband_power_device); platform_device_register(&tegra_baseband_power2_device); break; @@ -1168,7 +1252,6 @@ static void __init tegra_cardhu_init(void) cardhu_dtv_init(); cardhu_suspend_init(); cardhu_touch_init(); - cardhu_gps_init(); cardhu_modem_init(); cardhu_kbc_init(); cardhu_scroll_init(); @@ -1182,7 +1265,6 @@ static void __init tegra_cardhu_init(void) cardhu_pins_state_init(); cardhu_emc_init(); tegra_release_bootloader_fb(); - cardhu_nfc_init(); cardhu_pci_init(); #ifdef CONFIG_TEGRA_WDT_RECOVERY tegra_wdt_recovery_init(); diff --git a/arch/arm/mach-tegra/board-enterprise-baseband.c b/arch/arm/mach-tegra/board-enterprise-baseband.c index 7552e2871541..9143103fd036 100644 --- a/arch/arm/mach-tegra/board-enterprise-baseband.c +++ b/arch/arm/mach-tegra/board-enterprise-baseband.c @@ -67,35 +67,42 @@ static struct gpio modem_gpios[] = { {ULPI_D1, GPIOF_OUT_INIT_LOW, "ULPI_D1"}, }; -static int baseband_phy_on(void); -static int baseband_phy_off(void); -static void baseband_phy_restore_start(void); -static void baseband_phy_restore_end(void); +static void baseband_phy_init(void); +static void baseband_phy_on(void); +static void baseband_phy_off(void); -static struct tegra_ulpi_trimmer e1219_trimmer = { 10, 1, 1, 1 }; - -static struct tegra_ulpi_config ehci2_null_ulpi_phy_config = { - .trimmer = &e1219_trimmer, - .post_phy_on = baseband_phy_on, +static struct tegra_usb_phy_platform_ops ulpi_null_plat_ops = { + .init = baseband_phy_init, .pre_phy_off = baseband_phy_off, - .phy_restore_start = baseband_phy_restore_start, - .phy_restore_end = baseband_phy_restore_end, - .phy_restore_gpio = MDM2AP_ACK, - .ulpi_dir_gpio = ULPI_DIR, - .ulpi_d0_gpio = ULPI_D0, - .ulpi_d1_gpio = ULPI_D1, + .post_phy_on = baseband_phy_on, }; -static struct tegra_ehci_platform_data ehci2_null_ulpi_platform_data = { - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 0, - .phy_config = &ehci2_null_ulpi_phy_config, - .phy_type = TEGRA_USB_PHY_TYPE_NULL_ULPI, +static struct tegra_usb_platform_data tegra_ehci2_ulpi_null_pdata = { + .port_otg = false, + .has_hostpc = true, + .phy_intf = TEGRA_USB_PHY_INTF_ULPI_NULL, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = -1, + .vbus_reg = NULL, + .hot_plug = false, + .remote_wakeup_supported = false, + .power_off_on_suspend = true, + }, + .u_cfg.ulpi = { + .shadow_clk_delay = 10, + .clock_out_delay = 1, + .data_trimmer = 1, + .stpdirnxt_trimmer = 1, + .dir_trimmer = 1, + .clk = NULL, + }, + .ops = &ulpi_null_plat_ops, }; static int __init tegra_null_ulpi_init(void) { - tegra_ehci2_device.dev.platform_data = &ehci2_null_ulpi_platform_data; + tegra_ehci2_device.dev.platform_data = &tegra_ehci2_ulpi_null_pdata; platform_device_register(&tegra_ehci2_device); return 0; } @@ -114,7 +121,7 @@ static irqreturn_t mdm_start_thread(int irq, void *data) return IRQ_HANDLED; } -static int baseband_phy_on(void) +static void baseband_phy_init(void) { static bool phy_init = false; @@ -124,22 +131,15 @@ static int baseband_phy_on(void) phy_init = true; } pr_info("%s\n", __func__); - return 0; -} - -static int baseband_phy_off(void) -{ - pr_info("%s\n", __func__); - return 0; } -static void baseband_phy_restore_start(void) +static void baseband_phy_off(void) { /* set AP2MDM_ACK2 high */ gpio_set_value(AP2MDM_ACK2, 1); } -static void baseband_phy_restore_end(void) +static void baseband_phy_on(void) { /* set AP2MDM_ACK2 low */ gpio_set_value(AP2MDM_ACK2, 0); diff --git a/arch/arm/mach-tegra/board-enterprise.c b/arch/arm/mach-tegra/board-enterprise.c index a95ee617b1a8..d92ac57dd054 100644 --- a/arch/arm/mach-tegra/board-enterprise.c +++ b/arch/arm/mach-tegra/board-enterprise.c @@ -79,43 +79,6 @@ static struct tegra_thermal_data thermal_data = { #endif }; -/* !!!TODO: Change for enterprise (Taken from Cardhu) */ -static struct tegra_utmip_config utmi_phy_config[] = { - [0] = { - .hssync_start_delay = 0, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 15, - .xcvr_setup_offset = 0, - .xcvr_use_fuses = 1, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, - [1] = { - .hssync_start_delay = 0, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 15, - .xcvr_setup_offset = 0, - .xcvr_use_fuses = 1, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, - [2] = { - .hssync_start_delay = 0, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 8, - .xcvr_setup_offset = 0, - .xcvr_use_fuses = 1, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, -}; - static struct resource enterprise_bcm4329_rfkill_resources[] = { { .name = "bcm4329_nshutdown_gpio", @@ -653,66 +616,120 @@ static int __init enterprise_touch_init(void) return 0; } -static struct usb_phy_plat_data tegra_usb_phy_pdata[] = { - [0] = { - .instance = 0, - .vbus_gpio = -1, - .vbus_reg_supply = "usb_vbus", - .vbus_irq = ENT_TPS80031_IRQ_BASE + - TPS80031_INT_VBUS_DET, - }, - [1] = { - .instance = 1, - .vbus_gpio = -1, - }, - [2] = { - .instance = 2, - .vbus_gpio = -1, - }, -}; +static void enterprise_usb_hsic_postsupend(void) +{ + pr_debug("%s\n", __func__); +#ifdef CONFIG_TEGRA_BB_XMM_POWER + baseband_xmm_set_power_status(BBXMM_PS_L2); +#endif +} -static struct tegra_uhsic_config uhsic_phy_config = { - .enable_gpio = -1, - .reset_gpio = -1, - .sync_start_delay = 9, - .idle_wait_delay = 17, - .term_range_adj = 0, - .elastic_underrun_limit = 16, - .elastic_overrun_limit = 16, -}; +static void enterprise_usb_hsic_preresume(void) +{ + pr_debug("%s\n", __func__); +#ifdef CONFIG_TEGRA_BB_XMM_POWER + baseband_xmm_set_power_status(BBXMM_PS_L2TOL0); +#endif +} -static struct tegra_ehci_platform_data tegra_ehci_uhsic_pdata = { - .phy_type = TEGRA_USB_PHY_TYPE_HSIC, - .phy_config = &uhsic_phy_config, - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .default_enable = true, -}; +static void enterprise_usb_hsic_phy_power(void) +{ + pr_debug("%s\n", __func__); +#ifdef CONFIG_TEGRA_BB_XMM_POWER + baseband_xmm_set_power_status(BBXMM_PS_L0); +#endif +} -static struct tegra_ehci_platform_data tegra_ehci_pdata[] = { - [0] = { - .phy_config = &utmi_phy_config[0], - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .default_enable = false, - }, - [1] = { - .phy_config = &utmi_phy_config[1], - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .default_enable = false, - }, - [2] = { - .phy_config = &utmi_phy_config[2], - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .default_enable = false, - }, -}; +static void enterprise_usb_hsic_post_phy_off(void) +{ + pr_debug("%s\n", __func__); +#ifdef CONFIG_TEGRA_BB_XMM_POWER + baseband_xmm_set_power_status(BBXMM_PS_L3); +#endif +} -static struct tegra_otg_platform_data tegra_otg_pdata = { +static struct tegra_usb_phy_platform_ops hsic_xmm_plat_ops = { + .post_suspend = enterprise_usb_hsic_postsupend, + .pre_resume = enterprise_usb_hsic_preresume, + .port_power = enterprise_usb_hsic_phy_power, + .post_phy_off = enterprise_usb_hsic_post_phy_off, +}; + +static struct tegra_usb_platform_data tegra_ehci2_hsic_xmm_pdata = { + .port_otg = false, + .has_hostpc = true, + .phy_intf = TEGRA_USB_PHY_INTF_HSIC, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = -1, + .hot_plug = false, + .remote_wakeup_supported = false, + .power_off_on_suspend = false, + }, + .u_cfg.hsic = { + .sync_start_delay = 9, + .idle_wait_delay = 17, + .term_range_adj = 0, + .elastic_underrun_limit = 16, + .elastic_overrun_limit = 16, + }, + .ops = &hsic_xmm_plat_ops, +}; + + + +static struct tegra_usb_platform_data tegra_udc_pdata = { + .port_otg = true, + .has_hostpc = true, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_DEVICE, + .u_data.dev = { + .vbus_pmu_irq = 0, + .vbus_gpio = -1, + .charging_supported = false, + .remote_wakeup_supported = false, + }, + .u_cfg.utmi = { + .hssync_start_delay = 0, + .elastic_limit = 16, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_setup = 8, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, + }, +}; + +static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = { + .port_otg = true, + .has_hostpc = true, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = -1, + .vbus_reg = "usb_vbus", + .hot_plug = true, + .remote_wakeup_supported = true, + .power_off_on_suspend = true, + }, + .u_cfg.utmi = { + .hssync_start_delay = 0, + .elastic_limit = 16, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_setup = 15, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, + }, +}; + +static struct tegra_usb_otg_data tegra_otg_pdata = { .ehci_device = &tegra_ehci1_device, - .ehci_pdata = &tegra_ehci_pdata[0], + .ehci_pdata = &tegra_ehci1_utmi_pdata, }; struct platform_device *tegra_usb_hsic_host_register(void) @@ -733,8 +750,8 @@ struct platform_device *tegra_usb_hsic_host_register(void) pdev->dev.dma_mask = tegra_ehci2_device.dev.dma_mask; pdev->dev.coherent_dma_mask = tegra_ehci2_device.dev.coherent_dma_mask; - val = platform_device_add_data(pdev, &tegra_ehci_uhsic_pdata, - sizeof(struct tegra_ehci_platform_data)); + val = platform_device_add_data(pdev, &tegra_ehci2_hsic_xmm_pdata, + sizeof(struct tegra_usb_platform_data)); if (val) goto error; @@ -755,52 +772,12 @@ void tegra_usb_hsic_host_unregister(struct platform_device *pdev) platform_device_unregister(pdev); } -static int enterprise_usb_hsic_postsupend(void) -{ - pr_debug("%s\n", __func__); -#ifdef CONFIG_TEGRA_BB_XMM_POWER - baseband_xmm_set_power_status(BBXMM_PS_L2); -#endif - return 0; -} - -static int enterprise_usb_hsic_preresume(void) -{ - pr_debug("%s\n", __func__); -#ifdef CONFIG_TEGRA_BB_XMM_POWER - baseband_xmm_set_power_status(BBXMM_PS_L2TOL0); -#endif - return 0; -} - -static int enterprise_usb_hsic_phy_ready(void) -{ - pr_debug("%s\n", __func__); -#ifdef CONFIG_TEGRA_BB_XMM_POWER - baseband_xmm_set_power_status(BBXMM_PS_L0); -#endif - return 0; -} - -static int enterprise_usb_hsic_phy_off(void) -{ - pr_debug("%s\n", __func__); -#ifdef CONFIG_TEGRA_BB_XMM_POWER - baseband_xmm_set_power_status(BBXMM_PS_L3); -#endif - return 0; -} - static void enterprise_usb_init(void) { - struct fsl_usb2_platform_data *udc_pdata; - - tegra_usb_phy_init(tegra_usb_phy_pdata, ARRAY_SIZE(tegra_usb_phy_pdata)); + tegra_udc_device.dev.platform_data = &tegra_udc_pdata; tegra_otg_device.dev.platform_data = &tegra_otg_pdata; platform_device_register(&tegra_otg_device); - - udc_pdata = tegra_udc_device.dev.platform_data; } static struct platform_device *enterprise_audio_devices[] __initdata = { @@ -910,12 +887,9 @@ static void enterprise_baseband_init(void) enterprise_modem_init(); break; case TEGRA_BB_XMM6260: /* XMM6260 HSIC */ - /* xmm baseband - do not switch off phy during suspend */ - tegra_ehci_uhsic_pdata.power_down_on_bus_suspend = 0; - uhsic_phy_config.postsuspend = enterprise_usb_hsic_postsupend; - uhsic_phy_config.preresume = enterprise_usb_hsic_preresume; - uhsic_phy_config.usb_phy_ready = enterprise_usb_hsic_phy_ready; - uhsic_phy_config.post_phy_off = enterprise_usb_hsic_phy_off; + /* baseband-power.ko will register ehci2 device */ + tegra_ehci2_device.dev.platform_data = + &tegra_ehci2_hsic_xmm_pdata; /* enable XMM6260 baseband gpio(s) */ tegra_gpio_enable(tegra_baseband_power_data.modem.generic .mdm_reset); @@ -938,9 +912,9 @@ static void enterprise_baseband_init(void) break; #ifdef CONFIG_TEGRA_BB_M7400 case TEGRA_BB_M7400: /* M7400 HSIC */ - tegra_ehci_uhsic_pdata.power_down_on_bus_suspend = 0; + tegra_ehci2_hsic_xmm_pdata.u_data.host.power_off_on_suspend = 0; tegra_ehci2_device.dev.platform_data - = &tegra_ehci_uhsic_pdata; + = &tegra_ehci2_hsic_xmm_pdata; platform_device_register(&tegra_baseband_m7400_device); break; #endif diff --git a/arch/arm/mach-tegra/board-harmony-pcie.c b/arch/arm/mach-tegra/board-harmony-pcie.c index f3db0eeba2c9..f73cde4c5570 100644 --- a/arch/arm/mach-tegra/board-harmony-pcie.c +++ b/arch/arm/mach-tegra/board-harmony-pcie.c @@ -4,6 +4,8 @@ * Copyright (C) 2010 CompuLab, Ltd. * Mike Rapoport <mike@compulab.co.il> * + * Copyright (C) 2011-2012 NVIDIA 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. @@ -68,7 +70,6 @@ int __init harmony_pcie_init(void) return 0; -err_pcie: tegra_pinmux_set_tristate(TEGRA_PINGROUP_GPV, TEGRA_TRI_TRISTATE); tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXA, TEGRA_TRI_TRISTATE); tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXK, TEGRA_TRI_TRISTATE); diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c index 9bf8cde056a3..638c851fa7a8 100644 --- a/arch/arm/mach-tegra/board-harmony.c +++ b/arch/arm/mach-tegra/board-harmony.c @@ -32,6 +32,8 @@ #include <linux/i2c-tegra.h> #include <linux/memblock.h> #include <linux/delay.h> +#include <linux/mfd/tps6586x.h> +#include <linux/platform_data/tegra_usb.h> #include <sound/wm8903.h> @@ -81,20 +83,52 @@ static int __init parse_tag_nvidia(const struct tag *tag) } __tagtable(ATAG_NVIDIA, parse_tag_nvidia); -static struct tegra_utmip_config utmi_phy_config = { - .hssync_start_delay = 0, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 9, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, + +static struct tegra_usb_platform_data tegra_udc_pdata = { + .port_otg = false, + .has_hostpc = false, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_DEVICE, + .u_data.dev = { + .vbus_pmu_irq = 0, + .vbus_gpio = -1, + .charging_supported = false, + .remote_wakeup_supported = false, + }, + .u_cfg.utmi = { + .hssync_start_delay = 0, + .elastic_limit = 16, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_setup = 8, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, + }, }; -static struct tegra_ehci_platform_data tegra_ehci_pdata = { - .phy_config = &utmi_phy_config, - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, +static struct tegra_usb_platform_data tegra_ehci3_utmi_pdata = { + .port_otg = false, + .has_hostpc = false, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = TEGRA_GPIO_PD3, + .vbus_reg = NULL, + .hot_plug = true, + .remote_wakeup_supported = false, + .power_off_on_suspend = true, + }, + .u_cfg.utmi = { + .hssync_start_delay = 9, + .elastic_limit = 16, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_setup = 8, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + }, }; static struct tegra_nand_chip_parms nand_chip_parms[] = { @@ -283,39 +317,6 @@ static void __init harmony_i2c_init(void) i2c_register_board_info(0, &wm8903_board_info, 1); } -/* OTG gadget device */ -/*static u64 tegra_otg_dmamask = DMA_BIT_MASK(32); - - -static struct resource tegra_otg_resources[] = { - [0] = { - .start = TEGRA_USB_BASE, - .end = TEGRA_USB_BASE + TEGRA_USB_SIZE - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = INT_USB, - .end = INT_USB, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct fsl_usb2_platform_data tegra_otg_pdata = { - .operating_mode = FSL_USB2_DR_DEVICE, - .phy_mode = FSL_USB2_PHY_UTMI, -}; - -static struct platform_device tegra_otg = { - .name = "fsl-tegra-udc", - .id = -1, - .dev = { - .dma_mask = &tegra_otg_dmamask, - .coherent_dma_mask = 0xffffffff, - .platform_data = &tegra_otg_pdata, - }, - .resource = tegra_otg_resources, - .num_resources = ARRAY_SIZE(tegra_otg_resources), -};*/ /* PDA power */ static struct pda_power_pdata pda_power_pdata = { @@ -476,7 +477,8 @@ static void __init tegra_harmony_init(void) tegra_sdhci_device2.dev.platform_data = &sdhci_pdata2; tegra_sdhci_device4.dev.platform_data = &sdhci_pdata4; - tegra_ehci3_device.dev.platform_data = &tegra_ehci_pdata; + tegra_udc_device.dev.platform_data = &tegra_udc_pdata; + tegra_ehci3_device.dev.platform_data = &tegra_ehci3_utmi_pdata; platform_add_devices(harmony_devices, ARRAY_SIZE(harmony_devices)); harmony_i2c_init(); diff --git a/arch/arm/mach-tegra/board-kai.c b/arch/arm/mach-tegra/board-kai.c index c455fba4cef9..193d68632d52 100644 --- a/arch/arm/mach-tegra/board-kai.c +++ b/arch/arm/mach-tegra/board-kai.c @@ -82,42 +82,6 @@ static struct tegra_thermal_data thermal_data = { #endif }; -/* !!!TODO: Change for kai (Taken from Ventana) */ -static struct tegra_utmip_config utmi_phy_config[] = { - [0] = { - .hssync_start_delay = 0, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 15, - .xcvr_setup_offset = 0, - .xcvr_use_fuses = 1, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, - [1] = { - .hssync_start_delay = 0, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 15, - .xcvr_setup_offset = 0, - .xcvr_use_fuses = 1, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, - [2] = { - .hssync_start_delay = 0, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 8, - .xcvr_setup_offset = 0, - .xcvr_use_fuses = 1, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, -}; /* wl128x BT, FM, GPS connectivity chip */ struct ti_st_plat_data kai_wilink_pdata = { @@ -165,8 +129,15 @@ static struct platform_device kai_bluesleep_device = { static noinline void __init kai_tegra_setup_tibluesleep(void) { + int ret; + + ret = gpio_request(TEGRA_GPIO_PU6, "host_wake"); + if (ret) + pr_err("gpio_request failed for gpio: %d\n", TEGRA_GPIO_PU6); + else + gpio_direction_input(TEGRA_GPIO_PU6); + platform_device_register(&kai_bluesleep_device); - tegra_gpio_enable(TEGRA_GPIO_PU6); } static __initdata struct tegra_clk_init_table kai_clk_init_table[] = { @@ -695,47 +666,97 @@ static int __init kai_touch_init(void) return 0; } -static struct tegra_ehci_platform_data tegra_ehci_pdata[] = { - [0] = { - .phy_config = &utmi_phy_config[0], - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .default_enable = true, +static struct tegra_usb_platform_data tegra_udc_pdata = { + .port_otg = true, + .has_hostpc = true, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_DEVICE, + .u_data.dev = { + .vbus_pmu_irq = 0, + .vbus_gpio = -1, + .charging_supported = false, + .remote_wakeup_supported = false, }, - [1] = { - .phy_config = &utmi_phy_config[1], - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .default_enable = false, + .u_cfg.utmi = { + .hssync_start_delay = 0, + .elastic_limit = 16, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_setup = 8, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, }, }; -static struct tegra_otg_platform_data tegra_otg_pdata = { - .ehci_device = &tegra_ehci1_device, - .ehci_pdata = &tegra_ehci_pdata[0], +static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = { + .port_otg = true, + .has_hostpc = true, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = -1, + .vbus_reg = NULL, + .hot_plug = true, + .remote_wakeup_supported = true, + .power_off_on_suspend = true, + }, + .u_cfg.utmi = { + .hssync_start_delay = 0, + .elastic_limit = 16, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_setup = 15, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, + }, }; -#ifdef CONFIG_USB_SUPPORT -static struct usb_phy_plat_data tegra_usb_phy_pdata[] = { - [0] = { - .instance = 0, - .vbus_gpio = -1, + +static struct tegra_usb_platform_data tegra_ehci2_utmi_pdata = { + .port_otg = false, + .has_hostpc = true, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = -1, + .vbus_reg = NULL, + .hot_plug = false, + .remote_wakeup_supported = true, + .power_off_on_suspend = true, + }, - [1] = { - .instance = 1, - .vbus_gpio = -1, + .u_cfg.utmi = { + .hssync_start_delay = 0, + .elastic_limit = 16, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_setup = 8, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, }, }; +static struct tegra_usb_otg_data tegra_otg_pdata = { + .ehci_device = &tegra_ehci1_device, + .ehci_pdata = &tegra_ehci1_utmi_pdata, +}; + +#if CONFIG_USB_SUPPORT static void kai_usb_init(void) { - tegra_usb_phy_init(tegra_usb_phy_pdata, - ARRAY_SIZE(tegra_usb_phy_pdata)); - tegra_otg_device.dev.platform_data = &tegra_otg_pdata; platform_device_register(&tegra_otg_device); - tegra_ehci2_device.dev.platform_data = &tegra_ehci_pdata[1]; + /* Setup the udc platform data */ + tegra_udc_device.dev.platform_data = &tegra_udc_pdata; + + tegra_ehci2_device.dev.platform_data = &tegra_ehci2_utmi_pdata; platform_device_register(&tegra_ehci2_device); } diff --git a/arch/arm/mach-tegra/board-p1852.c b/arch/arm/mach-tegra/board-p1852.c index 43bef9975187..71c12756539d 100644 --- a/arch/arm/mach-tegra/board-p1852.c +++ b/arch/arm/mach-tegra/board-p1852.c @@ -57,42 +57,6 @@ #include "gpio-names.h" #include "fuse.h" -static struct tegra_utmip_config utmi_phy_config[] = { - [0] = { - .hssync_start_delay = 0, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 15, - .xcvr_setup_offset = 0, - .xcvr_use_fuses = 1, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, - [1] = { - .hssync_start_delay = 0, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 15, - .xcvr_setup_offset = 0, - .xcvr_use_fuses = 1, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, - [2] = { - .hssync_start_delay = 0, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 8, - .xcvr_setup_offset = 0, - .xcvr_use_fuses = 1, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, -}; - static __initdata struct tegra_clk_init_table p1852_clk_init_table[] = { /* name parent rate enabled */ { "pll_m", NULL, 0, true}, @@ -101,9 +65,10 @@ static __initdata struct tegra_clk_init_table p1852_clk_init_table[] = { { "pwm", "clk_32k", 32768, false}, { "blink", "clk_32k", 32768, true}, { "pll_a", NULL, 552960000, false}, - { "pll_a_out0", NULL, 12288000, false}, - { "d_audio", "pll_a_out0", 12288000, false}, - { "nor", "pll_p", 102000000, true}, + /* audio cif clock should be faster than i2s */ + { "pll_a_out0", NULL, 24576000, false}, + { "d_audio", "pll_a_out0", 24576000, false}, + { "nor", "pll_p", 86500000, true}, { "uarta", "pll_p", 480000000, true}, { "uartd", "pll_p", 480000000, true}, { "uarte", "pll_p", 480000000, true}, @@ -115,11 +80,11 @@ static __initdata struct tegra_clk_init_table p1852_clk_init_table[] = { { "sbc5", "pll_m", 100000000, true}, { "sbc6", "pll_m", 100000000, true}, { "cpu_g", "cclk_g", 900000000, true}, - { "i2s0", "pll_a_out0", 12288000, false}, - { "i2s1", "pll_a_out0", 12288000, false}, - { "i2s2", "pll_a_out0", 12288000, false}, - { "i2s3", "pll_a_out0", 12288000, false}, - { "i2s4", "pll_a_out0", 12288000, false}, + { "i2s0", "pll_a_out0", 24576000, false}, + { "i2s1", "pll_a_out0", 24576000, false}, + { "i2s2", "pll_a_out0", 24576000, false}, + { "i2s3", "pll_a_out0", 24576000, false}, + { "i2s4", "pll_a_out0", 24576000, false}, { "audio0", "i2s0_sync", 12288000, false}, { "audio1", "i2s1_sync", 12288000, false}, { "audio2", "i2s2_sync", 12288000, false}, @@ -241,16 +206,24 @@ static struct tegra_p1852_platform_data p1852_audio_pdata = { .cpu_dai_name = "tegra30-i2s.0", .codec_name = "spdif-dit.0", .name = "tegra-i2s-1", - .i2s_format = format_i2s, + .i2s_format = format_tdm, .master = 1, + .num_slots = 4, + .slot_width = 32, + .tx_mask = 0x0f, + .rx_mask = 0x0f, }, .codec_info[1] = { .codec_dai_name = "dit-hifi", - .cpu_dai_name = "tegra30-i2s.1", + .cpu_dai_name = "tegra30-i2s.4", .codec_name = "spdif-dit.1", .name = "tegra-i2s-2", - .i2s_format = format_i2s, - .master = 0, + .i2s_format = format_tdm, + .master = 1, + .num_slots = 8, + .slot_width = 32, + .tx_mask = 0xff, + .rx_mask = 0xff, }, }; @@ -278,7 +251,7 @@ static void p1852_i2s_audio_init(void) platform_device_register(&generic_codec_1); platform_device_register(&generic_codec_2); platform_device_register(&tegra_i2s_device0); - platform_device_register(&tegra_i2s_device1); + platform_device_register(&tegra_i2s_device4); platform_device_register(&tegra_ahub_device); platform_device_register(&tegra_snd_p1852); } @@ -349,56 +322,91 @@ static struct platform_device *p1852_devices[] __initdata = { &tegra_wdt_device }; -static struct usb_phy_plat_data tegra_usb_phy_pdata[] = { - [0] = { - .instance = 0, - .vbus_gpio = -1, - .vbus_reg_supply = NULL, +static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = { + .port_otg = false, + .has_hostpc = true, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = -1, + .vbus_reg = NULL, + .hot_plug = false, + .remote_wakeup_supported = true, + .power_off_on_suspend = true, }, - [1] = { - .instance = 1, - .vbus_gpio = -1, - }, - [2] = { - .instance = 2, - .vbus_gpio = -1, - .vbus_reg_supply = NULL, + .u_cfg.utmi = { + .hssync_start_delay = 0, + .idle_wait_delay = 17, + .elastic_limit = 16, + .term_range_adj = 6, + .xcvr_setup = 15, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, }, }; -static struct tegra_ehci_platform_data tegra_ehci_pdata[] = { - [0] = { - .phy_config = &utmi_phy_config[0], - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, +static struct tegra_usb_platform_data tegra_ehci2_utmi_pdata = { + .port_otg = false, + .has_hostpc = true, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = -1, + .vbus_reg = NULL, + .hot_plug = false, + .remote_wakeup_supported = true, + .power_off_on_suspend = true, + }, + .u_cfg.utmi = { + .hssync_start_delay = 0, + .idle_wait_delay = 17, + .elastic_limit = 16, + .term_range_adj = 6, + .xcvr_setup = 15, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, }, - [1] = { - .phy_config = &utmi_phy_config[1], - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, +}; + +static struct tegra_usb_platform_data tegra_ehci3_utmi_pdata = { + .port_otg = false, + .has_hostpc = true, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = -1, + .vbus_reg = NULL, + .hot_plug = false, + .remote_wakeup_supported = true, + .power_off_on_suspend = true, }, - [2] = { - .phy_config = &utmi_phy_config[2], - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, + .u_cfg.utmi = { + .hssync_start_delay = 0, + .idle_wait_delay = 17, + .elastic_limit = 16, + .term_range_adj = 6, + .xcvr_setup = 8, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, }, }; static void p1852_usb_init(void) { - /* Need to parse sku info to decide host/device mode */ - tegra_usb_phy_init(tegra_usb_phy_pdata, - ARRAY_SIZE(tegra_usb_phy_pdata)); - - tegra_ehci1_device.dev.platform_data = &tegra_ehci_pdata[0]; + tegra_ehci1_device.dev.platform_data = &tegra_ehci1_utmi_pdata; platform_device_register(&tegra_ehci1_device); - tegra_ehci2_device.dev.platform_data = &tegra_ehci_pdata[1]; + tegra_ehci2_device.dev.platform_data = &tegra_ehci2_utmi_pdata; platform_device_register(&tegra_ehci2_device); - tegra_ehci3_device.dev.platform_data = &tegra_ehci_pdata[2]; + tegra_ehci3_device.dev.platform_data = &tegra_ehci3_utmi_pdata; platform_device_register(&tegra_ehci3_device); - } static struct tegra_nor_platform_data p1852_nor_data = { diff --git a/arch/arm/mach-tegra/board-trimslice.c b/arch/arm/mach-tegra/board-trimslice.c index 823060ec478f..626cd1b34114 100644 --- a/arch/arm/mach-tegra/board-trimslice.c +++ b/arch/arm/mach-tegra/board-trimslice.c @@ -6,6 +6,7 @@ * * Based on board-harmony.c * Copyright (C) 2010 Google, Inc. + * Copyright (C) 2011-2012 NVIDIA Corporation. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -95,7 +96,7 @@ static struct platform_device *trimslice_devices[] __initdata = { &tegra_das_device, &tegra_pcm_device, &trimslice_audio_device, - &trimslice_pci_platform_data, + &tegra_pci_device, }; static struct i2c_board_info trimslice_i2c3_board_info[] = { diff --git a/arch/arm/mach-tegra/board-ventana.c b/arch/arm/mach-tegra/board-ventana.c index d371e720fdcf..779ffdba0f65 100644 --- a/arch/arm/mach-tegra/board-ventana.c +++ b/arch/arm/mach-tegra/board-ventana.c @@ -63,35 +63,6 @@ #include "wakeups-t2.h" #include "pm.h" -static struct tegra_utmip_config utmi_phy_config[] = { - [0] = { - .hssync_start_delay = 9, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 15, - .xcvr_setup_offset = 0, - .xcvr_use_fuses = 1, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, - [1] = { - .hssync_start_delay = 9, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 8, - .xcvr_setup_offset = 0, - .xcvr_use_fuses = 1, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, -}; - -static struct tegra_ulpi_config ulpi_phy_config = { - .reset_gpio = TEGRA_GPIO_PG2, - .clk = "cdev2", -}; static struct resource ventana_bcm4329_rfkill_resources[] = { { @@ -164,19 +135,6 @@ static __initdata struct tegra_clk_init_table ventana_clk_init_table[] = { { NULL, NULL, 0, 0}, }; -static struct tegra_ulpi_config ventana_ehci2_ulpi_phy_config = { - .reset_gpio = TEGRA_GPIO_PV1, - .clk = "cdev2", -}; - -static struct tegra_ehci_platform_data ventana_ehci2_ulpi_platform_data = { - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .phy_config = &ventana_ehci2_ulpi_phy_config, - .phy_type = TEGRA_USB_PHY_TYPE_LINK_ULPI, - .default_enable = true, -}; - static struct tegra_i2c_platform_data ventana_i2c1_platform_data = { .adapter_nr = 0, .bus_count = 1, @@ -498,73 +456,146 @@ static int __init ventana_touch_init_panjit(void) return 0; } -static struct usb_phy_plat_data tegra_usb_phy_pdata[] = { - [0] = { - .instance = 0, - .vbus_irq = TPS6586X_INT_BASE + TPS6586X_INT_USB_DET, - .vbus_gpio = TEGRA_GPIO_PD0, +static int __init ventana_gps_init(void) +{ + struct clk *clk32 = clk_get_sys(NULL, "blink"); + if (!IS_ERR(clk32)) { + clk_set_rate(clk32,clk32->parent->rate); + clk_enable(clk32); + } + + tegra_gpio_enable(TEGRA_GPIO_PZ3); + return 0; +} + +static struct tegra_usb_platform_data tegra_udc_pdata = { + .port_otg = true, + .has_hostpc = false, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_DEVICE, + .u_data.dev = { + .vbus_pmu_irq = 0, + .vbus_gpio = -1, + .charging_supported = false, + .remote_wakeup_supported = false, }, - [1] = { - .instance = 1, - .vbus_gpio = -1, + .u_cfg.utmi = { + .hssync_start_delay = 0, + .elastic_limit = 16, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_setup = 8, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, }, - [2] = { - .instance = 2, - .vbus_gpio = TEGRA_GPIO_PD3, +}; + +static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = { + .port_otg = true, + .has_hostpc = false, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = TEGRA_GPIO_PD0, + .vbus_reg = NULL, + .hot_plug = true, + .remote_wakeup_supported = false, + .power_off_on_suspend = true, + }, + .u_cfg.utmi = { + .hssync_start_delay = 9, + .elastic_limit = 16, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_setup = 8, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, }, }; -static struct tegra_ehci_platform_data tegra_ehci_pdata[] = { - [0] = { - .phy_config = &utmi_phy_config[0], - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .default_enable = true, +static void ulpi_link_platform_open(void) +{ + int reset_gpio = TEGRA_GPIO_PV1; + + gpio_request(reset_gpio, "ulpi_phy_reset"); + gpio_direction_output(reset_gpio, 0); + tegra_gpio_enable(reset_gpio); + + gpio_direction_output(reset_gpio, 0); + msleep(5); + gpio_direction_output(reset_gpio, 1); +} + +static struct tegra_usb_phy_platform_ops ulpi_link_plat_ops = { + .open = ulpi_link_platform_open, +}; + +static struct tegra_usb_platform_data tegra_ehci2_ulpi_link_pdata = { + .port_otg = false, + .has_hostpc = false, + .phy_intf = TEGRA_USB_PHY_INTF_ULPI_LINK, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = -1, + .vbus_reg = NULL, + .hot_plug = false, + .remote_wakeup_supported = false, + .power_off_on_suspend = true, }, - [1] = { - .phy_config = &ulpi_phy_config, - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .phy_type = TEGRA_USB_PHY_TYPE_LINK_ULPI, - .default_enable = true, + .u_cfg.ulpi = { + .shadow_clk_delay = 10, + .clock_out_delay = 1, + .data_trimmer = 4, + .stpdirnxt_trimmer = 4, + .dir_trimmer = 4, + .clk = "cdev2", }, - [2] = { - .phy_config = &utmi_phy_config[1], - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .hotplug = 1, - .default_enable = true, + .ops = &ulpi_link_plat_ops, +}; + +static struct tegra_usb_platform_data tegra_ehci3_utmi_pdata = { + .port_otg = false, + .has_hostpc = false, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = TEGRA_GPIO_PD3, + .vbus_reg = NULL, + .hot_plug = true, + .remote_wakeup_supported = false, + .power_off_on_suspend = true, + }, + .u_cfg.utmi = { + .hssync_start_delay = 9, + .elastic_limit = 16, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_setup = 8, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, }, }; -static struct tegra_otg_platform_data tegra_otg_pdata = { +static struct tegra_usb_otg_data tegra_otg_pdata = { .ehci_device = &tegra_ehci1_device, - .ehci_pdata = &tegra_ehci_pdata[0], + .ehci_pdata = &tegra_ehci1_utmi_pdata, }; -static int __init ventana_gps_init(void) -{ - struct clk *clk32 = clk_get_sys(NULL, "blink"); - if (!IS_ERR(clk32)) { - clk_set_rate(clk32,clk32->parent->rate); - clk_enable(clk32); - } - - tegra_gpio_enable(TEGRA_GPIO_PZ3); - return 0; -} - static void ventana_usb_init(void) { - tegra_usb_phy_init(tegra_usb_phy_pdata, ARRAY_SIZE(tegra_usb_phy_pdata)); /* OTG should be the first to be registered */ tegra_otg_device.dev.platform_data = &tegra_otg_pdata; platform_device_register(&tegra_otg_device); + tegra_udc_device.dev.platform_data = &tegra_udc_pdata; platform_device_register(&tegra_udc_device); + + tegra_ehci2_device.dev.platform_data = &tegra_ehci2_ulpi_link_pdata; platform_device_register(&tegra_ehci2_device); - tegra_ehci3_device.dev.platform_data=&tegra_ehci_pdata[2]; + tegra_ehci3_device.dev.platform_data = &tegra_ehci3_utmi_pdata; platform_device_register(&tegra_ehci3_device); } @@ -576,8 +607,6 @@ static void __init tegra_ventana_init(void) ventana_pinmux_init(); ventana_i2c_init(); ventana_uart_init(); - tegra_ehci2_device.dev.platform_data - = &ventana_ehci2_ulpi_platform_data; platform_add_devices(ventana_devices, ARRAY_SIZE(ventana_devices)); tegra_ram_console_debug_init(); ventana_sdhci_init(); diff --git a/arch/arm/mach-tegra/board-whistler-baseband.c b/arch/arm/mach-tegra/board-whistler-baseband.c index 143d14a8721d..eb50fb2f8237 100644 --- a/arch/arm/mach-tegra/board-whistler-baseband.c +++ b/arch/arm/mach-tegra/board-whistler-baseband.c @@ -24,10 +24,9 @@ #include "board.h" #include "board-whistler-baseband.h" -static int baseband_phy_on(void); -static int baseband_phy_off(void); -static void baseband_phy_restore_start(void); -static void baseband_phy_restore_end(void); +static void baseband_phy_init(void); +static void baseband_phy_on(void); +static void baseband_phy_off(void); static struct wake_lock mdm_wake_lock; @@ -57,30 +56,38 @@ static __initdata struct tegra_pingroup_config whistler_null_ulpi_pinmux[] = { TEGRA_TRI_NORMAL}, }; -static struct tegra_ulpi_trimmer e1219_trimmer = { 10, 1, 1, 1 }; - -static struct tegra_ulpi_config ehci2_null_ulpi_phy_config = { - .trimmer = &e1219_trimmer, - .post_phy_on = baseband_phy_on, +static struct tegra_usb_phy_platform_ops ulpi_null_plat_ops = { + .init = baseband_phy_init, .pre_phy_off = baseband_phy_off, - .phy_restore_start = baseband_phy_restore_start, - .phy_restore_end = baseband_phy_restore_end, - .phy_restore_gpio = MDM2AP_ACK, - .ulpi_dir_gpio = ULPI_DIR, - .ulpi_d0_gpio = ULPI_D0, - .ulpi_d1_gpio = ULPI_D1, + .post_phy_on = baseband_phy_on, }; -static struct tegra_ehci_platform_data ehci2_null_ulpi_platform_data = { - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 0, - .phy_config = &ehci2_null_ulpi_phy_config, - .phy_type = TEGRA_USB_PHY_TYPE_NULL_ULPI, +static struct tegra_usb_platform_data tegra_ehci2_ulpi_null_pdata = { + .port_otg = false, + .has_hostpc = true, + .phy_intf = TEGRA_USB_PHY_INTF_ULPI_NULL, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = -1, + .vbus_reg = NULL, + .hot_plug = false, + .remote_wakeup_supported = false, + .power_off_on_suspend = false, + }, + .u_cfg.ulpi = { + .shadow_clk_delay = 10, + .clock_out_delay = 1, + .data_trimmer = 1, + .stpdirnxt_trimmer = 1, + .dir_trimmer = 1, + .clk = NULL, + }, + .ops = &ulpi_null_plat_ops, }; static int __init tegra_null_ulpi_init(void) { - tegra_ehci2_device.dev.platform_data = &ehci2_null_ulpi_platform_data; + tegra_ehci2_device.dev.platform_data = &tegra_ehci2_ulpi_null_pdata; platform_device_register(&tegra_ehci2_device); return 0; } @@ -98,7 +105,7 @@ static irqreturn_t mdm_start_thread(int irq, void *data) return IRQ_HANDLED; } -static int baseband_phy_on(void) +static void baseband_phy_init(void) { static bool phy_init; @@ -108,22 +115,15 @@ static int baseband_phy_on(void) phy_init = true; } pr_info("%s\n", __func__); - return 0; -} - -static int baseband_phy_off(void) -{ - pr_info("%s\n", __func__); - return 0; } -static void baseband_phy_restore_start(void) +static void baseband_phy_off(void) { /* set AP2MDM_ACK2 high */ gpio_set_value(AP2MDM_ACK2, 1); } -static void baseband_phy_restore_end(void) +static void baseband_phy_on (void) { /* set AP2MDM_ACK2 low */ gpio_set_value(AP2MDM_ACK2, 0); diff --git a/arch/arm/mach-tegra/board-whistler-sdhci.c b/arch/arm/mach-tegra/board-whistler-sdhci.c index d98b1d53a52e..2d2a9c8c01f8 100644 --- a/arch/arm/mach-tegra/board-whistler-sdhci.c +++ b/arch/arm/mach-tegra/board-whistler-sdhci.c @@ -2,7 +2,7 @@ * arch/arm/mach-tegra/board-whistler-sdhci.c * * Copyright (C) 2010 Google, Inc. - * Copyright (C) 2011 NVIDIA Corporation. + * Copyright (C) 2011-2012 NVIDIA Corporation. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -256,8 +256,6 @@ static int __init whistler_wifi_init(void) } int __init whistler_sdhci_init(void) { - int ret; - tegra_gpio_enable(WHISTLER_EXT_SDCARD_DETECT); platform_device_register(&tegra_sdhci_device3); diff --git a/arch/arm/mach-tegra/board-whistler.c b/arch/arm/mach-tegra/board-whistler.c index ede0d0b11104..874ef18900e7 100644 --- a/arch/arm/mach-tegra/board-whistler.c +++ b/arch/arm/mach-tegra/board-whistler.c @@ -1,7 +1,7 @@ /* * arch/arm/mach-tegra/board-whistler.c * - * Copyright (c) 2010 - 2011, NVIDIA Corporation. + * Copyright (c) 2010-2012 NVIDIA Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -222,32 +222,6 @@ static void __init whistler_setup_bluesleep(void) return; } -static struct tegra_utmip_config utmi_phy_config[] = { - [0] = { - .hssync_start_delay = 9, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 15, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, - [1] = { - .hssync_start_delay = 9, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 8, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, -}; - -static struct tegra_ulpi_config ulpi_phy_config = { - .reset_gpio = TEGRA_GPIO_PG2, - .clk = "cdev2", -}; - static __initdata struct tegra_clk_init_table whistler_clk_init_table[] = { /* name parent rate enabled */ { "pwm", "clk_32k", 32768, false}, @@ -455,61 +429,71 @@ static int __init whistler_scroll_init(void) return 0; } -static struct usb_phy_plat_data tegra_usb_phy_pdata[] = { - [0] = { - .instance = 0, - .vbus_irq = MAX8907C_INT_BASE + MAX8907C_IRQ_VCHG_DC_R, - .vbus_gpio = USB1_VBUS_GPIO, - }, - [1] = { - .instance = 1, - .vbus_gpio = -1, +static int __init whistler_gps_init(void) +{ + tegra_gpio_enable(TEGRA_GPIO_PU4); + return 0; +} + +static struct tegra_usb_platform_data tegra_udc_pdata = { + .port_otg = true, + .has_hostpc = false, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_DEVICE, + .u_data.dev = { + .vbus_pmu_irq = 0, + .vbus_gpio = -1, + .charging_supported = false, + .remote_wakeup_supported = false, }, - [2] = { - .instance = 2, - .vbus_gpio = -1, + .u_cfg.utmi = { + .hssync_start_delay = 0, + .elastic_limit = 16, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_setup = 8, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, }, }; -static struct tegra_ehci_platform_data tegra_ehci_pdata[] = { - [0] = { - .phy_config = &utmi_phy_config[0], - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .default_enable = false, - }, - [1] = { - .phy_config = &ulpi_phy_config, - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .default_enable = false, - }, - [2] = { - .phy_config = &utmi_phy_config[1], - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .default_enable = false, +static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = { + .port_otg = true, + .has_hostpc = false, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = TEGRA_GPIO_PN6, + .vbus_reg = NULL, + .hot_plug = true, + .remote_wakeup_supported = false, + .power_off_on_suspend = true, + }, + .u_cfg.utmi = { + .hssync_start_delay = 9, + .elastic_limit = 16, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_setup = 8, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, }, }; -static struct tegra_otg_platform_data tegra_otg_pdata = { +static struct tegra_usb_otg_data tegra_otg_pdata = { .ehci_device = &tegra_ehci1_device, - .ehci_pdata = &tegra_ehci_pdata[0], + .ehci_pdata = &tegra_ehci1_utmi_pdata, }; -static int __init whistler_gps_init(void) -{ - tegra_gpio_enable(TEGRA_GPIO_PU4); - return 0; -} - +#define SERIAL_NUMBER_LENGTH 20 static void whistler_usb_init(void) { - tegra_usb_phy_init(tegra_usb_phy_pdata, ARRAY_SIZE(tegra_usb_phy_pdata)); - tegra_otg_device.dev.platform_data = &tegra_otg_pdata; platform_device_register(&tegra_otg_device); + tegra_udc_device.dev.platform_data = &tegra_udc_pdata; } static void __init tegra_whistler_init(void) diff --git a/arch/arm/mach-tegra/common-t2.c b/arch/arm/mach-tegra/common-t2.c index 6f9b177892ce..f90dfce6a690 100644 --- a/arch/arm/mach-tegra/common-t2.c +++ b/arch/arm/mach-tegra/common-t2.c @@ -3,7 +3,7 @@ * * Tegra 2 SoC-specific initialization (memory controller, etc.) * - * Copyright (c) 2009-2011, NVIDIA Corporation. + * Copyright (c) 2009-2012 NVIDIA Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -177,16 +177,18 @@ out: return IRQ_HANDLED; } -void __init tegra_mc_init(void) +static int __init tegra_mc_init(void) { if (request_irq(INT_MC_GENERAL, tegra_mc_error_isr, 0, "mc_status", NULL)) { pr_err("%s: unable to register MC error interrupt\n", __func__); + return -EINVAL; } else { void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE); u32 reg = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE | MC_INT_DECERR_EMEM_OTHERS; writel(reg, mc + MC_INT_MASK); } + return 0; } arch_initcall(tegra_mc_init); diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 78bd77dfb7d2..2986f1cf61ac 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -974,12 +974,14 @@ void cpufreq_store_default_gov(void) int cpufreq_change_gov(char *target_gov) { - unsigned int cpu = 0; + unsigned int cpu = 0, ret = -EINVAL; #ifndef CONFIG_TEGRA_AUTO_HOTPLUG for_each_online_cpu(cpu) #endif - return cpufreq_set_gov(target_gov, cpu); + ret = cpufreq_set_gov(target_gov, cpu); + + return ret; } int cpufreq_restore_default_gov(void) diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c index 2a4f94c4e22d..377772ff4291 100644 --- a/arch/arm/mach-tegra/devices.c +++ b/arch/arm/mach-tegra/devices.c @@ -584,28 +584,6 @@ static struct resource tegra_usb3_resources[] = { }, }; -static struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config = { - /* All existing boards use GPIO PV0 for phy reset */ - .reset_gpio = TEGRA_GPIO_PV0, - .clk = "cdev2", -}; - -static struct tegra_ehci_platform_data tegra_ehci1_pdata = { - .operating_mode = TEGRA_USB_OTG, - .power_down_on_bus_suspend = 1, -}; - -static struct tegra_ehci_platform_data tegra_ehci2_pdata = { - .phy_config = &tegra_ehci2_ulpi_phy_config, - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, -}; - -static struct tegra_ehci_platform_data tegra_ehci3_pdata = { - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, -}; - static u64 tegra_ehci_dmamask = DMA_BIT_MASK(32); struct platform_device tegra_ehci1_device = { @@ -614,7 +592,6 @@ struct platform_device tegra_ehci1_device = { .dev = { .dma_mask = &tegra_ehci_dmamask, .coherent_dma_mask = DMA_BIT_MASK(32), - .platform_data = &tegra_ehci1_pdata, }, .resource = tegra_usb1_resources, .num_resources = ARRAY_SIZE(tegra_usb1_resources), @@ -626,7 +603,6 @@ struct platform_device tegra_ehci2_device = { .dev = { .dma_mask = &tegra_ehci_dmamask, .coherent_dma_mask = DMA_BIT_MASK(32), - .platform_data = &tegra_ehci2_pdata, }, .resource = tegra_usb2_resources, .num_resources = ARRAY_SIZE(tegra_usb2_resources), @@ -638,7 +614,6 @@ struct platform_device tegra_ehci3_device = { .dev = { .dma_mask = &tegra_ehci_dmamask, .coherent_dma_mask = DMA_BIT_MASK(32), - .platform_data = &tegra_ehci3_pdata, }, .resource = tegra_usb3_resources, .num_resources = ARRAY_SIZE(tegra_usb3_resources), @@ -1226,18 +1201,12 @@ static struct resource tegra_udc_resources[] = { static u64 tegra_udc_dmamask = DMA_BIT_MASK(32); -static struct fsl_usb2_platform_data tegra_udc_pdata = { - .operating_mode = FSL_USB2_DR_DEVICE, - .phy_mode = FSL_USB2_PHY_UTMI, -}; - struct platform_device tegra_udc_device = { .name = "tegra-udc", .id = 0, .dev = { .dma_mask = &tegra_udc_dmamask, .coherent_dma_mask = DMA_BIT_MASK(32), - .platform_data = &tegra_udc_pdata, }, .resource = tegra_udc_resources, .num_resources = ARRAY_SIZE(tegra_udc_resources), diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h index ab3d4e920f46..71f1be769507 100644 --- a/arch/arm/mach-tegra/include/mach/dc.h +++ b/arch/arm/mach-tegra/include/mach/dc.h @@ -503,6 +503,7 @@ struct tegra_dc_platform_data { #define TEGRA_DC_FLAG_ENABLED (1 << 0) +int tegra_dc_get_stride(struct tegra_dc *dc, unsigned win); struct tegra_dc *tegra_dc_get_dc(unsigned idx); struct tegra_dc_win *tegra_dc_get_window(struct tegra_dc *dc, unsigned win); bool tegra_dc_get_connected(struct tegra_dc *); diff --git a/arch/arm/mach-tegra/include/mach/latency_allowance.h b/arch/arm/mach-tegra/include/mach/latency_allowance.h index f0d27f0b8ba9..8644075a88b3 100644 --- a/arch/arm/mach-tegra/include/mach/latency_allowance.h +++ b/arch/arm/mach-tegra/include/mach/latency_allowance.h @@ -1,7 +1,7 @@ /* * arch/arm/mach-tegra/include/mach/latency_allowance.h * - * Copyright (C) 2011, NVIDIA Corporation. + * Copyright (C) 2011-2012 NVIDIA Corporation. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -104,7 +104,7 @@ static inline int tegra_enable_latency_scaling(enum tegra_la_id id, static inline void tegra_disable_latency_scaling(enum tegra_la_id id) { - return 0; + return; } #else int tegra_set_latency_allowance(enum tegra_la_id id, diff --git a/arch/arm/mach-tegra/include/mach/usb_phy.h b/arch/arm/mach-tegra/include/mach/usb_phy.h index 3ad1128e2026..c721642c4417 100644 --- a/arch/arm/mach-tegra/include/mach/usb_phy.h +++ b/arch/arm/mach-tegra/include/mach/usb_phy.h @@ -18,150 +18,120 @@ #ifndef __MACH_USB_PHY_H #define __MACH_USB_PHY_H -#include <linux/clk.h> -#include <linux/regulator/consumer.h> -#include <linux/usb/otg.h> -#include <linux/platform_data/tegra_usb.h> - -struct tegra_utmip_config { - u8 hssync_start_delay; - u8 elastic_limit; - u8 idle_wait_delay; - u8 term_range_adj; - u8 xcvr_setup; - signed char xcvr_setup_offset; - u8 xcvr_use_fuses; - u8 xcvr_lsfslew; - u8 xcvr_lsrslew; -}; - -struct tegra_ulpi_trimmer { - u8 shadow_clk_delay; /* 0 ~ 31 */ - u8 clock_out_delay; /* 0 ~ 31 */ - u8 data_trimmer; /* 0 ~ 7 */ - u8 stpdirnxt_trimmer; /* 0 ~ 7 */ -}; - -struct tegra_ulpi_config { - int enable_gpio; - int reset_gpio; - const char *clk; - const struct tegra_ulpi_trimmer *trimmer; - int (*pre_phy_on)(void); - int (*post_phy_on)(void); - int (*pre_phy_off)(void); - int (*post_phy_off)(void); - void (*phy_restore_start)(void); - void (*phy_restore_end)(void); - int phy_restore_gpio; /* null phy restore ack from device */ - int ulpi_dir_gpio; /* ulpi dir */ - int ulpi_d0_gpio; /* usb linestate[0] */ - int ulpi_d1_gpio; /* usb linestate[1] */ -}; - -struct tegra_uhsic_config { - int enable_gpio; - int reset_gpio; - u8 sync_start_delay; - u8 idle_wait_delay; - u8 term_range_adj; - u8 elastic_underrun_limit; - u8 elastic_overrun_limit; - int (*postsuspend)(void); - int (*preresume)(void); - int (*usb_phy_ready)(void); - int (*post_phy_off)(void); -}; - -enum tegra_usb_phy_port_speed { - TEGRA_USB_PHY_PORT_SPEED_FULL = 0, - TEGRA_USB_PHY_PORT_SPEED_LOW, - TEGRA_USB_PHY_PORT_SPEED_HIGH, -}; - -enum tegra_usb_phy_mode { - TEGRA_USB_PHY_MODE_DEVICE, - TEGRA_USB_PHY_MODE_HOST, -}; - -struct usb_phy_plat_data { - int instance; - int vbus_irq; - int vbus_gpio; - char * vbus_reg_supply; -}; - -struct tegra_xtal_freq; - -struct tegra_usb_phy { - int instance; - const struct tegra_xtal_freq *freq; - void __iomem *regs; - void __iomem *pad_regs; - struct clk *clk; - struct clk *pll_u; - struct clk *pad_clk; - enum tegra_usb_phy_mode mode; - void *config; - struct regulator *reg_vdd; - struct regulator *reg_vbus; - enum tegra_usb_phy_type usb_phy_type; - bool regulator_on; - struct otg_transceiver *ulpi; - int initialized; - bool power_on; - bool remote_wakeup; - int hotplug; - unsigned int xcvr_setup_value; -}; - -typedef int (*tegra_phy_fp)(struct tegra_usb_phy *phy, bool is_dpd); -typedef void (*tegra_phy_restore_start_fp)(struct tegra_usb_phy *phy, - enum tegra_usb_phy_port_speed); -typedef void (*tegra_phy_restore_end_fp)(struct tegra_usb_phy *phy); - -struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs, - void *config, enum tegra_usb_phy_mode phy_mode, - enum tegra_usb_phy_type usb_phy_type); - -int tegra_usb_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd); - -void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy); - -void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy); - -void tegra_usb_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd); - -void tegra_usb_phy_postsuspend(struct tegra_usb_phy *phy, bool is_dpd); - -void tegra_usb_phy_preresume(struct tegra_usb_phy *phy, bool is_dpd); - -void tegra_usb_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd); - -void tegra_ehci_pre_reset(struct tegra_usb_phy *phy, bool is_dpd); - -void tegra_ehci_post_reset(struct tegra_usb_phy *phy, bool is_dpd); - -void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy, - enum tegra_usb_phy_port_speed port_speed); - -void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy); +/** + * Tegra USB phy opaque handle + */ +struct tegra_usb_phy; + +/** + * Opens the usb phy associated to the USB platform device + * tegra usb phy open must be called before accessing any phy APIs + */ +struct tegra_usb_phy *tegra_usb_phy_open(struct platform_device *pdev); +/** + * Closes the phy controller and its resources + */ void tegra_usb_phy_close(struct tegra_usb_phy *phy); -int tegra_usb_phy_bus_connect(struct tegra_usb_phy *phy); +/** + * Handles interrupts specific to the phy interface + * Note: udc or ehci driver will handle the controller interrupts + */ +int tegra_usb_phy_irq(struct tegra_usb_phy *phy); + +/** + * Initializes the phy specific functions after phy is power on + */ +int tegra_usb_phy_init(struct tegra_usb_phy *phy); + +/** + * Handles phy interface specific functionality after driver reset + */ +int tegra_usb_phy_reset(struct tegra_usb_phy *phy); + +/** + * Handles phy interface specific functionality before driver suspend + * Also, handles platform specific pre suspend functions + */ +int tegra_usb_phy_pre_suspend(struct tegra_usb_phy *phy); + +/** + * Handles phy interface specific suspend functionality + */ +int tegra_usb_phy_suspend(struct tegra_usb_phy *phy); + +/** + * Handles phy interface specific functionality after driver suspend + */ +int tegra_usb_phy_post_suspend(struct tegra_usb_phy *phy); + +/** + * Handles phy interface specific functionality before driver resume + * Also, handles platform specific pre resume functions + */ +int tegra_usb_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup); + +/** + * Handles phy interface specific resume functionality + */ +int tegra_usb_phy_resume(struct tegra_usb_phy *phy); +/** + * Handles phy interface specific functionality after driver resume + */ +int tegra_usb_phy_post_resume(struct tegra_usb_phy *phy); + +/** + * Handles phy interface specific functionality during port power on + */ +int tegra_usb_phy_port_power(struct tegra_usb_phy *phy); + +/** + * Handles phy interface specific functionality during bus reset + */ int tegra_usb_phy_bus_reset(struct tegra_usb_phy *phy); -int tegra_usb_phy_bus_idle(struct tegra_usb_phy *phy); +/** + * Handles phy interface specific functionality for turning off the phy to + * put the phy in low power mode + */ +int tegra_usb_phy_power_off(struct tegra_usb_phy *phy); -bool tegra_usb_phy_is_device_connected(struct tegra_usb_phy *phy); +/** + * Handles phy interface specific functionality for turning on the phy to + * bring phy out of low power mode + */ +int tegra_usb_phy_power_on(struct tegra_usb_phy *phy); -bool tegra_usb_phy_charger_detect(struct tegra_usb_phy *phy); +/** + * Indicates whether phy registers are accessible or not + * if phy is powered off then returns false else true + */ +bool tegra_usb_phy_hw_accessible(struct tegra_usb_phy *phy); + +/** + * Indicates whether compliance charger is connected or not + * if compliance charger is detected then returns true else false + */ +bool tegra_usb_phy_charger_detected(struct tegra_usb_phy *phy); + +/** + * Indicates whether phy resumed due to the remote wake event or not + * returns true if remote wake is detected. + */ +bool tegra_usb_phy_remote_wakeup(struct tegra_usb_phy *phy); + +/** + * Indicates controller has HOST PC register set or not + */ +bool tegra_usb_phy_has_hostpc(struct tegra_usb_phy *phy); -int __init tegra_usb_phy_init(struct usb_phy_plat_data *pdata, int size); +/** + * Indicates controller port supports OTG or not + */ +bool tegra_usb_phy_otg_supported(struct tegra_usb_phy *phy); -bool tegra_usb_phy_is_remotewake_detected(struct tegra_usb_phy *phy); void tegra_usb_phy_memory_prefetch_on(struct tegra_usb_phy *phy); diff --git a/arch/arm/mach-tegra/iovmm-gart.c b/arch/arm/mach-tegra/iovmm-gart.c index ad1ce3a7afc3..130901cb4883 100644 --- a/arch/arm/mach-tegra/iovmm-gart.c +++ b/arch/arm/mach-tegra/iovmm-gart.c @@ -4,7 +4,7 @@ * Tegra I/O VMM implementation for GART devices in Tegra and Tegra 2 series * systems-on-a-chip. * - * Copyright (c) 2010-2012, NVIDIA Corporation. + * Copyright (c) 2010-2012 NVIDIA Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -73,7 +73,7 @@ static int gart_map(struct tegra_iovmm_domain *, struct tegra_iovmm_area *); static void gart_unmap(struct tegra_iovmm_domain *, struct tegra_iovmm_area *, bool); static void gart_map_pfn(struct tegra_iovmm_domain *, - struct tegra_iovmm_area *, tegra_iovmm_addr_t, unsigned long); + struct tegra_iovmm_area *, unsigned long, unsigned long); static struct tegra_iovmm_domain *gart_alloc_domain( struct tegra_iovmm_device *, struct tegra_iovmm_client *); @@ -330,7 +330,7 @@ static void gart_unmap(struct tegra_iovmm_domain *domain, } static void gart_map_pfn(struct tegra_iovmm_domain *domain, - struct tegra_iovmm_area *iovma, tegra_iovmm_addr_t offs, + struct tegra_iovmm_area *iovma, unsigned long offs, unsigned long pfn) { struct gart_device *gart = diff --git a/arch/arm/mach-tegra/p852/board-p852.c b/arch/arm/mach-tegra/p852/board-p852.c index 21b867e15177..ffdf5d3e4bae 100644 --- a/arch/arm/mach-tegra/p852/board-p852.c +++ b/arch/arm/mach-tegra/p852/board-p852.c @@ -288,49 +288,6 @@ static struct platform_device debug_uart = { }, }; -static struct tegra_utmip_config utmi_phy_config[] = { - [0] = { - .hssync_start_delay = 0, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 15, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, - [1] = { - .hssync_start_delay = 0, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 8, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, -}; - -static struct tegra_ulpi_config ulpi_usb2_config = { - .reset_gpio = TEGRA_GPIO_PI5, -}; - -static struct tegra_ehci_platform_data tegra_ehci_pdata[] = { - [0] = { - .phy_config = &utmi_phy_config[0], - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 0, - }, - [1] = { - .phy_config = &ulpi_usb2_config, - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 0, - .phy_type = TEGRA_USB_PHY_TYPE_LINK_ULPI, - }, - [2] = { - .phy_config = &utmi_phy_config[1], - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 0, - }, -}; static void p852_usb_gpio_config(void) { @@ -529,6 +486,97 @@ static void __init p852_register_spidev(void) #define p852_register_spidev() do {} while (0) #endif +/* + FixMe: Copied below GPIO value from Ventana board. + Plz correct it accordingly for embedded board usage +*/ +#define TEGRA_GPIO_PV1 169 + +static void ulpi_link_platform_open(void) +{ + int reset_gpio = TEGRA_GPIO_PV1; + + gpio_request(reset_gpio, "ulpi_phy_reset"); + gpio_direction_output(reset_gpio, 0); + tegra_gpio_enable(reset_gpio); + + gpio_direction_output(reset_gpio, 0); + msleep(5); + gpio_direction_output(reset_gpio, 1); +} + +static struct tegra_usb_phy_platform_ops ulpi_link_plat_ops = { + .open = ulpi_link_platform_open, +}; + +static struct tegra_usb_platform_data tegra_ehci_ulpi_link_pdata = { + .port_otg = false, + .has_hostpc = false, + .phy_intf = TEGRA_USB_PHY_INTF_ULPI_LINK, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = -1, + .vbus_reg = NULL, + .hot_plug = false, + .remote_wakeup_supported = false, + .power_off_on_suspend = false, + }, + .u_cfg.ulpi = { + .shadow_clk_delay = 10, + .clock_out_delay = 1, + .data_trimmer = 4, + .stpdirnxt_trimmer = 4, + .dir_trimmer = 4, + .clk = "cdev2", + }, + .ops = &ulpi_link_plat_ops, +}; + +static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = { + .port_otg = false, + .has_hostpc = false, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = -1, + .vbus_reg = NULL, + .hot_plug = true, + .remote_wakeup_supported = true, + .power_off_on_suspend = false, + }, + .u_cfg.utmi = { + .hssync_start_delay = 0, + .idle_wait_delay = 17, + .elastic_limit = 16, + .term_range_adj = 6, + .xcvr_setup = 15, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + }, +}; + +static struct tegra_usb_platform_data tegra_ehci3_utmi_pdata = { + .port_otg = false, + .has_hostpc = false, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .op_mode = TEGRA_USB_OPMODE_HOST, + .u_data.host = { + .vbus_gpio = -1, + .vbus_reg = NULL, + .hot_plug = true, + .remote_wakeup_supported = true, + .power_off_on_suspend = false, + }, + .u_cfg.utmi = { + .hssync_start_delay = 0, + .idle_wait_delay = 17, + .elastic_limit = 16, + .term_range_adj = 6, + .xcvr_setup = 8, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + }, +}; static void __init p852_usb_init(void) { @@ -541,16 +589,16 @@ static void __init p852_usb_init(void) else */ { - tegra_ehci1_device.dev.platform_data = &tegra_ehci_pdata[0]; + tegra_ehci1_device.dev.platform_data = &tegra_ehci1_utmi_pdata; platform_device_register(&tegra_ehci1_device); } if (!(p852_sku_peripherals & P852_SKU_ULPI_DISABLE)) { - tegra_ehci2_device.dev.platform_data = &tegra_ehci_pdata[1]; + tegra_ehci2_device.dev.platform_data = &tegra_ehci_ulpi_link_pdata; platform_device_register(&tegra_ehci2_device); } - tegra_ehci3_device.dev.platform_data = &tegra_ehci_pdata[2]; + tegra_ehci3_device.dev.platform_data = &tegra_ehci3_utmi_pdata; platform_device_register(&tegra_ehci3_device); } diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c index 1c4ee1b1f5ce..80a9a121f193 100644 --- a/arch/arm/mach-tegra/pcie.c +++ b/arch/arm/mach-tegra/pcie.c @@ -294,6 +294,9 @@ #define PCIE_CONF_REG(r) \ (((r) & ~0x3) | (((r) < 256) ? PCIE_CFG_OFF : PCIE_EXT_CFG_OFF)) +#define PCIE_CTRL_REGS 7 +#define COMBINE_PCIE_PCIX_SPACE 2 + struct tegra_pcie_port { int index; u8 root_bus_nr; @@ -349,6 +352,12 @@ static struct resource pcie_prefetch_mem_space; static bool is_pcie_noirq_op = false; /* used to backup config space registers of all pcie devices */ static u32 *pbackup_config_space = NULL; +static u16 *pbackup_pcie_cap_space = NULL; +static u16 *pbackup_pcix_cap_space = NULL; +/* use same save state and position variables to store pcie */ +/* and pcix capability offsets at even & odd index respectively */ +static struct pci_cap_saved_state **pcie_save_state; +static int *pos; void __iomem *tegra_pcie_io_base; EXPORT_SYMBOL(tegra_pcie_io_base); @@ -986,7 +995,7 @@ static void tegra_pcie_clocks_put(void) clk_put(tegra_pcie.pcie_xclk); } -static int __init tegra_pcie_get_resources(void) +static int tegra_pcie_get_resources(void) { struct resource *res_mmio = 0; int err; @@ -1112,11 +1121,22 @@ retry: return false; } -static void __init tegra_pcie_add_port(int index, u32 offset, u32 reset_reg) +static void tegra_enable_clock_clamp(int index) { - struct tegra_pcie_port *pp; unsigned int data; + /* Power mangagement settings */ + /* Enable clock clamping by default */ + data = rp_readl(NV_PCIE2_RP_PRIV_MISC, index); + data |= (PCIE2_RP_PRIV_MISC_CTLR_CLK_CLAMP_ENABLE) | + (PCIE2_RP_PRIV_MISC_TMS_CLK_CLAMP_ENABLE); + rp_writel(data, NV_PCIE2_RP_PRIV_MISC, index); +} + +static void tegra_pcie_add_port(int index, u32 offset, u32 reset_reg) +{ + struct tegra_pcie_port *pp; + pp = tegra_pcie.port + tegra_pcie.num_ports; pp->index = -1; @@ -1128,13 +1148,7 @@ static void __init tegra_pcie_add_port(int index, u32 offset, u32 reset_reg) printk(KERN_INFO "PCIE: port %d: link down, ignoring\n", index); return; } - /* Power mangagement settings */ - /* Enable clock clamping by default */ - data = rp_readl(NV_PCIE2_RP_PRIV_MISC, index); - data |= (PCIE2_RP_PRIV_MISC_CTLR_CLK_CLAMP_ENABLE) | - (PCIE2_RP_PRIV_MISC_TMS_CLK_CLAMP_ENABLE); - rp_writel(data, NV_PCIE2_RP_PRIV_MISC, index); - + tegra_enable_clock_clamp(index); tegra_pcie.num_ports++; pp->index = index; pp->root_bus_nr = -1; @@ -1178,9 +1192,47 @@ static int tegra_pcie_init(void) return err; } +static int tegra_pcie_allocate_config_states(int ndev, int size) +{ + /* backup config space registers of all devices since it gets reset in + save state call from suspend noirq due to disabling of read in it */ + pbackup_config_space = kzalloc(ndev*size*sizeof(u32), GFP_KERNEL); + if (!pbackup_config_space) + return -ENODEV; + pbackup_pcie_cap_space = kzalloc(ndev*PCIE_CTRL_REGS*sizeof(u16), GFP_KERNEL); + if (!pbackup_pcie_cap_space) + return -ENODEV; + pbackup_pcix_cap_space = kzalloc(ndev*sizeof(u16), GFP_KERNEL); + if (!pbackup_pcix_cap_space) + return -ENODEV; + pcie_save_state = kzalloc(COMBINE_PCIE_PCIX_SPACE*ndev* + sizeof(struct pci_cap_saved_state*), GFP_KERNEL); + if (!pbackup_pcix_cap_space) + return -ENODEV; + pos = kzalloc(COMBINE_PCIE_PCIX_SPACE*ndev*sizeof(int), GFP_KERNEL); + if (!pos) + return -ENODEV; + + return 0; +} + +static void tegra_pcie_deallocate_config_states(void) +{ + if (pbackup_config_space) + kzfree(pbackup_config_space); + if (pbackup_pcie_cap_space) + kzfree(pbackup_pcie_cap_space); + if (pbackup_pcix_cap_space) + kzfree(pbackup_pcix_cap_space); + if (pcie_save_state) + kzfree(pcie_save_state); + if (pos) + kzfree(pos); +} + static int tegra_pci_probe(struct platform_device *pdev) { - int ret; + int ret, size = 0, ndev = 0; struct pci_dev *dev = NULL; tegra_pcie.plat_data = pdev->dev.platform_data; @@ -1194,39 +1246,91 @@ static int tegra_pci_probe(struct platform_device *pdev) /* disable async PM of pci devices to ensure right order */ /* suspend/resume calls of tegra and bus driver */ - for_each_pci_dev(dev) + for_each_pci_dev(dev){ device_disable_async_suspend(&dev->dev); + size = sizeof(dev->saved_config_space) / sizeof(u32); + ndev++; + } + tegra_pcie_allocate_config_states(ndev, size); return ret; } +static int tegra_pcie_save_state(struct pci_dev *pdev, int ndev) +{ + int size; + + /*save pcie control registers */ + pos[ndev] = pci_pcie_cap(pdev); + if (pos[ndev]){ + pcie_save_state[ndev] = pci_find_saved_cap(pdev, PCI_CAP_ID_EXP); + if (!pcie_save_state[ndev]) { + dev_err(&pdev->dev, "buffer not found in %s\n", __func__); + return -ENOMEM; + } + memcpy(&pbackup_pcie_cap_space[PCIE_CTRL_REGS*(ndev/2)], + pcie_save_state[ndev]->cap.data, PCIE_CTRL_REGS*sizeof(u16)); + } + /* save pcix state */ + pos[ndev+1] = pci_find_capability(pdev, PCI_CAP_ID_PCIX); + if (pos[ndev+1] > 0){ + pcie_save_state[ndev+1] = pci_find_saved_cap(pdev, PCI_CAP_ID_PCIX); + if (!pcie_save_state[ndev+1]) { + dev_err(&pdev->dev, "buffer not found in %s\n", __func__); + return -ENOMEM; + } + memcpy(&pbackup_pcix_cap_space[ndev/2], + pcie_save_state[ndev+1]->cap.data, sizeof(u16)); + } + /* save config space registers */ + size = sizeof(pdev->saved_config_space) / sizeof(u32); + memcpy(&pbackup_config_space[size*ndev/2], + pdev->saved_config_space, size*sizeof(u32)); + + return 0; +} + +static void tegra_pcie_restore_state(struct pci_dev *pdev, int ndev) +{ + int size; + + /* restore pcie control registers */ + if (pcie_save_state[ndev] && (pos[ndev] > 0)) + memcpy(pcie_save_state[ndev]->cap.data, + &pbackup_pcie_cap_space[PCIE_CTRL_REGS*(ndev/2)], + PCIE_CTRL_REGS*sizeof(u16)); + + /* restore pcix state */ + if (pcie_save_state[ndev+1] && (pos[ndev+1] > 0)) + memcpy(pcie_save_state[ndev+1]->cap.data, + &pbackup_pcix_cap_space[ndev/2], sizeof(u16)); + + /* restore config space registers */ + size = sizeof(pdev->saved_config_space) / sizeof(u32); + memcpy(pdev->saved_config_space, + &pbackup_config_space[size*ndev/2], size*sizeof(u32)); +} + static int tegra_pci_suspend(struct device *dev) { - int ret = 0; + int ret = 0, ndev = 0; struct pci_dev *pdev = NULL; - int i, size, ndev = 0; if (!tegra_pcie.num_ports) - return ret; + return ret; for_each_pci_dev(pdev) { /* save state of pcie devices before powering off regulators */ pci_save_state(pdev); - size = sizeof(pdev->saved_config_space) / sizeof(u32); - ndev++; + if (!pdev->subordinate) + pci_prepare_to_sleep(pdev); } - /* backup config space registers of all devices since it gets reset in - save state call from suspend noirq due to disabling of read in it */ - pbackup_config_space = kzalloc(ndev * size* sizeof(u32), GFP_KERNEL); - if (!pbackup_config_space) - return -ENODEV; - ndev = 0; for_each_pci_dev(pdev) { - for (i = 0;i < size;i++) { - memcpy(&pbackup_config_space[i + size*ndev], - &pdev->saved_config_space[i], sizeof(u32)); - } + /* save control and config space registers*/ + ret = tegra_pcie_save_state(pdev, ndev*2); + if (ret < 0) + return ret; ndev++; } @@ -1239,50 +1343,45 @@ static int tegra_pci_resume_noirq(struct device *dev) { struct pci_dev *pdev = NULL; - for_each_pci_dev(pdev) { - /* set this flag to avoid restore state in resume noirq */ + /* set this flag to avoid restore state in resume noirq */ + for_each_pci_dev(pdev) pdev->state_saved = 0; - } + return 0; } static int tegra_pci_resume(struct device *dev) { - int ret = 0; - int i, size, ndev = 0; + int ret = 0, ndev = 0; struct pci_dev *pdev = NULL; + int port; if (!tegra_pcie.num_ports) - return ret; + return ret; ret = tegra_pcie_power_on(); + /* enable read/write registers after powering on */ + is_pcie_noirq_op = false; tegra_pcie_enable_controller(); tegra_pcie_setup_translations(); - /* enable read/write registers after powering on */ - is_pcie_noirq_op = false; + for (port = 0; port < MAX_PCIE_SUPPORTED_PORTS; port++) + if (tegra_pcie.plat_data->port_status[port]) + tegra_enable_clock_clamp(port); for_each_pci_dev(pdev) { - /* do fixup here for all dev's since not done in resume noirq */ - pci_fixup_device(pci_fixup_resume_early, pdev); - + /* restore control and config space registers*/ + tegra_pcie_restore_state(pdev, ndev*2); /* set this flag to force restore state in resume */ pdev->state_saved = 1; - - /* restore config space registers from backup buffer */ - size = sizeof(pdev->saved_config_space) / sizeof(u32); - for (i = 0;i < size;i++) { - memcpy(&pdev->saved_config_space[i], - &pbackup_config_space[i + size*ndev], sizeof(u32)); - } ndev++; } - kzfree(pbackup_config_space); return ret; } static int tegra_pci_remove(struct platform_device *pdev) { + tegra_pcie_deallocate_config_states(); return 0; } #ifdef CONFIG_PM diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c index af30cf2ea18c..fa88b11552d9 100644 --- a/arch/arm/mach-tegra/tegra2_clocks.c +++ b/arch/arm/mach-tegra/tegra2_clocks.c @@ -779,8 +779,9 @@ static int tegra2_pll_clk_set_rate(struct clk *c, unsigned long rate) if (sel->input_rate == 0) { unsigned long cfreq; - BUG_ON(c->flags & PLLU); struct clk_pll_freq_table cfg; + + BUG_ON(c->flags & PLLU); sel = &cfg; switch (input_rate) { @@ -2771,7 +2772,7 @@ unsigned long tegra_emc_to_cpu_ratio(unsigned long cpu_rate) #ifdef CONFIG_PM_SLEEP static u32 clk_rst_suspend[RST_DEVICES_NUM + CLK_OUT_ENB_NUM + - PERIPH_CLK_SOURCE_NUM + 22]; + PERIPH_CLK_SOURCE_NUM + 24]; static int tegra_clk_suspend(void) { @@ -2779,6 +2780,8 @@ static int tegra_clk_suspend(void) u32 *ctx = clk_rst_suspend; *ctx++ = clk_readl(OSC_CTRL) & OSC_CTRL_MASK; + *ctx++ = clk_readl(tegra_pll_p_out1.reg); + *ctx++ = clk_readl(tegra_pll_p_out3.reg); *ctx++ = clk_readl(tegra_pll_c.reg + PLL_BASE); *ctx++ = clk_readl(tegra_pll_c.reg + PLL_MISC(&tegra_pll_c)); *ctx++ = clk_readl(tegra_pll_a.reg + PLL_BASE); @@ -2831,11 +2834,26 @@ static void tegra_clk_resume(void) unsigned long off, i; const u32 *ctx = clk_rst_suspend; u32 val; + u32 pll_p_out12, pll_p_out34; + u32 pll_m_out1, pll_a_out0, pll_c_out1; val = clk_readl(OSC_CTRL) & ~OSC_CTRL_MASK; val |= *ctx++; clk_writel(val, OSC_CTRL); + /* Since we are going to reset devices and switch clock sources in this + * function, plls and secondary dividers is required to be enabled. The + * actual value will be restored back later. Note that boot plls: pllm, + * pllp, and pllu are already configured and enabled. + */ + + val = PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE; + val |= val << 16; + pll_p_out12 = *ctx++; + clk_writel(pll_p_out12 | val, tegra_pll_p_out1.reg); + pll_p_out34 = *ctx++; + clk_writel(pll_p_out34 | val, tegra_pll_p_out3.reg); + clk_writel(*ctx++, tegra_pll_c.reg + PLL_BASE); clk_writel(*ctx++, tegra_pll_c.reg + PLL_MISC(&tegra_pll_c)); clk_writel(*ctx++, tegra_pll_a.reg + PLL_BASE); @@ -2848,9 +2866,13 @@ static void tegra_clk_resume(void) clk_writel(*ctx++, tegra_pll_u.reg + PLL_MISC(&tegra_pll_u)); udelay(1000); - clk_writel(*ctx++, tegra_pll_m_out1.reg); - clk_writel(*ctx++, tegra_pll_a_out0.reg); - clk_writel(*ctx++, tegra_pll_c_out1.reg); + val = PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE; + pll_m_out1 = *ctx++; + clk_writel(pll_m_out1 | val, tegra_pll_m_out1.reg); + pll_a_out0 = *ctx++; + clk_writel(pll_a_out0 | val, tegra_pll_a_out0.reg); + pll_c_out1 = *ctx++; + clk_writel(pll_c_out1 | val, tegra_pll_c_out1.reg); clk_writel(*ctx++, tegra_clk_cclk.reg); clk_writel(*ctx++, tegra_clk_cclk.reg + SUPER_CLK_DIVIDER); @@ -2887,6 +2909,13 @@ static void tegra_clk_resume(void) clk_writel(*ctx++, MISC_CLK_ENB); clk_writel(*ctx++, CLK_MASK_ARM); + + /* Restore back the actual pll and secondary divider values */ + clk_writel(pll_p_out12, tegra_pll_p_out1.reg); + clk_writel(pll_p_out34, tegra_pll_p_out3.reg); + clk_writel(pll_m_out1, tegra_pll_m_out1.reg); + clk_writel(pll_a_out0, tegra_pll_a_out0.reg); + clk_writel(pll_c_out1, tegra_pll_c_out1.reg); } #else diff --git a/arch/arm/mach-tegra/tegra2_mc.c b/arch/arm/mach-tegra/tegra2_mc.c index 6df9c232c02f..1b72af0735f6 100644 --- a/arch/arm/mach-tegra/tegra2_mc.c +++ b/arch/arm/mach-tegra/tegra2_mc.c @@ -896,8 +896,10 @@ static enum hrtimer_restart sample_timer_function(struct hrtimer *handle) #define REGISTER_SYSFS(_name, _val) \ tegra_mc_dram_##_name##_kobj = \ kobject_create_and_add(#_name, tegra_mc_dram_kobj); \ - sysfs_create_group(tegra_mc_dram_##_name##_kobj, \ - &tegra_mc_dram_##_name##_attr_group); + if (sysfs_create_group(tegra_mc_dram_##_name##_kobj, \ + &tegra_mc_dram_##_name##_attr_group)) \ + printk(KERN_ERR "\n sysfs_create_group failed at %s" \ + " line %d\n", __FILE__, __LINE__); static int tegra_mc_init(void) { diff --git a/arch/arm/mach-tegra/tegra2_usb_phy.c b/arch/arm/mach-tegra/tegra2_usb_phy.c new file mode 100644 index 000000000000..819721c49a29 --- /dev/null +++ b/arch/arm/mach-tegra/tegra2_usb_phy.c @@ -0,0 +1,1598 @@ +/* + * arch/arm/mach-tegra/tegra2_usb_phy.c + * + * Copyright (C) 2011 NVIDIA 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. + * + */ +#include <linux/resource.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/usb/otg.h> +#include <linux/usb/ulpi.h> +#include <linux/interrupt.h> +#include <linux/clk.h> +#include <linux/regulator/consumer.h> +#include <linux/platform_data/tegra_usb.h> +#include <mach/iomap.h> +#include <mach/pinmux.h> +#include <asm/mach-types.h> +#include <mach/usb_phy.h> +#include "tegra_usb_phy.h" +#include "fuse.h" + + +#define USB_USBCMD 0x140 +#define USB_USBCMD_RS (1 << 0) +#define USB_USBCMD_RESET (1 << 1) + +#define USB_USBSTS 0x144 +#define USB_USBSTS_PCI (1 << 2) +#define USB_USBSTS_SRI (1 << 7) +#define USB_USBSTS_HCH (1 << 12) + +#define USB_ASYNCLISTADDR 0x158 + +#define USB_TXFILLTUNING 0x164 +#define USB_FIFO_TXFILL_THRES(x) (((x) & 0x1f) << 16) +#define USB_FIFO_TXFILL_MASK 0x1f0000 + +#define ULPI_VIEWPORT 0x170 +#define ULPI_WAKEUP (1 << 31) +#define ULPI_RUN (1 << 30) +#define ULPI_RD_WR (1 << 29) + +#define USB_PORTSC 0x184 +#define USB_PORTSC_PTS(x) (((x) & 0x3) << 30) +#define USB_PORTSC_PSPD(x) (((x) & 0x3) << 26) +#define USB_PORTSC_PHCD (1 << 23) +#define USB_PORTSC_WKOC (1 << 22) +#define USB_PORTSC_WKDS (1 << 21) +#define USB_PORTSC_WKCN (1 << 20) +#define USB_PORTSC_PTC(x) (((x) & 0xf) << 16) +#define USB_PORTSC_PP (1 << 12) +#define USB_PORTSC_LS(x) (((x) & 0x3) << 10) +#define USB_PORTSC_SUSP (1 << 7) +#define USB_PORTSC_OCC (1 << 5) +#define USB_PORTSC_PEC (1 << 3) +#define USB_PORTSC_PE (1 << 2) +#define USB_PORTSC_CSC (1 << 1) +#define USB_PORTSC_CCS (1 << 0) +#define USB_PORTSC_RWC_BITS (USB_PORTSC_CSC | USB_PORTSC_PEC | USB_PORTSC_OCC) +#define USB_PORTSC_PSPD_MASK 3 + +#define USB_USBMODE_REG_OFFSET 0x1a8 +#define USB_USBMODE_MASK (3 << 0) +#define USB_USBMODE_HOST (3 << 0) +#define USB_USBMODE_DEVICE (2 << 0) + +#define USB_SUSP_CTRL 0x400 +#define USB_WAKE_ON_CNNT_EN_DEV (1 << 3) +#define USB_WAKE_ON_DISCON_EN_DEV (1 << 4) +#define USB_SUSP_CLR (1 << 5) +#define USB_CLKEN (1 << 6) +#define USB_PHY_CLK_VALID (1 << 7) +#define USB_PHY_CLK_VALID_INT_ENB (1 << 9) +#define UTMIP_RESET (1 << 11) +#define UHSIC_RESET (1 << 11) +#define UTMIP_PHY_ENABLE (1 << 12) +#define UHSIC_PHY_ENABLE (1 << 12) +#define ULPI_PHY_ENABLE (1 << 13) +#define USB_SUSP_SET (1 << 14) +#define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16) +#define USB_PHY_CLK_VALID_INT_STS (1 << 8) + +#define USB_PHY_VBUS_WAKEUP_ID 0x408 +#define VDAT_DET_INT_EN (1 << 16) +#define VDAT_DET_CHG_DET (1 << 17) +#define VDAT_DET_STS (1 << 18) +#define USB_ID_STATUS (1 << 2) + +#define USB1_LEGACY_CTRL 0x410 +#define USB1_NO_LEGACY_MODE (1 << 0) +#define USB1_VBUS_SENSE_CTL_MASK (3 << 1) +#define USB1_VBUS_SENSE_CTL_VBUS_WAKEUP (0 << 1) +#define USB1_VBUS_SENSE_CTL_AB_SESS_VLD_OR_VBUS_WAKEUP \ + (1 << 1) +#define USB1_VBUS_SENSE_CTL_AB_SESS_VLD (2 << 1) +#define USB1_VBUS_SENSE_CTL_A_SESS_VLD (3 << 1) + +#define ULPIS2S_CTRL 0x418 +#define ULPIS2S_ENA (1 << 0) +#define ULPIS2S_SUPPORT_DISCONNECT (1 << 2) +#define ULPIS2S_PLLU_MASTER_BLASTER60 (1 << 3) +#define ULPIS2S_SPARE(x) (((x) & 0xF) << 8) +#define ULPIS2S_FORCE_ULPI_CLK_OUT (1 << 12) +#define ULPIS2S_DISCON_DONT_CHECK_SE0 (1 << 13) +#define ULPIS2S_SUPPORT_HS_KEEP_ALIVE (1 << 14) +#define ULPIS2S_DISABLE_STP_PU (1 << 15) +#define ULPIS2S_SLV0_CLAMP_XMIT (1 << 16) + +#define ULPI_TIMING_CTRL_0 0x424 +#define ULPI_CLOCK_OUT_DELAY(x) ((x) & 0x1F) +#define ULPI_OUTPUT_PINMUX_BYP (1 << 10) +#define ULPI_CLKOUT_PINMUX_BYP (1 << 11) +#define ULPI_SHADOW_CLK_LOOPBACK_EN (1 << 12) +#define ULPI_SHADOW_CLK_SEL (1 << 13) +#define ULPI_CORE_CLK_SEL (1 << 14) +#define ULPI_SHADOW_CLK_DELAY(x) (((x) & 0x1F) << 16) +#define ULPI_LBK_PAD_EN (1 << 26) +#define ULPI_LBK_PAD_E_INPUT_OR (1 << 27) +#define ULPI_CLK_OUT_ENA (1 << 28) +#define ULPI_CLK_PADOUT_ENA (1 << 29) + +#define ULPI_TIMING_CTRL_1 0x428 +#define ULPI_DATA_TRIMMER_LOAD (1 << 0) +#define ULPI_DATA_TRIMMER_SEL(x) (((x) & 0x7) << 1) +#define ULPI_STPDIRNXT_TRIMMER_LOAD (1 << 16) +#define ULPI_STPDIRNXT_TRIMMER_SEL(x) (((x) & 0x7) << 17) +#define ULPI_DIR_TRIMMER_LOAD (1 << 24) +#define ULPI_DIR_TRIMMER_SEL(x) (((x) & 0x7) << 25) + +#define UTMIP_PLL_CFG1 0x804 +#define UHSIC_PLL_CFG1 0x804 +#define UTMIP_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0) +#define UTMIP_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27) +#define UHSIC_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0) +#define UHSIC_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 14) + +#define UTMIP_XCVR_UHSIC_HSRX_CFG0 0x808 +#define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0) +#define UHSIC_ELASTIC_UNDERRUN_LIMIT(x) (((x) & 0x1f) << 2) +#define UHSIC_ELASTIC_OVERRUN_LIMIT(x) (((x) & 0x1f) << 8) +#define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8) +#define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10) +#define UHSIC_IDLE_WAIT(x) (((x) & 0x1f) << 13) +#define UTMIP_FORCE_PD_POWERDOWN (1 << 14) +#define UTMIP_FORCE_PD2_POWERDOWN (1 << 16) +#define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18) +#define UTMIP_XCVR_LSBIAS_SEL (1 << 21) +#define UTMIP_XCVR_SETUP_MSB(x) (((x) & 0x7) << 22) +#define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25) +#define UTMIP_XCVR_MAX_OFFSET 2 +#define UTMIP_XCVR_SETUP_MAX_VALUE 0x7f +#define UTMIP_XCVR_SETUP_MIN_VALUE 0 +#define XCVR_SETUP_MSB_CALIB(x) ((x) >> 4) + +#define UTMIP_BIAS_CFG0 0x80c +#define UTMIP_OTGPD (1 << 11) +#define UTMIP_BIASPD (1 << 10) + +#define UHSIC_HSRX_CFG1 0x80c +#define UHSIC_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1) + +#define UTMIP_HSRX_CFG0 0x810 +#define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10) +#define UTMIP_IDLE_WAIT(x) (((x) & 0x1f) << 15) + +#define UTMIP_HSRX_CFG1 0x814 +#define UHSIC_MISC_CFG0 0x814 +#define UTMIP_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1) +#define UHSIC_SUSPEND_EXIT_ON_EDGE (1 << 7) +#define UHSIC_DETECT_SHORT_CONNECT (1 << 8) +#define UHSIC_FORCE_XCVR_MODE (1 << 15) + +#define UHSIC_MISC_CFG1 0x818 +#define UHSIC_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 2) + +#define UHSIC_PADS_CFG0 0x81c +#define UHSIC_TX_RTUNEN 0xf000 +#define UHSIC_TX_RTUNE(x) (((x) & 0xf) << 12) + +#define UTMIP_TX_CFG0 0x820 +#define UHSIC_PADS_CFG1 0x820 +#define UHSIC_PD_BG (1 << 2) +#define UHSIC_PD_TX (1 << 3) +#define UHSIC_PD_TRK (1 << 4) +#define UHSIC_PD_RX (1 << 5) +#define UHSIC_PD_ZI (1 << 6) +#define UHSIC_RX_SEL (1 << 7) +#define UHSIC_RPD_DATA (1 << 9) +#define UHSIC_RPD_STROBE (1 << 10) +#define UHSIC_RPU_DATA (1 << 11) +#define UHSIC_RPU_STROBE (1 << 12) +#define UTMIP_FS_PREABMLE_J (1 << 19) +#define UTMIP_HS_DISCON_DISABLE (1 << 8) + +#define UTMIP_MISC_CFG0 0x824 +#define UTMIP_DPDM_OBSERVE (1 << 26) +#define UTMIP_DPDM_OBSERVE_SEL(x) (((x) & 0xf) << 27) +#define UTMIP_DPDM_OBSERVE_SEL_FS_J UTMIP_DPDM_OBSERVE_SEL(0xf) +#define UTMIP_DPDM_OBSERVE_SEL_FS_K UTMIP_DPDM_OBSERVE_SEL(0xe) +#define UTMIP_DPDM_OBSERVE_SEL_FS_SE1 UTMIP_DPDM_OBSERVE_SEL(0xd) +#define UTMIP_DPDM_OBSERVE_SEL_FS_SE0 UTMIP_DPDM_OBSERVE_SEL(0xc) +#define UTMIP_SUSPEND_EXIT_ON_EDGE (1 << 22) +#define FORCE_PULLDN_DM (1 << 8) +#define FORCE_PULLDN_DP (1 << 9) +#define COMB_TERMS (1 << 0) +#define ALWAYS_FREE_RUNNING_TERMS (1 << 1) + +#define USB1_PREFETCH_ID 6 +#define USB2_PREFETCH_ID 18 +#define USB3_PREFETCH_ID 17 + +#define UTMIP_MISC_CFG1 0x828 +#define UTMIP_PLL_ACTIVE_DLY_COUNT(x) (((x) & 0x1f) << 18) +#define UTMIP_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 6) + +#define UHSIC_STAT_CFG0 0x828 +#define UHSIC_CONNECT_DETECT (1 << 0) + +#define UTMIP_DEBOUNCE_CFG0 0x82c +#define UTMIP_BIAS_DEBOUNCE_A(x) (((x) & 0xffff) << 0) + +#define UTMIP_BAT_CHRG_CFG0 0x830 +#define UTMIP_PD_CHRG (1 << 0) +#define UTMIP_ON_SINK_EN (1 << 2) +#define UTMIP_OP_SRC_EN (1 << 3) + +#define UTMIP_SPARE_CFG0 0x834 +#define FUSE_SETUP_SEL (1 << 3) +#define FUSE_ATERM_SEL (1 << 4) + +#define UTMIP_XCVR_CFG1 0x838 +#define UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0) +#define UTMIP_FORCE_PDCHRP_POWERDOWN (1 << 2) +#define UTMIP_FORCE_PDDR_POWERDOWN (1 << 4) +#define UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18) + +#define UTMIP_BIAS_CFG1 0x83c +#define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3) + +#define FUSE_USB_CALIB_0 0x1F0 +#define FUSE_USB_CALIB_XCVR_SETUP(x) (((x) & 0x7F) << 0) + +/* These values (in milli second) are taken from the battery charging spec */ +#define TDP_SRC_ON_MS 100 +#define TDPSRC_CON_MS 40 + +#ifdef DEBUG +#define DBG(stuff...) pr_info("tegra2_usb_phy: " stuff) +#else +#define DBG(stuff...) do {} while (0) +#endif + +static DEFINE_SPINLOCK(utmip_pad_lock); +static int utmip_pad_count; +static int utmip_pad_state_on; + +static struct tegra_xtal_freq utmip_freq_table[] = { + { + .freq = 12000000, + .enable_delay = 0x02, + .stable_count = 0x2F, + .active_delay = 0x04, + .xtal_freq_count = 0x76, + .debounce = 0x7530, + .pdtrk_count = 5, + }, + { + .freq = 13000000, + .enable_delay = 0x02, + .stable_count = 0x33, + .active_delay = 0x05, + .xtal_freq_count = 0x7F, + .debounce = 0x7EF4, + .pdtrk_count = 5, + }, + { + .freq = 19200000, + .enable_delay = 0x03, + .stable_count = 0x4B, + .active_delay = 0x06, + .xtal_freq_count = 0xBB, + .debounce = 0xBB80, + .pdtrk_count = 7, + }, + { + .freq = 26000000, + .enable_delay = 0x04, + .stable_count = 0x66, + .active_delay = 0x09, + .xtal_freq_count = 0xFE, + .debounce = 0xFDE8, + .pdtrk_count = 9, + }, +}; + +static struct tegra_xtal_freq uhsic_freq_table[] = { + { + .freq = 12000000, + .enable_delay = 0x02, + .stable_count = 0x2F, + .active_delay = 0x0, + .xtal_freq_count = 0x1CA, + }, + { + .freq = 13000000, + .enable_delay = 0x02, + .stable_count = 0x33, + .active_delay = 0x0, + .xtal_freq_count = 0x1F0, + }, + { + .freq = 19200000, + .enable_delay = 0x03, + .stable_count = 0x4B, + .active_delay = 0x0, + .xtal_freq_count = 0x2DD, + }, + { + .freq = 26000000, + .enable_delay = 0x04, + .stable_count = 0x66, + .active_delay = 0x0, + .xtal_freq_count = 0x3E0, + }, +}; + +static void usb_phy_fence_read(struct tegra_usb_phy *phy) +{ + /* Fence read for coherency of AHB master intiated writes */ + if (phy->inst == 0) + readb(IO_ADDRESS(IO_PPCS_PHYS + USB1_PREFETCH_ID)); + else if (phy->inst == 1) + readb(IO_ADDRESS(IO_PPCS_PHYS + USB2_PREFETCH_ID)); + else if (phy->inst == 2) + readb(IO_ADDRESS(IO_PPCS_PHYS + USB3_PREFETCH_ID)); + + return; +} + +static int usb_phy_bringup_host_controller(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x] port_speed[%d] - 0\n", + readl(base + USB_USBSTS), readl(base + USB_PORTSC), + phy->port_speed); + + /* enable host mode */ + val = readl(base + USB_USBMODE_REG_OFFSET); + val |= USB_USBMODE_HOST; + writel(val, base + USB_USBMODE_REG_OFFSET); + + /* Enable Port Power */ + val = readl(base + USB_PORTSC); + val |= USB_PORTSC_PP; + writel(val, base + USB_PORTSC); + udelay(10); + + /* Check if the phy resume from LP0. When the phy resume from LP0 + * USB register will be reset.to zero */ + if (!readl(base + USB_ASYNCLISTADDR)) { + val = readl(base + USB_USBCMD); + val |= USB_USBCMD_RS; + writel(val, base + USB_USBCMD); + + /* Program the field PTC based on the saved speed mode */ + val = readl(base + USB_PORTSC); + val &= ~(USB_PORTSC_PTC(~0)); + if (phy->port_speed == USB_PHY_PORT_SPEED_HIGH) + val |= USB_PORTSC_PTC(5); + else if (phy->port_speed == USB_PHY_PORT_SPEED_FULL) + val |= USB_PORTSC_PTC(6); + else if (phy->port_speed == USB_PHY_PORT_SPEED_LOW) + val |= USB_PORTSC_PTC(7); + writel(val, base + USB_PORTSC); + udelay(10); + + /* Disable test mode by setting PTC field to NORMAL_OP */ + val = readl(base + USB_PORTSC); + val &= ~(USB_PORTSC_PTC(~0)); + writel(val, base + USB_PORTSC); + udelay(10); + } + + /* Poll until CCS is enabled */ + if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_CCS, + USB_PORTSC_CCS, 2000)) { + pr_err("%s: timeout waiting for USB_PORTSC_CCS\n", __func__); + } + + /* Poll until PE is enabled */ + if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_PE, + USB_PORTSC_PE, 2000)) { + pr_err("%s: timeout waiting for USB_PORTSC_PE\n", __func__); + } + + /* Clear the PCI status, to avoid an interrupt taken upon resume */ + val = readl(base + USB_USBSTS); + val |= USB_USBSTS_PCI; + writel(val, base + USB_USBSTS); + + /* Put controller in suspend mode by writing 1 to SUSP bit of PORTSC */ + val = readl(base + USB_PORTSC); + if ((val & USB_PORTSC_PP) && (val & USB_PORTSC_PE)) { + val |= USB_PORTSC_SUSP; + writel(val, base + USB_PORTSC); + /* Need a 4ms delay before the controller goes to suspend */ + mdelay(4); + + /* Wait until port suspend completes */ + if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_SUSP, + USB_PORTSC_SUSP, 1000)) { + pr_err("%s: timeout waiting for PORT_SUSPEND\n", + __func__); + } + } + + DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n", + readl(base + USB_USBSTS), readl(base + USB_PORTSC)); + + return 0; +} + +static void usb_phy_wait_for_sof(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + val = readl(base + USB_USBSTS); + writel(val, base + USB_USBSTS); + udelay(20); + /* wait for two SOFs */ + if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_SRI, + USB_USBSTS_SRI, 2500)) + pr_err("%s: timeout waiting for SOF\n", __func__); + + val = readl(base + USB_USBSTS); + writel(val, base + USB_USBSTS); + if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_SRI, 0, 2500)) + pr_err("%s: timeout waiting for SOF\n", __func__); + + if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_SRI, + USB_USBSTS_SRI, 2500)) + pr_err("%s: timeout waiting for SOF\n", __func__); + + udelay(20); +} + +static unsigned int utmi_phy_xcvr_setup_value(struct tegra_usb_phy *phy) +{ + struct tegra_utmi_config *cfg = &phy->pdata->u_cfg.utmi; + signed long val; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + if (cfg->xcvr_use_fuses) { + val = FUSE_USB_CALIB_XCVR_SETUP( + tegra_fuse_readl(FUSE_USB_CALIB_0)); + if (cfg->xcvr_setup_offset <= UTMIP_XCVR_MAX_OFFSET) + val = val + cfg->xcvr_setup_offset; + + if (val > UTMIP_XCVR_SETUP_MAX_VALUE) { + val = UTMIP_XCVR_SETUP_MAX_VALUE; + pr_info("%s: reset XCVR_SETUP to max value\n", + __func__); + } else if (val < UTMIP_XCVR_SETUP_MIN_VALUE) { + val = UTMIP_XCVR_SETUP_MIN_VALUE; + pr_info("%s: reset XCVR_SETUP to min value\n", + __func__); + } + } else { + val = cfg->xcvr_setup; + } + + return (unsigned int) val; +} + + +static int utmi_phy_open(struct tegra_usb_phy *phy) +{ + unsigned long parent_rate; + int i; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + phy->utmi_pad_clk = clk_get_sys("utmip-pad", NULL); + if (IS_ERR(phy->utmi_pad_clk)) { + pr_err("%s: can't get utmip pad clock\n", __func__); + return PTR_ERR(phy->utmi_pad_clk); + } + + phy->utmi_xcvr_setup = utmi_phy_xcvr_setup_value(phy); + + parent_rate = clk_get_rate(clk_get_parent(phy->pllu_clk)); + for (i = 0; i < ARRAY_SIZE(utmip_freq_table); i++) { + if (utmip_freq_table[i].freq == parent_rate) { + phy->freq = &utmip_freq_table[i]; + break; + } + } + if (!phy->freq) { + pr_err("invalid pll_u parent rate %ld\n", parent_rate); + return -EINVAL; + } + + return 0; +} + +static void utmi_phy_close(struct tegra_usb_phy *phy) +{ + DBG("%s inst:[%d]\n", __func__, phy->inst); + + clk_put(phy->utmi_pad_clk); +} + +static int utmi_phy_pad_power_on(struct tegra_usb_phy *phy) +{ + unsigned long val, flags; + void __iomem *pad_base = IO_ADDRESS(TEGRA_USB_BASE); + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + clk_enable(phy->utmi_pad_clk); + + spin_lock_irqsave(&utmip_pad_lock, flags); + + utmip_pad_count++; + val = readl(pad_base + UTMIP_BIAS_CFG0); + val &= ~(UTMIP_OTGPD | UTMIP_BIASPD); + writel(val, pad_base + UTMIP_BIAS_CFG0); + utmip_pad_state_on = true; + + spin_unlock_irqrestore(&utmip_pad_lock, flags); + + clk_disable(phy->utmi_pad_clk); + + return 0; +} + +static int utmi_phy_pad_power_off(struct tegra_usb_phy *phy) +{ + unsigned long val, flags; + void __iomem *pad_base = IO_ADDRESS(TEGRA_USB_BASE); + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + clk_enable(phy->utmi_pad_clk); + spin_lock_irqsave(&utmip_pad_lock, flags); + + if (!utmip_pad_count) { + pr_err("%s: utmip pad already powered off\n", __func__); + goto out; + } + if (--utmip_pad_count == 0) { + val = readl(pad_base + UTMIP_BIAS_CFG0); + val |= UTMIP_OTGPD | UTMIP_BIASPD; + writel(val, pad_base + UTMIP_BIAS_CFG0); + utmip_pad_state_on = false; + } +out: + spin_unlock_irqrestore(&utmip_pad_lock, flags); + clk_disable(phy->utmi_pad_clk); + + return 0; +} + +static int utmi_phy_irq(struct tegra_usb_phy *phy) +{ + void __iomem *base = phy->regs; + unsigned long val = 0; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + usb_phy_fence_read(phy); + if (phy->pdata->u_data.host.hot_plug) { + val = readl(base + USB_SUSP_CTRL); + if ((val & USB_PHY_CLK_VALID_INT_STS)) { + val &= ~USB_PHY_CLK_VALID_INT_ENB | + USB_PHY_CLK_VALID_INT_STS; + writel(val , (base + USB_SUSP_CTRL)); + pr_info("%s: usb device plugged-in\n", __func__); + val = readl(base + USB_USBSTS); + if (!(val & USB_USBSTS_PCI)) + return IRQ_NONE; + val = readl(base + USB_PORTSC); + val &= ~(USB_PORTSC_WKCN | USB_PORTSC_RWC_BITS); + writel(val , (base + USB_PORTSC)); + } + } + + return IRQ_HANDLED; +} + + +static int utmi_phy_post_resume(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + val = readl(base + UTMIP_TX_CFG0); + val &= ~UTMIP_HS_DISCON_DISABLE; + writel(val, base + UTMIP_TX_CFG0); + return 0; +} + +static int utmi_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + val = readl(base + UTMIP_TX_CFG0); + val |= UTMIP_HS_DISCON_DISABLE; + writel(val, base + UTMIP_TX_CFG0); + + usb_phy_wait_for_sof(phy); + + return 0; +} + +static int utmi_phy_power_off(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + if (!phy->phy_clk_on) { + DBG("%s(%d) inst:[%d] phy clk is already off\n", + __func__, __LINE__, phy->inst); + return 0; + } + + if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) { + val = readl(base + USB_SUSP_CTRL); + val &= ~(USB_WAKEUP_DEBOUNCE_COUNT(~0)); + val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5); + writel(val, base + USB_SUSP_CTRL); + + val = readl(base + UTMIP_BAT_CHRG_CFG0); + val |= UTMIP_PD_CHRG; + writel(val, base + UTMIP_BAT_CHRG_CFG0); + } + + if (!phy->pdata->u_data.host.hot_plug) { + val = readl(base + UTMIP_XCVR_UHSIC_HSRX_CFG0); + val |= (UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN | + UTMIP_FORCE_PDZI_POWERDOWN); + writel(val, base + UTMIP_XCVR_UHSIC_HSRX_CFG0); + } + + val = readl(base + UTMIP_XCVR_CFG1); + val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN | + UTMIP_FORCE_PDDR_POWERDOWN; + writel(val, base + UTMIP_XCVR_CFG1); + + if (phy->inst != 0) { + val = readl(base + UTMIP_BIAS_CFG0); + val |= UTMIP_OTGPD; + writel(val, base + UTMIP_BIAS_CFG0); + } + + phy->port_speed = (readl(base + USB_PORTSC) >> 26) & + USB_PORTSC_PSPD_MASK; + + if (phy->pdata->u_data.host.hot_plug) { + bool enable_hotplug = true; + /* if it is OTG port then make sure to enable hot-plug feature + only if host adaptor is connected, i.e id is low */ + if (phy->pdata->port_otg) { + val = readl(base + USB_PHY_VBUS_WAKEUP_ID); + enable_hotplug = (val & USB_ID_STATUS) ? false : true; + } + if (enable_hotplug) { + val = readl(base + USB_PORTSC); + val |= USB_PORTSC_WKCN; + writel(val, base + USB_PORTSC); + + val = readl(base + USB_SUSP_CTRL); + val |= USB_PHY_CLK_VALID_INT_ENB; + writel(val, base + USB_SUSP_CTRL); + } else { + /* Disable PHY clock valid interrupts while going into suspend*/ + val = readl(base + USB_SUSP_CTRL); + val &= ~USB_PHY_CLK_VALID_INT_ENB; + writel(val, base + USB_SUSP_CTRL); + } + } + + if (phy->inst == 2) { + val = readl(base + USB_PORTSC); + val |= USB_PORTSC_PHCD; + writel(val, base + USB_PORTSC); + } else { + val = readl(base + USB_SUSP_CTRL); + val |= USB_SUSP_SET; + writel(val, base + USB_SUSP_CTRL); + udelay(10); + val = readl(base + USB_SUSP_CTRL); + val &= ~USB_SUSP_SET; + writel(val, base + USB_SUSP_CTRL); + } + + if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, + 0, 2500)) + pr_warn("%s: timeout waiting for phy to stabilize\n", __func__); + + utmi_phy_pad_power_off(phy); + + phy->phy_clk_on = false; + phy->hw_accessible = false; + + DBG("%s(%d) inst:[%d]END\n", __func__, __LINE__, phy->inst); + + return 0; +} + +static int utmi_phy_power_on(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + struct tegra_utmi_config *config = &phy->pdata->u_cfg.utmi; + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + if (phy->phy_clk_on) { + DBG("%s(%d) inst:[%d] phy clk is already on\n", + __func__, __LINE__, phy->inst); + return 0; + } + + val = readl(base + USB_SUSP_CTRL); + val |= UTMIP_RESET; + writel(val, base + USB_SUSP_CTRL); + + val = readl(base + UTMIP_TX_CFG0); + val |= UTMIP_FS_PREABMLE_J; + writel(val, base + UTMIP_TX_CFG0); + + val = readl(base + UTMIP_HSRX_CFG0); + val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0)); + val |= UTMIP_IDLE_WAIT(config->idle_wait_delay); + val |= UTMIP_ELASTIC_LIMIT(config->elastic_limit); + writel(val, base + UTMIP_HSRX_CFG0); + + val = readl(base + UTMIP_HSRX_CFG1); + val &= ~(UTMIP_HS_SYNC_START_DLY(~0)); + val |= UTMIP_HS_SYNC_START_DLY(config->hssync_start_delay); + writel(val, base + UTMIP_HSRX_CFG1); + + val = readl(base + UTMIP_DEBOUNCE_CFG0); + val &= ~UTMIP_BIAS_DEBOUNCE_A(~0); + val |= UTMIP_BIAS_DEBOUNCE_A(phy->freq->debounce); + writel(val, base + UTMIP_DEBOUNCE_CFG0); + + val = readl(base + UTMIP_MISC_CFG0); + val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE; + writel(val, base + UTMIP_MISC_CFG0); + + val = readl(base + UTMIP_MISC_CFG1); + val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | UTMIP_PLLU_STABLE_COUNT(~0)); + val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) | + UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count); + writel(val, base + UTMIP_MISC_CFG1); + + val = readl(base + UTMIP_PLL_CFG1); + val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | UTMIP_PLLU_ENABLE_DLY_COUNT(~0)); + val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) | + UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay); + writel(val, base + UTMIP_PLL_CFG1); + + if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) { + val = readl(base + USB_SUSP_CTRL); + val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV); + writel(val, base + USB_SUSP_CTRL); + + val = readl(base + UTMIP_BAT_CHRG_CFG0); + val &= ~UTMIP_PD_CHRG; + writel(val, base + UTMIP_BAT_CHRG_CFG0); + } else { + val = readl(base + UTMIP_BAT_CHRG_CFG0); + val |= UTMIP_PD_CHRG; + writel(val, base + UTMIP_BAT_CHRG_CFG0); + } + + utmi_phy_pad_power_on(phy); + + val = readl(base + UTMIP_XCVR_UHSIC_HSRX_CFG0); + val &= ~(UTMIP_XCVR_LSBIAS_SEL | UTMIP_FORCE_PD_POWERDOWN | + UTMIP_FORCE_PD2_POWERDOWN | UTMIP_FORCE_PDZI_POWERDOWN | + UTMIP_XCVR_SETUP(~0) | UTMIP_XCVR_LSFSLEW(~0) | + UTMIP_XCVR_LSRSLEW(~0) | UTMIP_XCVR_HSSLEW_MSB(~0)); + val |= UTMIP_XCVR_SETUP(phy->utmi_xcvr_setup); + val |= UTMIP_XCVR_SETUP_MSB(XCVR_SETUP_MSB_CALIB(phy->utmi_xcvr_setup)); + val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew); + val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew); + + writel(val, base + UTMIP_XCVR_UHSIC_HSRX_CFG0); + + val = readl(base + UTMIP_XCVR_CFG1); + val &= ~(UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN | + UTMIP_FORCE_PDDR_POWERDOWN | UTMIP_XCVR_TERM_RANGE_ADJ(~0)); + val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj); + writel(val, base + UTMIP_XCVR_CFG1); + + + val = readl(base + UTMIP_BIAS_CFG1); + val &= ~(UTMIP_BIAS_PDTRK_COUNT(~0)); + val |= UTMIP_BIAS_PDTRK_COUNT(phy->freq->pdtrk_count); + writel(val, base + UTMIP_BIAS_CFG1); + + val = readl(base + UTMIP_SPARE_CFG0); + val &= ~FUSE_SETUP_SEL; + writel(val, base + UTMIP_SPARE_CFG0); + + val = readl(base + USB_SUSP_CTRL); + val |= UTMIP_PHY_ENABLE; + writel(val, base + USB_SUSP_CTRL); + + val = readl(base + USB_SUSP_CTRL); + val &= ~UTMIP_RESET; + writel(val, base + USB_SUSP_CTRL); + + if (phy->inst == 0) { + val = readl(base + USB_SUSP_CTRL); + val &= ~USB_SUSP_SET; + writel(val, base + USB_SUSP_CTRL); + } else { + val = readl(base + USB_PORTSC); + val &= ~USB_PORTSC_PHCD; + writel(val, base + USB_PORTSC); + } + + if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, + USB_PHY_CLK_VALID, USB_PHY_CLK_VALID, 2500)) + pr_warn("%s: timeout waiting for phy to stabilize\n", __func__); + + if (phy->inst == 2) { + val = readl(base + USB_PORTSC); + val &= ~(USB_PORTSC_PTS(~0)); + writel(val, base + USB_PORTSC); + } + + phy->phy_clk_on = true; + phy->hw_accessible = true; + + return 0; +} + +static void utmi_phy_restore_start(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + val = readl(base + UTMIP_MISC_CFG0); + val &= ~(UTMIP_DPDM_OBSERVE_SEL(~0)); + + if (phy->port_speed == USB_PHY_PORT_SPEED_LOW) + val |= UTMIP_DPDM_OBSERVE_SEL_FS_K; + else + val |= UTMIP_DPDM_OBSERVE_SEL_FS_J; + writel(val, base + UTMIP_MISC_CFG0); + udelay(1); + + val = readl(base + UTMIP_MISC_CFG0); + val |= UTMIP_DPDM_OBSERVE; + writel(val, base + UTMIP_MISC_CFG0); + udelay(10); +} + +static void utmi_phy_restore_end(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + val = readl(base + UTMIP_MISC_CFG0); + val &= ~UTMIP_DPDM_OBSERVE; + writel(val, base + UTMIP_MISC_CFG0); + udelay(10); +} + + +static int utmi_phy_resume(struct tegra_usb_phy *phy) +{ + int status = 0; + unsigned long val, flags; + void __iomem *base = phy->regs; + void __iomem *pad_base = IO_ADDRESS(TEGRA_USB_BASE); + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) { + if (phy->port_speed < USB_PHY_PORT_SPEED_UNKNOWN) { + utmi_phy_restore_start(phy); + usb_phy_bringup_host_controller(phy); + utmi_phy_restore_end(phy); + } else { + /* device is plugged in when system is in LP0 */ + /* bring up the controller from LP0*/ + val = readl(base + USB_USBCMD); + val |= USB_USBCMD_RESET; + writel(val, base + USB_USBCMD); + + if (usb_phy_reg_status_wait(base + USB_USBCMD, + USB_USBCMD_RESET, 0, 2500) < 0) { + pr_err("%s: timeout waiting for reset\n", __func__); + } + + val = readl(base + USB_USBMODE_REG_OFFSET); + val &= ~USB_USBMODE_MASK; + val |= USB_USBMODE_HOST; + writel(val, base + USB_USBMODE_REG_OFFSET); + + if (phy->inst == 2) { + val = readl(base + USB_PORTSC); + val &= ~USB_PORTSC_PTS(~0); + writel(val, base + USB_PORTSC); + } + writel(USB_USBCMD_RS, base + USB_USBCMD); + + if (usb_phy_reg_status_wait(base + USB_USBCMD, + USB_USBCMD_RS, USB_USBCMD_RS, 2500) < 0) { + pr_err("%s: timeout waiting for run bit\n", __func__); + } + + /* Enable Port Power */ + val = readl(base + USB_PORTSC); + val |= USB_PORTSC_PP; + writel(val, base + USB_PORTSC); + udelay(10); + + DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n", + readl(base + USB_USBSTS), readl(base + USB_PORTSC)); + } + } else { + /* Restoring the pad powers */ + clk_enable(phy->utmi_pad_clk); + + spin_lock_irqsave(&utmip_pad_lock, flags); + + val = readl(pad_base + UTMIP_BIAS_CFG0); + if (utmip_pad_state_on) + val &= ~(UTMIP_OTGPD | UTMIP_BIASPD); + else + val |= (UTMIP_OTGPD | UTMIP_BIASPD); + writel(val, pad_base + UTMIP_BIAS_CFG0); + + spin_unlock_irqrestore(&utmip_pad_lock, flags); + clk_disable(phy->utmi_pad_clk); + } + + return status; +} + +static bool utmi_phy_charger_detect(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + bool status; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + /* Enable charger detection logic */ + val = readl(base + UTMIP_BAT_CHRG_CFG0); + val |= UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN; + writel(val, base + UTMIP_BAT_CHRG_CFG0); + + /* Source should be on for 100 ms as per USB charging spec */ + msleep(TDP_SRC_ON_MS); + + val = readl(base + USB_PHY_VBUS_WAKEUP_ID); + /* If charger is not connected disable the interrupt */ + val &= ~VDAT_DET_INT_EN; + val |= VDAT_DET_CHG_DET; + writel(val, base + USB_PHY_VBUS_WAKEUP_ID); + + val = readl(base + USB_PHY_VBUS_WAKEUP_ID); + if (val & VDAT_DET_STS) + status = true; + else + status = false; + + /* Disable charger detection logic */ + val = readl(base + UTMIP_BAT_CHRG_CFG0); + val &= ~(UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN); + writel(val, base + UTMIP_BAT_CHRG_CFG0); + + /* Delay of 40 ms before we pull the D+ as per battery charger spec */ + msleep(TDPSRC_CON_MS); + + return status; +} + + +static int uhsic_phy_open(struct tegra_usb_phy *phy) +{ + unsigned long parent_rate; + int i; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + parent_rate = clk_get_rate(clk_get_parent(phy->pllu_clk)); + for (i = 0; i < ARRAY_SIZE(uhsic_freq_table); i++) { + if (uhsic_freq_table[i].freq == parent_rate) { + phy->freq = &uhsic_freq_table[i]; + break; + } + } + if (!phy->freq) { + pr_err("invalid pll_u parent rate %ld\n", parent_rate); + return -EINVAL; + } + + return 0; +} + +static int uhsic_phy_irq(struct tegra_usb_phy *phy) +{ + usb_phy_fence_read(phy); + return IRQ_HANDLED; +} + +static int uhsic_phy_power_on(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + struct tegra_hsic_config *config = &phy->pdata->u_cfg.hsic; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + if (phy->phy_clk_on) { + DBG("%s(%d) inst:[%d] phy clk is already On\n", __func__, + __LINE__, phy->inst); + return 0; + } + + val = readl(base + UHSIC_PADS_CFG1); + val &= ~(UHSIC_PD_BG | UHSIC_PD_TX | UHSIC_PD_TRK | UHSIC_PD_RX | + UHSIC_PD_ZI | UHSIC_RPD_DATA | UHSIC_RPD_STROBE); + val |= UHSIC_RX_SEL; + writel(val, base + UHSIC_PADS_CFG1); + udelay(2); + + val = readl(base + USB_SUSP_CTRL); + val |= UHSIC_RESET; + writel(val, base + USB_SUSP_CTRL); + udelay(30); + + val = readl(base + USB_SUSP_CTRL); + val |= UHSIC_PHY_ENABLE; + writel(val, base + USB_SUSP_CTRL); + + val = readl(base + UTMIP_XCVR_UHSIC_HSRX_CFG0); + val |= UHSIC_IDLE_WAIT(config->idle_wait_delay); + val |= UHSIC_ELASTIC_UNDERRUN_LIMIT(config->elastic_underrun_limit); + val |= UHSIC_ELASTIC_OVERRUN_LIMIT(config->elastic_overrun_limit); + writel(val, base + UTMIP_XCVR_UHSIC_HSRX_CFG0); + + val = readl(base + UHSIC_HSRX_CFG1); + val |= UHSIC_HS_SYNC_START_DLY(config->sync_start_delay); + writel(val, base + UHSIC_HSRX_CFG1); + + val = readl(base + UHSIC_MISC_CFG0); + val |= UHSIC_SUSPEND_EXIT_ON_EDGE; + writel(val, base + UHSIC_MISC_CFG0); + + val = readl(base + UHSIC_MISC_CFG1); + val |= UHSIC_PLLU_STABLE_COUNT(phy->freq->stable_count); + writel(val, base + UHSIC_MISC_CFG1); + + val = readl(base + UHSIC_PLL_CFG1); + val |= UHSIC_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay); + val |= UHSIC_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count); + writel(val, base + UHSIC_PLL_CFG1); + + val = readl(base + USB_SUSP_CTRL); + val &= ~(UHSIC_RESET); + writel(val, base + USB_SUSP_CTRL); + udelay(2); + + val = readl(base + USB_PORTSC); + val &= ~(USB_PORTSC_PTS(~0)); + writel(val, base + USB_PORTSC); + + val = readl(base + USB_TXFILLTUNING); + if ((val & USB_FIFO_TXFILL_MASK) != USB_FIFO_TXFILL_THRES(0x10)) { + val = USB_FIFO_TXFILL_THRES(0x10); + writel(val, base + USB_TXFILLTUNING); + } + + val = readl(base + USB_PORTSC); + val &= ~(USB_PORTSC_WKOC | USB_PORTSC_WKDS | USB_PORTSC_WKCN); + writel(val, base + USB_PORTSC); + + val = readl(base + UHSIC_PADS_CFG0); + val &= ~(UHSIC_TX_RTUNEN); + /* set Rtune impedance to 40 ohm */ + val |= UHSIC_TX_RTUNE(0); + writel(val, base + UHSIC_PADS_CFG0); + + if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, + USB_PHY_CLK_VALID, 2500)) { + pr_err("%s: timeout waiting for phy to stabilize\n", __func__); + return -ETIMEDOUT; + } + + phy->phy_clk_on = true; + phy->hw_accessible = true; + + return 0; +} + +static int uhsic_phy_power_off(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + if (!phy->phy_clk_on) { + DBG("%s(%d) inst:[%d] phy clk is already off\n", __func__, + __LINE__, phy->inst); + return 0; + } + + val = readl(base + UHSIC_PADS_CFG1); + val &= ~UHSIC_RPU_STROBE; + val |= UHSIC_RPD_STROBE; + writel(val, base + UHSIC_PADS_CFG1); + + val = readl(base + USB_SUSP_CTRL); + val |= UHSIC_RESET; + writel(val, base + USB_SUSP_CTRL); + udelay(30); + + val = readl(base + USB_SUSP_CTRL); + val &= ~UHSIC_PHY_ENABLE; + writel(val, base + USB_SUSP_CTRL); + + phy->phy_clk_on = false; + phy->hw_accessible = false; + + return 0; +} + +static int uhsic_phy_bus_port_power(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + val = readl(base + UHSIC_MISC_CFG0); + val |= UHSIC_DETECT_SHORT_CONNECT; + writel(val, base + UHSIC_MISC_CFG0); + udelay(1); + + val = readl(base + UHSIC_MISC_CFG0); + val |= UHSIC_FORCE_XCVR_MODE; + writel(val, base + UHSIC_MISC_CFG0); + + val = readl(base + UHSIC_PADS_CFG1); + val &= ~UHSIC_RPD_STROBE; + val |= UHSIC_RPU_STROBE; + writel(val, base + UHSIC_PADS_CFG1); + + val = readl(base + USB_USBCMD); + val &= ~USB_USBCMD_RS; + writel(val, base + USB_USBCMD); + + if (usb_phy_reg_status_wait(base + UHSIC_STAT_CFG0, + UHSIC_CONNECT_DETECT, UHSIC_CONNECT_DETECT, 2000)) { + pr_err("%s: timeout waiting for UHSIC_CONNECT_DETECT\n", + __func__); + return -ETIMEDOUT; + } + +/* FIXME : need to check whether this piece is required or not + if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_LS(2), + USB_PORTSC_LS(2), 2000)) { + pr_err("%s: timeout waiting for dplus state\n", __func__); + return -ETIMEDOUT; + } +*/ + return 0; +} + + +static int uhsic_phy_bus_reset(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + val = readl(base + USB_PORTSC); + val |= USB_PORTSC_PTC(5); + writel(val, base + USB_PORTSC); + udelay(2); + + val = readl(base + USB_PORTSC); + val &= ~(USB_PORTSC_PTC(~0)); + writel(val, base + USB_PORTSC); + udelay(2); + + if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_LS(0), + 0, 2000)) { + pr_err("%s: timeout waiting for USB_PORTSC_LS\n", __func__); + return -ETIMEDOUT; + } + + /* Poll until CCS is enabled */ + if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_CCS, + USB_PORTSC_CCS, 2000)) { + pr_err("%s: timeout waiting for USB_PORTSC_CCS\n", __func__); + return -ETIMEDOUT; + } + + if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_PSPD(2), + USB_PORTSC_PSPD(2), 2000)) { + pr_err("%s: timeout waiting for USB_PORTSC_PSPD\n", __func__); + return -ETIMEDOUT; + } + + val = readl(base + USB_USBCMD); + val &= ~USB_USBCMD_RS; + writel(val, base + USB_USBCMD); + + if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_HCH, + USB_USBSTS_HCH, 2000)) { + pr_err("%s: timeout waiting for USB_USBSTS_HCH\n", __func__); + return -ETIMEDOUT; + } + + val = readl(base + UHSIC_PADS_CFG1); + val &= ~UHSIC_RPU_STROBE; + val |= UHSIC_RPD_STROBE; + writel(val, base + UHSIC_PADS_CFG1); + + mdelay(50); + + val = readl(base + UHSIC_PADS_CFG1); + val &= ~UHSIC_RPD_STROBE; + val |= UHSIC_RPU_STROBE; + writel(val, base + UHSIC_PADS_CFG1); + + val = readl(base + USB_USBCMD); + val |= USB_USBCMD_RS; + writel(val, base + USB_USBCMD); + + val = readl(base + UHSIC_PADS_CFG1); + val &= ~UHSIC_RPU_STROBE; + writel(val, base + UHSIC_PADS_CFG1); + + if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS, + USB_USBCMD_RS, 2000)) { + pr_err("%s: timeout waiting for USB_USBCMD_RS\n", __func__); + return -ETIMEDOUT; + } + + return 0; +} + + +static int uhsic_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup) +{ + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + usb_phy_wait_for_sof(phy); + + return 0; +} + +static int uhsic_phy_resume(struct tegra_usb_phy *phy) +{ + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + uhsic_phy_bus_port_power(phy); + + return 0; +} + + +static int uhsic_phy_post_resume(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + val = readl(base + USB_TXFILLTUNING); + if ((val & USB_FIFO_TXFILL_MASK) != USB_FIFO_TXFILL_THRES(0x10)) { + val = USB_FIFO_TXFILL_THRES(0x10); + writel(val, base + USB_TXFILLTUNING); + } + + return 0; +} + +static void ulpi_set_trimmer(struct tegra_usb_phy *phy) +{ + struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi; + void __iomem *base = phy->regs; + unsigned long val; + + val = ULPI_DATA_TRIMMER_SEL(config->data_trimmer); + val |= ULPI_STPDIRNXT_TRIMMER_SEL(config->stpdirnxt_trimmer); + val |= ULPI_DIR_TRIMMER_SEL(config->dir_trimmer); + writel(val, base + ULPI_TIMING_CTRL_1); + udelay(10); + + val |= ULPI_DATA_TRIMMER_LOAD; + val |= ULPI_STPDIRNXT_TRIMMER_LOAD; + val |= ULPI_DIR_TRIMMER_LOAD; + writel(val, base + ULPI_TIMING_CTRL_1); +} + + +static int ulpi_link_phy_open(struct tegra_usb_phy *phy) +{ + struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi; + int err = 0; + + phy->ulpi_clk = NULL; + + if (config->clk) { + phy->ulpi_clk = clk_get_sys(NULL, config->clk); + if (IS_ERR(phy->ulpi_clk)) { + pr_err("%s: can't get ulpi clock\n", __func__); + err = -ENXIO; + } + } + + phy->ulpi_vp = otg_ulpi_create(&ulpi_viewport_access_ops, 0); + phy->ulpi_vp->io_priv = phy->regs + ULPI_VIEWPORT; + + return err; +} + +static void ulpi_link_phy_close(struct tegra_usb_phy *phy) +{ + DBG("%s inst:[%d]\n", __func__, phy->inst); + if (phy->ulpi_clk) + clk_put(phy->ulpi_clk); +} + +static int ulpi_link_phy_irq(struct tegra_usb_phy *phy) +{ + usb_phy_fence_read(phy); + return IRQ_HANDLED; +} + +static int ulpi_link_phy_power_off(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + int ret; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + if (!phy->phy_clk_on) { + DBG("%s(%d) inst:[%d] phy clk is already off\n", __func__, + __LINE__, phy->inst); + return 0; + } + + /* Disable VbusValid, SessEnd comparators */ + ret = otg_io_write(phy->ulpi_vp, 0x00, 0x0D); + if (ret) + pr_err("%s: ulpi write 0x0D failed\n", __func__); + + ret = otg_io_write(phy->ulpi_vp, 0x00, 0x10); + if (ret) + pr_err("%s: ulpi write 0x10 failed\n", __func__); + + /* Disable IdFloat comparator */ + ret = otg_io_write(phy->ulpi_vp, 0x00, 0x19); + if (ret) + pr_err("%s: ulpi write 0x19 failed\n", __func__); + + ret = otg_io_write(phy->ulpi_vp, 0x00, 0x1D); + if (ret) + pr_err("%s: ulpi write 0x1D failed\n", __func__); + + phy->port_speed = (readl(base + USB_PORTSC) >> 26) & + USB_PORTSC_PSPD_MASK; + + /* Clear WKCN/WKDS/WKOC wake-on events that can cause the USB + * Controller to immediately bring the ULPI PHY out of low power + */ + val = readl(base + USB_PORTSC); + val &= ~(USB_PORTSC_WKOC | USB_PORTSC_WKDS | USB_PORTSC_WKCN); + writel(val, base + USB_PORTSC); + + /* Put the PHY in the low power mode */ + val = readl(base + USB_PORTSC); + val |= USB_PORTSC_PHCD; + writel(val, base + USB_PORTSC); + + if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, + 0, 2500)) { + pr_err("%s: timeout waiting for phy to stop\n", __func__); + } + + if (phy->ulpi_clk) + clk_disable(phy->ulpi_clk); + + phy->phy_clk_on = false; + phy->hw_accessible = false; + + return 0; +} + +static int ulpi_link_phy_power_on(struct tegra_usb_phy *phy) +{ + int ret; + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + if (phy->phy_clk_on) { + DBG("%s(%d) inst:[%d] phy clk is already On\n", __func__, + __LINE__, phy->inst); + return 0; + } + + if (phy->ulpi_clk) { + clk_enable(phy->ulpi_clk); + mdelay(1); + } + + val = readl(base + USB_SUSP_CTRL); + val |= UHSIC_RESET; + writel(val, base + USB_SUSP_CTRL); + + val = readl(base + ULPI_TIMING_CTRL_0); + val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP; + writel(val, base + ULPI_TIMING_CTRL_0); + + val = readl(base + USB_SUSP_CTRL); + val |= ULPI_PHY_ENABLE; + writel(val, base + USB_SUSP_CTRL); + + val = readl(base + USB_SUSP_CTRL); + val |= USB_SUSP_CLR; + writel(val, base + USB_SUSP_CTRL); + + if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, + USB_PHY_CLK_VALID, 2500)) + pr_err("%s: timeout waiting for phy to stabilize\n", __func__); + + if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_CLKEN, + USB_CLKEN, 2500)) + pr_err("%s: timeout waiting for AHB clock\n", __func__); + + val = readl(base + USB_SUSP_CTRL); + val &= ~USB_SUSP_CLR; + writel(val, base + USB_SUSP_CTRL); + + val = 0; + writel(val, base + ULPI_TIMING_CTRL_1); + + ulpi_set_trimmer(phy); + + /* Fix VbusInvalid due to floating VBUS */ + ret = otg_io_write(phy->ulpi_vp, 0x40, 0x08); + if (ret) { + pr_err("%s: ulpi write failed\n", __func__); + return ret; + } + + ret = otg_io_write(phy->ulpi_vp, 0x80, 0x0B); + if (ret) { + pr_err("%s: ulpi write failed\n", __func__); + return ret; + } + + val = readl(base + USB_PORTSC); + val |= USB_PORTSC_WKOC | USB_PORTSC_WKDS | USB_PORTSC_WKCN; + writel(val, base + USB_PORTSC); + + phy->phy_clk_on = true; + phy->hw_accessible = true; + + return 0; +} + +static inline void ulpi_link_phy_set_tristate(bool enable) +{ +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + int tristate = (enable) ? TEGRA_TRI_TRISTATE : TEGRA_TRI_NORMAL; + + tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, tristate); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, tristate); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, tristate); +#endif +} + +static void ulpi_link_phy_restore_start(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + /*Tristate ulpi interface before USB controller resume*/ + ulpi_link_phy_set_tristate(true); + + val = readl(base + ULPI_TIMING_CTRL_0); + val &= ~ULPI_OUTPUT_PINMUX_BYP; + writel(val, base + ULPI_TIMING_CTRL_0); +} + +static void ulpi_link_phy_restore_end(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + val = readl(base + ULPI_TIMING_CTRL_0); + val |= ULPI_OUTPUT_PINMUX_BYP; + writel(val, base + ULPI_TIMING_CTRL_0); + + ulpi_link_phy_set_tristate(false); +} + +static int ulpi_link_phy_resume(struct tegra_usb_phy *phy) +{ + int status = 0; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + if (phy->pdata->u_data.host.power_off_on_suspend) { + status = ulpi_link_phy_power_on(phy); + if (phy->port_speed < USB_PHY_PORT_SPEED_UNKNOWN) { + ulpi_link_phy_restore_start(phy); + usb_phy_bringup_host_controller(phy); + ulpi_link_phy_restore_end(phy); + } + } + + return status; +} + +static struct tegra_usb_phy_ops utmi_phy_ops = { + .open = utmi_phy_open, + .close = utmi_phy_close, + .irq = utmi_phy_irq, + .power_on = utmi_phy_power_on, + .power_off = utmi_phy_power_off, + .pre_resume = utmi_phy_pre_resume, + .resume = utmi_phy_resume, + .post_resume = utmi_phy_post_resume, + .charger_detect = utmi_phy_charger_detect, +}; + +static struct tegra_usb_phy_ops uhsic_phy_ops = { + .open = uhsic_phy_open, + .irq = uhsic_phy_irq, + .power_on = uhsic_phy_power_on, + .power_off = uhsic_phy_power_off, + .pre_resume = uhsic_phy_pre_resume, + .resume = uhsic_phy_resume, + .post_resume = uhsic_phy_post_resume, + .port_power = uhsic_phy_bus_port_power, + .bus_reset = uhsic_phy_bus_reset, +}; + +static struct tegra_usb_phy_ops ulpi_link_phy_ops = { + .open = ulpi_link_phy_open, + .close = ulpi_link_phy_close, + .irq = ulpi_link_phy_irq, + .power_on = ulpi_link_phy_power_on, + .power_off = ulpi_link_phy_power_off, + .resume = ulpi_link_phy_resume, +}; + +static struct tegra_usb_phy_ops ulpi_null_phy_ops; +static struct tegra_usb_phy_ops icusb_phy_ops; + + +static struct tegra_usb_phy_ops *phy_ops[] = { + [TEGRA_USB_PHY_INTF_UTMI] = &utmi_phy_ops, + [TEGRA_USB_PHY_INTF_ULPI_LINK] = &ulpi_link_phy_ops, + [TEGRA_USB_PHY_INTF_ULPI_NULL] = &ulpi_null_phy_ops, + [TEGRA_USB_PHY_INTF_HSIC] = &uhsic_phy_ops, + [TEGRA_USB_PHY_INTF_ICUSB] = &icusb_phy_ops, +}; + +int tegra2_usb_phy_init_ops(struct tegra_usb_phy *phy) +{ + phy->ops = phy_ops[phy->pdata->phy_intf]; + + return 0; +} diff --git a/arch/arm/mach-tegra/tegra3_clocks.c b/arch/arm/mach-tegra/tegra3_clocks.c index 2dfdb1db39b7..9ff183377c2d 100644 --- a/arch/arm/mach-tegra/tegra3_clocks.c +++ b/arch/arm/mach-tegra/tegra3_clocks.c @@ -284,7 +284,7 @@ #define PLLE_SS_COEFFICIENTS_12MHZ \ ((0x18<<PLLE_SS_INCINTRV_SHIFT) | (0x1<<PLLE_SS_INC_SHIFT) | \ (0x24<<PLLE_SS_MAX_SHIFT)) -#define PLLE_SS_DISABLE ((1<<12) | (1<<11) | (1<<10)) +#define PLLE_SS_DISABLE ((1<<14) | (1<<12) | (1<<11) | (1<<10)) #define PLLE_AUX 0x48c #define PLLE_AUX_PLLP_SEL (1<<2) @@ -3906,7 +3906,7 @@ static struct clk tegra_clk_sclk = { .reg = 0x28, .ops = &tegra_super_ops, .max_rate = 378000000, - .min_rate = 40000000, + .min_rate = 12000000, }; static struct clk tegra_clk_virtual_cpu_g = { @@ -3961,7 +3961,7 @@ static struct clk tegra_clk_hclk = { .reg_shift = 4, .ops = &tegra_bus_ops, .max_rate = 378000000, - .min_rate = 40000000, + .min_rate = 12000000, }; static struct clk tegra_clk_pclk = { @@ -3972,7 +3972,7 @@ static struct clk tegra_clk_pclk = { .reg_shift = 0, .ops = &tegra_bus_ops, .max_rate = 167000000, - .min_rate = 40000000, + .min_rate = 12000000, }; static struct raw_notifier_head sbus_rate_change_nh; diff --git a/arch/arm/mach-tegra/tegra3_usb_phy.c b/arch/arm/mach-tegra/tegra3_usb_phy.c new file mode 100644 index 000000000000..5b3e51974d3b --- /dev/null +++ b/arch/arm/mach-tegra/tegra3_usb_phy.c @@ -0,0 +1,2409 @@ +/* + * arch/arm/mach-tegra/tegra3_usb_phy.c + * + * Copyright (C) 2011 NVIDIA 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. + * + */ +#include <linux/resource.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/clk.h> +#include <linux/regulator/consumer.h> +#include <linux/platform_data/tegra_usb.h> +#include <mach/iomap.h> +#include <mach/pinmux.h> +#include "tegra_usb_phy.h" +#include "fuse.h" + +#define USB_USBCMD 0x130 +#define USB_USBCMD_RS (1 << 0) +#define USB_CMD_RESET (1<<1) + +#define USB_USBSTS 0x134 +#define USB_USBSTS_PCI (1 << 2) +#define USB_USBSTS_SRI (1 << 7) +#define USB_USBSTS_HCH (1 << 12) + +#define USB_USBINTR 0x138 + +#define USB_TXFILLTUNING 0x154 +#define USB_FIFO_TXFILL_THRES(x) (((x) & 0x1f) << 16) +#define USB_FIFO_TXFILL_MASK 0x1f0000 + +#define USB_ASYNCLISTADDR 0x148 + +#define ICUSB_CTRL 0x15c + +#define USB_PORTSC 0x174 +#define USB_PORTSC_WKOC (1 << 22) +#define USB_PORTSC_WKDS (1 << 21) +#define USB_PORTSC_WKCN (1 << 20) +#define USB_PORTSC_PTC(x) (((x) & 0xf) << 16) +#define USB_PORTSC_PP (1 << 12) +#define USB_PORTSC_LS(x) (((x) & 0x3) << 10) +#define USB_PORTSC_SUSP (1 << 7) +#define USB_PORTSC_RESUME (1 << 6) +#define USB_PORTSC_OCC (1 << 5) +#define USB_PORTSC_PEC (1 << 3) +#define USB_PORTSC_PE (1 << 2) +#define USB_PORTSC_CSC (1 << 1) +#define USB_PORTSC_CCS (1 << 0) +#define USB_PORTSC_RWC_BITS (USB_PORTSC_CSC | USB_PORTSC_PEC | USB_PORTSC_OCC) + +#define HOSTPC1_DEVLC 0x1b4 +#define HOSTPC1_DEVLC_PHCD (1 << 22) +#define HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29) +#define HOSTPC1_DEVLC_PTS_MASK 7 +#define HOSTPC1_DEVLC_PTS_HSIC 4 +#define HOSTPC1_DEVLC_STS (1 << 28) +#define HOSTPC1_DEVLC_PSPD(x) (((x) & 0x3) << 25) +#define HOSTPC1_DEVLC_PSPD_MASK 3 +#define HOSTPC1_DEVLC_PSPD_HIGH_SPEED 2 + +#define USB_USBMODE 0x1f8 +#define USB_USBMODE_MASK (3 << 0) +#define USB_USBMODE_HOST (3 << 0) +#define USB_USBMODE_DEVICE (2 << 0) + +#define USB_SUSP_CTRL 0x400 +#define USB_WAKE_ON_CNNT_EN_DEV (1 << 3) +#define USB_WAKE_ON_DISCON_EN_DEV (1 << 4) +#define USB_SUSP_CLR (1 << 5) +#define USB_PHY_CLK_VALID (1 << 7) +#define USB_PHY_CLK_VALID_INT_ENB (1 << 9) +#define USB_PHY_CLK_VALID_INT_STS (1 << 8) +#define UTMIP_RESET (1 << 11) +#define UTMIP_PHY_ENABLE (1 << 12) +#define ULPI_PHY_ENABLE (1 << 13) +#define UHSIC_RESET (1 << 14) +#define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16) +#define UHSIC_PHY_ENABLE (1 << 19) +#define ULPIS2S_SLV0_RESET (1 << 20) +#define ULPIS2S_SLV1_RESET (1 << 21) +#define ULPIS2S_LINE_RESET (1 << 22) +#define ULPI_PADS_RESET (1 << 23) +#define ULPI_PADS_CLKEN_RESET (1 << 24) + +#define USB_PHY_VBUS_WAKEUP_ID 0x408 +#define VDAT_DET_INT_EN (1 << 16) +#define VDAT_DET_CHG_DET (1 << 17) +#define VDAT_DET_STS (1 << 18) +#define USB_ID_STATUS (1 << 2) + +#define ULPIS2S_CTRL 0x418 +#define ULPIS2S_ENA (1 << 0) +#define ULPIS2S_SUPPORT_DISCONNECT (1 << 2) +#define ULPIS2S_PLLU_MASTER_BLASTER60 (1 << 3) +#define ULPIS2S_SPARE(x) (((x) & 0xF) << 8) +#define ULPIS2S_FORCE_ULPI_CLK_OUT (1 << 12) +#define ULPIS2S_DISCON_DONT_CHECK_SE0 (1 << 13) +#define ULPIS2S_SUPPORT_HS_KEEP_ALIVE (1 << 14) +#define ULPIS2S_DISABLE_STP_PU (1 << 15) +#define ULPIS2S_SLV0_CLAMP_XMIT (1 << 16) + +#define ULPI_TIMING_CTRL_0 0x424 +#define ULPI_CLOCK_OUT_DELAY(x) ((x) & 0x1F) +#define ULPI_OUTPUT_PINMUX_BYP (1 << 10) +#define ULPI_CLKOUT_PINMUX_BYP (1 << 11) +#define ULPI_SHADOW_CLK_LOOPBACK_EN (1 << 12) +#define ULPI_SHADOW_CLK_SEL (1 << 13) +#define ULPI_CORE_CLK_SEL (1 << 14) +#define ULPI_SHADOW_CLK_DELAY(x) (((x) & 0x1F) << 16) +#define ULPI_LBK_PAD_EN (1 << 26) +#define ULPI_LBK_PAD_E_INPUT_OR (1 << 27) +#define ULPI_CLK_OUT_ENA (1 << 28) +#define ULPI_CLK_PADOUT_ENA (1 << 29) + +#define ULPI_TIMING_CTRL_1 0x428 +#define ULPI_DATA_TRIMMER_LOAD (1 << 0) +#define ULPI_DATA_TRIMMER_SEL(x) (((x) & 0x7) << 1) +#define ULPI_STPDIRNXT_TRIMMER_LOAD (1 << 16) +#define ULPI_STPDIRNXT_TRIMMER_SEL(x) (((x) & 0x7) << 17) +#define ULPI_DIR_TRIMMER_LOAD (1 << 24) +#define ULPI_DIR_TRIMMER_SEL(x) (((x) & 0x7) << 25) + +#define UTMIP_XCVR_CFG0 0x808 +#define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0) +#define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8) +#define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10) +#define UTMIP_FORCE_PD_POWERDOWN (1 << 14) +#define UTMIP_FORCE_PD2_POWERDOWN (1 << 16) +#define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18) +#define UTMIP_XCVR_LSBIAS_SEL (1 << 21) +#define UTMIP_XCVR_SETUP_MSB(x) (((x) & 0x7) << 22) +#define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25) +#define UTMIP_XCVR_MAX_OFFSET 2 +#define UTMIP_XCVR_SETUP_MAX_VALUE 0x7f +#define UTMIP_XCVR_SETUP_MIN_VALUE 0 +#define XCVR_SETUP_MSB_CALIB(x) ((x) >> 4) + +#define UTMIP_BIAS_CFG0 0x80c +#define UTMIP_OTGPD (1 << 11) +#define UTMIP_BIASPD (1 << 10) +#define UTMIP_HSSQUELCH_LEVEL(x) (((x) & 0x3) << 0) +#define UTMIP_HSDISCON_LEVEL(x) (((x) & 0x3) << 2) +#define UTMIP_HSDISCON_LEVEL_MSB (1 << 24) + +#define UTMIP_HSRX_CFG0 0x810 +#define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10) +#define UTMIP_IDLE_WAIT(x) (((x) & 0x1f) << 15) + +#define UTMIP_HSRX_CFG1 0x814 +#define UTMIP_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1) + +#define UTMIP_TX_CFG0 0x820 +#define UTMIP_FS_PREABMLE_J (1 << 19) +#define UTMIP_HS_DISCON_DISABLE (1 << 8) + +#define UTMIP_DEBOUNCE_CFG0 0x82c +#define UTMIP_BIAS_DEBOUNCE_A(x) (((x) & 0xffff) << 0) + +#define UTMIP_BAT_CHRG_CFG0 0x830 +#define UTMIP_PD_CHRG (1 << 0) +#define UTMIP_ON_SINK_EN (1 << 2) +#define UTMIP_OP_SRC_EN (1 << 3) + +#define UTMIP_XCVR_CFG1 0x838 +#define UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0) +#define UTMIP_FORCE_PDCHRP_POWERDOWN (1 << 2) +#define UTMIP_FORCE_PDDR_POWERDOWN (1 << 4) +#define UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18) + +#define UTMIP_BIAS_CFG1 0x83c +#define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3) +#define UTMIP_BIAS_PDTRK_POWERDOWN (1 << 0) +#define UTMIP_BIAS_PDTRK_POWERUP (1 << 1) + +#define UTMIP_MISC_CFG0 0x824 +#define UTMIP_DPDM_OBSERVE (1 << 26) +#define UTMIP_DPDM_OBSERVE_SEL(x) (((x) & 0xf) << 27) +#define UTMIP_DPDM_OBSERVE_SEL_FS_J UTMIP_DPDM_OBSERVE_SEL(0xf) +#define UTMIP_DPDM_OBSERVE_SEL_FS_K UTMIP_DPDM_OBSERVE_SEL(0xe) +#define UTMIP_DPDM_OBSERVE_SEL_FS_SE1 UTMIP_DPDM_OBSERVE_SEL(0xd) +#define UTMIP_DPDM_OBSERVE_SEL_FS_SE0 UTMIP_DPDM_OBSERVE_SEL(0xc) +#define UTMIP_SUSPEND_EXIT_ON_EDGE (1 << 22) +#define FORCE_PULLDN_DM (1 << 8) +#define FORCE_PULLDN_DP (1 << 9) +#define COMB_TERMS (1 << 0) +#define ALWAYS_FREE_RUNNING_TERMS (1 << 1) + +#define UTMIP_SPARE_CFG0 0x834 +#define FUSE_SETUP_SEL (1 << 3) +#define FUSE_ATERM_SEL (1 << 4) + +#define UTMIP_PMC_WAKEUP0 0x84c +#define EVENT_INT_ENB (1 << 0) + +#define UTMIP_BIAS_STS0 0x840 +#define UTMIP_RCTRL_VAL(x) (((x) & 0xffff) << 0) +#define UTMIP_TCTRL_VAL(x) (((x) & (0xffff << 16)) >> 16) + +#define UHSIC_PLL_CFG1 0xc04 +#define UHSIC_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0) +#define UHSIC_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 14) + +#define UHSIC_HSRX_CFG0 0xc08 +#define UHSIC_ELASTIC_UNDERRUN_LIMIT(x) (((x) & 0x1f) << 2) +#define UHSIC_ELASTIC_OVERRUN_LIMIT(x) (((x) & 0x1f) << 8) +#define UHSIC_IDLE_WAIT(x) (((x) & 0x1f) << 13) + +#define UHSIC_HSRX_CFG1 0xc0c +#define UHSIC_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1) + +#define UHSIC_TX_CFG0 0xc10 +#define UHSIC_HS_READY_WAIT_FOR_VALID (1 << 9) +#define UHSIC_MISC_CFG0 0xc14 +#define UHSIC_SUSPEND_EXIT_ON_EDGE (1 << 7) +#define UHSIC_DETECT_SHORT_CONNECT (1 << 8) +#define UHSIC_FORCE_XCVR_MODE (1 << 15) +#define UHSIC_DISABLE_BUSRESET (1 << 20) +#define UHSIC_MISC_CFG1 0xc18 +#define UHSIC_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 2) + +#define UHSIC_PADS_CFG0 0xc1c +#define UHSIC_TX_RTUNEN 0xf000 +#define UHSIC_TX_RTUNE(x) (((x) & 0xf) << 12) + +#define UHSIC_PADS_CFG1 0xc20 +#define UHSIC_PD_BG (1 << 2) +#define UHSIC_PD_TX (1 << 3) +#define UHSIC_PD_TRK (1 << 4) +#define UHSIC_PD_RX (1 << 5) +#define UHSIC_PD_ZI (1 << 6) +#define UHSIC_RX_SEL (1 << 7) +#define UHSIC_RPD_DATA (1 << 9) +#define UHSIC_RPD_STROBE (1 << 10) +#define UHSIC_RPU_DATA (1 << 11) +#define UHSIC_RPU_STROBE (1 << 12) + +#define UHSIC_STAT_CFG0 0xc28 +#define UHSIC_CONNECT_DETECT (1 << 0) + +#define PMC_USB_DEBOUNCE 0xec +#define UTMIP_LINE_DEB_CNT(x) (((x) & 0xf) << 16) + +#define PMC_USB_AO 0xf0 +#define PMC_POWER_DOWN_MASK 0xffff +#define HSIC_RESERVED_P0 (3 << 14) +#define HSIC_STOBE_VAL_PD_P0 (1 << 13) +#define HSIC_DATA_VAL_PD_P0 (1 << 12) +#define USB_ID_PD(inst) (1 << ((4*(inst))+3)) +#define VBUS_WAKEUP_PD(inst) (1 << ((4*(inst))+2)) +#define USBON_VAL_PD(inst) (1 << ((4*(inst))+1)) +#define USBON_VAL_PD_P2 (1 << 9) +#define USBON_VAL_PD_P1 (1 << 5) +#define USBON_VAL_PD_P0 (1 << 1) +#define USBOP_VAL_PD(inst) (1 << (4*(inst))) +#define USBOP_VAL_PD_P2 (1 << 8) +#define USBOP_VAL_PD_P1 (1 << 4) +#define USBOP_VAL_PD_P0 (1 << 0) +#define PMC_USB_AO_PD_P2 (0xf << 8) +#define PMC_USB_AO_ID_PD_P0 (1 << 3) +#define PMC_USB_AO_VBUS_WAKEUP_PD_P0 (1 << 2) + +#define PMC_TRIGGERS 0x1ec +#define UTMIP_CLR_WALK_PTR(inst) (1 << (inst)) +#define UTMIP_CLR_WALK_PTR_P2 (1 << 2) +#define UTMIP_CLR_WALK_PTR_P1 (1 << 1) +#define UTMIP_CLR_WALK_PTR_P0 (1 << 0) +#define UTMIP_CAP_CFG(inst) (1 << ((inst)+4)) +#define UTMIP_CAP_CFG_P2 (1 << 6) +#define UTMIP_CAP_CFG_P1 (1 << 5) +#define UTMIP_CAP_CFG_P0 (1 << 4) +#define UTMIP_CLR_WAKE_ALARM(inst) (1 << ((inst)+12)) +#define UTMIP_CLR_WAKE_ALARM_P2 (1 << 14) + +#define PMC_PAD_CFG (0x1f4) + +#define PMC_UTMIP_TERM_PAD_CFG 0x1f8 +#define PMC_TCTRL_VAL(x) (((x) & 0x1f) << 5) +#define PMC_RCTRL_VAL(x) (((x) & 0x1f) << 0) + +#define UHSIC_SLEEPWALK_REG 0x210 +#define UHSIC_DATA_RPD_D (1 << 25) +#define UHSIC_STRB_RPD_D (1 << 24) +#define UHSIC_DATA_RPD_C (1 << 17) +#define UHSIC_STRB_RPD_C (1 << 16) +#define UHSIC_DATA_RPD_B (1 << 9) +#define UHSIC_STRB_RPD_B (1 << 8) +#define UHSIC_DATA_RPD_A (1 << 1) +#define UHSIC_STRB_RPD_A (1 << 0) + +#define PMC_SLEEP_CFG 0x1fc +#define UTMIP_TCTRL_USE_PMC(inst) (1 << ((8*(inst))+3)) +#define UTMIP_TCTRL_USE_PMC_P2 (1 << 19) +#define UTMIP_TCTRL_USE_PMC_P1 (1 << 11) +#define UTMIP_TCTRL_USE_PMC_P0 (1 << 3) +#define UTMIP_RCTRL_USE_PMC(inst) (1 << ((8*(inst))+2)) +#define UTMIP_RCTRL_USE_PMC_P2 (1 << 18) +#define UTMIP_RCTRL_USE_PMC_P1 (1 << 10) +#define UTMIP_RCTRL_USE_PMC_P0 (1 << 2) +#define UTMIP_FSLS_USE_PMC(inst) (1 << ((8*(inst))+1)) +#define UTMIP_FSLS_USE_PMC_P2 (1 << 17) +#define UTMIP_FSLS_USE_PMC_P1 (1 << 9) +#define UTMIP_FSLS_USE_PMC_P0 (1 << 1) +#define UTMIP_MASTER_ENABLE(inst) (1 << (8*(inst))) +#define UTMIP_MASTER_ENABLE_P2 (1 << 16) +#define UTMIP_MASTER_ENABLE_P1 (1 << 8) +#define UTMIP_MASTER_ENABLE_P0 (1 << 0) +#define UHSIC_MASTER_ENABLE_P0 (1 << 24) +#define UHSIC_WAKE_VAL_P0(x) (((x) & 0xf) << 28) + +#define PMC_SLEEPWALK_CFG 0x200 +#define UTMIP_LINEVAL_WALK_EN(inst) (1 << ((8*(inst))+7)) +#define UTMIP_LINEVAL_WALK_EN_P2 (1 << 23) +#define UTMIP_LINEVAL_WALK_EN_P1 (1 << 15) +#define UTMIP_LINEVAL_WALK_EN_P0 (1 << 7) +#define UTMIP_WAKE_VAL(inst, x) (((x) & 0xf) << ((8*(inst))+4)) +#define UTMIP_WAKE_VAL_P2(x) (((x) & 0xf) << 20) +#define UTMIP_WAKE_VAL_P1(x) (((x) & 0xf) << 12) +#define UTMIP_WAKE_VAL_P0(x) (((x) & 0xf) << 4) +#define WAKE_VAL_NONE 0xc +#define WAKE_VAL_ANY 0xF +#define WAKE_VAL_FSJ 0x2 +#define WAKE_VAL_FSK 0x1 +#define WAKE_VAL_SE0 0x0 + +#define PMC_SLEEPWALK_REG(inst) (0x204 + (4*(inst))) +#define UTMIP_USBOP_RPD_A (1 << 0) +#define UTMIP_USBON_RPD_A (1 << 1) +#define UTMIP_AP_A (1 << 4) +#define UTMIP_AN_A (1 << 5) +#define UTMIP_HIGHZ_A (1 << 6) +#define UTMIP_USBOP_RPD_B (1 << 8) +#define UTMIP_USBON_RPD_B (1 << 9) +#define UTMIP_AP_B (1 << 12) +#define UTMIP_AN_B (1 << 13) +#define UTMIP_HIGHZ_B (1 << 14) +#define UTMIP_USBOP_RPD_C (1 << 16) +#define UTMIP_USBON_RPD_C (1 << 17) +#define UTMIP_AP_C (1 << 20) +#define UTMIP_AN_C (1 << 21) +#define UTMIP_HIGHZ_C (1 << 22) +#define UTMIP_USBOP_RPD_D (1 << 24) +#define UTMIP_USBON_RPD_D (1 << 25) +#define UTMIP_AP_D (1 << 28) +#define UTMIP_AN_D (1 << 29) +#define UTMIP_HIGHZ_D (1 << 30) + +#define UTMIP_UHSIC_STATUS 0x214 +#define UTMIP_WALK_PTR_VAL(inst) (0x3 << ((inst)*2)) +#define UTMIP_USBOP_VAL(inst) (1 << ((2*(inst)) + 8)) +#define UTMIP_USBOP_VAL_P2 (1 << 12) +#define UTMIP_USBOP_VAL_P1 (1 << 10) +#define UTMIP_USBOP_VAL_P0 (1 << 8) +#define UTMIP_USBON_VAL(inst) (1 << ((2*(inst)) + 9)) +#define UTMIP_USBON_VAL_P2 (1 << 13) +#define UTMIP_USBON_VAL_P1 (1 << 11) +#define UTMIP_USBON_VAL_P0 (1 << 9) +#define UTMIP_WAKE_ALARM(inst) (1 << ((inst) + 16)) +#define UTMIP_WAKE_ALARM_P2 (1 << 18) +#define UTMIP_WAKE_ALARM_P1 (1 << 17) +#define UTMIP_WAKE_ALARM_P0 (1 << 16) +#define UTMIP_WALK_PTR(inst) (1 << ((inst)*2)) +#define UTMIP_WALK_PTR_P2 (1 << 4) +#define UTMIP_WALK_PTR_P1 (1 << 2) +#define UTMIP_WALK_PTR_P0 (1 << 0) + +#define USB1_PREFETCH_ID 6 +#define USB2_PREFETCH_ID 18 +#define USB3_PREFETCH_ID 17 + +#define PMC_UTMIP_UHSIC_FAKE 0x218 +#define USBON_VAL(inst) (1 << ((4*(inst))+1)) +#define USBON_VAL_P2 (1 << 9) +#define USBON_VAL_P1 (1 << 5) +#define USBON_VAL_P0 (1 << 1) +#define USBOP_VAL(inst) (1 << (4*(inst))) +#define USBOP_VAL_P2 (1 << 8) +#define USBOP_VAL_P1 (1 << 4) +#define USBOP_VAL_P0 (1 << 0) + +#define PMC_UTMIP_BIAS_MASTER_CNTRL 0x30c +#define BIAS_MASTER_PROG_VAL (1 << 1) + +#define PMC_UTMIP_MASTER_CONFIG 0x310 +#define UTMIP_PWR(inst) (1 << (inst)) + +#define FUSE_USB_CALIB_0 0x1F0 +#define FUSE_USB_CALIB_XCVR_SETUP(x) (((x) & 0x7F) << 0) + +/* These values (in milli second) are taken from the battery charging spec */ +#define TDP_SRC_ON_MS 100 +#define TDPSRC_CON_MS 40 + +#ifdef DEBUG +#define DBG(stuff...) pr_info("tegra3_usb_phy: " stuff) +#else +#define DBG(stuff...) do {} while (0) +#endif + +#if 0 +#define PHY_DBG(stuff...) pr_info("tegra3_usb_phy: " stuff) +#else +#define PHY_DBG(stuff...) do {} while (0) +#endif + +static u32 utmip_rctrl_val, utmip_tctrl_val; +static DEFINE_SPINLOCK(utmip_pad_lock); +static int utmip_pad_count; + +static struct tegra_xtal_freq utmip_freq_table[] = { + { + .freq = 12000000, + .enable_delay = 0x02, + .stable_count = 0x2F, + .active_delay = 0x04, + .xtal_freq_count = 0x76, + .debounce = 0x7530, + .pdtrk_count = 5, + }, + { + .freq = 13000000, + .enable_delay = 0x02, + .stable_count = 0x33, + .active_delay = 0x05, + .xtal_freq_count = 0x7F, + .debounce = 0x7EF4, + .pdtrk_count = 5, + }, + { + .freq = 19200000, + .enable_delay = 0x03, + .stable_count = 0x4B, + .active_delay = 0x06, + .xtal_freq_count = 0xBB, + .debounce = 0xBB80, + .pdtrk_count = 7, + }, + { + .freq = 26000000, + .enable_delay = 0x04, + .stable_count = 0x66, + .active_delay = 0x09, + .xtal_freq_count = 0xFE, + .debounce = 0xFDE8, + .pdtrk_count = 9, + }, +}; + +static struct tegra_xtal_freq uhsic_freq_table[] = { + { + .freq = 12000000, + .enable_delay = 0x02, + .stable_count = 0x2F, + .active_delay = 0x0, + .xtal_freq_count = 0x1CA, + }, + { + .freq = 13000000, + .enable_delay = 0x02, + .stable_count = 0x33, + .active_delay = 0x0, + .xtal_freq_count = 0x1F0, + }, + { + .freq = 19200000, + .enable_delay = 0x03, + .stable_count = 0x4B, + .active_delay = 0x0, + .xtal_freq_count = 0x2DD, + }, + { + .freq = 26000000, + .enable_delay = 0x04, + .stable_count = 0x66, + .active_delay = 0x0, + .xtal_freq_count = 0x3E0, + }, +}; + +static void usb_phy_fence_read(struct tegra_usb_phy *phy) +{ + /* Fence read for coherency of AHB master intiated writes */ + if (phy->inst == 0) + readb(IO_ADDRESS(IO_PPCS_PHYS + USB1_PREFETCH_ID)); + else if (phy->inst == 1) + readb(IO_ADDRESS(IO_PPCS_PHYS + USB2_PREFETCH_ID)); + else if (phy->inst == 2) + readb(IO_ADDRESS(IO_PPCS_PHYS + USB3_PREFETCH_ID)); + + return; +} + +static void utmip_setup_pmc_wake_detect(struct tegra_usb_phy *phy) +{ + unsigned long val, pmc_pad_cfg_val; + void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); + unsigned int inst = phy->inst; + void __iomem *base = phy->regs; + bool port_connected; + enum usb_phy_port_speed port_speed; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + /* check for port connect status */ + val = readl(base + USB_PORTSC); + port_connected = val & USB_PORTSC_CCS; + + if (!port_connected) + return; + + port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) & + HOSTPC1_DEVLC_PSPD_MASK; + /*Set PMC MASTER bits to do the following + * a. Take over the UTMI drivers + * b. set up such that it will take over resume + * if remote wakeup is detected + * Prepare PMC to take over suspend-wake detect-drive resume until USB + * controller ready + */ + + /* disable master enable in PMC */ + val = readl(pmc_base + PMC_SLEEP_CFG); + val &= ~UTMIP_MASTER_ENABLE(inst); + writel(val, pmc_base + PMC_SLEEP_CFG); + + /* UTMIP_PWR_PX=1 for power savings mode */ + val = readl(pmc_base + PMC_UTMIP_MASTER_CONFIG); + val |= UTMIP_PWR(inst); + writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG); + + /* config debouncer */ + val = readl(pmc_base + PMC_USB_DEBOUNCE); + val &= ~UTMIP_LINE_DEB_CNT(~0); + val |= UTMIP_LINE_DEB_CNT(4); + writel(val, pmc_base + PMC_USB_DEBOUNCE); + + /* Make sure nothing is happening on the line with respect to PMC */ + val = readl(pmc_base + PMC_UTMIP_UHSIC_FAKE); + val &= ~USBOP_VAL(inst); + val &= ~USBON_VAL(inst); + writel(val, pmc_base + PMC_UTMIP_UHSIC_FAKE); + + /* Make sure wake value for line is none */ + val = readl(pmc_base + PMC_SLEEPWALK_CFG); + val &= ~UTMIP_LINEVAL_WALK_EN(inst); + writel(val, pmc_base + PMC_SLEEPWALK_CFG); + val = readl(pmc_base + PMC_SLEEP_CFG); + val &= ~UTMIP_WAKE_VAL(inst, ~0); + val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE); + writel(val, pmc_base + PMC_SLEEP_CFG); + + /* turn off pad detectors */ + val = readl(pmc_base + PMC_USB_AO); + val |= (USBOP_VAL_PD(inst) | USBON_VAL_PD(inst)); + writel(val, pmc_base + PMC_USB_AO); + + /* Remove fake values and make synchronizers work a bit */ + val = readl(pmc_base + PMC_UTMIP_UHSIC_FAKE); + val &= ~USBOP_VAL(inst); + val &= ~USBON_VAL(inst); + writel(val, pmc_base + PMC_UTMIP_UHSIC_FAKE); + + /* Enable which type of event can trigger a walk, + in this case usb_line_wake */ + val = readl(pmc_base + PMC_SLEEPWALK_CFG); + val |= UTMIP_LINEVAL_WALK_EN(inst); + writel(val, pmc_base + PMC_SLEEPWALK_CFG); + + /* Enable which type of event can trigger a walk, + * in this case usb_line_wake */ + val = readl(pmc_base + PMC_SLEEPWALK_CFG); + val |= UTMIP_LINEVAL_WALK_EN(inst); + writel(val, pmc_base + PMC_SLEEPWALK_CFG); + + /* Clear the walk pointers and wake alarm */ + val = readl(pmc_base + PMC_TRIGGERS); + val |= UTMIP_CLR_WAKE_ALARM(inst) | UTMIP_CLR_WALK_PTR(inst); + writel(val, pmc_base + PMC_TRIGGERS); + + + /* Capture FS/LS pad configurations */ + pmc_pad_cfg_val = readl(pmc_base + PMC_PAD_CFG); + val = readl(pmc_base + PMC_TRIGGERS); + val |= UTMIP_CAP_CFG(inst); + writel(val, pmc_base + PMC_TRIGGERS); + udelay(1); + pmc_pad_cfg_val = readl(pmc_base + PMC_PAD_CFG); + + /* BIAS MASTER_ENABLE=0 */ + val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL); + val &= ~BIAS_MASTER_PROG_VAL; + writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL); + + /* program walk sequence, maintain a J, followed by a driven K + * to signal a resume once an wake event is detected */ + val = readl(pmc_base + PMC_SLEEPWALK_REG(inst)); + val &= ~UTMIP_AP_A; + val |= UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A | UTMIP_AN_A |UTMIP_HIGHZ_A | + UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_AP_B | UTMIP_AN_B | + UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_AP_C | UTMIP_AN_C | + UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_AP_D | UTMIP_AN_D; + writel(val, pmc_base + PMC_SLEEPWALK_REG(inst)); + + if (port_speed == USB_PHY_PORT_SPEED_LOW) { + val = readl(pmc_base + PMC_SLEEPWALK_REG(inst)); + val &= ~(UTMIP_AN_B | UTMIP_HIGHZ_B | UTMIP_AN_C | + UTMIP_HIGHZ_C | UTMIP_AN_D | UTMIP_HIGHZ_D); + writel(val, pmc_base + PMC_SLEEPWALK_REG(inst)); + } else { + val = readl(pmc_base + PMC_SLEEPWALK_REG(inst)); + val &= ~(UTMIP_AP_B | UTMIP_HIGHZ_B | UTMIP_AP_C | + UTMIP_HIGHZ_C | UTMIP_AP_D | UTMIP_HIGHZ_D); + writel(val, pmc_base + PMC_SLEEPWALK_REG(inst)); + } + + /* turn on pad detectors */ + val = readl(pmc_base + PMC_USB_AO); + val &= ~(USBOP_VAL_PD(inst) | USBON_VAL_PD(inst)); + writel(val, pmc_base + PMC_USB_AO); + + /* Add small delay before usb detectors provide stable line values */ + mdelay(1); + + /* Program thermally encoded RCTRL_VAL, TCTRL_VAL into PMC space */ + val = readl(pmc_base + PMC_UTMIP_TERM_PAD_CFG); + val = PMC_TCTRL_VAL(utmip_tctrl_val) | PMC_RCTRL_VAL(utmip_rctrl_val); + writel(val, pmc_base + PMC_UTMIP_TERM_PAD_CFG); + + phy->remote_wakeup = false; + + /* Turn over pad configuration to PMC for line wake events*/ + val = readl(pmc_base + PMC_SLEEP_CFG); + val &= ~UTMIP_WAKE_VAL(inst, ~0); + val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_ANY); + val |= UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst); + val |= UTMIP_MASTER_ENABLE(inst) | UTMIP_FSLS_USE_PMC(inst); + writel(val, pmc_base + PMC_SLEEP_CFG); + + val = readl(base + UTMIP_PMC_WAKEUP0); + val |= EVENT_INT_ENB; + writel(val, base + UTMIP_PMC_WAKEUP0); + PHY_DBG("%s ENABLE_PMC inst = %d\n", __func__, inst); +} + +static void utmip_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); + unsigned int inst = phy->inst; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + val = readl(pmc_base + PMC_SLEEP_CFG); + val &= ~UTMIP_WAKE_VAL(inst, 0xF); + val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE); + writel(val, pmc_base + PMC_SLEEP_CFG); + + val = readl(pmc_base + PMC_TRIGGERS); + val |= UTMIP_CLR_WAKE_ALARM(inst) | UTMIP_CLR_WALK_PTR(inst); + writel(val, pmc_base + PMC_TRIGGERS); + + val = readl(base + UTMIP_PMC_WAKEUP0); + val &= ~EVENT_INT_ENB; + writel(val, base + UTMIP_PMC_WAKEUP0); + + /* Disable PMC master mode by clearing MASTER_EN */ + val = readl(pmc_base + PMC_SLEEP_CFG); + val &= ~(UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) | + UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst)); + writel(val, pmc_base + PMC_SLEEP_CFG); + + val = readl(pmc_base + PMC_TRIGGERS); + val &= ~UTMIP_CAP_CFG(inst); + writel(val, pmc_base + PMC_TRIGGERS); + + /* turn off pad detectors */ + val = readl(pmc_base + PMC_USB_AO); + val |= (USBOP_VAL_PD(inst) | USBON_VAL_PD(inst)); + writel(val, pmc_base + PMC_USB_AO); + + phy->remote_wakeup = false; + PHY_DBG("%s DISABLE_PMC inst = %d\n", __func__, inst); +} + +bool utmi_phy_remotewake_detected(struct tegra_usb_phy *phy) +{ + void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); + void __iomem *base = phy->regs; + unsigned int inst = phy->inst; + u32 val; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + val = readl(base + UTMIP_PMC_WAKEUP0); + if (val & EVENT_INT_ENB) { + val = readl(pmc_base + UTMIP_UHSIC_STATUS); + if (UTMIP_WAKE_ALARM(inst) & val) { + val = readl(pmc_base + PMC_SLEEP_CFG); + val &= ~UTMIP_WAKE_VAL(inst, 0xF); + val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE); + writel(val, pmc_base + PMC_SLEEP_CFG); + + val = readl(pmc_base + PMC_TRIGGERS); + val |= UTMIP_CLR_WAKE_ALARM(inst) | + UTMIP_CLR_WALK_PTR(inst); + writel(val, pmc_base + PMC_TRIGGERS); + + val = readl(base + UTMIP_PMC_WAKEUP0); + val &= ~EVENT_INT_ENB; + writel(val, base + UTMIP_PMC_WAKEUP0); + phy->remote_wakeup = true; + return true; + } + } + return false; +} + +static void utmi_phy_enable_trking_data(struct tegra_usb_phy *phy) +{ + void __iomem *base = IO_ADDRESS(TEGRA_USB_BASE); + void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); + static bool init_done = false; + u32 val; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + /* Should be done only once after system boot */ + if (init_done) + return; + + clk_enable(phy->utmi_pad_clk); + /* Bias pad MASTER_ENABLE=1 */ + val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL); + val |= BIAS_MASTER_PROG_VAL; + writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL); + + /* Setting the tracking length time */ + val = readl(base + UTMIP_BIAS_CFG1); + val &= ~UTMIP_BIAS_PDTRK_COUNT(~0); + val |= UTMIP_BIAS_PDTRK_COUNT(5); + writel(val, base + UTMIP_BIAS_CFG1); + + /* Bias PDTRK is Shared and MUST be done from USB1 ONLY, PD_TRK=0 */ + val = readl(base + UTMIP_BIAS_CFG1); + val &= ~UTMIP_BIAS_PDTRK_POWERDOWN; + writel(val, base + UTMIP_BIAS_CFG1); + + val = readl(base + UTMIP_BIAS_CFG1); + val |= UTMIP_BIAS_PDTRK_POWERUP; + writel(val, base + UTMIP_BIAS_CFG1); + + /* Wait for 25usec */ + udelay(25); + + /* Bias pad MASTER_ENABLE=0 */ + val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL); + val &= ~BIAS_MASTER_PROG_VAL; + writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL); + + /* Wait for 1usec */ + udelay(1); + + /* Bias pad MASTER_ENABLE=1 */ + val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL); + val |= BIAS_MASTER_PROG_VAL; + writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL); + + /* Read RCTRL and TCTRL from UTMIP space */ + val = readl(base + UTMIP_BIAS_STS0); + utmip_rctrl_val = ffz(UTMIP_RCTRL_VAL(val)); + utmip_tctrl_val = ffz(UTMIP_TCTRL_VAL(val)); + + /* PD_TRK=1 */ + val = readl(base + UTMIP_BIAS_CFG1); + val |= UTMIP_BIAS_PDTRK_POWERDOWN; + writel(val, base + UTMIP_BIAS_CFG1); + + /* Program thermally encoded RCTRL_VAL, TCTRL_VAL into PMC space */ + val = readl(pmc_base + PMC_UTMIP_TERM_PAD_CFG); + val = PMC_TCTRL_VAL(utmip_tctrl_val) | PMC_RCTRL_VAL(utmip_rctrl_val); + writel(val, pmc_base + PMC_UTMIP_TERM_PAD_CFG); + clk_disable(phy->utmi_pad_clk); + init_done = true; +} + +static void utmip_powerdown_pmc_wake_detect(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); + unsigned int inst = phy->inst; + + /* power down UTMIP interfaces */ + val = readl(pmc_base + PMC_UTMIP_MASTER_CONFIG); + val |= UTMIP_PWR(inst); + writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG); + + /* setup sleep walk usb controller */ + val = UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A | UTMIP_HIGHZ_A | + UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_HIGHZ_B | + UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_HIGHZ_C | + UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_HIGHZ_D; + writel(val, pmc_base + PMC_SLEEPWALK_REG(inst)); + + /* Program thermally encoded RCTRL_VAL, TCTRL_VAL into PMC space */ + val = readl(pmc_base + PMC_UTMIP_TERM_PAD_CFG); + val = PMC_TCTRL_VAL(utmip_tctrl_val) | PMC_RCTRL_VAL(utmip_rctrl_val); + writel(val, pmc_base + PMC_UTMIP_TERM_PAD_CFG); + + /* Turn over pad configuration to PMC */ + val = readl(pmc_base + PMC_SLEEP_CFG); + val &= ~UTMIP_WAKE_VAL(inst, ~0); + val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE) | + UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) | + UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst); + writel(val, pmc_base + PMC_SLEEP_CFG); + PHY_DBG("%s ENABLE_PMC inst = %d\n", __func__, inst); +} + +static void utmip_powerup_pmc_wake_detect(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); + unsigned int inst = phy->inst; + + /* Disable PMC master mode by clearing MASTER_EN */ + val = readl(pmc_base + PMC_SLEEP_CFG); + val &= ~(UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) | + UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst)); + writel(val, pmc_base + PMC_SLEEP_CFG); + mdelay(1); + PHY_DBG("%s DISABLE_PMC inst = %d\n", __func__, inst); +} + +static void uhsic_powerdown_pmc_wake_detect(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); + + /* turn on pad detectors for HSIC*/ + val = readl(pmc_base + PMC_USB_AO); + val |= (HSIC_RESERVED_P0 | HSIC_STOBE_VAL_PD_P0 | HSIC_DATA_VAL_PD_P0); + writel(val, pmc_base + PMC_USB_AO); + + /* enable pull downs on HSIC PMC */ + val = UHSIC_STRB_RPD_A | UHSIC_DATA_RPD_A | UHSIC_STRB_RPD_B | + UHSIC_DATA_RPD_B | UHSIC_STRB_RPD_C | UHSIC_DATA_RPD_C | + UHSIC_STRB_RPD_D | UHSIC_DATA_RPD_D; + writel(val, pmc_base + UHSIC_SLEEPWALK_REG); + + /* Turn over pad configuration to PMC */ + val = readl(pmc_base + PMC_SLEEP_CFG); + val &= ~UHSIC_WAKE_VAL_P0(~0); + val |= UHSIC_WAKE_VAL_P0(WAKE_VAL_NONE) | UHSIC_MASTER_ENABLE_P0; + writel(val, pmc_base + PMC_SLEEP_CFG); +} + +static void uhsic_powerup_pmc_wake_detect(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); + + /* turn on pad detectors for HSIC*/ + val = readl(pmc_base + PMC_USB_AO); + val &= ~(HSIC_RESERVED_P0 | HSIC_STOBE_VAL_PD_P0 | HSIC_DATA_VAL_PD_P0); + writel(val, pmc_base + PMC_USB_AO); + + /* Disable PMC master mode by clearing MASTER_EN */ + val = readl(pmc_base + PMC_SLEEP_CFG); + val &= ~(UHSIC_MASTER_ENABLE_P0); + writel(val, pmc_base + PMC_SLEEP_CFG); + mdelay(1); +} + +static void usb_phy_power_down_pmc(void) +{ + unsigned long val; + void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); + + /* power down all 3 UTMIP interfaces */ + val = readl(pmc_base + PMC_UTMIP_MASTER_CONFIG); + val |= UTMIP_PWR(0) | UTMIP_PWR(1) | UTMIP_PWR(2); + writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG); + + /* turn on pad detectors */ + writel(PMC_POWER_DOWN_MASK, pmc_base + PMC_USB_AO); + + /* setup sleep walk fl all 3 usb controllers */ + val = UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A | UTMIP_HIGHZ_A | + UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_HIGHZ_B | + UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_HIGHZ_C | + UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_HIGHZ_D; + writel(val, pmc_base + PMC_SLEEPWALK_REG(0)); + writel(val, pmc_base + PMC_SLEEPWALK_REG(1)); + writel(val, pmc_base + PMC_SLEEPWALK_REG(2)); + + /* enable pull downs on HSIC PMC */ + val = UHSIC_STRB_RPD_A | UHSIC_DATA_RPD_A | UHSIC_STRB_RPD_B | + UHSIC_DATA_RPD_B | UHSIC_STRB_RPD_C | UHSIC_DATA_RPD_C | + UHSIC_STRB_RPD_D | UHSIC_DATA_RPD_D; + writel(val, pmc_base + UHSIC_SLEEPWALK_REG); + + /* Turn over pad configuration to PMC */ + val = readl(pmc_base + PMC_SLEEP_CFG); + val &= ~UTMIP_WAKE_VAL(0, ~0); + val &= ~UTMIP_WAKE_VAL(1, ~0); + val &= ~UTMIP_WAKE_VAL(2, ~0); + val &= ~UHSIC_WAKE_VAL_P0(~0); + val |= UTMIP_WAKE_VAL(0, WAKE_VAL_NONE) | UHSIC_WAKE_VAL_P0(WAKE_VAL_NONE) | + UTMIP_WAKE_VAL(1, WAKE_VAL_NONE) | UTMIP_WAKE_VAL(2, WAKE_VAL_NONE) | + UTMIP_RCTRL_USE_PMC(0) | UTMIP_RCTRL_USE_PMC(1) | UTMIP_RCTRL_USE_PMC(2) | + UTMIP_TCTRL_USE_PMC(0) | UTMIP_TCTRL_USE_PMC(1) | UTMIP_TCTRL_USE_PMC(2) | + UTMIP_FSLS_USE_PMC(0) | UTMIP_FSLS_USE_PMC(1) | UTMIP_FSLS_USE_PMC(2) | + UTMIP_MASTER_ENABLE(0) | UTMIP_MASTER_ENABLE(1) | UTMIP_MASTER_ENABLE(2) | + UHSIC_MASTER_ENABLE_P0; + writel(val, pmc_base + PMC_SLEEP_CFG); +} + +static int usb_phy_bringup_host_controller(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + PHY_DBG("[%d] USB_USBSTS[0x%x] USB_PORTSC[0x%x] port_speed[%d]\n", __LINE__, + readl(base + USB_USBSTS), readl(base + USB_PORTSC), + phy->port_speed); + + /* Device is plugged in when system is in LP0 */ + /* Bring up the controller from LP0*/ + val = readl(base + USB_USBCMD); + val |= USB_CMD_RESET; + writel(val, base + USB_USBCMD); + + if (usb_phy_reg_status_wait(base + USB_USBCMD, + USB_CMD_RESET, 0, 2500) < 0) { + pr_err("%s: timeout waiting for reset\n", __func__); + } + + val = readl(base + USB_USBMODE); + val &= ~USB_USBMODE_MASK; + val |= USB_USBMODE_HOST; + writel(val, base + USB_USBMODE); + + val = readl(base + HOSTPC1_DEVLC); + val &= ~HOSTPC1_DEVLC_PTS(~0); + val |= HOSTPC1_DEVLC_STS; + writel(val, base + HOSTPC1_DEVLC); + + /* Enable Port Power */ + val = readl(base + USB_PORTSC); + val |= USB_PORTSC_PP; + writel(val, base + USB_PORTSC); + udelay(10); + + /* Check if the phy resume from LP0. When the phy resume from LP0 + * USB register will be reset.to zero */ + if (!readl(base + USB_ASYNCLISTADDR)) { + /* Program the field PTC based on the saved speed mode */ + val = readl(base + USB_PORTSC); + val &= ~USB_PORTSC_PTC(~0); + if (phy->port_speed == USB_PHY_PORT_SPEED_HIGH) + val |= USB_PORTSC_PTC(5); + else if (phy->port_speed == USB_PHY_PORT_SPEED_FULL) + val |= USB_PORTSC_PTC(6); + else if (phy->port_speed == USB_PHY_PORT_SPEED_LOW) + val |= USB_PORTSC_PTC(7); + writel(val, base + USB_PORTSC); + udelay(10); + + /* Disable test mode by setting PTC field to NORMAL_OP */ + val = readl(base + USB_PORTSC); + val &= ~USB_PORTSC_PTC(~0); + writel(val, base + USB_PORTSC); + udelay(10); + } + + /* Poll until CCS is enabled */ + if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_CCS, + USB_PORTSC_CCS, 2000)) { + pr_err("%s: timeout waiting for USB_PORTSC_CCS\n", __func__); + } + + /* Poll until PE is enabled */ + if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_PE, + USB_PORTSC_PE, 2000)) { + pr_err("%s: timeout waiting for USB_PORTSC_PE\n", __func__); + } + + /* Clear the PCI status, to avoid an interrupt taken upon resume */ + val = readl(base + USB_USBSTS); + val |= USB_USBSTS_PCI; + writel(val, base + USB_USBSTS); + + if (!phy->remote_wakeup) { + /* Put controller in suspend mode by writing 1 to SUSP bit of PORTSC */ + val = readl(base + USB_PORTSC); + if ((val & USB_PORTSC_PP) && (val & USB_PORTSC_PE)) { + val |= USB_PORTSC_SUSP; + writel(val, base + USB_PORTSC); + /* Need a 4ms delay before the controller goes to suspend */ + mdelay(4); + + /* Wait until port suspend completes */ + if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_SUSP, + USB_PORTSC_SUSP, 1000)) { + pr_err("%s: timeout waiting for PORT_SUSPEND\n", + __func__); + } + } + } + PHY_DBG("[%d] USB_USBSTS[0x%x] USB_PORTSC[0x%x] port_speed[%d]\n", __LINE__, + readl(base + USB_USBSTS), readl(base + USB_PORTSC), + phy->port_speed); + + DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n", + readl(base + USB_USBSTS), readl(base + USB_PORTSC)); + return 0; +} + +static void usb_phy_wait_for_sof(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + val = readl(base + USB_USBSTS); + writel(val, base + USB_USBSTS); + udelay(20); + /* wait for two SOFs */ + if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_SRI, + USB_USBSTS_SRI, 2500)) + pr_err("%s: timeout waiting for SOF\n", __func__); + + val = readl(base + USB_USBSTS); + writel(val, base + USB_USBSTS); + if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_SRI, 0, 2500)) + pr_err("%s: timeout waiting for SOF\n", __func__); + + if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_SRI, + USB_USBSTS_SRI, 2500)) + pr_err("%s: timeout waiting for SOF\n", __func__); + + udelay(20); +} + +static unsigned int utmi_phy_xcvr_setup_value(struct tegra_usb_phy *phy) +{ + struct tegra_utmi_config *cfg = &phy->pdata->u_cfg.utmi; + signed long val; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + if (cfg->xcvr_use_fuses) { + val = FUSE_USB_CALIB_XCVR_SETUP( + tegra_fuse_readl(FUSE_USB_CALIB_0)); + if (cfg->xcvr_setup_offset <= UTMIP_XCVR_MAX_OFFSET) + val = val + cfg->xcvr_setup_offset; + + if (val > UTMIP_XCVR_SETUP_MAX_VALUE) { + val = UTMIP_XCVR_SETUP_MAX_VALUE; + pr_info("%s: reset XCVR_SETUP to max value\n", + __func__); + } else if (val < UTMIP_XCVR_SETUP_MIN_VALUE) { + val = UTMIP_XCVR_SETUP_MIN_VALUE; + pr_info("%s: reset XCVR_SETUP to min value\n", + __func__); + } + } else { + val = cfg->xcvr_setup; + } + + return (unsigned int) val; +} + +static int utmi_phy_open(struct tegra_usb_phy *phy) +{ + void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); + unsigned long parent_rate, val; + int i; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + phy->utmi_pad_clk = clk_get_sys("utmip-pad", NULL); + if (IS_ERR(phy->utmi_pad_clk)) { + pr_err("%s: can't get utmip pad clock\n", __func__); + return PTR_ERR(phy->utmi_pad_clk); + } + + phy->utmi_xcvr_setup = utmi_phy_xcvr_setup_value(phy); + + parent_rate = clk_get_rate(clk_get_parent(phy->pllu_clk)); + for (i = 0; i < ARRAY_SIZE(utmip_freq_table); i++) { + if (utmip_freq_table[i].freq == parent_rate) { + phy->freq = &utmip_freq_table[i]; + break; + } + } + if (!phy->freq) { + pr_err("invalid pll_u parent rate %ld\n", parent_rate); + return -EINVAL; + } + + /* Power-up the VBUS detector for UTMIP PHY */ + val = readl(pmc_base + PMC_USB_AO); + val &= ~(PMC_USB_AO_VBUS_WAKEUP_PD_P0 | PMC_USB_AO_ID_PD_P0); + writel((val | PMC_USB_AO_PD_P2), (pmc_base + PMC_USB_AO)); + + utmip_powerup_pmc_wake_detect(phy); + + return 0; +} + +static void utmi_phy_close(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s inst:[%d]\n", __func__, phy->inst); + + /* Disable PHY clock valid interrupts while going into suspend*/ + if (phy->pdata->u_data.host.hot_plug) { + val = readl(base + USB_SUSP_CTRL); + val &= ~USB_PHY_CLK_VALID_INT_ENB; + writel(val, base + USB_SUSP_CTRL); + } + + val = readl(base + USB_PORTSC); + val |= USB_PORTSC_WKCN; + writel(val, base + USB_PORTSC); + + clk_put(phy->utmi_pad_clk); +} + +static int utmi_phy_pad_power_on(struct tegra_usb_phy *phy) +{ + unsigned long val, flags; + void __iomem *pad_base = IO_ADDRESS(TEGRA_USB_BASE); + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + clk_enable(phy->utmi_pad_clk); + + spin_lock_irqsave(&utmip_pad_lock, flags); + utmip_pad_count++; + + val = readl(pad_base + UTMIP_BIAS_CFG0); + val &= ~(UTMIP_OTGPD | UTMIP_BIASPD); + val |= UTMIP_HSSQUELCH_LEVEL(0x2) | UTMIP_HSDISCON_LEVEL(0x1) | + UTMIP_HSDISCON_LEVEL_MSB; + writel(val, pad_base + UTMIP_BIAS_CFG0); + + spin_unlock_irqrestore(&utmip_pad_lock, flags); + + clk_disable(phy->utmi_pad_clk); + + return 0; +} + +static int utmi_phy_pad_power_off(struct tegra_usb_phy *phy) +{ + unsigned long val, flags; + void __iomem *pad_base = IO_ADDRESS(TEGRA_USB_BASE); + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + clk_enable(phy->utmi_pad_clk); + spin_lock_irqsave(&utmip_pad_lock, flags); + + if (!utmip_pad_count) { + pr_err("%s: utmip pad already powered off\n", __func__); + goto out; + } + if (--utmip_pad_count == 0) { + val = readl(pad_base + UTMIP_BIAS_CFG0); + val |= UTMIP_OTGPD | UTMIP_BIASPD; + val &= ~(UTMIP_HSSQUELCH_LEVEL(~0) | UTMIP_HSDISCON_LEVEL(~0) | + UTMIP_HSDISCON_LEVEL_MSB); + writel(val, pad_base + UTMIP_BIAS_CFG0); + } +out: + spin_unlock_irqrestore(&utmip_pad_lock, flags); + clk_disable(phy->utmi_pad_clk); + + return 0; +} + +static int utmi_phy_irq(struct tegra_usb_phy *phy) +{ + void __iomem *base = phy->regs; + unsigned long val = 0; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n", + readl(base + USB_USBSTS), readl(base + USB_PORTSC)); + DBG("USB_USBMODE[0x%x] USB_USBCMD[0x%x]\n", + readl(base + USB_USBMODE), readl(base + USB_USBCMD)); + + usb_phy_fence_read(phy); + /* check if there is any remote wake event */ + if (utmi_phy_remotewake_detected(phy)) + pr_info("%s: utmip remote wake detected\n", __func__); + + if (phy->pdata->u_data.host.hot_plug) { + val = readl(base + USB_SUSP_CTRL); + if ((val & USB_PHY_CLK_VALID_INT_STS)) { + val &= ~USB_PHY_CLK_VALID_INT_ENB | + USB_PHY_CLK_VALID_INT_STS; + writel(val , (base + USB_SUSP_CTRL)); + pr_info("%s: usb device plugged-in\n", __func__); + val = readl(base + USB_USBSTS); + if (!(val & USB_USBSTS_PCI)) + return IRQ_NONE; + val = readl(base + USB_PORTSC); + val &= ~(USB_PORTSC_WKCN | USB_PORTSC_RWC_BITS); + writel(val , (base + USB_PORTSC)); + } + } + + return IRQ_HANDLED; +} + +static void utmi_phy_enable_obs_bus(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + /* (2LS WAR)is not required for LS and FS devices and is only for HS */ + if ((phy->port_speed == USB_PHY_PORT_SPEED_LOW) || + (phy->port_speed == USB_PHY_PORT_SPEED_FULL)) { + /* do not enable the OBS bus */ + val = readl(base + UTMIP_MISC_CFG0); + val &= ~(UTMIP_DPDM_OBSERVE_SEL(~0)); + writel(val, base + UTMIP_MISC_CFG0); + DBG("%s(%d) Disable OBS bus\n", __func__, __LINE__); + return; + } + /* Force DP/DM pulldown active for Host mode */ + val = readl(base + UTMIP_MISC_CFG0); + val |= FORCE_PULLDN_DM | FORCE_PULLDN_DP | + COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS; + writel(val, base + UTMIP_MISC_CFG0); + val = readl(base + UTMIP_MISC_CFG0); + val &= ~UTMIP_DPDM_OBSERVE_SEL(~0); + if (phy->port_speed == USB_PHY_PORT_SPEED_LOW) + val |= UTMIP_DPDM_OBSERVE_SEL_FS_J; + else + val |= UTMIP_DPDM_OBSERVE_SEL_FS_K; + writel(val, base + UTMIP_MISC_CFG0); + udelay(1); + + val = readl(base + UTMIP_MISC_CFG0); + val |= UTMIP_DPDM_OBSERVE; + writel(val, base + UTMIP_MISC_CFG0); + udelay(10); + DBG("%s(%d) Enable OBS bus\n", __func__, __LINE__); + PHY_DBG("ENABLE_OBS_BUS\n"); +} + +static int utmi_phy_disable_obs_bus(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + /* check if OBS bus is already enabled */ + val = readl(base + UTMIP_MISC_CFG0); + if (val & UTMIP_DPDM_OBSERVE) { + PHY_DBG("DISABLE_OBS_BUS\n"); + /* Change the UTMIP OBS bus to drive SE0 */ + val = readl(base + UTMIP_MISC_CFG0); + val &= ~UTMIP_DPDM_OBSERVE_SEL(~0); + val |= UTMIP_DPDM_OBSERVE_SEL_FS_SE0; + writel(val, base + UTMIP_MISC_CFG0); + + /* Wait for 3us(2 LS bit times) */ + udelay(3); + + /* Release UTMIP OBS bus */ + val = readl(base + UTMIP_MISC_CFG0); + val &= ~UTMIP_DPDM_OBSERVE; + writel(val, base + UTMIP_MISC_CFG0); + + /* Release DP/DM pulldown for Host mode */ + val = readl(base + UTMIP_MISC_CFG0); + val &= ~(FORCE_PULLDN_DM | FORCE_PULLDN_DP | + COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS); + writel(val, base + UTMIP_MISC_CFG0); + + val = readl(base + USB_USBCMD); + val |= USB_USBCMD_RS; + writel(val, base + USB_USBCMD); + if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS, + USB_USBCMD_RS, 2000)) { + pr_err("%s: timeout waiting for USB_USBCMD_RS\n", __func__); + return -ETIMEDOUT; + } + } + return 0; +} + +static int utmi_phy_post_resume(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); + unsigned int inst = phy->inst; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + val = readl(pmc_base + PMC_SLEEP_CFG); + /* if PMC is not disabled by now then disable it */ + if (val & UTMIP_MASTER_ENABLE(inst)) { + utmip_phy_disable_pmc_bus_ctrl(phy); + } + + utmi_phy_disable_obs_bus(phy); + + return 0; +} + +static int utmi_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup) +{ + unsigned long val; + void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); + void __iomem *base = phy->regs; + unsigned int inst = phy->inst; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + val = (readl(base + HOSTPC1_DEVLC) >> 25) & + HOSTPC1_DEVLC_PSPD_MASK; + if (val == USB_PHY_PORT_SPEED_HIGH) { + /* Disable interrupts */ + writel(0, base + USB_USBINTR); + /* Clear the run bit to stop SOFs - 2LS WAR */ + val = readl(base + USB_USBCMD); + val &= ~USB_USBCMD_RS; + writel(val, base + USB_USBCMD); + } + + val = readl(pmc_base + PMC_SLEEP_CFG); + if (val & UTMIP_MASTER_ENABLE(inst)) { + if (!remote_wakeup) + utmip_phy_disable_pmc_bus_ctrl(phy); + } else { + utmi_phy_enable_obs_bus(phy); + } + + return 0; +} + +static int utmi_phy_power_off(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + PHY_DBG("%s(%d) inst:[%d] BEGIN\n", __func__, __LINE__, phy->inst); + if (!phy->phy_clk_on) { + PHY_DBG("%s(%d) inst:[%d] phy clk is already off\n", + __func__, __LINE__, phy->inst); + return 0; + } + + if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) { + utmip_powerdown_pmc_wake_detect(phy); + + val = readl(base + USB_SUSP_CTRL); + val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0); + val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5); + writel(val, base + USB_SUSP_CTRL); + + val = readl(base + UTMIP_BAT_CHRG_CFG0); + val |= UTMIP_PD_CHRG; + writel(val, base + UTMIP_BAT_CHRG_CFG0); + } else { + utmip_setup_pmc_wake_detect(phy); + } + + if (!phy->pdata->u_data.host.hot_plug) { + val = readl(base + UTMIP_XCVR_CFG0); + val |= (UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN | + UTMIP_FORCE_PDZI_POWERDOWN); + writel(val, base + UTMIP_XCVR_CFG0); + } + + val = readl(base + UTMIP_XCVR_CFG1); + val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN | + UTMIP_FORCE_PDDR_POWERDOWN; + writel(val, base + UTMIP_XCVR_CFG1); + + val = readl(base + UTMIP_BIAS_CFG1); + val |= UTMIP_BIAS_PDTRK_COUNT(0x5); + writel(val, base + UTMIP_BIAS_CFG1); + + utmi_phy_pad_power_off(phy); + + phy->port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) & + HOSTPC1_DEVLC_PSPD_MASK; + + if (phy->pdata->u_data.host.hot_plug) { + bool enable_hotplug = true; + /* if it is OTG port then make sure to enable hot-plug feature + only if host adaptor is connected, i.e id is low */ + if (phy->pdata->port_otg) { + val = readl(base + USB_PHY_VBUS_WAKEUP_ID); + enable_hotplug = (val & USB_ID_STATUS) ? false : true; + } + if (enable_hotplug) { + val = readl(base + USB_PORTSC); + val |= USB_PORTSC_WKCN; + writel(val, base + USB_PORTSC); + + val = readl(base + USB_SUSP_CTRL); + val |= USB_PHY_CLK_VALID_INT_ENB; + writel(val, base + USB_SUSP_CTRL); + } else { + /* Disable PHY clock valid interrupts while going into suspend*/ + val = readl(base + USB_SUSP_CTRL); + val &= ~USB_PHY_CLK_VALID_INT_ENB; + writel(val, base + USB_SUSP_CTRL); + } + } + + val = readl(base + HOSTPC1_DEVLC); + val |= HOSTPC1_DEVLC_PHCD; + writel(val, base + HOSTPC1_DEVLC); + + if (!phy->pdata->u_data.host.hot_plug) { + val = readl(base + USB_SUSP_CTRL); + val |= UTMIP_RESET; + writel(val, base + USB_SUSP_CTRL); + } + + phy->phy_clk_on = false; + phy->hw_accessible = false; + + PHY_DBG("%s(%d) inst:[%d] END\n", __func__, __LINE__, phy->inst); + + return 0; +} + + +static int utmi_phy_power_on(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + struct tegra_utmi_config *config = &phy->pdata->u_cfg.utmi; + + PHY_DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + if (phy->phy_clk_on) { + PHY_DBG("%s(%d) inst:[%d] phy clk is already On\n", + __func__, __LINE__, phy->inst); + return 0; + } + val = readl(base + USB_SUSP_CTRL); + val |= UTMIP_RESET; + writel(val, base + USB_SUSP_CTRL); + + val = readl(base + UTMIP_TX_CFG0); + val |= UTMIP_FS_PREABMLE_J; + writel(val, base + UTMIP_TX_CFG0); + + val = readl(base + UTMIP_HSRX_CFG0); + val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0)); + val |= UTMIP_IDLE_WAIT(config->idle_wait_delay); + val |= UTMIP_ELASTIC_LIMIT(config->elastic_limit); + writel(val, base + UTMIP_HSRX_CFG0); + + val = readl(base + UTMIP_HSRX_CFG1); + val &= ~UTMIP_HS_SYNC_START_DLY(~0); + val |= UTMIP_HS_SYNC_START_DLY(config->hssync_start_delay); + writel(val, base + UTMIP_HSRX_CFG1); + + val = readl(base + UTMIP_DEBOUNCE_CFG0); + val &= ~UTMIP_BIAS_DEBOUNCE_A(~0); + val |= UTMIP_BIAS_DEBOUNCE_A(phy->freq->debounce); + writel(val, base + UTMIP_DEBOUNCE_CFG0); + + val = readl(base + UTMIP_MISC_CFG0); + val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE; + writel(val, base + UTMIP_MISC_CFG0); + + if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) { + val = readl(base + USB_SUSP_CTRL); + val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV); + writel(val, base + USB_SUSP_CTRL); + + val = readl(base + UTMIP_BAT_CHRG_CFG0); + val &= ~UTMIP_PD_CHRG; + writel(val, base + UTMIP_BAT_CHRG_CFG0); + } else { + val = readl(base + UTMIP_BAT_CHRG_CFG0); + val |= UTMIP_PD_CHRG; + writel(val, base + UTMIP_BAT_CHRG_CFG0); + } + + utmi_phy_pad_power_on(phy); + + val = readl(base + UTMIP_XCVR_CFG0); + val &= ~(UTMIP_XCVR_LSBIAS_SEL | UTMIP_FORCE_PD_POWERDOWN | + UTMIP_FORCE_PD2_POWERDOWN | UTMIP_FORCE_PDZI_POWERDOWN | + UTMIP_XCVR_SETUP(~0) | UTMIP_XCVR_LSFSLEW(~0) | + UTMIP_XCVR_LSRSLEW(~0) | UTMIP_XCVR_HSSLEW_MSB(~0)); + val |= UTMIP_XCVR_SETUP(phy->utmi_xcvr_setup); + val |= UTMIP_XCVR_SETUP_MSB(XCVR_SETUP_MSB_CALIB(phy->utmi_xcvr_setup)); + val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew); + val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew); + val |= UTMIP_XCVR_HSSLEW_MSB(0x8); + writel(val, base + UTMIP_XCVR_CFG0); + + val = readl(base + UTMIP_XCVR_CFG1); + val &= ~(UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN | + UTMIP_FORCE_PDDR_POWERDOWN | UTMIP_XCVR_TERM_RANGE_ADJ(~0)); + val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj); + writel(val, base + UTMIP_XCVR_CFG1); + + val = readl(base + UTMIP_BIAS_CFG1); + val &= ~UTMIP_BIAS_PDTRK_COUNT(~0); + val |= UTMIP_BIAS_PDTRK_COUNT(phy->freq->pdtrk_count); + writel(val, base + UTMIP_BIAS_CFG1); + + val = readl(base + UTMIP_SPARE_CFG0); + val &= ~FUSE_SETUP_SEL; + val |= FUSE_ATERM_SEL; + writel(val, base + UTMIP_SPARE_CFG0); + + val = readl(base + USB_SUSP_CTRL); + val |= UTMIP_PHY_ENABLE; + writel(val, base + USB_SUSP_CTRL); + + val = readl(base + USB_SUSP_CTRL); + val &= ~UTMIP_RESET; + writel(val, base + USB_SUSP_CTRL); + + val = readl(base + HOSTPC1_DEVLC); + val &= ~HOSTPC1_DEVLC_PHCD; + writel(val, base + HOSTPC1_DEVLC); + + if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, + USB_PHY_CLK_VALID, USB_PHY_CLK_VALID, 2500)) + pr_warn("%s: timeout waiting for phy to stabilize\n", __func__); + + utmi_phy_enable_trking_data(phy); + + if (phy->inst == 2) + writel(0, base + ICUSB_CTRL); + + val = readl(base + USB_USBMODE); + val &= ~USB_USBMODE_MASK; + if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) + val |= USB_USBMODE_HOST; + else + val |= USB_USBMODE_DEVICE; + writel(val, base + USB_USBMODE); + + val = readl(base + HOSTPC1_DEVLC); + val &= ~HOSTPC1_DEVLC_PTS(~0); + val |= HOSTPC1_DEVLC_STS; + writel(val, base + HOSTPC1_DEVLC); + + if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) + utmip_powerup_pmc_wake_detect(phy); + phy->phy_clk_on = true; + phy->hw_accessible = true; + PHY_DBG("%s(%d) End inst:[%d]\n", __func__, __LINE__, phy->inst); + return 0; +} + +static void utmi_phy_restore_start(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); + int inst = phy->inst; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + val = readl(pmc_base + UTMIP_UHSIC_STATUS); + /* check whether we wake up from the remote resume */ + if (UTMIP_WALK_PTR_VAL(inst) & val) { + phy->remote_wakeup = true; + } else { + if (!((UTMIP_USBON_VAL(phy->inst) | + UTMIP_USBOP_VAL(phy->inst)) & val)) { + utmip_phy_disable_pmc_bus_ctrl(phy); + } + } + utmi_phy_enable_obs_bus(phy); +} + +static void utmi_phy_restore_end(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + int wait_time_us = 25000; /* FPR should be set by this time */ + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + /* check whether we wake up from the remote resume */ + if (phy->remote_wakeup) { + /* wait until SUSPEND and RESUME bit is cleared on remote resume */ + do { + val = readl(base + USB_PORTSC); + udelay(1); + if (wait_time_us == 0) { + PHY_DBG("%s PMC REMOTE WAKEUP FPR timeout val = 0x%x instance = %d\n", __func__, val, phy->inst); + utmip_phy_disable_pmc_bus_ctrl(phy); + utmi_phy_post_resume(phy); + return; + } + wait_time_us--; + } while (val & (USB_PORTSC_RESUME | USB_PORTSC_SUSP)); + + /* wait for 25 ms to port resume complete */ + msleep(25); + /* disable PMC master control */ + utmip_phy_disable_pmc_bus_ctrl(phy); + + /* Clear PCI and SRI bits to avoid an interrupt upon resume */ + val = readl(base + USB_USBSTS); + writel(val, base + USB_USBSTS); + /* wait to avoid SOF if there is any */ + if (usb_phy_reg_status_wait(base + USB_USBSTS, + USB_USBSTS_SRI, USB_USBSTS_SRI, 2500) < 0) { + pr_err("%s: timeout waiting for SOF\n", __func__); + } + utmi_phy_post_resume(phy); + } +} + +static int utmi_phy_resume(struct tegra_usb_phy *phy) +{ + int status = 0; + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) { + if (phy->port_speed < USB_PHY_PORT_SPEED_UNKNOWN) { + utmi_phy_restore_start(phy); + usb_phy_bringup_host_controller(phy); + utmi_phy_restore_end(phy); + } else { + /* device is plugged in when system is in LP0 */ + /* bring up the controller from LP0*/ + val = readl(base + USB_USBCMD); + val |= USB_CMD_RESET; + writel(val, base + USB_USBCMD); + + if (usb_phy_reg_status_wait(base + USB_USBCMD, + USB_CMD_RESET, 0, 2500) < 0) { + pr_err("%s: timeout waiting for reset\n", __func__); + } + + val = readl(base + USB_USBMODE); + val &= ~USB_USBMODE_MASK; + val |= USB_USBMODE_HOST; + writel(val, base + USB_USBMODE); + + val = readl(base + HOSTPC1_DEVLC); + val &= ~HOSTPC1_DEVLC_PTS(~0); + val |= HOSTPC1_DEVLC_STS; + writel(val, base + HOSTPC1_DEVLC); + + writel(USB_USBCMD_RS, base + USB_USBCMD); + + if (usb_phy_reg_status_wait(base + USB_USBCMD, + USB_USBCMD_RS, USB_USBCMD_RS, 2500) < 0) { + pr_err("%s: timeout waiting for run bit\n", __func__); + } + + /* Enable Port Power */ + val = readl(base + USB_PORTSC); + val |= USB_PORTSC_PP; + writel(val, base + USB_PORTSC); + udelay(10); + + DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n", + readl(base + USB_USBSTS), readl(base + USB_PORTSC)); + } + } + + return status; +} + +bool utmi_phy_charger_detect(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + bool status; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + if (phy->pdata->op_mode != TEGRA_USB_OPMODE_DEVICE) { + /* Charger detection is not there for ULPI + * return Charger not available */ + return false; + } + + /* Enable charger detection logic */ + val = readl(base + UTMIP_BAT_CHRG_CFG0); + val |= UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN; + writel(val, base + UTMIP_BAT_CHRG_CFG0); + + /* Source should be on for 100 ms as per USB charging spec */ + msleep(TDP_SRC_ON_MS); + + val = readl(base + USB_PHY_VBUS_WAKEUP_ID); + /* If charger is not connected disable the interrupt */ + val &= ~VDAT_DET_INT_EN; + val |= VDAT_DET_CHG_DET; + writel(val, base + USB_PHY_VBUS_WAKEUP_ID); + + val = readl(base + USB_PHY_VBUS_WAKEUP_ID); + if (val & VDAT_DET_STS) + status = true; + else + status = false; + + /* Disable charger detection logic */ + val = readl(base + UTMIP_BAT_CHRG_CFG0); + val &= ~(UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN); + writel(val, base + UTMIP_BAT_CHRG_CFG0); + + /* Delay of 40 ms before we pull the D+ as per battery charger spec */ + msleep(TDPSRC_CON_MS); + + return status; +} + +static int uhsic_phy_open(struct tegra_usb_phy *phy) +{ + unsigned long parent_rate; + int i; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + parent_rate = clk_get_rate(clk_get_parent(phy->pllu_clk)); + for (i = 0; i < ARRAY_SIZE(uhsic_freq_table); i++) { + if (uhsic_freq_table[i].freq == parent_rate) { + phy->freq = &uhsic_freq_table[i]; + break; + } + } + if (!phy->freq) { + pr_err("invalid pll_u parent rate %ld\n", parent_rate); + return -EINVAL; + } + + utmip_powerup_pmc_wake_detect(phy); + + return 0; +} + +static int uhsic_phy_irq(struct tegra_usb_phy *phy) +{ + usb_phy_fence_read(phy); + return IRQ_HANDLED; +} + +static int uhsic_phy_power_on(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + struct tegra_hsic_config *config = &phy->pdata->u_cfg.hsic; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + utmip_powerup_pmc_wake_detect(phy); + + if (phy->phy_clk_on) { + DBG("%s(%d) inst:[%d] phy clk is already On\n", + __func__, __LINE__, phy->inst); + return 0; + } + + val = readl(base + UHSIC_PADS_CFG1); + val &= ~(UHSIC_PD_BG | UHSIC_PD_TX | UHSIC_PD_TRK | UHSIC_PD_RX | + UHSIC_PD_ZI | UHSIC_RPD_DATA | UHSIC_RPD_STROBE); + val |= UHSIC_RX_SEL; + writel(val, base + UHSIC_PADS_CFG1); + udelay(2); + + val = readl(base + USB_SUSP_CTRL); + val |= UHSIC_RESET; + writel(val, base + USB_SUSP_CTRL); + udelay(30); + + val = readl(base + USB_SUSP_CTRL); + val |= UHSIC_PHY_ENABLE; + writel(val, base + USB_SUSP_CTRL); + + val = readl(base + UHSIC_HSRX_CFG0); + val |= UHSIC_IDLE_WAIT(config->idle_wait_delay); + val |= UHSIC_ELASTIC_UNDERRUN_LIMIT(config->elastic_underrun_limit); + val |= UHSIC_ELASTIC_OVERRUN_LIMIT(config->elastic_overrun_limit); + writel(val, base + UHSIC_HSRX_CFG0); + + val = readl(base + UHSIC_HSRX_CFG1); + val |= UHSIC_HS_SYNC_START_DLY(config->sync_start_delay); + writel(val, base + UHSIC_HSRX_CFG1); + + /* WAR HSIC TX */ + val = readl(base + UHSIC_TX_CFG0); + val &= ~UHSIC_HS_READY_WAIT_FOR_VALID; + writel(val, base + UHSIC_TX_CFG0); + + val = readl(base + UHSIC_MISC_CFG0); + val |= UHSIC_SUSPEND_EXIT_ON_EDGE; + /* Disable generic bus reset, to allow AP30 specific bus reset*/ + val |= UHSIC_DISABLE_BUSRESET; + writel(val, base + UHSIC_MISC_CFG0); + + val = readl(base + UHSIC_MISC_CFG1); + val |= UHSIC_PLLU_STABLE_COUNT(phy->freq->stable_count); + writel(val, base + UHSIC_MISC_CFG1); + + val = readl(base + UHSIC_PLL_CFG1); + val |= UHSIC_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay); + val |= UHSIC_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count); + writel(val, base + UHSIC_PLL_CFG1); + + val = readl(base + USB_SUSP_CTRL); + val &= ~(UHSIC_RESET); + writel(val, base + USB_SUSP_CTRL); + udelay(2); + + val = readl(base + USB_USBMODE); + val |= USB_USBMODE_HOST; + writel(val, base + USB_USBMODE); + + /* Change the USB controller PHY type to HSIC */ + val = readl(base + HOSTPC1_DEVLC); + val &= ~HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK); + val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC); + val &= ~HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK); + val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED); + writel(val, base + HOSTPC1_DEVLC); + + val = readl(base + USB_TXFILLTUNING); + if ((val & USB_FIFO_TXFILL_MASK) != USB_FIFO_TXFILL_THRES(0x10)) { + val = USB_FIFO_TXFILL_THRES(0x10); + writel(val, base + USB_TXFILLTUNING); + } + + val = readl(base + USB_PORTSC); + val &= ~(USB_PORTSC_WKOC | USB_PORTSC_WKDS | USB_PORTSC_WKCN); + writel(val, base + USB_PORTSC); + + val = readl(base + UHSIC_PADS_CFG0); + val &= ~(UHSIC_TX_RTUNEN); + /* set Rtune impedance to 50 ohm */ + val |= UHSIC_TX_RTUNE(8); + writel(val, base + UHSIC_PADS_CFG0); + + if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, + USB_PHY_CLK_VALID, USB_PHY_CLK_VALID, 2500)) { + pr_err("%s: timeout waiting for phy to stabilize\n", __func__); + return -ETIMEDOUT; + } + + phy->phy_clk_on = true; + phy->hw_accessible = true; + + return 0; +} + +static int uhsic_phy_power_off(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + if (!phy->phy_clk_on) { + DBG("%s(%d) inst:[%d] phy clk is already off\n", + __func__, __LINE__, phy->inst); + return 0; + } + + val = readl(base + UHSIC_PADS_CFG1); + val &= ~UHSIC_RPU_STROBE; + val |= UHSIC_RPD_STROBE; + writel(val, base + UHSIC_PADS_CFG1); + + val = readl(base + USB_SUSP_CTRL); + val |= UHSIC_RESET; + writel(val, base + USB_SUSP_CTRL); + udelay(30); + + utmip_powerdown_pmc_wake_detect(phy); + + phy->phy_clk_on = false; + phy->hw_accessible = false; + + return 0; +} + +int uhsic_phy_bus_port_power(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + val = readl(base + UHSIC_STAT_CFG0); + val &= ~UHSIC_CONNECT_DETECT; + writel(val, base + UHSIC_STAT_CFG0); + + val = readl(base + USB_USBMODE); + val |= USB_USBMODE_HOST; + writel(val, base + USB_USBMODE); + + /* Change the USB controller PHY type to HSIC */ + val = readl(base + HOSTPC1_DEVLC); + val &= ~(HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK)); + val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC); + val &= ~(HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK)); + val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED); + writel(val, base + HOSTPC1_DEVLC); + + val = readl(base + UHSIC_MISC_CFG0); + val |= UHSIC_DETECT_SHORT_CONNECT; + writel(val, base + UHSIC_MISC_CFG0); + udelay(1); + + val = readl(base + UHSIC_MISC_CFG0); + val |= UHSIC_FORCE_XCVR_MODE; + writel(val, base + UHSIC_MISC_CFG0); + + val = readl(base + UHSIC_PADS_CFG1); + val &= ~UHSIC_RPD_STROBE; + /* safe to enable RPU on STROBE at all times during idle */ + val |= UHSIC_RPU_STROBE; + writel(val, base + UHSIC_PADS_CFG1); + + val = readl(base + USB_USBCMD); + val &= ~USB_USBCMD_RS; + writel(val, base + USB_USBCMD); + + if (usb_phy_reg_status_wait(base + UHSIC_STAT_CFG0, + UHSIC_CONNECT_DETECT, UHSIC_CONNECT_DETECT, 25000)) { + pr_err("%s: timeout waiting for UHSIC_CONNECT_DETECT\n", + __func__); + return -ETIMEDOUT; + } + + return 0; +} + +static int uhsic_phy_bus_reset(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + /* Change the USB controller PHY type to HSIC */ + val = readl(base + HOSTPC1_DEVLC); + val &= ~HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK); + val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC); + val &= ~HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK); + val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED); + writel(val, base + HOSTPC1_DEVLC); + /* wait here, otherwise HOSTPC1_DEVLC_PSPD will timeout */ + mdelay(5); + + val = readl(base + USB_PORTSC); + val |= USB_PORTSC_PTC(5); + writel(val, base + USB_PORTSC); + udelay(2); + + val = readl(base + USB_PORTSC); + val &= ~(USB_PORTSC_PTC(~0)); + writel(val, base + USB_PORTSC); + udelay(2); + + if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_LS(0), + 0, 2000)) { + pr_err("%s: timeout waiting for USB_PORTSC_LS\n", __func__); + return -ETIMEDOUT; + } + + /* Poll until CCS is enabled */ + if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_CCS, + USB_PORTSC_CCS, 2000)) { + pr_err("%s: timeout waiting for USB_PORTSC_CCS\n", __func__); + return -ETIMEDOUT; + } + + if (usb_phy_reg_status_wait(base + HOSTPC1_DEVLC, + HOSTPC1_DEVLC_PSPD(2), + HOSTPC1_DEVLC_PSPD(2), 2000) < 0) { + pr_err("%s: timeout waiting hsic high speed configuration\n", + __func__); + return -ETIMEDOUT; + } + + val = readl(base + USB_USBCMD); + val &= ~USB_USBCMD_RS; + writel(val, base + USB_USBCMD); + + if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_HCH, + USB_USBSTS_HCH, 2000)) { + pr_err("%s: timeout waiting for USB_USBSTS_HCH\n", __func__); + return -ETIMEDOUT; + } + + val = readl(base + UHSIC_PADS_CFG1); + val &= ~UHSIC_RPU_STROBE; + val |= UHSIC_RPD_STROBE; + writel(val, base + UHSIC_PADS_CFG1); + + mdelay(50); + + val = readl(base + UHSIC_PADS_CFG1); + val &= ~UHSIC_RPD_STROBE; + val |= UHSIC_RPU_STROBE; + writel(val, base + UHSIC_PADS_CFG1); + + val = readl(base + USB_USBCMD); + val |= USB_USBCMD_RS; + writel(val, base + USB_USBCMD); + + val = readl(base + UHSIC_PADS_CFG1); + val &= ~UHSIC_RPU_STROBE; + writel(val, base + UHSIC_PADS_CFG1); + + if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS, + USB_USBCMD_RS, 2000)) { + pr_err("%s: timeout waiting for USB_USBCMD_RS\n", __func__); + return -ETIMEDOUT; + } + + return 0; +} + + +int uhsic_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup) +{ + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + usb_phy_wait_for_sof(phy); + + return 0; +} + +int uhsic_phy_resume(struct tegra_usb_phy *phy) +{ + void __iomem *base = phy->regs; + unsigned long val; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + /* Check if the phy resume from LP0. When the phy resume from LP0 + * USB register will be reset.to zero */ + if (!readl(base + USB_ASYNCLISTADDR)) { + + val = readl(base + USB_USBCMD); + val |= USB_CMD_RESET; + writel(val, base + USB_USBCMD); + + if (usb_phy_reg_status_wait(base + USB_USBCMD, + USB_CMD_RESET, 0, 2500) < 0) { + pr_err("%s: timeout waiting for reset\n", __func__); + } + + val = readl(base + USB_USBMODE); + val &= ~USB_USBMODE_MASK; + val |= USB_USBMODE_HOST; + writel(val, base + USB_USBMODE); + + /* Enable Port Power */ + val = readl(base + USB_PORTSC); + val |= USB_PORTSC_PP; + writel(val, base + USB_PORTSC); + udelay(10); + + DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n", + readl(base + USB_USBSTS), readl(base + USB_PORTSC)); + + uhsic_phy_bus_port_power(phy); + } + + return 0; +} + +static int uhsic_phy_post_resume(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + val = readl(base + USB_TXFILLTUNING); + if ((val & USB_FIFO_TXFILL_MASK) != USB_FIFO_TXFILL_THRES(0x10)) { + val = USB_FIFO_TXFILL_THRES(0x10); + writel(val, base + USB_TXFILLTUNING); + } + + return 0; +} + +static void ulpi_set_trimmer(struct tegra_usb_phy *phy) +{ + struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi; + void __iomem *base = phy->regs; + unsigned long val; + + val = ULPI_DATA_TRIMMER_SEL(config->data_trimmer); + val |= ULPI_STPDIRNXT_TRIMMER_SEL(config->stpdirnxt_trimmer); + val |= ULPI_DIR_TRIMMER_SEL(config->dir_trimmer); + writel(val, base + ULPI_TIMING_CTRL_1); + udelay(10); + + val |= ULPI_DATA_TRIMMER_LOAD; + val |= ULPI_STPDIRNXT_TRIMMER_LOAD; + val |= ULPI_DIR_TRIMMER_LOAD; + writel(val, base + ULPI_TIMING_CTRL_1); +} + +static void reset_utmip_uhsic(void __iomem *base) +{ + unsigned long val; + + val = readl(base + USB_SUSP_CTRL); + val |= UHSIC_RESET; + writel(val, base + USB_SUSP_CTRL); + + val = readl(base + USB_SUSP_CTRL); + val |= UTMIP_RESET; + writel(val, base + USB_SUSP_CTRL); +} + +static void ulpi_set_host(void __iomem *base) +{ + unsigned long val; + + val = readl(base + USB_USBMODE); + val |= USB_USBMODE_HOST; + writel(val, base + USB_USBMODE); + + val = readl(base + HOSTPC1_DEVLC); + val |= HOSTPC1_DEVLC_PTS(2); + writel(val, base + HOSTPC1_DEVLC); +} + + + +static inline void null_phy_set_tristate(bool enable) +{ +#ifndef CONFIG_ARCH_TEGRA_2x_SOC + int tristate = (enable) ? TEGRA_TRI_TRISTATE : TEGRA_TRI_NORMAL; + DBG("%s(%d) inst:[%s] FIXME enable pin group +++\n", __func__, + __LINE__, enable ? "TRISTATE" : "NORMAL"); + + tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA0, tristate); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA1, tristate); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA2, tristate); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA3, tristate); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA4, tristate); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA5, tristate); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA6, tristate); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA7, tristate); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_NXT, tristate); + + if (enable) + tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DIR, tristate); +#endif + +} + + +static int ulpi_null_phy_power_off(struct tegra_usb_phy *phy) +{ + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + if (!phy->phy_clk_on) { + DBG("%s(%d) inst:[%d] phy clk is already off\n", __func__, + __LINE__, phy->inst); + return 0; + } + + null_phy_set_tristate(true); + + phy->phy_clk_on = false; + phy->hw_accessible = false; + + return 0; +} + +static int ulpi_null_phy_init(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + val = readl(base + ULPIS2S_CTRL); + val |= ULPIS2S_SLV0_CLAMP_XMIT; + writel(val, base + ULPIS2S_CTRL); + + val = readl(base + USB_SUSP_CTRL); + val |= ULPIS2S_SLV0_RESET; + writel(val, base + USB_SUSP_CTRL); + udelay(10); + + return 0; +} + +static int ulpi_null_phy_irq(struct tegra_usb_phy *phy) +{ + usb_phy_fence_read(phy); + return IRQ_HANDLED; +} + +static int ulpi_null_phy_cmd_reset(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + ulpi_set_host(base); + + /* remove slave0 reset */ + val = readl(base + USB_SUSP_CTRL); + val &= ~ULPIS2S_SLV0_RESET; + writel(val, base + USB_SUSP_CTRL); + + val = readl(base + ULPIS2S_CTRL); + val &= ~ULPIS2S_SLV0_CLAMP_XMIT; + writel(val, base + ULPIS2S_CTRL); + udelay(10); + + return 0; +} + +static int ulpi_null_phy_power_on(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi; + static bool cold_boot = true; + + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + if (phy->phy_clk_on) { + DBG("%s(%d) inst:[%d] phy clk is already On\n", __func__, + __LINE__, phy->inst); + return 0; + } + reset_utmip_uhsic(base); + + /* remove ULPI PADS CLKEN reset */ + val = readl(base + USB_SUSP_CTRL); + val &= ~ULPI_PADS_CLKEN_RESET; + writel(val, base + USB_SUSP_CTRL); + udelay(10); + + val = readl(base + ULPI_TIMING_CTRL_0); + val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP; + writel(val, base + ULPI_TIMING_CTRL_0); + + val = readl(base + USB_SUSP_CTRL); + val |= ULPI_PHY_ENABLE; + writel(val, base + USB_SUSP_CTRL); + udelay(10); + + /* set timming parameters */ + val = readl(base + ULPI_TIMING_CTRL_0); + val |= ULPI_SHADOW_CLK_LOOPBACK_EN; + val &= ~ULPI_SHADOW_CLK_SEL; + val &= ~ULPI_LBK_PAD_EN; + val |= ULPI_SHADOW_CLK_DELAY(config->shadow_clk_delay); + val |= ULPI_CLOCK_OUT_DELAY(config->clock_out_delay); + val |= ULPI_LBK_PAD_E_INPUT_OR; + writel(val, base + ULPI_TIMING_CTRL_0); + + writel(0, base + ULPI_TIMING_CTRL_1); + udelay(10); + + /* start internal 60MHz clock */ + val = readl(base + ULPIS2S_CTRL); + val |= ULPIS2S_ENA; + val |= ULPIS2S_SUPPORT_DISCONNECT; + val |= ULPIS2S_SPARE((phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) ? 3 : 1); + val |= ULPIS2S_PLLU_MASTER_BLASTER60; + writel(val, base + ULPIS2S_CTRL); + + /* select ULPI_CORE_CLK_SEL to SHADOW_CLK */ + val = readl(base + ULPI_TIMING_CTRL_0); + val |= ULPI_CORE_CLK_SEL; + writel(val, base + ULPI_TIMING_CTRL_0); + udelay(10); + + /* enable ULPI null phy clock - can't set the trimmers before this */ + val = readl(base + ULPI_TIMING_CTRL_0); + val |= ULPI_CLK_OUT_ENA; + writel(val, base + ULPI_TIMING_CTRL_0); + udelay(10); + + if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, + USB_PHY_CLK_VALID, 2500)) { + pr_err("%s: timeout waiting for phy to stabilize\n", __func__); + return -ETIMEDOUT; + } + + /* set ULPI trimmers */ + ulpi_set_trimmer(phy); + + ulpi_set_host(base); + + /* remove slave0 reset */ + val = readl(base + USB_SUSP_CTRL); + val &= ~ULPIS2S_SLV0_RESET; + writel(val, base + USB_SUSP_CTRL); + + /* remove slave1 and line reset */ + val = readl(base + USB_SUSP_CTRL); + val &= ~ULPIS2S_SLV1_RESET; + val &= ~ULPIS2S_LINE_RESET; + + /* remove ULPI PADS reset */ + val &= ~ULPI_PADS_RESET; + writel(val, base + USB_SUSP_CTRL); + + if (cold_boot) { + val = readl(base + ULPI_TIMING_CTRL_0); + val |= ULPI_CLK_PADOUT_ENA; + writel(val, base + ULPI_TIMING_CTRL_0); + cold_boot = false; + } + udelay(10); + + phy->phy_clk_on = true; + phy->hw_accessible = true; + + return 0; +} + + +int ulpi_null_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup) +{ + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + usb_phy_wait_for_sof(phy); + return 0; +} + +static struct tegra_usb_phy_ops utmi_phy_ops = { + .open = utmi_phy_open, + .close = utmi_phy_close, + .irq = utmi_phy_irq, + .power_on = utmi_phy_power_on, + .power_off = utmi_phy_power_off, + .pre_resume = utmi_phy_pre_resume, + .resume = utmi_phy_resume, + .post_resume = utmi_phy_post_resume, + .charger_detect = utmi_phy_charger_detect, +}; + +static struct tegra_usb_phy_ops uhsic_phy_ops = { + .open = uhsic_phy_open, + .irq = uhsic_phy_irq, + .power_on = uhsic_phy_power_on, + .power_off = uhsic_phy_power_off, + .pre_resume = uhsic_phy_pre_resume, + .resume = uhsic_phy_resume, + .post_resume = uhsic_phy_post_resume, + .port_power = uhsic_phy_bus_port_power, + .bus_reset = uhsic_phy_bus_reset, +}; + +static struct tegra_usb_phy_ops ulpi_null_phy_ops = { + .init = ulpi_null_phy_init, + .irq = ulpi_null_phy_irq, + .power_on = ulpi_null_phy_power_on, + .power_off = ulpi_null_phy_power_off, + .pre_resume = ulpi_null_phy_pre_resume, + .reset = ulpi_null_phy_cmd_reset, +}; + +static struct tegra_usb_phy_ops ulpi_link_phy_ops; +static struct tegra_usb_phy_ops icusb_phy_ops; + +static struct tegra_usb_phy_ops *phy_ops[] = { + [TEGRA_USB_PHY_INTF_UTMI] = &utmi_phy_ops, + [TEGRA_USB_PHY_INTF_ULPI_LINK] = &ulpi_link_phy_ops, + [TEGRA_USB_PHY_INTF_ULPI_NULL] = &ulpi_null_phy_ops, + [TEGRA_USB_PHY_INTF_HSIC] = &uhsic_phy_ops, + [TEGRA_USB_PHY_INTF_ICUSB] = &icusb_phy_ops, +}; + +int tegra3_usb_phy_init_ops(struct tegra_usb_phy *phy) +{ + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + phy->ops = phy_ops[phy->pdata->phy_intf]; + + /* FIXME: uncommenting below line to make USB host mode fail*/ + /* usb_phy_power_down_pmc(); */ + + return 0; +} diff --git a/arch/arm/mach-tegra/tegra_usb_phy.h b/arch/arm/mach-tegra/tegra_usb_phy.h new file mode 100644 index 000000000000..36b88db94f52 --- /dev/null +++ b/arch/arm/mach-tegra/tegra_usb_phy.h @@ -0,0 +1,104 @@ +/* + * arch/arm/mach-tegra/include/mach/tegra_usb_phy.h + * + * Copyright (C) 2011 NVIDIA 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 __MACH_TEGRA_USB_PHY_H +#define __MACH_TEGRA_USB_PHY_H + +/** + * defines USB port speeds supported in USB2.0 + */ +enum usb_phy_port_speed { + USB_PHY_PORT_SPEED_FULL = 0, + USB_PHY_PORT_SPEED_LOW, + USB_PHY_PORT_SPEED_HIGH, + USB_PHY_PORT_SPEED_UNKNOWN, +}; + +/** + * defines structure for oscillator dependent parameters + */ +struct tegra_xtal_freq { + int freq; + u8 enable_delay; + u8 stable_count; + u8 active_delay; + u16 xtal_freq_count; + u16 debounce; + u8 pdtrk_count; +}; + +/** + * pre decleration of the usb phy data structure + */ +struct tegra_usb_phy; + +/** + * defines function pointers used for differnt phy interfaces + */ +struct tegra_usb_phy_ops { + int (*open)(struct tegra_usb_phy *phy); + void (*close)(struct tegra_usb_phy *phy); + int (*irq)(struct tegra_usb_phy *phy); + int (*init)(struct tegra_usb_phy *phy); + int (*reset)(struct tegra_usb_phy *phy); + int (*pre_suspend)(struct tegra_usb_phy *phy); + int (*suspend)(struct tegra_usb_phy *phy); + int (*post_suspend)(struct tegra_usb_phy *phy); + int (*pre_resume)(struct tegra_usb_phy *phy, bool remote_wakeup); + int (*resume)(struct tegra_usb_phy *phy); + int (*post_resume)(struct tegra_usb_phy *phy); + int (*port_power)(struct tegra_usb_phy *phy); + int (*bus_reset)(struct tegra_usb_phy *phy); + int (*power_off)(struct tegra_usb_phy *phy); + int (*power_on)(struct tegra_usb_phy *phy); + bool (*charger_detect)(struct tegra_usb_phy *phy); +}; + +/** + * defines usb phy data structure + */ +struct tegra_usb_phy { + struct platform_device *pdev; + struct tegra_usb_platform_data *pdata; + struct clk *pllu_clk; + struct clk *ctrlr_clk; + struct clk *ulpi_clk; + struct clk *utmi_pad_clk; + struct clk *emc_clk; + struct clk *sys_clk; + struct regulator *vdd_reg; + struct regulator *vbus_reg; + struct tegra_usb_phy_ops *ops; + struct tegra_xtal_freq *freq; + struct otg_transceiver *ulpi_vp; + enum usb_phy_port_speed port_speed; + signed char utmi_xcvr_setup; + void __iomem *regs; + int inst; + bool phy_clk_on; + bool phy_power_on; + bool remote_wakeup; + bool hw_accessible; +}; + +int usb_phy_reg_status_wait(void __iomem *reg, u32 mask, + u32 result, u32 timeout); + +int tegra3_usb_phy_init_ops(struct tegra_usb_phy *phy); +int tegra2_usb_phy_init_ops(struct tegra_usb_phy *phy); + + +#endif /* __MACH_TEGRA_USB_PHY_H */ diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c index 8c36159e085a..6f568fd2cd29 100644 --- a/arch/arm/mach-tegra/usb_phy.c +++ b/arch/arm/mach-tegra/usb_phy.c @@ -18,7 +18,6 @@ * GNU General Public License for more details. * */ - #include <linux/resource.h> #include <linux/delay.h> #include <linux/interrupt.h> @@ -27,581 +26,16 @@ #include <linux/platform_device.h> #include <linux/io.h> #include <linux/gpio.h> -#include <linux/usb/otg.h> -#include <linux/usb/ulpi.h> -#include <asm/mach-types.h> -#include <mach/usb_phy.h> +#include <linux/interrupt.h> +#include <linux/clk.h> +#include <linux/regulator/consumer.h> +#include <linux/platform_data/tegra_usb.h> +#include "tegra_usb_phy.h" #include <mach/iomap.h> -#include <mach/pinmux.h> -#include "fuse.h" - - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC -#define USB_USBCMD 0x140 -#define USB_USBCMD_RS (1 << 0) - -#define USB_USBSTS 0x144 -#define USB_USBSTS_PCI (1 << 2) -#define USB_USBSTS_HCH (1 << 12) - -#define USB_TXFILLTUNING 0x164 -#define USB_FIFO_TXFILL_THRES(x) (((x) & 0x1f) << 16) -#define USB_FIFO_TXFILL_MASK 0x1f0000 - -#define ULPI_VIEWPORT 0x170 -#define ULPI_WAKEUP (1 << 31) -#define ULPI_RUN (1 << 30) -#define ULPI_RD_WR (1 << 29) - -#define USB_PORTSC1 0x184 -#define USB_PORTSC1_PTS(x) (((x) & 0x3) << 30) -#define USB_PORTSC1_PSPD(x) (((x) & 0x3) << 26) -#define USB_PORTSC1_PHCD (1 << 23) -#define USB_PORTSC1_WKOC (1 << 22) -#define USB_PORTSC1_WKDS (1 << 21) -#define USB_PORTSC1_WKCN (1 << 20) -#define USB_PORTSC1_PTC(x) (((x) & 0xf) << 16) -#define USB_PORTSC1_PP (1 << 12) -#define USB_PORTSC1_LS(x) (((x) & 0x3) << 10) -#define USB_PORTSC1_SUSP (1 << 7) -#define USB_PORTSC1_PE (1 << 2) -#define USB_PORTSC1_CCS (1 << 0) - -#define USB_SUSP_CTRL 0x400 -#define USB_WAKE_ON_CNNT_EN_DEV (1 << 3) -#define USB_WAKE_ON_DISCON_EN_DEV (1 << 4) -#define USB_SUSP_CLR (1 << 5) -#define USB_CLKEN (1 << 6) -#define USB_PHY_CLK_VALID (1 << 7) -#define USB_PHY_CLK_VALID_INT_ENB (1 << 9) -#define UTMIP_RESET (1 << 11) -#define UHSIC_RESET (1 << 11) -#define UTMIP_PHY_ENABLE (1 << 12) -#define UHSIC_PHY_ENABLE (1 << 12) -#define ULPI_PHY_ENABLE (1 << 13) -#define USB_SUSP_SET (1 << 14) -#define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16) - -#define USB_PHY_VBUS_WAKEUP_ID 0x408 -#define VDAT_DET_INT_EN (1 << 16) -#define VDAT_DET_CHG_DET (1 << 17) -#define VDAT_DET_STS (1 << 18) - -#define USB1_LEGACY_CTRL 0x410 -#define USB1_NO_LEGACY_MODE (1 << 0) -#define USB1_VBUS_SENSE_CTL_MASK (3 << 1) -#define USB1_VBUS_SENSE_CTL_VBUS_WAKEUP (0 << 1) -#define USB1_VBUS_SENSE_CTL_AB_SESS_VLD_OR_VBUS_WAKEUP \ - (1 << 1) -#define USB1_VBUS_SENSE_CTL_AB_SESS_VLD (2 << 1) -#define USB1_VBUS_SENSE_CTL_A_SESS_VLD (3 << 1) - - -#define UTMIP_PLL_CFG1 0x804 -#define UTMIP_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0) -#define UTMIP_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27) - -#define UTMIP_XCVR_CFG0 0x808 -#define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0) -#define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8) -#define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10) -#define UTMIP_FORCE_PD_POWERDOWN (1 << 14) -#define UTMIP_FORCE_PD2_POWERDOWN (1 << 16) -#define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18) -#define UTMIP_XCVR_LSBIAS_SEL (1 << 21) -#define UTMIP_XCVR_SETUP_MSB(x) (((x) & 0x7) << 22) -#define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25) - -#define UTMIP_XCVR_MAX_OFFSET 2 -#define UTMIP_XCVR_SETUP_MAX_VALUE 0x7f -#define UTMIP_XCVR_SETUP_MIN_VALUE 0 -#define XCVR_SETUP_MSB_CALIB(x) ((x) >> 4) - -#define UTMIP_BIAS_CFG0 0x80c -#define UTMIP_OTGPD (1 << 11) -#define UTMIP_BIASPD (1 << 10) - -#define UTMIP_HSRX_CFG0 0x810 -#define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10) -#define UTMIP_IDLE_WAIT(x) (((x) & 0x1f) << 15) - -#define UTMIP_HSRX_CFG1 0x814 -#define UTMIP_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1) - -#define UTMIP_TX_CFG0 0x820 -#define UTMIP_FS_PREABMLE_J (1 << 19) -#define UTMIP_HS_DISCON_DISABLE (1 << 8) - -#define UTMIP_MISC_CFG1 0x828 -#define UTMIP_PLL_ACTIVE_DLY_COUNT(x) (((x) & 0x1f) << 18) -#define UTMIP_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 6) - -#define UTMIP_DEBOUNCE_CFG0 0x82c -#define UTMIP_BIAS_DEBOUNCE_A(x) (((x) & 0xffff) << 0) - -#define UTMIP_BAT_CHRG_CFG0 0x830 -#define UTMIP_PD_CHRG (1 << 0) -#define UTMIP_ON_SINK_EN (1 << 2) -#define UTMIP_OP_SRC_EN (1 << 3) - -#define UTMIP_XCVR_CFG1 0x838 -#define UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0) -#define UTMIP_FORCE_PDCHRP_POWERDOWN (1 << 2) -#define UTMIP_FORCE_PDDR_POWERDOWN (1 << 4) -#define UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18) - -#define UTMIP_BIAS_CFG1 0x83c -#define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3) - -#define UHSIC_PLL_CFG1 0x804 -#define UHSIC_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0) -#define UHSIC_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 14) - -#define UHSIC_HSRX_CFG0 0x808 -#define UHSIC_ELASTIC_UNDERRUN_LIMIT(x) (((x) & 0x1f) << 2) -#define UHSIC_ELASTIC_OVERRUN_LIMIT(x) (((x) & 0x1f) << 8) -#define UHSIC_IDLE_WAIT(x) (((x) & 0x1f) << 13) - -#define UHSIC_HSRX_CFG1 0x80c -#define UHSIC_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1) - -#define UHSIC_TX_CFG0 0x810 -#define UHSIC_HS_POSTAMBLE_OUTPUT_ENABLE (1 << 6) - -#define UHSIC_MISC_CFG0 0x814 -#define UHSIC_SUSPEND_EXIT_ON_EDGE (1 << 7) -#define UHSIC_DETECT_SHORT_CONNECT (1 << 8) -#define UHSIC_FORCE_XCVR_MODE (1 << 15) - -#define UHSIC_MISC_CFG1 0X818 -#define UHSIC_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 2) - -#define UHSIC_PADS_CFG0 0x81c -#define UHSIC_TX_RTUNEN 0xf000 -#define UHSIC_TX_RTUNE(x) (((x) & 0xf) << 12) - -#define UHSIC_PADS_CFG1 0x820 -#define UHSIC_PD_BG (1 << 2) -#define UHSIC_PD_TX (1 << 3) -#define UHSIC_PD_TRK (1 << 4) -#define UHSIC_PD_RX (1 << 5) -#define UHSIC_PD_ZI (1 << 6) -#define UHSIC_RX_SEL (1 << 7) -#define UHSIC_RPD_DATA (1 << 9) -#define UHSIC_RPD_STROBE (1 << 10) -#define UHSIC_RPU_DATA (1 << 11) -#define UHSIC_RPU_STROBE (1 << 12) - -#define UHSIC_STAT_CFG0 0x828 -#define UHSIC_CONNECT_DETECT (1 << 0) - - -#else -#define USB_USBCMD 0x130 -#define USB_USBCMD_RS (1 << 0) - -#define USB_USBSTS 0x134 -#define USB_USBSTS_PCI (1 << 2) -#define USB_USBSTS_SRI (1 << 7) -#define USB_USBSTS_HCH (1 << 12) - -#define USB_TXFILLTUNING 0x154 -#define USB_FIFO_TXFILL_THRES(x) (((x) & 0x1f) << 16) -#define USB_FIFO_TXFILL_MASK 0x1f0000 - -#define ULPI_VIEWPORT 0x160 - -#define USB_PORTSC1 0x174 -#define USB_PORTSC1_WKOC (1 << 22) -#define USB_PORTSC1_WKDS (1 << 21) -#define USB_PORTSC1_WKCN (1 << 20) -#define USB_PORTSC1_PTC(x) (((x) & 0xf) << 16) -#define USB_PORTSC1_PP (1 << 12) -#define USB_PORTSC1_LS(x) (((x) & 0x3) << 10) -#define USB_PORTSC1_SUSP (1 << 7) -#define USB_PORTSC1_RESUME (1 << 6) -#define USB_PORTSC1_PE (1 << 2) -#define USB_PORTSC1_CCS (1 << 0) - -#define USB_SUSP_CTRL 0x400 -#define USB_WAKE_ON_CNNT_EN_DEV (1 << 3) -#define USB_WAKE_ON_DISCON_EN_DEV (1 << 4) -#define USB_SUSP_CLR (1 << 5) -#define USB_PHY_CLK_VALID (1 << 7) -#define USB_PHY_CLK_VALID_INT_ENB (1 << 9) - - -#define UTMIP_RESET (1 << 11) -#define UTMIP_PHY_ENABLE (1 << 12) -#define ULPI_PHY_ENABLE (1 << 13) -#define UHSIC_RESET (1 << 14) - -#define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16) -#define UHSIC_PHY_ENABLE (1 << 19) -#define ULPIS2S_SLV0_RESET (1 << 20) -#define ULPIS2S_SLV1_RESET (1 << 21) -#define ULPIS2S_LINE_RESET (1 << 22) -#define ULPI_PADS_RESET (1 << 23) -#define ULPI_PADS_CLKEN_RESET (1 << 24) - -#define USB_PHY_VBUS_WAKEUP_ID 0x408 -#define VDAT_DET_INT_EN (1 << 16) -#define VDAT_DET_CHG_DET (1 << 17) -#define VDAT_DET_STS (1 << 18) - -#define USB1_LEGACY_CTRL 0x410 -#define USB1_NO_LEGACY_MODE (1 << 0) -#define USB1_VBUS_SENSE_CTL_MASK (3 << 1) -#define USB1_VBUS_SENSE_CTL_VBUS_WAKEUP (0 << 1) -#define USB1_VBUS_SENSE_CTL_AB_SESS_VLD_OR_VBUS_WAKEUP \ - (1 << 1) -#define USB1_VBUS_SENSE_CTL_AB_SESS_VLD (2 << 1) -#define USB1_VBUS_SENSE_CTL_A_SESS_VLD (3 << 1) - -#define UTMIP_PLL_CFG1 0x804 -#define UTMIP_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0) -#define UTMIP_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27) - -#define UTMIP_XCVR_CFG0 0x808 -#define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0) -#define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8) -#define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10) -#define UTMIP_FORCE_PD_POWERDOWN (1 << 14) -#define UTMIP_FORCE_PD2_POWERDOWN (1 << 16) -#define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18) -#define UTMIP_XCVR_LSBIAS_SEL (1 << 21) -#define UTMIP_XCVR_SETUP_MSB(x) (((x) & 0x7) << 22) -#define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25) - -#define UTMIP_XCVR_MAX_OFFSET 2 -#define UTMIP_XCVR_SETUP_MAX_VALUE 0x7f -#define UTMIP_XCVR_SETUP_MIN_VALUE 0 -#define XCVR_SETUP_MSB_CALIB(x) ((x) >> 4) - -#define UTMIP_BIAS_CFG0 0x80c -#define UTMIP_OTGPD (1 << 11) -#define UTMIP_BIASPD (1 << 10) -#define UTMIP_HSSQUELCH_LEVEL(x) (((x) & 0x3) << 0) -#define UTMIP_HSDISCON_LEVEL(x) (((x) & 0x3) << 2) -#define UTMIP_HSDISCON_LEVEL_MSB (1 << 24) - -#define UTMIP_HSRX_CFG0 0x810 -#define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10) -#define UTMIP_IDLE_WAIT(x) (((x) & 0x1f) << 15) - -#define UTMIP_HSRX_CFG1 0x814 -#define UTMIP_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1) - -#define UTMIP_TX_CFG0 0x820 -#define UTMIP_FS_PREABMLE_J (1 << 19) -#define UTMIP_HS_DISCON_DISABLE (1 << 8) - -#define UTMIP_MISC_CFG1 0x828 -#define UTMIP_PLL_ACTIVE_DLY_COUNT(x) (((x) & 0x1f) << 18) -#define UTMIP_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 6) - -#define UTMIP_DEBOUNCE_CFG0 0x82c -#define UTMIP_BIAS_DEBOUNCE_A(x) (((x) & 0xffff) << 0) - -#define UTMIP_BAT_CHRG_CFG0 0x830 -#define UTMIP_PD_CHRG (1 << 0) -#define UTMIP_ON_SINK_EN (1 << 2) -#define UTMIP_OP_SRC_EN (1 << 3) - -#define UTMIP_XCVR_CFG1 0x838 -#define UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0) -#define UTMIP_FORCE_PDCHRP_POWERDOWN (1 << 2) -#define UTMIP_FORCE_PDDR_POWERDOWN (1 << 4) -#define UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18) - -#define UTMIP_BIAS_CFG1 0x83c -#define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3) -#define UTMIP_BIAS_PDTRK_POWERDOWN (1 << 0) -#define UTMIP_BIAS_PDTRK_POWERUP (1 << 1) - -#define HOSTPC1_DEVLC 0x1b4 -#define HOSTPC1_DEVLC_PHCD (1 << 22) -#define HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29) -#define HOSTPC1_DEVLC_PTS_MASK 7 -#define HOSTPC1_DEVLC_PTS_HSIC 4 -#define HOSTPC1_DEVLC_STS (1 << 28) -#define HOSTPC1_DEVLC_PSPD(x) (((x) & 0x3) << 25) -#define HOSTPC1_DEVLC_PSPD_MASK 3 -#define HOSTPC1_DEVLC_PSPD_HIGH_SPEED 2 - -#define TEGRA_USB_USBMODE_REG_OFFSET 0x1f8 -#define TEGRA_USB_USBMODE_HOST (3 << 0) - -#define TEGRA_PMC_USB_AO 0xf0 -#define TEGRA_PMC_USB_AO_VBUS_WAKEUP_PD_P0 (1 << 2) -#define TEGRA_PMC_USB_AO_ID_PD_P0 (1 << 3) -#define TEGRA_PMC_USB_AO_PD_P2 (0xf << 8) - -#define ICUSB_CTRL 0x15c - -#define UHSIC_PLL_CFG1 0xc04 -#define UHSIC_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0) -#define UHSIC_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 14) - -#define UHSIC_HSRX_CFG0 0xc08 -#define UHSIC_ELASTIC_UNDERRUN_LIMIT(x) (((x) & 0x1f) << 2) -#define UHSIC_ELASTIC_OVERRUN_LIMIT(x) (((x) & 0x1f) << 8) -#define UHSIC_IDLE_WAIT(x) (((x) & 0x1f) << 13) - -#define UHSIC_HSRX_CFG1 0xc0c -#define UHSIC_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1) - -#define UHSIC_TX_CFG0 0xc10 -#define UHSIC_HS_READY_WAIT_FOR_VALID (1 << 9) - -#define UHSIC_MISC_CFG0 0xc14 -#define UHSIC_SUSPEND_EXIT_ON_EDGE (1 << 7) -#define UHSIC_DETECT_SHORT_CONNECT (1 << 8) -#define UHSIC_FORCE_XCVR_MODE (1 << 15) -#define UHSIC_DISABLE_BUSRESET (1 << 20) - -#define UHSIC_MISC_CFG1 0xc18 -#define UHSIC_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 2) - -#define UHSIC_PADS_CFG0 0xc1c -#define UHSIC_TX_RTUNEN 0xf000 -#define UHSIC_TX_RTUNE(x) (((x) & 0xf) << 12) - -#define UHSIC_PADS_CFG1 0xc20 -#define UHSIC_PD_BG (1 << 2) -#define UHSIC_PD_TX (1 << 3) -#define UHSIC_PD_TRK (1 << 4) -#define UHSIC_PD_RX (1 << 5) -#define UHSIC_PD_ZI (1 << 6) -#define UHSIC_RX_SEL (1 << 7) -#define UHSIC_RPD_DATA (1 << 9) -#define UHSIC_RPD_STROBE (1 << 10) -#define UHSIC_RPU_DATA (1 << 11) -#define UHSIC_RPU_STROBE (1 << 12) - -#define UHSIC_STAT_CFG0 0xc28 -#define UHSIC_CONNECT_DETECT (1 << 0) - -#define PMC_UTMIP_MASTER_CONFIG 0x310 -#define UTMIP_PWR(inst) (1 << (inst)) - -#define PMC_USB_DEBOUNCE 0xec -#define UTMIP_LINE_DEB_CNT(x) (((x) & 0xf) << 16) - -#define PMC_UTMIP_UHSIC_FAKE 0x218 -#define USBON_VAL(inst) (1 << ((4*(inst))+1)) -#define USBON_VAL_P2 (1 << 9) -#define USBON_VAL_P1 (1 << 5) -#define USBON_VAL_P0 (1 << 1) -#define USBOP_VAL(inst) (1 << (4*(inst))) -#define USBOP_VAL_P2 (1 << 8) -#define USBOP_VAL_P1 (1 << 4) -#define USBOP_VAL_P0 (1 << 0) - -#define PMC_SLEEPWALK_CFG 0x200 -#define UTMIP_LINEVAL_WALK_EN(inst) (1 << ((8*(inst))+7)) -#define UTMIP_LINEVAL_WALK_EN_P2 (1 << 23) -#define UTMIP_LINEVAL_WALK_EN_P1 (1 << 15) -#define UTMIP_LINEVAL_WALK_EN_P0 (1 << 7) -#define UTMIP_WAKE_VAL(inst, x) (((x) & 0xf) << ((8*(inst))+4)) -#define UTMIP_WAKE_VAL_P2(x) (((x) & 0xf) << 20) -#define UTMIP_WAKE_VAL_P1(x) (((x) & 0xf) << 12) -#define UTMIP_WAKE_VAL_P0(x) (((x) & 0xf) << 4) -#define WAKE_VAL_NONE 0xc -#define WAKE_VAL_FSJ 0x2 -#define WAKE_VAL_FSK 0x1 -#define WAKE_VAL_SE0 0x0 -#define WAKE_VAL_ANY 0xf - -#define PMC_SLEEP_CFG 0x1fc -#define UTMIP_TCTRL_USE_PMC(inst) (1 << ((8*(inst))+3)) -#define UTMIP_TCTRL_USE_PMC_P2 (1 << 19) -#define UTMIP_TCTRL_USE_PMC_P1 (1 << 11) -#define UTMIP_TCTRL_USE_PMC_P0 (1 << 3) -#define UTMIP_RCTRL_USE_PMC(inst) (1 << ((8*(inst))+2)) -#define UTMIP_RCTRL_USE_PMC_P2 (1 << 18) -#define UTMIP_RCTRL_USE_PMC_P1 (1 << 10) -#define UTMIP_RCTRL_USE_PMC_P0 (1 << 2) -#define UTMIP_FSLS_USE_PMC(inst) (1 << ((8*(inst))+1)) -#define UTMIP_FSLS_USE_PMC_P2 (1 << 17) -#define UTMIP_FSLS_USE_PMC_P1 (1 << 9) -#define UTMIP_FSLS_USE_PMC_P0 (1 << 1) -#define UTMIP_MASTER_ENABLE(inst) (1 << (8*(inst))) -#define UTMIP_MASTER_ENABLE_P2 (1 << 16) -#define UTMIP_MASTER_ENABLE_P1 (1 << 8) -#define UTMIP_MASTER_ENABLE_P0 (1 << 0) -#define UHSIC_MASTER_ENABLE_P0 (1 << 24) -#define UHSIC_WAKE_VAL_P0(x) (((x) & 0xf) << 28) - -#define PMC_USB_AO 0xf0 -#define PMC_POWER_DOWN_MASK 0xffff -#define HSIC_RESERVED_P0 (3 << 14) -#define HSIC_STOBE_VAL_PD_P0 (1 << 13) -#define HSIC_DATA_VAL_PD_P0 (1 << 12) -#define USB_ID_PD(inst) (1 << ((4*(inst))+3)) -#define VBUS_WAKEUP_PD(inst) (1 << ((4*(inst))+2)) -#define USBON_VAL_PD(inst) (1 << ((4*(inst))+1)) -#define USBON_VAL_PD_P2 (1 << 9) -#define USBON_VAL_PD_P1 (1 << 5) -#define USBON_VAL_PD_P0 (1 << 1) -#define USBOP_VAL_PD(inst) (1 << (4*(inst))) -#define USBOP_VAL_PD_P2 (1 << 8) -#define USBOP_VAL_PD_P1 (1 << 4) -#define USBOP_VAL_PD_P0 (1 << 0) - -#define PMC_TRIGGERS 0x1ec -#define UTMIP_CLR_WALK_PTR(inst) (1 << (inst)) -#define UTMIP_CLR_WALK_PTR_P2 (1 << 2) -#define UTMIP_CLR_WALK_PTR_P1 (1 << 1) -#define UTMIP_CLR_WALK_PTR_P0 (1 << 0) -#define UTMIP_CAP_CFG(inst) (1 << ((inst)+4)) -#define UTMIP_CAP_CFG_P2 (1 << 6) -#define UTMIP_CAP_CFG_P1 (1 << 5) -#define UTMIP_CAP_CFG_P0 (1 << 4) -#define UTMIP_CLR_WAKE_ALARM(inst) (1 << ((inst)+12)) -#define UTMIP_CLR_WAKE_ALARM_P2 (1 << 14) - -#define PMC_PAD_CFG (0x1f4) - -#define PMC_UTMIP_BIAS_MASTER_CNTRL 0x30c -#define BIAS_MASTER_PROG_VAL (1 << 1) - -#define PMC_SLEEPWALK_REG(inst) (0x204 + (4*(inst))) -#define PMC_SLEEPWALK_P0 0x204 -#define PMC_SLEEPWALK_P1 0x208 -#define PMC_SLEEPWALK_P2 0x20c -#define UTMIP_USBOP_RPD_A (1 << 0) -#define UTMIP_USBON_RPD_A (1 << 1) -#define UTMIP_AP_A (1 << 4) -#define UTMIP_AN_A (1 << 5) -#define UTMIP_HIGHZ_A (1 << 6) -#define UTMIP_USBOP_RPD_B (1 << 8) -#define UTMIP_USBON_RPD_B (1 << 9) -#define UTMIP_AP_B (1 << 12) -#define UTMIP_AN_B (1 << 13) -#define UTMIP_HIGHZ_B (1 << 14) -#define UTMIP_USBOP_RPD_C (1 << 16) -#define UTMIP_USBON_RPD_C (1 << 17) -#define UTMIP_AP_C (1 << 20) -#define UTMIP_AN_C (1 << 21) -#define UTMIP_HIGHZ_C (1 << 22) -#define UTMIP_USBOP_RPD_D (1 << 24) -#define UTMIP_USBON_RPD_D (1 << 25) -#define UTMIP_AP_D (1 << 28) -#define UTMIP_AN_D (1 << 29) -#define UTMIP_HIGHZ_D (1 << 30) - -#define UTMIP_PMC_WAKEUP0 0x84c -#define EVENT_INT_ENB (1 << 0) - -#define UTMIP_UHSIC_STATUS 0x214 -#define UTMIP_WALK_PTR_VAL(inst) (0x3 << ((inst)*2)) -#define UTMIP_USBOP_VAL(inst) (1 << ((2*(inst)) + 8)) -#define UTMIP_USBOP_VAL_P2 (1 << 12) -#define UTMIP_USBOP_VAL_P1 (1 << 10) -#define UTMIP_USBOP_VAL_P0 (1 << 8) -#define UTMIP_USBON_VAL(inst) (1 << ((2*(inst)) + 9)) -#define UTMIP_USBON_VAL_P2 (1 << 13) -#define UTMIP_USBON_VAL_P1 (1 << 11) -#define UTMIP_USBON_VAL_P0 (1 << 9) -#define UTMIP_WAKE_ALARM(inst) (1 << ((inst) + 16)) -#define UTMIP_WAKE_ALARM_P2 (1 << 18) -#define UTMIP_WAKE_ALARM_P1 (1 << 17) -#define UTMIP_WAKE_ALARM_P0 (1 << 16) -#define UTMIP_WALK_PTR(inst) (1 << ((inst)*2)) -#define UTMIP_WALK_PTR_P2 (1 << 4) -#define UTMIP_WALK_PTR_P1 (1 << 2) -#define UTMIP_WALK_PTR_P0 (1 << 0) - -#define UTMIP_BIAS_STS0 0x840 -#define UTMIP_RCTRL_VAL(x) (((x) & 0xffff) << 0) -#define UTMIP_TCTRL_VAL(x) (((x) & (0xffff << 16)) >> 16) - -#define PMC_UTMIP_TERM_PAD_CFG 0x1f8 -#define PMC_TCTRL_VAL(x) (((x) & 0x1f) << 5) -#define PMC_RCTRL_VAL(x) (((x) & 0x1f) << 0) - -#define UHSIC_SLEEPWALK_REG 0x210 -#define UHSIC_DATA_RPD_D (1 << 25) -#define UHSIC_STRB_RPD_D (1 << 24) -#define UHSIC_DATA_RPD_C (1 << 17) -#define UHSIC_STRB_RPD_C (1 << 16) -#define UHSIC_DATA_RPD_B (1 << 9) -#define UHSIC_STRB_RPD_B (1 << 8) -#define UHSIC_DATA_RPD_A (1 << 1) -#define UHSIC_STRB_RPD_A (1 << 0) - -static u32 utmip_rctrl_val, utmip_tctrl_val; - -#endif - -/* Common registers */ -#define UTMIP_MISC_CFG0 0x824 -#define UTMIP_DPDM_OBSERVE (1 << 26) -#define UTMIP_DPDM_OBSERVE_SEL(x) (((x) & 0xf) << 27) -#define UTMIP_DPDM_OBSERVE_SEL_FS_J UTMIP_DPDM_OBSERVE_SEL(0xf) -#define UTMIP_DPDM_OBSERVE_SEL_FS_K UTMIP_DPDM_OBSERVE_SEL(0xe) -#define UTMIP_DPDM_OBSERVE_SEL_FS_SE1 UTMIP_DPDM_OBSERVE_SEL(0xd) -#define UTMIP_DPDM_OBSERVE_SEL_FS_SE0 UTMIP_DPDM_OBSERVE_SEL(0xc) -#define UTMIP_SUSPEND_EXIT_ON_EDGE (1 << 22) -#define FORCE_PULLDN_DM (1 << 8) -#define FORCE_PULLDN_DP (1 << 9) -#define COMB_TERMS (1 << 0) -#define ALWAYS_FREE_RUNNING_TERMS (1 << 1) - -#define ULPIS2S_CTRL 0x418 -#define ULPIS2S_ENA (1 << 0) -#define ULPIS2S_SUPPORT_DISCONNECT (1 << 2) -#define ULPIS2S_PLLU_MASTER_BLASTER60 (1 << 3) -#define ULPIS2S_SPARE(x) (((x) & 0xF) << 8) -#define ULPIS2S_FORCE_ULPI_CLK_OUT (1 << 12) -#define ULPIS2S_DISCON_DONT_CHECK_SE0 (1 << 13) -#define ULPIS2S_SUPPORT_HS_KEEP_ALIVE (1 << 14) -#define ULPIS2S_DISABLE_STP_PU (1 << 15) -#define ULPIS2S_SLV0_CLAMP_XMIT (1 << 16) - - -#define ULPI_TIMING_CTRL_0 0x424 -#define ULPI_CLOCK_OUT_DELAY(x) ((x) & 0x1F) -#define ULPI_OUTPUT_PINMUX_BYP (1 << 10) -#define ULPI_CLKOUT_PINMUX_BYP (1 << 11) -#define ULPI_SHADOW_CLK_LOOPBACK_EN (1 << 12) -#define ULPI_SHADOW_CLK_SEL (1 << 13) -#define ULPI_CORE_CLK_SEL (1 << 14) -#define ULPI_SHADOW_CLK_DELAY(x) (((x) & 0x1F) << 16) -#define ULPI_LBK_PAD_EN (1 << 26) -#define ULPI_LBK_PAD_E_INPUT_OR (1 << 27) -#define ULPI_CLK_OUT_ENA (1 << 28) -#define ULPI_CLK_PADOUT_ENA (1 << 29) - -#define ULPI_TIMING_CTRL_1 0x428 -#define ULPI_DATA_TRIMMER_LOAD (1 << 0) -#define ULPI_DATA_TRIMMER_SEL(x) (((x) & 0x7) << 1) -#define ULPI_STPDIRNXT_TRIMMER_LOAD (1 << 16) -#define ULPI_STPDIRNXT_TRIMMER_SEL(x) (((x) & 0x7) << 17) -#define ULPI_DIR_TRIMMER_LOAD (1 << 24) -#define ULPI_DIR_TRIMMER_SEL(x) (((x) & 0x7) << 25) - -#define UTMIP_SPARE_CFG0 0x834 -#define FUSE_SETUP_SEL (1 << 3) -#define FUSE_ATERM_SEL (1 << 4) - -#define FUSE_USB_CALIB_0 0x1F0 -#define FUSE_USB_CALIB_XCVR_SETUP(x) (((x) & 0x7F) << 0) - -#define UHSIC_PLL_CFG0 0x800 - -#define UHSIC_CMD_CFG0 0x824 -#define UHSIC_PRETEND_CONNECT_DETECT (1 << 5) - -#define UHSIC_SPARE_CFG0 0x82c - -/* These values (in milli second) are taken from the battery charging spec */ -#define TDP_SRC_ON_MS 100 -#define TDPSRC_CON_MS 40 - -#define CONNECT_DETECT_TIMEOUT 25000 +#define ERR(stuff...) pr_err("usb_phy: " stuff) +#define WARNING(stuff...) pr_warning("usb_phy: " stuff) +#define INFO(stuff...) pr_info("usb_phy: " stuff) #define AHB_MEM_PREFETCH_CFG3 0xe0 #define AHB_MEM_PREFETCH_CFG4 0xe4 @@ -609,2587 +43,599 @@ static u32 utmip_rctrl_val, utmip_tctrl_val; #define AHB_MEM_PREFETCH_CFG2 0xf0 #define PREFETCH_ENB (1 << 31) -static DEFINE_SPINLOCK(utmip_pad_lock); -static int utmip_pad_count; - -struct tegra_xtal_freq { - int freq; - u8 enable_delay; - u8 stable_count; - u8 active_delay; - u16 xtal_freq_count; - u16 debounce; - u8 pdtrk_count; -}; - -static const struct tegra_xtal_freq tegra_freq_table[] = { - { - .freq = 12000000, - .enable_delay = 0x02, - .stable_count = 0x2F, - .active_delay = 0x04, - .xtal_freq_count = 0x76, - .debounce = 0x7530, - .pdtrk_count = 5, - }, - { - .freq = 13000000, - .enable_delay = 0x02, - .stable_count = 0x33, - .active_delay = 0x05, - .xtal_freq_count = 0x7F, - .debounce = 0x7EF4, - .pdtrk_count = 5, - }, - { - .freq = 19200000, - .enable_delay = 0x03, - .stable_count = 0x4B, - .active_delay = 0x06, - .xtal_freq_count = 0xBB, - .debounce = 0xBB80, - .pdtrk_count = 7, - }, - { - .freq = 26000000, - .enable_delay = 0x04, - .stable_count = 0x66, - .active_delay = 0x09, - .xtal_freq_count = 0xFE, - .debounce = 0xFDE8, - .pdtrk_count = 9, - }, -}; - -static const struct tegra_xtal_freq tegra_uhsic_freq_table[] = { - { - .freq = 12000000, - .enable_delay = 0x02, - .stable_count = 0x2F, - .active_delay = 0x0, - .xtal_freq_count = 0x1CA, - }, - { - .freq = 13000000, - .enable_delay = 0x02, - .stable_count = 0x33, - .active_delay = 0x0, - .xtal_freq_count = 0x1F0, - }, - { - .freq = 19200000, - .enable_delay = 0x03, - .stable_count = 0x4B, - .active_delay = 0x0, - .xtal_freq_count = 0x2DD, - }, - { - .freq = 26000000, - .enable_delay = 0x04, - .stable_count = 0x66, - .active_delay = 0x0, - .xtal_freq_count = 0x3E0, - }, -}; - -static struct tegra_utmip_config utmip_default[] = { - [0] = { - .hssync_start_delay = 9, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 9, - .xcvr_setup_offset = 0, - .xcvr_use_fuses = 1, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, - [2] = { - .hssync_start_delay = 9, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup_offset = 0, - .xcvr_use_fuses = 1, - .xcvr_setup = 9, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, -}; - -struct usb_phy_plat_data usb_phy_data[] = { - { 0, 0, -1, NULL}, - { 0, 0, -1, NULL}, - { 0, 0, -1, NULL}, -}; - -static int utmip_pad_open(struct tegra_usb_phy *phy) +#ifdef DEBUG +#define DBG(stuff...) pr_info("usb_phy: " stuff) +#else +#define DBG(stuff...) do {} while (0) +#endif + +static void print_usb_plat_data_info(struct tegra_usb_phy *phy) { - phy->pad_clk = clk_get_sys("utmip-pad", NULL); - if (IS_ERR(phy->pad_clk)) { - pr_err("%s: can't get utmip pad clock\n", __func__); - return PTR_ERR(phy->pad_clk); - } + struct tegra_usb_platform_data *pdata = phy->pdata; + char op_mode[][50] = { + "TEGRA_USB_OPMODE_DEVICE", + "TEGRA_USB_OPMODE_HOST" + }; + char phy_intf[][50] = { + "USB_PHY_INTF_UTMI", + "USB_PHY_INTF_ULPI_LINK", + "USB_PHY_INTF_ULPI_NULL", + "USB_PHY_INTF_HSIC", + "USB_PHY_INTF_ICUSB" + }; - if (phy->instance == 0) { - phy->pad_regs = phy->regs; + pr_info("tegra USB phy - inst[%d] platform info:\n", phy->inst); + pr_info("port_otg: %s\n", pdata->port_otg ? "yes" : "no"); + pr_info("has_hostpc: %s\n", pdata->has_hostpc ? "yes" : "no"); + pr_info("phy_interface: %s\n", phy_intf[pdata->phy_intf]); + pr_info("op_mode: %s\n", op_mode[pdata->op_mode]); + if (pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) { + pr_info("vbus_pmu_irq: %d\n", pdata->u_data.dev.vbus_pmu_irq); + pr_info("vbus_gpio: %d\n", pdata->u_data.dev.vbus_gpio); + pr_info("charging: %s\n", pdata->u_data.dev.charging_supported ? + "enabled" : "disabled"); + pr_info("remote_wakeup: %s\n", pdata->u_data.dev.remote_wakeup_supported + ? "enabled" : "disabled"); } else { - phy->pad_regs = ioremap(TEGRA_USB_BASE, TEGRA_USB_SIZE); - if (!phy->pad_regs) { - pr_err("%s: can't remap usb registers\n", __func__); - clk_put(phy->pad_clk); - return -ENOMEM; - } + pr_info("vbus_gpio: %d\n", pdata->u_data.host.vbus_gpio); + pr_info("vbus_reg: %s\n", pdata->u_data.host.vbus_reg ? + pdata->u_data.host.vbus_reg : "NULL"); + pr_info("hot_plug: %s\n", pdata->u_data.host.hot_plug ? + "enabled" : "disabled"); + pr_info("remote_wakeup: %s\n", pdata->u_data.host.remote_wakeup_supported + ? "enabled" : "disabled"); } - return 0; } -static void utmip_pad_close(struct tegra_usb_phy *phy) +static void usb_host_vbus_enable(struct tegra_usb_phy *phy, bool enable) { - if (phy->instance != 0) - iounmap(phy->pad_regs); - clk_put(phy->pad_clk); -} - -static int utmip_pad_power_on(struct tegra_usb_phy *phy) -{ - unsigned long val, flags; - void __iomem *base = phy->pad_regs; - - clk_enable(phy->pad_clk); - - spin_lock_irqsave(&utmip_pad_lock, flags); - - utmip_pad_count++; - val = readl(base + UTMIP_BIAS_CFG0); - val &= ~(UTMIP_OTGPD | UTMIP_BIASPD); -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - val |= UTMIP_HSSQUELCH_LEVEL(0x2) | UTMIP_HSDISCON_LEVEL(0x1) | - UTMIP_HSDISCON_LEVEL_MSB; -#endif - writel(val, base + UTMIP_BIAS_CFG0); - - spin_unlock_irqrestore(&utmip_pad_lock, flags); - - clk_disable(phy->pad_clk); - - return 0; -} - -static int utmip_pad_power_off(struct tegra_usb_phy *phy, bool is_dpd) -{ - unsigned long val, flags; - void __iomem *base = phy->pad_regs; - - if (!utmip_pad_count) { - pr_err("%s: utmip pad already powered off\n", __func__); - return -EINVAL; - } - - clk_enable(phy->pad_clk); - - spin_lock_irqsave(&utmip_pad_lock, flags); - - if (--utmip_pad_count == 0 && is_dpd) { - val = readl(base + UTMIP_BIAS_CFG0); - val |= UTMIP_OTGPD | UTMIP_BIASPD; -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - val &= ~(UTMIP_HSSQUELCH_LEVEL(~0) | UTMIP_HSDISCON_LEVEL(~0) | - UTMIP_HSDISCON_LEVEL_MSB); -#endif - writel(val, base + UTMIP_BIAS_CFG0); + if (phy->vbus_reg) { + if (enable) + regulator_enable(phy->vbus_reg); + else + regulator_disable(phy->vbus_reg); + } else { + int gpio = phy->pdata->u_data.host.vbus_gpio; + if (gpio == -1) + return; + gpio_set_value_cansleep(gpio, enable ? 1 : 0); } - - spin_unlock_irqrestore(&utmip_pad_lock, flags); - - clk_disable(phy->pad_clk); - - return 0; } -static int utmi_wait_register(void __iomem *reg, u32 mask, u32 result) +int usb_phy_reg_status_wait(void __iomem *reg, u32 mask, + u32 result, u32 timeout) { - unsigned long timeout = 2500; do { if ((readl(reg) & mask) == result) return 0; udelay(1); timeout--; } while (timeout); - return -1; -} -static int utmi_wait_register_timeout(void __iomem *reg, u32 mask, u32 result, - unsigned long timeout) -{ - do { - if ((readl(reg) & mask) == result) - return 0; - udelay(1); - timeout--; - } while (timeout); return -1; } -static void utmi_phy_clk_disable(struct tegra_usb_phy *phy) -{ - unsigned long val; - void __iomem *base = phy->regs; - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - if (phy->instance == 0) { - val = readl(base + USB_SUSP_CTRL); - val |= USB_SUSP_SET; - writel(val, base + USB_SUSP_CTRL); - - udelay(10); - - val = readl(base + USB_SUSP_CTRL); - val &= ~USB_SUSP_SET; - writel(val, base + USB_SUSP_CTRL); - } - - if (phy->instance == 2) { - val = readl(base + USB_PORTSC1); - val |= USB_PORTSC1_PHCD; - writel(val, base + USB_PORTSC1); - } -#else - val = readl(base + HOSTPC1_DEVLC); - val |= HOSTPC1_DEVLC_PHCD; - writel(val, base + HOSTPC1_DEVLC); -#endif - if (phy->hotplug) { - val = readl(base + USB_SUSP_CTRL); - val |= USB_PHY_CLK_VALID_INT_ENB; - writel(val, base + USB_SUSP_CTRL); - } else { - val = readl(base + USB_SUSP_CTRL); - val |= UTMIP_RESET; - writel(val, base + USB_SUSP_CTRL); - } - - if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0) - pr_err("%s: timeout waiting for phy to stabilize\n", __func__); -} - -static void utmi_phy_clk_enable(struct tegra_usb_phy *phy) -{ - unsigned long val; - void __iomem *base = phy->regs; - - if (phy->instance == 0) { - val = readl(base + USB_SUSP_CTRL); - val |= USB_SUSP_CLR; - writel(val, base + USB_SUSP_CTRL); - - udelay(10); - - val = readl(base + USB_SUSP_CTRL); - val &= ~USB_SUSP_CLR; - writel(val, base + USB_SUSP_CTRL); - } - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - if (phy->instance == 2) { - val = readl(base + USB_PORTSC1); - val &= ~USB_PORTSC1_PHCD; - writel(val, base + USB_PORTSC1); - } -#endif - - if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, - USB_PHY_CLK_VALID) < 0) - pr_err("%s: timeout waiting for phy to stabilize\n", __func__); -} - -static void vbus_enable(struct tegra_usb_phy *phy) +int tegra_usb_phy_init_ops(struct tegra_usb_phy *phy) { -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - int gpio_status; - int gpio = usb_phy_data[phy->instance].vbus_gpio; - - if (gpio == -1) - return; - - gpio_status = gpio_request(gpio,"VBUS_USB"); - if (gpio_status < 0) { - printk("VBUS_USB request GPIO FAILED\n"); - WARN_ON(1); - return; - } - if (gpio < TEGRA_NR_GPIOS) tegra_gpio_enable(gpio); - gpio_status = gpio_direction_output(gpio, 1); - if (gpio_status < 0) { - printk("VBUS_USB request GPIO DIRECTION FAILED \n"); - WARN_ON(1); - return; - } - gpio_set_value_cansleep(gpio, 1); -#else - if (phy->reg_vbus) - regulator_enable(phy->reg_vbus); -#endif -} + int err = 0; -static void vbus_disable(struct tegra_usb_phy *phy) -{ -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - int gpio = usb_phy_data[phy->instance].vbus_gpio; - - if (gpio == -1) - return; + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); - gpio_set_value_cansleep(gpio, 0); - gpio_free(gpio); -#else - if (phy->reg_vbus) - regulator_disable(phy->reg_vbus); -#endif -} - -#ifndef CONFIG_ARCH_TEGRA_2x_SOC -static void utmip_phy_enable_trking_data(struct tegra_usb_phy *phy) -{ - void __iomem *base = phy->pad_regs; - void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); - static bool init_done = false; - u32 val; - - /* Should be done only once after system boot */ - if (init_done) - return; - - clk_enable(phy->pad_clk); - /* Bias pad MASTER_ENABLE=1 */ - val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL); - val |= BIAS_MASTER_PROG_VAL; - writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL); - - /* Setting the tracking length time */ - val = readl(base + UTMIP_BIAS_CFG1); - val &= ~UTMIP_BIAS_PDTRK_COUNT(~0); - val |= UTMIP_BIAS_PDTRK_COUNT(5); - writel(val, base + UTMIP_BIAS_CFG1); - - /* Bias PDTRK is Shared and MUST be done from USB1 ONLY, PD_TRK=0 */ - val = readl(base + UTMIP_BIAS_CFG1); - val &= ~ UTMIP_BIAS_PDTRK_POWERDOWN; - writel(val, base + UTMIP_BIAS_CFG1); - - val = readl(base + UTMIP_BIAS_CFG1); - val |= UTMIP_BIAS_PDTRK_POWERUP; - writel(val, base + UTMIP_BIAS_CFG1); - - /* Wait for 25usec */ - udelay(25); - - /* Bias pad MASTER_ENABLE=0 */ - val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL); - val &= ~BIAS_MASTER_PROG_VAL; - writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL); - - /* Wait for 1usec */ - udelay(1); - - /* Bias pad MASTER_ENABLE=1 */ - val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL); - val |= BIAS_MASTER_PROG_VAL; - writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL); - - /* Read RCTRL and TCTRL from UTMIP space */ - val = readl(base + UTMIP_BIAS_STS0); - utmip_rctrl_val = ffz(UTMIP_RCTRL_VAL(val)); - utmip_tctrl_val = ffz(UTMIP_TCTRL_VAL(val)); - - /* PD_TRK=1 */ - val = readl(base + UTMIP_BIAS_CFG1); - val |= UTMIP_BIAS_PDTRK_POWERDOWN; - writel(val, base + UTMIP_BIAS_CFG1); - - /* Program thermally encoded RCTRL_VAL, TCTRL_VAL into PMC space */ - val = readl(pmc_base + PMC_UTMIP_TERM_PAD_CFG); - val = PMC_TCTRL_VAL(utmip_tctrl_val) | PMC_RCTRL_VAL(utmip_rctrl_val); - writel(val, pmc_base + PMC_UTMIP_TERM_PAD_CFG); - clk_disable(phy->pad_clk); - init_done = true; -} - -static void utmip_powerdown_pmc_wake_detect(struct tegra_usb_phy *phy) -{ - unsigned long val; - void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); - unsigned int inst = phy->instance; - - /* power down UTMIP interfaces */ - val = readl(pmc_base + PMC_UTMIP_MASTER_CONFIG); - val |= UTMIP_PWR(inst); - writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG); - - /* setup sleep walk usb controller */ - val = UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A | UTMIP_HIGHZ_A | - UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_HIGHZ_B | - UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_HIGHZ_C | - UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_HIGHZ_D; - writel(val, pmc_base + PMC_SLEEPWALK_REG(inst)); - - /* Program thermally encoded RCTRL_VAL, TCTRL_VAL into PMC space */ - val = readl(pmc_base + PMC_UTMIP_TERM_PAD_CFG); - val = PMC_TCTRL_VAL(utmip_tctrl_val) | PMC_RCTRL_VAL(utmip_rctrl_val); - writel(val, pmc_base + PMC_UTMIP_TERM_PAD_CFG); - - /* Turn over pad configuration to PMC */ - val = readl(pmc_base + PMC_SLEEP_CFG); - val &= ~UTMIP_WAKE_VAL(inst, ~0); - val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE) | - UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) | - UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst); - writel(val, pmc_base + PMC_SLEEP_CFG); -} + if (phy->pdata->has_hostpc) + err = tegra3_usb_phy_init_ops(phy); + else + err = tegra2_usb_phy_init_ops(phy); -static void utmip_powerup_pmc_wake_detect(struct tegra_usb_phy *phy) -{ - unsigned long val; - void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); - unsigned int inst = phy->instance; - - /* Disable PMC master mode by clearing MASTER_EN */ - val = readl(pmc_base + PMC_SLEEP_CFG); - val &= ~(UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) | - UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst)); - writel(val, pmc_base + PMC_SLEEP_CFG); - mdelay(1); + return err; } -static void uhsic_powerdown_pmc_wake_detect(struct tegra_usb_phy *phy) +static irqreturn_t usb_phy_dev_vbus_pmu_irq_thr(int irq, void *pdata) { - unsigned long val; - void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); - - /* turn on pad detectors for HSIC*/ - val = readl(pmc_base + PMC_USB_AO); - val |= (HSIC_RESERVED_P0 | HSIC_STOBE_VAL_PD_P0 | HSIC_DATA_VAL_PD_P0); - writel(val, pmc_base + PMC_USB_AO); - - /* enable pull downs on HSIC PMC */ - val = UHSIC_STRB_RPD_A | UHSIC_DATA_RPD_A | UHSIC_STRB_RPD_B | - UHSIC_DATA_RPD_B | UHSIC_STRB_RPD_C | UHSIC_DATA_RPD_C | - UHSIC_STRB_RPD_D | UHSIC_DATA_RPD_D; - writel(val, pmc_base + UHSIC_SLEEPWALK_REG); - - /* Turn over pad configuration to PMC */ - val = readl(pmc_base + PMC_SLEEP_CFG); - val &= ~UHSIC_WAKE_VAL_P0(~0); - val |= UHSIC_WAKE_VAL_P0(WAKE_VAL_NONE) | UHSIC_MASTER_ENABLE_P0; - writel(val, pmc_base + PMC_SLEEP_CFG); -} + /* FIXME : Need to enable pmu vbus handling */ -static void uhsic_powerup_pmc_wake_detect(struct tegra_usb_phy *phy) -{ - unsigned long val; - void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); - - /* turn on pad detectors for HSIC*/ - val = readl(pmc_base + PMC_USB_AO); - val &= ~(HSIC_RESERVED_P0 | HSIC_STOBE_VAL_PD_P0 | HSIC_DATA_VAL_PD_P0); - writel(val, pmc_base + PMC_USB_AO); - - /* Disable PMC master mode by clearing MASTER_EN */ - val = readl(pmc_base + PMC_SLEEP_CFG); - val &= ~(UHSIC_MASTER_ENABLE_P0); - writel(val, pmc_base + PMC_SLEEP_CFG); - mdelay(1); + return IRQ_NONE; } -#endif -static unsigned int tegra_phy_xcvr_setup_value(struct tegra_utmip_config *cfg) +static void tegra_usb_phy_release_clocks(struct tegra_usb_phy *phy) { - signed long val; - - if (cfg->xcvr_use_fuses) { - val = FUSE_USB_CALIB_XCVR_SETUP( - tegra_fuse_readl(FUSE_USB_CALIB_0)); - if (cfg->xcvr_setup_offset <= UTMIP_XCVR_MAX_OFFSET) - val = val + cfg->xcvr_setup_offset; - - if (val > UTMIP_XCVR_SETUP_MAX_VALUE) { - val = UTMIP_XCVR_SETUP_MAX_VALUE; - pr_info("%s: reset XCVR_SETUP to max value\n", - __func__); - } else if (val < UTMIP_XCVR_SETUP_MIN_VALUE) { - val = UTMIP_XCVR_SETUP_MIN_VALUE; - pr_info("%s: reset XCVR_SETUP to min value\n", - __func__); - } - } else { - val = cfg->xcvr_setup; - } - - return (unsigned int)val; + clk_put(phy->emc_clk); + clk_put(phy->sys_clk); + clk_put(phy->ctrlr_clk); + clk_disable(phy->pllu_clk); + clk_put(phy->pllu_clk); } -static int utmi_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd) +static int tegra_usb_phy_get_clocks(struct tegra_usb_phy *phy) { - unsigned long val; - void __iomem *base = phy->regs; - unsigned int xcvr_setup_value; - struct tegra_utmip_config *config = phy->config; - - val = readl(base + USB_SUSP_CTRL); - val |= UTMIP_RESET; - writel(val, base + USB_SUSP_CTRL); - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - if (phy->instance == 0) { - val = readl(base + USB1_LEGACY_CTRL); - val |= USB1_NO_LEGACY_MODE; - writel(val, base + USB1_LEGACY_CTRL); - } -#endif - - val = readl(base + UTMIP_TX_CFG0); - val |= UTMIP_FS_PREABMLE_J; - writel(val, base + UTMIP_TX_CFG0); - - val = readl(base + UTMIP_HSRX_CFG0); - val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0)); - val |= UTMIP_IDLE_WAIT(config->idle_wait_delay); - val |= UTMIP_ELASTIC_LIMIT(config->elastic_limit); - writel(val, base + UTMIP_HSRX_CFG0); - - val = readl(base + UTMIP_HSRX_CFG1); - val &= ~UTMIP_HS_SYNC_START_DLY(~0); - val |= UTMIP_HS_SYNC_START_DLY(config->hssync_start_delay); - writel(val, base + UTMIP_HSRX_CFG1); - - val = readl(base + UTMIP_DEBOUNCE_CFG0); - val &= ~UTMIP_BIAS_DEBOUNCE_A(~0); - val |= UTMIP_BIAS_DEBOUNCE_A(phy->freq->debounce); - writel(val, base + UTMIP_DEBOUNCE_CFG0); - - val = readl(base + UTMIP_MISC_CFG0); - val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE; - writel(val, base + UTMIP_MISC_CFG0); - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - val = readl(base + UTMIP_MISC_CFG1); - val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | UTMIP_PLLU_STABLE_COUNT(~0)); - val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) | - UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count); - writel(val, base + UTMIP_MISC_CFG1); - - val = readl(base + UTMIP_PLL_CFG1); - val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | UTMIP_PLLU_ENABLE_DLY_COUNT(~0)); - val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) | - UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay); - writel(val, base + UTMIP_PLL_CFG1); -#endif + int err = 0; - if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) { - val = readl(base + USB_SUSP_CTRL); - val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV); - writel(val, base + USB_SUSP_CTRL); + phy->pllu_clk = clk_get_sys(NULL, "pll_u"); + if (IS_ERR(phy->pllu_clk)) { + ERR("inst:[%d] Can't get pllu_clk clock\n", phy->inst); + err = PTR_ERR(phy->pllu_clk); + goto fail_pll; } + clk_enable(phy->pllu_clk); - utmip_pad_power_on(phy); - - xcvr_setup_value = phy->xcvr_setup_value; - - val = readl(base + UTMIP_XCVR_CFG0); - val &= ~(UTMIP_XCVR_LSBIAS_SEL | UTMIP_FORCE_PD_POWERDOWN | - UTMIP_FORCE_PD2_POWERDOWN | UTMIP_FORCE_PDZI_POWERDOWN | - UTMIP_XCVR_SETUP(~0) | UTMIP_XCVR_LSFSLEW(~0) | - UTMIP_XCVR_LSRSLEW(~0) | UTMIP_XCVR_HSSLEW_MSB(~0)); - val |= UTMIP_XCVR_SETUP(xcvr_setup_value); - val |= UTMIP_XCVR_SETUP_MSB(XCVR_SETUP_MSB_CALIB(xcvr_setup_value)); - val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew); - val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew); -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - val |= UTMIP_XCVR_HSSLEW_MSB(0x8); -#endif - writel(val, base + UTMIP_XCVR_CFG0); - - val = readl(base + UTMIP_XCVR_CFG1); - val &= ~(UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN | - UTMIP_FORCE_PDDR_POWERDOWN | UTMIP_XCVR_TERM_RANGE_ADJ(~0)); - val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj); - writel(val, base + UTMIP_XCVR_CFG1); - - val = readl(base + UTMIP_BAT_CHRG_CFG0); - if (phy->mode == TEGRA_USB_PHY_MODE_HOST) - val |= UTMIP_PD_CHRG; - else - val &= ~UTMIP_PD_CHRG; - writel(val, base + UTMIP_BAT_CHRG_CFG0); - - val = readl(base + UTMIP_BIAS_CFG1); - val &= ~UTMIP_BIAS_PDTRK_COUNT(~0); - val |= UTMIP_BIAS_PDTRK_COUNT(phy->freq->pdtrk_count); - writel(val, base + UTMIP_BIAS_CFG1); - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - val = readl(base + UTMIP_SPARE_CFG0); - val &= ~FUSE_SETUP_SEL; - writel(val, base + UTMIP_SPARE_CFG0); - - if (phy->instance == 2) { - val = readl(base + UTMIP_SPARE_CFG0); - val |= FUSE_SETUP_SEL; - writel(val, base + UTMIP_SPARE_CFG0); - - val = readl(base + USB_SUSP_CTRL); - val |= UTMIP_PHY_ENABLE; - writel(val, base + USB_SUSP_CTRL); + phy->ctrlr_clk = clk_get(&phy->pdev->dev, NULL); + if (IS_ERR(phy->ctrlr_clk)) { + dev_err(&phy->pdev->dev, "Can't get controller clock\n"); + err = PTR_ERR(phy->ctrlr_clk); + goto fail_ctrlr_clk; } -#else - val = readl(base + UTMIP_SPARE_CFG0); - val &= ~FUSE_SETUP_SEL; - val |= FUSE_ATERM_SEL; - writel(val, base + UTMIP_SPARE_CFG0); - - val = readl(base + USB_SUSP_CTRL); - val |= UTMIP_PHY_ENABLE; - writel(val, base + USB_SUSP_CTRL); -#endif - - val = readl(base + USB_SUSP_CTRL); - val &= ~UTMIP_RESET; - writel(val, base + USB_SUSP_CTRL); - - if (phy->instance == 0) { - val = readl(base + USB1_LEGACY_CTRL); - val &= ~USB1_VBUS_SENSE_CTL_MASK; - val |= USB1_VBUS_SENSE_CTL_A_SESS_VLD; - writel(val, base + USB1_LEGACY_CTRL); -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - val = readl(base + USB_SUSP_CTRL); - val &= ~USB_SUSP_SET; - writel(val, base + USB_SUSP_CTRL); -#endif - } - - utmi_phy_clk_enable(phy); -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - if (phy->instance == 2) { - val = readl(base + USB_PORTSC1); - val &= ~USB_PORTSC1_PTS(~0); - writel(val, base + USB_PORTSC1); - } -#else - if (phy->instance == 0) - utmip_phy_enable_trking_data(phy); - - if(phy->instance == 2) { - writel(0, base + ICUSB_CTRL); + phy->sys_clk = clk_get(&phy->pdev->dev, "sclk"); + if (IS_ERR(phy->sys_clk)) { + dev_err(&phy->pdev->dev, "Can't get sclk clock\n"); + err = PTR_ERR(phy->sys_clk); + goto fail_sclk; } + clk_set_rate(phy->sys_clk, 80000000); - if (phy->mode == TEGRA_USB_PHY_MODE_HOST) { - val = readl(base + TEGRA_USB_USBMODE_REG_OFFSET); - writel((val | TEGRA_USB_USBMODE_HOST), - (base + TEGRA_USB_USBMODE_REG_OFFSET)); + phy->emc_clk = clk_get(&phy->pdev->dev, "emc"); + if (IS_ERR(phy->emc_clk)) { + dev_err(&phy->pdev->dev, "Can't get emc clock\n"); + err = PTR_ERR(phy->emc_clk); + goto fail_emc; } - val = readl(base + HOSTPC1_DEVLC); - val &= ~HOSTPC1_DEVLC_PTS(~0); - val |= HOSTPC1_DEVLC_STS; - writel(val, base + HOSTPC1_DEVLC); - - if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) - utmip_powerup_pmc_wake_detect(phy); -#endif - return 0; -} - -#ifndef CONFIG_ARCH_TEGRA_2x_SOC -static void utmip_setup_pmc_wake_detect(struct tegra_usb_phy *phy) -{ - unsigned long val, pmc_pad_cfg_val; - void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); - unsigned int inst = phy->instance; - void __iomem *base = phy->regs; - bool port_connected; - enum tegra_usb_phy_port_speed port_speed; - - /* check for port connect status */ - val = readl(base + USB_PORTSC1); - port_connected = val & USB_PORTSC1_CCS; - - if (!port_connected) - return; - - port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) & - HOSTPC1_DEVLC_PSPD_MASK; - /*Set PMC MASTER bits to do the following - * a. Take over the UTMI drivers - * b. set up such that it will take over resume - * if remote wakeup is detected - * Prepare PMC to take over suspend-wake detect-drive resume until USB - * controller ready - */ - - /* disable master enable in PMC */ - val = readl(pmc_base + PMC_SLEEP_CFG); - val &= ~UTMIP_MASTER_ENABLE(inst); - writel(val, pmc_base + PMC_SLEEP_CFG); - - /* UTMIP_PWR_PX=1 for power savings mode */ - val = readl(pmc_base + PMC_UTMIP_MASTER_CONFIG); - val |= UTMIP_PWR(inst); - writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG); - - /* config debouncer */ - val = readl(pmc_base + PMC_USB_DEBOUNCE); - val &= ~UTMIP_LINE_DEB_CNT(~0); - val |= UTMIP_LINE_DEB_CNT(1); - writel(val, pmc_base + PMC_USB_DEBOUNCE); - - /* Make sure nothing is happening on the line with respect to PMC */ - val = readl(pmc_base + PMC_UTMIP_UHSIC_FAKE); - val &= ~USBOP_VAL(inst); - val &= ~USBON_VAL(inst); - writel(val, pmc_base + PMC_UTMIP_UHSIC_FAKE); - - /* Make sure wake value for line is none */ - val = readl(pmc_base + PMC_SLEEPWALK_CFG); - val &= ~UTMIP_LINEVAL_WALK_EN(inst); - writel(val, pmc_base + PMC_SLEEPWALK_CFG); - val = readl(pmc_base + PMC_SLEEP_CFG); - val &= ~UTMIP_WAKE_VAL(inst, ~0); - val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE); - writel(val, pmc_base + PMC_SLEEP_CFG); - - /* turn off pad detectors */ - val = readl(pmc_base + PMC_USB_AO); - val |= (USBOP_VAL_PD(inst) | USBON_VAL_PD(inst)); - writel(val, pmc_base + PMC_USB_AO); - - /* Remove fake values and make synchronizers work a bit */ - val = readl(pmc_base + PMC_UTMIP_UHSIC_FAKE); - val &= ~USBOP_VAL(inst); - val &= ~USBON_VAL(inst); - writel(val, pmc_base + PMC_UTMIP_UHSIC_FAKE); - - /* Enable which type of event can trigger a walk, - in this case usb_line_wake */ - val = readl(pmc_base + PMC_SLEEPWALK_CFG); - val |= UTMIP_LINEVAL_WALK_EN(inst); - writel(val, pmc_base + PMC_SLEEPWALK_CFG); - - /* Enable which type of event can trigger a walk, - * in this case usb_line_wake */ - val = readl(pmc_base + PMC_SLEEPWALK_CFG); - val |= UTMIP_LINEVAL_WALK_EN(inst); - writel(val, pmc_base + PMC_SLEEPWALK_CFG); - - /* Clear the walk pointers and wake alarm */ - val = readl(pmc_base + PMC_TRIGGERS); - val |= UTMIP_CLR_WAKE_ALARM(inst) | UTMIP_CLR_WALK_PTR(inst); - writel(val, pmc_base + PMC_TRIGGERS); - - - /* Capture FS/LS pad configurations */ - pmc_pad_cfg_val = readl(pmc_base + PMC_PAD_CFG); - val = readl(pmc_base + PMC_TRIGGERS); - val |= UTMIP_CAP_CFG(inst); - writel(val, pmc_base + PMC_TRIGGERS); - udelay(1); - pmc_pad_cfg_val = readl(pmc_base + PMC_PAD_CFG); - - /* BIAS MASTER_ENABLE=0 */ - val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL); - val &= ~BIAS_MASTER_PROG_VAL; - writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL); - - /* program walk sequence, maintain a J, followed by a driven K - * to signal a resume once an wake event is detected */ - val = readl(pmc_base + PMC_SLEEPWALK_REG(inst)); - val &= ~UTMIP_AP_A; - val |= UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A| UTMIP_AN_A | UTMIP_HIGHZ_A | - UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_AP_B | UTMIP_AN_B | - UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_AP_C | UTMIP_AN_C | - UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_AP_D | UTMIP_AN_D; - writel(val, pmc_base + PMC_SLEEPWALK_REG(inst)); - - if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW) { - val = readl(pmc_base + PMC_SLEEPWALK_REG(inst)); - val &= ~(UTMIP_AN_B | UTMIP_HIGHZ_B | UTMIP_AN_C | - UTMIP_HIGHZ_C | UTMIP_AN_D | UTMIP_HIGHZ_D); - writel(val, pmc_base + PMC_SLEEPWALK_REG(inst)); - } else { - val = readl(pmc_base + PMC_SLEEPWALK_REG(inst)); - val &= ~(UTMIP_AP_B | UTMIP_HIGHZ_B | UTMIP_AP_C | - UTMIP_HIGHZ_C | UTMIP_AP_D | UTMIP_HIGHZ_D); - writel(val, pmc_base + PMC_SLEEPWALK_REG(inst)); - } + if(phy->pdata->has_hostpc) + clk_set_rate(phy->emc_clk, 100000000); + else + clk_set_rate(phy->emc_clk, 300000000); - /* turn on pad detectors */ - val = readl(pmc_base + PMC_USB_AO); - val &= ~(USBOP_VAL_PD(inst) | USBON_VAL_PD(inst)); - writel(val, pmc_base + PMC_USB_AO); + return err; - /* Add small delay before usb detectors provide stable line values */ - mdelay(1); +fail_emc: + clk_put(phy->sys_clk); - /* Program thermally encoded RCTRL_VAL, TCTRL_VAL into PMC space */ - val = readl(pmc_base + PMC_UTMIP_TERM_PAD_CFG); - val = PMC_TCTRL_VAL(utmip_tctrl_val) | PMC_RCTRL_VAL(utmip_rctrl_val); - writel(val, pmc_base + PMC_UTMIP_TERM_PAD_CFG); +fail_sclk: + clk_put(phy->ctrlr_clk); - phy->remote_wakeup = false; +fail_ctrlr_clk: + clk_disable(phy->pllu_clk); + clk_put(phy->pllu_clk); - /* Turn over pad configuration to PMC for line wake events*/ - val = readl(pmc_base + PMC_SLEEP_CFG); - val &= ~UTMIP_WAKE_VAL(inst, ~0); - val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_ANY); - val |= UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst); - val |= UTMIP_MASTER_ENABLE(inst) | UTMIP_FSLS_USE_PMC(inst); - writel(val, pmc_base + PMC_SLEEP_CFG); +fail_pll: - val = readl(base + UTMIP_PMC_WAKEUP0); - val |= EVENT_INT_ENB; - writel(val, base + UTMIP_PMC_WAKEUP0); + return err; } -#endif -static int utmi_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd) +struct tegra_usb_phy *tegra_usb_phy_open(struct platform_device *pdev) { - unsigned long val; - void __iomem *base = phy->regs; - -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - if (phy->mode == TEGRA_USB_PHY_MODE_HOST) - utmip_setup_pmc_wake_detect(phy); - else - utmip_powerdown_pmc_wake_detect(phy); -#endif - if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) { - val = readl(base + USB_SUSP_CTRL); - val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0); - val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5); - writel(val, base + USB_SUSP_CTRL); - } + struct tegra_usb_phy *phy; + struct tegra_usb_platform_data *pdata; + struct resource *res; + int err; - if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) { - val = readl(base + UTMIP_BAT_CHRG_CFG0); - val |= UTMIP_PD_CHRG; - writel(val, base + UTMIP_BAT_CHRG_CFG0); + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, pdev->id); + pdata = dev_get_platdata(&pdev->dev); + if (!pdata) { + dev_err(&pdev->dev, "inst:[%d] Platform data missing\n", + pdev->id); + return ERR_PTR(-EINVAL); } - if (phy->instance != 2) { - val = readl(base + UTMIP_XCVR_CFG0); - val |= (UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN | - UTMIP_FORCE_PDZI_POWERDOWN); - writel(val, base + UTMIP_XCVR_CFG0); + phy = kzalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL); + if (!phy) { + ERR("inst:[%d] malloc usb phy failed\n", pdev->id); + return ERR_PTR(-ENOMEM); } - val = readl(base + UTMIP_XCVR_CFG1); - val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN | - UTMIP_FORCE_PDDR_POWERDOWN; - writel(val, base + UTMIP_XCVR_CFG1); - -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - val = readl(base + UTMIP_BIAS_CFG1); - val |= UTMIP_BIAS_PDTRK_COUNT(0x5); - writel(val, base + UTMIP_BIAS_CFG1); -#endif - if (phy->hotplug) { - val = readl(base + USB_PORTSC1); - val |= USB_PORTSC1_WKCN; - writel(val, base + USB_PORTSC1); - } - if (phy->instance != 0) { - val = readl(base + UTMIP_BIAS_CFG0); - val |= UTMIP_OTGPD; - writel(val, base + UTMIP_BIAS_CFG0); + phy->pdata = kzalloc(sizeof(struct tegra_usb_platform_data), GFP_KERNEL); + if (!phy->pdata) { + ERR("inst:[%d] malloc usb phy pdata failed\n", pdev->id); + kfree(phy); + return ERR_PTR(-ENOMEM); } - utmi_phy_clk_disable(phy); - - utmip_pad_power_off(phy, true); - return 0; -} + memcpy(phy->pdata, pdata, sizeof(struct tegra_usb_platform_data)); + phy->pdev = pdev; + phy->inst = pdev->id; -static void utmip_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy) -{ -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - unsigned long val; - void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); - unsigned int inst = phy->instance; - void __iomem *base = phy->regs; - - val = readl(pmc_base + PMC_SLEEP_CFG); - val &= ~UTMIP_WAKE_VAL(inst, 0x0); - val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE); - writel(val, pmc_base + PMC_SLEEP_CFG); - - val = readl(pmc_base + PMC_TRIGGERS); - val |= UTMIP_CLR_WAKE_ALARM(inst) | UTMIP_CLR_WALK_PTR(inst); - writel(val, pmc_base + PMC_TRIGGERS); - - val = readl(base + UTMIP_PMC_WAKEUP0); - val &= ~EVENT_INT_ENB; - writel(val, base + UTMIP_PMC_WAKEUP0); - - /* Disable PMC master mode by clearing MASTER_EN */ - val = readl(pmc_base + PMC_SLEEP_CFG); - val &= ~(UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) | - UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst)); - writel(val, pmc_base + PMC_SLEEP_CFG); - - val = readl(pmc_base + PMC_TRIGGERS); - val &= ~UTMIP_CAP_CFG(inst); - writel(val, pmc_base + PMC_TRIGGERS); - - /* turn off pad detectors */ - val = readl(pmc_base + PMC_USB_AO); - val |= (USBOP_VAL_PD(inst) | USBON_VAL_PD(inst)); - writel(val, pmc_base + PMC_USB_AO); - - phy->remote_wakeup = false; -#endif -} + print_usb_plat_data_info(phy); -static void utmi_phy_enable_obs_bus(struct tegra_usb_phy *phy, - enum tegra_usb_phy_port_speed port_speed) -{ - unsigned long val; - void __iomem *base = phy->regs; - - /* (2LS WAR)is not required for LS and FS devices and is only for HS */ - if (port_speed != TEGRA_USB_PHY_PORT_SPEED_HIGH) { - /* do not enable the OBS bus */ - val = readl(base + UTMIP_MISC_CFG0); - val &= ~UTMIP_DPDM_OBSERVE_SEL(~0); - writel(val, base + UTMIP_MISC_CFG0); - return; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ERR("inst:[%d] failed to get I/O memory\n", phy->inst); + err = -ENXIO; + goto fail_io; } -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - /* Force DP/DM pulldown active for Host mode */ - val = readl(base + UTMIP_MISC_CFG0); - val |= FORCE_PULLDN_DM | FORCE_PULLDN_DP | - COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS; - writel(val, base + UTMIP_MISC_CFG0); -#endif - val = readl(base + UTMIP_MISC_CFG0); - val &= ~UTMIP_DPDM_OBSERVE_SEL(~0); - if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW) - val |= UTMIP_DPDM_OBSERVE_SEL_FS_J; - else - val |= UTMIP_DPDM_OBSERVE_SEL_FS_K; - writel(val, base + UTMIP_MISC_CFG0); - udelay(1); - - val = readl(base + UTMIP_MISC_CFG0); - val |= UTMIP_DPDM_OBSERVE; - writel(val, base + UTMIP_MISC_CFG0); - udelay(10); -} -static void utmi_phy_disable_obs_bus(struct tegra_usb_phy *phy) -{ - unsigned long val; - void __iomem *base = phy->regs; - - /* check if OBS bus is already enabled */ - val = readl(base + UTMIP_MISC_CFG0); - if (val & UTMIP_DPDM_OBSERVE) { - /* Change the UTMIP OBS bus to drive SE0 */ - val = readl(base + UTMIP_MISC_CFG0); - val &= ~UTMIP_DPDM_OBSERVE_SEL(~0); - val |= UTMIP_DPDM_OBSERVE_SEL_FS_SE0; - writel(val, base + UTMIP_MISC_CFG0); - - /* Wait for 3us(2 LS bit times) */ - udelay (3); - - /* Release UTMIP OBS bus */ - val = readl(base + UTMIP_MISC_CFG0); - val &= ~UTMIP_DPDM_OBSERVE; - writel(val, base + UTMIP_MISC_CFG0); - -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - /* Release DP/DM pulldown for Host mode */ - val = readl(base + UTMIP_MISC_CFG0); - val &= ~(FORCE_PULLDN_DM | FORCE_PULLDN_DP | - COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS); - writel(val, base + UTMIP_MISC_CFG0); -#endif + phy->regs = ioremap(res->start, resource_size(res)); + if (!phy->regs) { + ERR("inst:[%d] Failed to remap I/O memory\n", phy->inst); + err = -ENOMEM; + goto fail_io; } -} - -static int utmi_phy_preresume(struct tegra_usb_phy *phy, bool remote_wakeup) -{ -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - unsigned long val; - void __iomem *base = phy->regs; - enum tegra_usb_phy_port_speed port_speed; - - val = readl(base + UTMIP_TX_CFG0); - val |= UTMIP_HS_DISCON_DISABLE; - writel(val, base + UTMIP_TX_CFG0); - - port_speed = (readl(base + USB_PORTSC1) >> 26) & 0x3; - if (remote_wakeup && (port_speed == TEGRA_USB_PHY_PORT_SPEED_HIGH)) { - val = readl(base + USB_USBCMD); - val &= ~USB_USBCMD_RS; - writel(val, base + USB_USBCMD); - if (utmi_wait_register(base + USB_USBSTS, - USB_USBSTS_HCH, USB_USBSTS_HCH) < 0) { - pr_err("%s: timeout waiting for stopping controller\n", __func__); - return -ETIMEDOUT; - } + phy->vdd_reg = regulator_get(NULL, "avdd_usb"); + if (IS_ERR_OR_NULL(phy->vdd_reg)) { + ERR("inst:[%d] couldn't get regulator avdd_usb: %ld\n", + phy->inst, PTR_ERR(phy->vdd_reg)); + phy->vdd_reg = NULL; } - utmi_phy_enable_obs_bus(phy, port_speed); -#else - unsigned long val; - void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); - unsigned int inst = phy->instance; - void __iomem *base = phy->regs; - enum tegra_usb_phy_port_speed port_speed; - - val = readl(pmc_base + PMC_SLEEP_CFG); - if (val & UTMIP_MASTER_ENABLE(inst)) { - if (!remote_wakeup) - utmip_phy_disable_pmc_bus_ctrl(phy); - } else { - port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) & - HOSTPC1_DEVLC_PSPD_MASK; - utmi_phy_enable_obs_bus(phy, port_speed); + err = tegra_usb_phy_get_clocks(phy); + if (err) { + ERR("inst:[%d] Failed to init clocks\n", phy->inst); + goto fail_clk; } -#endif - - return 0; -} -static int utmi_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd) -{ - unsigned long val; -#if defined(CONFIG_ARCH_TEGRA_2x_SOC) - void __iomem *base = phy->regs; -#else - void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); -#endif - unsigned int inst = phy->instance; - -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - val = readl(pmc_base + PMC_SLEEP_CFG); - /* if PMC is not disabled by now then disable it */ - if (val & UTMIP_MASTER_ENABLE(inst)) { - utmip_phy_disable_pmc_bus_ctrl(phy); - } - utmi_phy_disable_obs_bus(phy); -#else - val = readl(base + USB_USBCMD); - if (val & USB_USBCMD_RS) { - val &= ~USB_USBCMD_RS; - writel(val, base + USB_USBCMD); - if (utmi_wait_register(base + USB_USBSTS, - USB_USBSTS_HCH, USB_USBSTS_HCH) < 0) { - pr_err("%s: timeout waiting for stopping controller\n", __func__); - return -ETIMEDOUT; + if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) { + if (phy->pdata->u_data.dev.vbus_pmu_irq) { + err = request_threaded_irq( + phy->pdata->u_data.dev.vbus_pmu_irq, + NULL, usb_phy_dev_vbus_pmu_irq_thr, + IRQF_SHARED, "usb_pmu_vbus_irq", phy); + if (err) { + ERR("inst:[%d] Failed to register IRQ\n", + phy->inst); + goto fail_init; + } + } + } else { + if (phy->pdata->u_data.host.vbus_reg) { + phy->vbus_reg = regulator_get(NULL, + phy->pdata->u_data.host.vbus_reg); + if (WARN_ON(IS_ERR_OR_NULL(phy->vbus_reg))) { + ERR("failed to get regulator vdd_vbus_usb: %ld,\ + instance : %d\n", PTR_ERR(phy->vbus_reg), + phy->inst); + err = PTR_ERR(phy->vbus_reg); + goto fail_init; + } + } else { + int gpio = phy->pdata->u_data.host.vbus_gpio; + if (gpio != -1) { + if (gpio_request(gpio, "usb_host_vbus") < 0) { + ERR("inst:[%d] host vbus gpio \ + req failed\n", phy->inst); + goto fail_init; + } + if (gpio < TEGRA_NR_GPIOS) + tegra_gpio_enable(gpio); + if (gpio_direction_output(gpio, 1) < 0) { + ERR("inst:[%d] host vbus gpio \ + dir failed\n", phy->inst); + goto fail_init; + } + } } + usb_host_vbus_enable(phy, true); } - writel(val, base + USB_USBCMD); - utmi_phy_disable_obs_bus(phy); - val = readl(base + USB_USBCMD); - val |= USB_USBCMD_RS; - writel(val, base + USB_USBCMD); - val = readl(base + UTMIP_TX_CFG0); - val &= ~UTMIP_HS_DISCON_DISABLE; - writel(val, base + UTMIP_TX_CFG0); -#endif + err = tegra_usb_phy_init_ops(phy); + if (err) { + ERR("inst:[%d] Failed to init ops\n", phy->inst); + goto fail_init; + } - return 0; -} - -static int uhsic_phy_postsuspend(struct tegra_usb_phy *phy, bool is_dpd) -{ - struct tegra_uhsic_config *uhsic_config = phy->config; - - if (uhsic_config->postsuspend) - uhsic_config->postsuspend(); - - return 0; -} - -static int uhsic_phy_preresume(struct tegra_usb_phy *phy, bool remote_wakeup) -{ - struct tegra_uhsic_config *uhsic_config = phy->config; - - if (uhsic_config->preresume) - uhsic_config->preresume(); - - return 0; -} - -static int usb_phy_set_tx_fill_tuning(struct tegra_usb_phy *phy, bool is_dpd) -{ - unsigned long val; - void __iomem *base = phy->regs; + if (phy->pdata->ops && phy->pdata->ops->open) + phy->pdata->ops->open(); - val = readl(base + USB_TXFILLTUNING); - if ((val & USB_FIFO_TXFILL_MASK) != USB_FIFO_TXFILL_THRES(0x10)) { - val = USB_FIFO_TXFILL_THRES(0x10); - writel(val, base + USB_TXFILLTUNING); + if (phy->ops && phy->ops->open) { + err = phy->ops->open(phy); + if (err) { + ERR("inst:[%d] Failed to open hw ops\n", phy->inst); + goto fail_init; + } } - return 0; -} + if (phy->vdd_reg) + regulator_enable(phy->vdd_reg); -static void utmi_phy_restore_start(struct tegra_usb_phy *phy, - enum tegra_usb_phy_port_speed port_speed) -{ -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - unsigned long val; - void __iomem *base = phy->regs; + return phy; - val = readl(base + UTMIP_MISC_CFG0); - val &= ~UTMIP_DPDM_OBSERVE_SEL(~0); - if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW) - val |= UTMIP_DPDM_OBSERVE_SEL_FS_K; - else - val |= UTMIP_DPDM_OBSERVE_SEL_FS_J; - writel(val, base + UTMIP_MISC_CFG0); - udelay(1); - - val = readl(base + UTMIP_MISC_CFG0); - val |= UTMIP_DPDM_OBSERVE; - writel(val, base + UTMIP_MISC_CFG0); - udelay(10); -#else - unsigned long val; - void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); - int inst = phy->instance; +fail_init: + tegra_usb_phy_release_clocks(phy); - val = readl(pmc_base + UTMIP_UHSIC_STATUS); - /* check whether we wake up from the remote resume */ - if (UTMIP_WALK_PTR_VAL(inst) & val) { - phy->remote_wakeup = true; + if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) { + if (phy->pdata->u_data.dev.vbus_pmu_irq) + free_irq(phy->pdata->u_data.dev.vbus_pmu_irq, phy); } else { - if (!((UTMIP_USBON_VAL(phy->instance) | - UTMIP_USBOP_VAL(phy->instance)) & val)) { - utmip_phy_disable_pmc_bus_ctrl(phy); - } - } - utmi_phy_enable_obs_bus(phy, port_speed); -#endif -} - -static void utmi_phy_restore_end(struct tegra_usb_phy *phy) -{ -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - unsigned long val; - void __iomem *base = phy->regs; - - val = readl(base + UTMIP_MISC_CFG0); - val &= ~UTMIP_DPDM_OBSERVE; - writel(val, base + UTMIP_MISC_CFG0); - udelay(10); -#else - unsigned long val; - void __iomem *base = phy->regs; - int wait_time_us = 3000; /* FPR should be set by this time */ - - /* check whether we wake up from the remote resume */ - if (phy->remote_wakeup) { - /* wait until FPR bit is set automatically on remote resume */ - do { - val = readl(base + USB_PORTSC1); - udelay(1); - if (wait_time_us == 0) { - utmip_phy_disable_pmc_bus_ctrl(phy); - tegra_usb_phy_postresume(phy, false); - return; + usb_host_vbus_enable(phy, false); + + if (phy->vbus_reg) + regulator_put(phy->vbus_reg); + else { + int gpio = phy->pdata->u_data.host.vbus_gpio; + if (gpio != -1) { + gpio_set_value_cansleep(gpio, 0); + gpio_free(gpio); } - wait_time_us--; - } while (!(val & USB_PORTSC1_RESUME)); - /* wait for 25 ms to port resume complete */ - msleep(25); - /* disable PMC master control */ - utmip_phy_disable_pmc_bus_ctrl(phy); - - /* Clear PCI and SRI bits to avoid an interrupt upon resume */ - val = readl(base + USB_USBSTS); - writel(val, base + USB_USBSTS); - /* wait to avoid SOF if there is any */ - if (utmi_wait_register(base + USB_USBSTS, - USB_USBSTS_SRI, USB_USBSTS_SRI) < 0) { - pr_err("%s: timeout waiting for SOF\n", __func__); } - tegra_usb_phy_postresume(phy, false); } -#endif -} - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC -static void ulpi_set_tristate(bool enable) -{ - int tristate = (enable)? TEGRA_TRI_TRISTATE : TEGRA_TRI_NORMAL; - - tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, tristate); - tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, tristate); - tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, tristate); -} -#endif -static void ulpi_phy_reset(void __iomem *base) -{ - unsigned long val; - - val = readl(base + USB_SUSP_CTRL); - val |= UHSIC_RESET; - writel(val, base + USB_SUSP_CTRL); - -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - val = readl(base + USB_SUSP_CTRL); - val |= UTMIP_RESET; - writel(val, base + USB_SUSP_CTRL); -#endif -} - -static void ulpi_set_host(void __iomem *base) -{ -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - unsigned long val; - - val = readl(base + TEGRA_USB_USBMODE_REG_OFFSET); - val |= TEGRA_USB_USBMODE_HOST; - writel(val, base + TEGRA_USB_USBMODE_REG_OFFSET); - - val = readl(base + HOSTPC1_DEVLC); - val |= HOSTPC1_DEVLC_PTS(2); - writel(val, base + HOSTPC1_DEVLC); -#endif -} - -static void ulpi_set_trimmer(void __iomem *base, u8 data, u8 sdn, u8 dir) -{ - unsigned long val; - - val = ULPI_DATA_TRIMMER_SEL(data); - val |= ULPI_STPDIRNXT_TRIMMER_SEL(sdn); - val |= ULPI_DIR_TRIMMER_SEL(dir); - writel(val, base + ULPI_TIMING_CTRL_1); - udelay(10); - - val |= ULPI_DATA_TRIMMER_LOAD; - val |= ULPI_STPDIRNXT_TRIMMER_LOAD; - val |= ULPI_DIR_TRIMMER_LOAD; - writel(val, base + ULPI_TIMING_CTRL_1); -} - -static inline void ulpi_pinmux_bypass(struct tegra_usb_phy *phy, bool enable) -{ - unsigned long val; - void __iomem *base = phy->regs; - - val = readl(base + ULPI_TIMING_CTRL_0); - - if (enable) - val |= ULPI_OUTPUT_PINMUX_BYP; - else - val &= ~ULPI_OUTPUT_PINMUX_BYP; - - writel(val, base + ULPI_TIMING_CTRL_0); -} - -static void ulpi_phy_restore_start(struct tegra_usb_phy *phy, - enum tegra_usb_phy_port_speed port_speed) -{ -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - unsigned long val; - void __iomem *base = phy->regs; - - /*Tristate ulpi interface before USB controller resume*/ - ulpi_set_tristate(true); +fail_clk: + regulator_put(phy->vdd_reg); + iounmap(phy->regs); +fail_io: + kfree(phy); - val = readl(base + ULPI_TIMING_CTRL_0); - val &= ~ULPI_OUTPUT_PINMUX_BYP; - writel(val, base + ULPI_TIMING_CTRL_0); -#endif + return ERR_PTR(err); } -static void ulpi_phy_restore_end(struct tegra_usb_phy *phy) -{ -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - unsigned long val; - void __iomem *base = phy->regs; - - val = readl(base + ULPI_TIMING_CTRL_0); - val |= ULPI_OUTPUT_PINMUX_BYP; - writel(val, base + ULPI_TIMING_CTRL_0); - ulpi_set_tristate(false); -#endif -} -static int ulpi_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd) +void tegra_usb_phy_close(struct tegra_usb_phy *phy) { - int ret; - unsigned long val; - void __iomem *base = phy->regs; -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - struct tegra_ulpi_config *config = phy->config; -#endif - - if (phy->clk) - clk_enable(phy->clk); + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); - msleep(1); - - if (!phy->initialized) { - phy->initialized = 1; -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - gpio_direction_output(config->reset_gpio, 0); - msleep(5); - gpio_direction_output(config->reset_gpio, 1); -#endif + if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) { + if (phy->pdata->u_data.dev.vbus_pmu_irq) + free_irq(phy->pdata->u_data.dev.vbus_pmu_irq, phy); + } else { + usb_host_vbus_enable(phy, false); + + if (phy->vbus_reg) + regulator_put(phy->vbus_reg); + else { + int gpio = phy->pdata->u_data.host.vbus_gpio; + if (gpio != -1) { + gpio_set_value_cansleep(gpio, 0); + gpio_free(gpio); + } + } } - ulpi_phy_reset(base); - ulpi_set_host(base); - - val = readl(base + ULPI_TIMING_CTRL_0); - val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP; - writel(val, base + ULPI_TIMING_CTRL_0); - - val = readl(base + USB_SUSP_CTRL); - val |= ULPI_PHY_ENABLE; - writel(val, base + USB_SUSP_CTRL); - - val = readl(base + USB_SUSP_CTRL); - val |= USB_SUSP_CLR; - writel(val, base + USB_SUSP_CTRL); - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, - USB_PHY_CLK_VALID) < 0) - pr_err("%s: timeout waiting for phy to stabilize\n", __func__); - - if (utmi_wait_register(base + USB_SUSP_CTRL, USB_CLKEN, USB_CLKEN) < 0) - pr_err("%s: timeout waiting for AHB clock\n", __func__); -#else - udelay(100); -#endif - - val = readl(base + USB_SUSP_CTRL); - val &= ~USB_SUSP_CLR; - writel(val, base + USB_SUSP_CTRL); - - val = 0; - writel(val, base + ULPI_TIMING_CTRL_1); + tegra_usb_phy_release_clocks(phy); - ulpi_set_trimmer(base, 4, 4, 4); - - /* Fix VbusInvalid due to floating VBUS */ - ret = otg_io_write(phy->ulpi, 0x40, 0x08); - if (ret) { - pr_err("%s: ulpi write failed\n", __func__); - return ret; - } - - ret = otg_io_write(phy->ulpi, 0x80, 0x0B); - if (ret) { - pr_err("%s: ulpi write failed\n", __func__); - return ret; + if (phy->vdd_reg) { + regulator_disable(phy->vdd_reg); + regulator_put(phy->vdd_reg); } - val = readl(base + USB_PORTSC1); - val |= USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN; - writel(val, base + USB_PORTSC1); - - return 0; -} - -static int ulpi_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd) -{ - unsigned long val; - void __iomem *base = phy->regs; -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - int ret; - - /* Disable VbusValid, SessEnd comparators */ - ret = otg_io_write(phy->ulpi, 0x00, 0x0D); - if (ret) - pr_err("%s: ulpi write 0x0D failed\n", __func__); - - ret = otg_io_write(phy->ulpi, 0x00, 0x10); - if (ret) - pr_err("%s: ulpi write 0x10 failed\n", __func__); - - /* Disable IdFloat comparator */ - ret = otg_io_write(phy->ulpi, 0x00, 0x19); - if (ret) - pr_err("%s: ulpi write 0x19 failed\n", __func__); - - ret = otg_io_write(phy->ulpi, 0x00, 0x1D); - if (ret) - pr_err("%s: ulpi write 0x1D failed\n", __func__); - - /* Clear WKCN/WKDS/WKOC wake-on events that can cause the USB - * Controller to immediately bring the ULPI PHY out of low power - */ - val = readl(base + USB_PORTSC1); - val &= ~(USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN); - writel(val, base + USB_PORTSC1); - - /* Put the PHY in the low power mode */ - val = readl(base + USB_PORTSC1); - val |= USB_PORTSC1_PHCD; - writel(val, base + USB_PORTSC1); - - if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0) - pr_err("%s: timeout waiting for phy to stop\n", __func__); -#else - val = readl(base + HOSTPC1_DEVLC); - val &= ~(HOSTPC1_DEVLC_PHCD); - writel(val, base + HOSTPC1_DEVLC); -#endif + if (phy->ops && phy->ops->close) + phy->ops->close(phy); - if(phy->clk) - clk_disable(phy->clk); + if (phy->pdata->ops && phy->pdata->ops->close) + phy->pdata->ops->close(); - return 0; + kfree(phy->pdata); + kfree(phy); } -static inline void null_phy_set_tristate(bool enable) +irqreturn_t tegra_usb_phy_irq(struct tegra_usb_phy *phy) { - int tristate = (enable) ? TEGRA_TRI_TRISTATE : TEGRA_TRI_NORMAL; - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, tristate); - tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, tristate); - tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, tristate); -#else - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA0, tristate); - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA1, tristate); - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA2, tristate); - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA3, tristate); - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA4, tristate); - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA5, tristate); - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA6, tristate); - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA7, tristate); - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_NXT, tristate); - - if (enable) - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DIR, tristate); -#endif -} + irqreturn_t status = IRQ_HANDLED; -static void null_phy_restore_start(struct tegra_usb_phy *phy, - enum tegra_usb_phy_port_speed port_speed) -{ - struct tegra_ulpi_config *config = phy->config; + if (phy->ops && phy->ops->irq) + status = phy->ops->irq(phy); - if (config->phy_restore_start) - config->phy_restore_start(); + return status; } - -static void null_phy_restore_end(struct tegra_usb_phy *phy) +int tegra_usb_phy_init(struct tegra_usb_phy *phy) { - unsigned long val; - void __iomem *base = phy->regs; - struct tegra_ulpi_config *config = phy->config; + int status = 0; - /* disable ULPI pinmux bypass */ - ulpi_pinmux_bypass(phy, false); + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); - /* driving linestate using GPIO */ - gpio_set_value(config->ulpi_d0_gpio, 0); - gpio_set_value(config->ulpi_d1_gpio, 0); - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - /* driving DIR high */ - gpio_set_value(config->ulpi_dir_gpio, 1); -#endif + if (phy->pdata->ops && phy->pdata->ops->init) + phy->pdata->ops->init(); - /* remove ULPI tristate */ - null_phy_set_tristate(false); - - if (config->phy_restore_end) - config->phy_restore_end(); - - if (gpio_is_valid(config->phy_restore_gpio)) { - int phy_restore_gpio = config->phy_restore_gpio; - int retry = 20000; - - while (retry) { - /* poll phy_restore_gpio high */ - if (gpio_get_value(phy_restore_gpio)) - break; - retry--; - } + if (phy->ops && phy->ops->init) + status = phy->ops->init(phy); - if (retry == 0) - pr_info("phy_restore_gpio timeout\n"); - } - - /* enable ULPI CLK output pad */ - val = readl(base + ULPI_TIMING_CTRL_0); - val |= ULPI_CLK_PADOUT_ENA; - writel(val, base + ULPI_TIMING_CTRL_0); - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - udelay(5); /* wait for CLK stabilize */ - - /* enable ULPI pinmux bypass */ - ulpi_pinmux_bypass(phy, true); -#else - /* enable ULPI pinmux bypass */ - ulpi_pinmux_bypass(phy, true); - udelay(5); - - /* remove DIR tristate */ - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DIR, TEGRA_TRI_NORMAL); -#endif + return status; } -static int null_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd) +int tegra_usb_phy_power_off(struct tegra_usb_phy *phy) { - const struct tegra_ulpi_trimmer default_trimmer = {0, 0, 4, 4}; - unsigned long val; - void __iomem *base = phy->regs; - struct tegra_ulpi_config *config = phy->config; - static bool cold_boot = true; - - if (!config->trimmer) - config->trimmer = &default_trimmer; - - ulpi_phy_reset(base); - -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - /* remove ULPI PADS CLKEN reset */ - val = readl(base + USB_SUSP_CTRL); - val &= ~ULPI_PADS_CLKEN_RESET; - writel(val, base + USB_SUSP_CTRL); - udelay(10); -#endif - val = readl(base + ULPI_TIMING_CTRL_0); - val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP; - writel(val, base + ULPI_TIMING_CTRL_0); - - if (config->pre_phy_on && config->pre_phy_on()) - return -EAGAIN; - - val = readl(base + USB_SUSP_CTRL); - val |= ULPI_PHY_ENABLE; - writel(val, base + USB_SUSP_CTRL); - udelay(10); - - /* set timming parameters */ - val = readl(base + ULPI_TIMING_CTRL_0); - val |= ULPI_SHADOW_CLK_LOOPBACK_EN; -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - val &= ~ULPI_SHADOW_CLK_SEL; - val &= ~ULPI_LBK_PAD_EN; -#else - val |= ULPI_SHADOW_CLK_SEL; - val |= ULPI_LBK_PAD_EN; -#endif - val |= ULPI_SHADOW_CLK_DELAY(config->trimmer->shadow_clk_delay); - val |= ULPI_CLOCK_OUT_DELAY(config->trimmer->clock_out_delay); - val |= ULPI_LBK_PAD_E_INPUT_OR; - writel(val, base + ULPI_TIMING_CTRL_0); - - writel(0, base + ULPI_TIMING_CTRL_1); - udelay(10); - - /* start internal 60MHz clock */ - val = readl(base + ULPIS2S_CTRL); - val |= ULPIS2S_ENA; - val |= ULPIS2S_SUPPORT_DISCONNECT; - val |= ULPIS2S_SPARE((phy->mode == TEGRA_USB_PHY_MODE_HOST) ? 3 : 1); - val |= ULPIS2S_PLLU_MASTER_BLASTER60; - writel(val, base + ULPIS2S_CTRL); - - /* select ULPI_CORE_CLK_SEL to SHADOW_CLK */ - val = readl(base + ULPI_TIMING_CTRL_0); - val |= ULPI_CORE_CLK_SEL; - writel(val, base + ULPI_TIMING_CTRL_0); - udelay(10); - - /* enable ULPI null phy clock - can't set the trimmers before this */ - val = readl(base + ULPI_TIMING_CTRL_0); - val |= ULPI_CLK_OUT_ENA; - writel(val, base + ULPI_TIMING_CTRL_0); - udelay(10); - - if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, - USB_PHY_CLK_VALID)) { - pr_err("%s: timeout waiting for phy to stabilize\n", __func__); - return -ETIMEDOUT; - } + int err = 0; - /* set ULPI trimmers */ - ulpi_set_trimmer(base, config->trimmer->data_trimmer, - config->trimmer->stpdirnxt_trimmer, 1); + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); - ulpi_set_host(base); + if (!phy->phy_power_on) + return err; -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - /* remove slave0 reset */ - val = readl(base + USB_SUSP_CTRL); - val &= ~ULPIS2S_SLV0_RESET; - writel(val, base + USB_SUSP_CTRL); - - /* remove slave1 and line reset */ - val = readl(base + USB_SUSP_CTRL); - val &= ~ULPIS2S_SLV1_RESET; - val &= ~ULPIS2S_LINE_RESET; - - /* remove ULPI PADS reset */ - val &= ~ULPI_PADS_RESET; - writel(val, base + USB_SUSP_CTRL); -#endif - if (cold_boot) { - val = readl(base + ULPI_TIMING_CTRL_0); - val |= ULPI_CLK_PADOUT_ENA; - writel(val, base + ULPI_TIMING_CTRL_0); - cold_boot = false; + if (phy->ops && phy->ops->power_off) { + if (phy->pdata->ops && phy->pdata->ops->pre_phy_off) + phy->pdata->ops->pre_phy_off(); + err = phy->ops->power_off(phy); + if (phy->pdata->ops && phy->pdata->ops->post_phy_off) + phy->pdata->ops->post_phy_off(); } - udelay(10); - - if (config->post_phy_on && config->post_phy_on()) - return -EAGAIN; - - return 0; -} - -static int null_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd) -{ - struct tegra_ulpi_config *config = phy->config; - - if (config->pre_phy_off && config->pre_phy_off()) - return -EAGAIN; - - null_phy_set_tristate(true); + clk_disable(phy->emc_clk); + clk_disable(phy->sys_clk); + clk_disable(phy->ctrlr_clk); - if (config->post_phy_off && config->post_phy_off()) - return -EAGAIN; + phy->phy_power_on = false; - return 0; -} - -static int null_phy_pre_usbcmd_reset(struct tegra_usb_phy *phy, bool is_dpd) -{ -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - unsigned long val; - void __iomem *base = phy->regs; - - val = readl(base + ULPIS2S_CTRL); - val |= ULPIS2S_SLV0_CLAMP_XMIT; - writel(val, base + ULPIS2S_CTRL); - - val = readl(base + USB_SUSP_CTRL); - val |= ULPIS2S_SLV0_RESET; - writel(val, base + USB_SUSP_CTRL); - udelay(10); -#endif - return 0; -} - -static int null_phy_post_usbcmd_reset(struct tegra_usb_phy *phy, bool is_dpd) -{ -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - unsigned long val; - void __iomem *base = phy->regs; - - ulpi_set_host(base); - - /* remove slave0 reset */ - val = readl(base + USB_SUSP_CTRL); - val &= ~ULPIS2S_SLV0_RESET; - writel(val, base + USB_SUSP_CTRL); - - val = readl(base + ULPIS2S_CTRL); - val &= ~ULPIS2S_SLV0_CLAMP_XMIT; - writel(val, base + ULPIS2S_CTRL); - udelay(10); -#endif - return 0; + return err; } -static int uhsic_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd) +int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) { - unsigned long val; - void __iomem *base = phy->regs; - struct tegra_uhsic_config *uhsic_config = phy->config; - -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - uhsic_powerup_pmc_wake_detect(phy); -#endif - - if (uhsic_config->enable_gpio != -1) { - gpio_set_value_cansleep(uhsic_config->enable_gpio, 1); - /* keep hsic reset asserted for 1 ms */ - udelay(1000); - } - - val = readl(base + UHSIC_PADS_CFG1); - val &= ~(UHSIC_PD_BG | UHSIC_PD_TX | UHSIC_PD_TRK | UHSIC_PD_RX | - UHSIC_PD_ZI | UHSIC_RPD_DATA | UHSIC_RPD_STROBE); - val |= UHSIC_RX_SEL; - writel(val, base + UHSIC_PADS_CFG1); - udelay(2); - - val = readl(base + USB_SUSP_CTRL); - val |= UHSIC_RESET; - writel(val, base + USB_SUSP_CTRL); - udelay(30); - - val = readl(base + USB_SUSP_CTRL); - val |= UHSIC_PHY_ENABLE; - writel(val, base + USB_SUSP_CTRL); - - val = readl(base + UHSIC_HSRX_CFG0); - val |= UHSIC_IDLE_WAIT(uhsic_config->idle_wait_delay); - val |= UHSIC_ELASTIC_UNDERRUN_LIMIT(uhsic_config->elastic_underrun_limit); - val |= UHSIC_ELASTIC_OVERRUN_LIMIT(uhsic_config->elastic_overrun_limit); - writel(val, base + UHSIC_HSRX_CFG0); - - val = readl(base + UHSIC_HSRX_CFG1); - val |= UHSIC_HS_SYNC_START_DLY(uhsic_config->sync_start_delay); - writel(val, base + UHSIC_HSRX_CFG1); - -#ifdef CONFIG_ARCH_TEGRA_3x_SOC - /* WAR HSIC TX */ - val = readl(base + UHSIC_TX_CFG0); - val &= ~UHSIC_HS_READY_WAIT_FOR_VALID; - writel(val, base + UHSIC_TX_CFG0); -#endif - - val = readl(base + UHSIC_MISC_CFG0); - val |= UHSIC_SUSPEND_EXIT_ON_EDGE; -#ifdef CONFIG_ARCH_TEGRA_3x_SOC - /* Disable generic bus reset, to allow AP30 specific bus reset*/ - val |= UHSIC_DISABLE_BUSRESET; -#endif - writel(val, base + UHSIC_MISC_CFG0); - - val = readl(base + UHSIC_MISC_CFG1); - val |= UHSIC_PLLU_STABLE_COUNT(phy->freq->stable_count); - writel(val, base + UHSIC_MISC_CFG1); - - val = readl(base + UHSIC_PLL_CFG1); - val |= UHSIC_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay); - val |= UHSIC_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count); - writel(val, base + UHSIC_PLL_CFG1); - - val = readl(base + USB_SUSP_CTRL); - val &= ~(UHSIC_RESET); - writel(val, base + USB_SUSP_CTRL); - udelay(2); - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - val = readl(base + USB_PORTSC1); - val &= ~USB_PORTSC1_PTS(~0); - writel(val, base + USB_PORTSC1); - -#endif -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - val = readl(base + TEGRA_USB_USBMODE_REG_OFFSET); - val |= TEGRA_USB_USBMODE_HOST; - writel(val, base + TEGRA_USB_USBMODE_REG_OFFSET); - - /* Change the USB controller PHY type to HSIC */ - val = readl(base + HOSTPC1_DEVLC); - val &= ~HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK); - val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC); - val &= ~HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK); - val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED); - writel(val, base + HOSTPC1_DEVLC); -#endif - usb_phy_set_tx_fill_tuning(phy, is_dpd); + int status = 0; - val = readl(base + USB_PORTSC1); - val &= ~(USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN); - writel(val, base + USB_PORTSC1); + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); - val = readl(base + UHSIC_PADS_CFG0); - val &= ~(UHSIC_TX_RTUNEN); -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - /* set Rtune impedance to 40 ohm */ - val |= UHSIC_TX_RTUNE(0); -#else - /* set Rtune impedance to 50 ohm */ - val |= UHSIC_TX_RTUNE(8); -#endif - writel(val, base + UHSIC_PADS_CFG0); + if (phy->phy_power_on) + return status; - if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, - USB_PHY_CLK_VALID)) { - pr_err("%s: timeout waiting for phy to stabilize\n", __func__); - return -ETIMEDOUT; - } - - return 0; -} + clk_enable(phy->ctrlr_clk); + clk_enable(phy->sys_clk); + clk_enable(phy->emc_clk); -static int uhsic_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd) -{ - unsigned long val; - void __iomem *base = phy->regs; - struct tegra_uhsic_config *uhsic_config = phy->config; - - val = readl(base + UHSIC_PADS_CFG1); - val &= ~UHSIC_RPU_STROBE; - val |= UHSIC_RPD_STROBE; - writel(val, base + UHSIC_PADS_CFG1); - - val = readl(base + USB_SUSP_CTRL); - val |= UHSIC_RESET; - writel(val, base + USB_SUSP_CTRL); - udelay(30); - - if (uhsic_config->enable_gpio != -1) { - gpio_set_value_cansleep(uhsic_config->enable_gpio, 0); - /* keep hsic reset de-asserted for 1 ms */ - udelay(1000); + if (phy->ops && phy->ops->power_on) { + if (phy->pdata->ops && phy->pdata->ops->pre_phy_on) + phy->pdata->ops->pre_phy_on(); + status = phy->ops->power_on(phy); + if (phy->pdata->ops && phy->pdata->ops->post_phy_on) + phy->pdata->ops->post_phy_on(); } - if (uhsic_config->post_phy_off && uhsic_config->post_phy_off()) - return -EAGAIN; -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - uhsic_powerdown_pmc_wake_detect(phy); -#endif + phy->phy_power_on = true; - return 0; + return status; } -#ifdef CONFIG_USB_TEGRA_OTG -extern void tegra_otg_check_vbus_detection(void); -#endif - -static irqreturn_t usb_phy_vbus_irq_thr(int irq, void *pdata) +int tegra_usb_phy_reset(struct tegra_usb_phy *phy) { - struct tegra_usb_phy *phy = pdata; - - if (phy->reg_vdd && !phy->regulator_on) { - regulator_enable(phy->reg_vdd); - phy->regulator_on = 1; - /* - * Optimal time to get the regulator turned on - * before detecting vbus interrupt. - */ - mdelay(15); - } + int status = 0; -#ifdef CONFIG_USB_TEGRA_OTG - tegra_otg_check_vbus_detection(); -#endif + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + if (phy->ops && phy->ops->reset) + status = phy->ops->reset(phy); - return IRQ_HANDLED; + return status; } - -struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs, - void *config, enum tegra_usb_phy_mode phy_mode, - enum tegra_usb_phy_type usb_phy_type) +int tegra_usb_phy_pre_suspend(struct tegra_usb_phy *phy) { - struct tegra_usb_phy *phy; - struct tegra_ulpi_config *ulpi_config; - unsigned long parent_rate; - int i; - int err; -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - struct tegra_uhsic_config *uhsic_config; - int reset_gpio, enable_gpio; -#endif + int status = 0; - phy = kzalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL); - if (!phy) - return ERR_PTR(-ENOMEM); + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); - phy->instance = instance; - phy->regs = regs; - phy->config = config; - phy->mode = phy_mode; - phy->usb_phy_type = usb_phy_type; - phy->initialized = 0; - phy->regulator_on = 0; - phy->power_on = 0; - phy->remote_wakeup = false; - phy->hotplug = 0; - phy->xcvr_setup_value = 0; - - if (!phy->config) { - if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_LINK_ULPI || - phy->usb_phy_type == TEGRA_USB_PHY_TYPE_NULL_ULPI) { - pr_err("%s: ulpi phy configuration missing", __func__); - err = -EINVAL; - goto err0; - } else { - phy->config = &utmip_default[instance]; - } - } + if (phy->pdata->ops && phy->pdata->ops->pre_suspend) + phy->pdata->ops->pre_suspend(); - phy->pll_u = clk_get_sys(NULL, "pll_u"); - if (IS_ERR(phy->pll_u)) { - pr_err("Can't get pll_u clock\n"); - err = PTR_ERR(phy->pll_u); - goto err0; - } - clk_enable(phy->pll_u); - - parent_rate = clk_get_rate(clk_get_parent(phy->pll_u)); - if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC) { - for (i = 0; i < ARRAY_SIZE(tegra_uhsic_freq_table); i++) { - if (tegra_uhsic_freq_table[i].freq == parent_rate) { - phy->freq = &tegra_uhsic_freq_table[i]; - break; - } - } - } else { - for (i = 0; i < ARRAY_SIZE(tegra_freq_table); i++) { - if (tegra_freq_table[i].freq == parent_rate) { - phy->freq = &tegra_freq_table[i]; - break; - } - } - } - if (!phy->freq) { - pr_err("invalid pll_u parent rate %ld\n", parent_rate); - err = -EINVAL; - goto err1; - } + if (phy->ops && phy->ops->pre_suspend) + status = phy->ops->pre_suspend(phy); - if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) { - err = utmip_pad_open(phy); - phy->xcvr_setup_value = tegra_phy_xcvr_setup_value(phy->config); - if (err < 0) - goto err1; - } else if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_LINK_ULPI) { - ulpi_config = config; - - if (ulpi_config->clk) { - phy->clk = clk_get_sys(NULL, ulpi_config->clk); - if (IS_ERR(phy->clk)) { - pr_err("%s: can't get ulpi clock\n", __func__); - err = -ENXIO; - goto err1; - } - } else { - /* Some USB ULPI chips are not driven by Tegra clocks or PLL */ - phy->clk = NULL; - } - tegra_gpio_enable(ulpi_config->reset_gpio); - gpio_request(ulpi_config->reset_gpio, "ulpi_phy_reset_b"); - gpio_direction_output(ulpi_config->reset_gpio, 0); - phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0); - phy->ulpi->io_priv = regs + ULPI_VIEWPORT; - } -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - else if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC) { - uhsic_config = config; - enable_gpio = gpio_request(uhsic_config->enable_gpio, - "uhsic_enable"); - reset_gpio = gpio_request(uhsic_config->reset_gpio, - "uhsic_reset"); - /* hsic enable signal deasserted, hsic reset asserted */ - if (!enable_gpio) - gpio_direction_output(uhsic_config->enable_gpio, - 0 /* deasserted */); - if (!reset_gpio) - gpio_direction_output(uhsic_config->reset_gpio, - 0 /* asserted */); - if (!enable_gpio) - tegra_gpio_enable(uhsic_config->enable_gpio); - if (!reset_gpio) - tegra_gpio_enable(uhsic_config->reset_gpio); - /* keep hsic reset asserted for 1 ms */ - udelay(1000); - /* enable (power on) hsic */ - if (!enable_gpio) - gpio_set_value_cansleep(uhsic_config->enable_gpio, 1); - udelay(1000); - /* deassert reset */ - if (!reset_gpio) - gpio_set_value_cansleep(uhsic_config->reset_gpio, 1); - } -#endif - - phy->reg_vdd = regulator_get(NULL, "avdd_usb"); - if (IS_ERR_OR_NULL(phy->reg_vdd)) { - pr_err("couldn't get regulator avdd_usb: %ld \n", - PTR_ERR(phy->reg_vdd)); - phy->reg_vdd = NULL; - } - - if (instance == 0 && usb_phy_data[0].vbus_irq) { - err = request_threaded_irq(usb_phy_data[0].vbus_irq, NULL, usb_phy_vbus_irq_thr, IRQF_SHARED, - "usb_phy_vbus", phy); - if (err) { - pr_err("Failed to register IRQ\n"); - goto err1; - } - } - -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - /* Power-up the VBUS detector for UTMIP PHY */ - if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) { - unsigned long val; - void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); - - /* turn on pad detectors for HSIC*/ - val = readl(pmc_base + PMC_USB_AO); - val &= ~(TEGRA_PMC_USB_AO_VBUS_WAKEUP_PD_P0 | TEGRA_PMC_USB_AO_ID_PD_P0); - writel(val, pmc_base + PMC_USB_AO); - - utmip_powerup_pmc_wake_detect(phy); - - if (usb_phy_data[phy->instance].vbus_reg_supply) { - phy->reg_vbus = regulator_get(NULL, usb_phy_data[phy->instance].vbus_reg_supply); - if (WARN_ON(IS_ERR_OR_NULL(phy->reg_vbus))) { - pr_err("couldn't get regulator vdd_vbus_usb: %ld, instance : %d\n", - PTR_ERR(phy->reg_vbus), phy->instance); - err = PTR_ERR(phy->reg_vbus); - goto err1; - } - } - } - if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC) { - uhsic_powerup_pmc_wake_detect(phy); - } - -#endif - if (((instance == 2) || (instance == 0)) && - (phy->mode == TEGRA_USB_PHY_MODE_HOST)) { - vbus_enable(phy); - } - return phy; - -err1: - clk_disable(phy->pll_u); - clk_put(phy->pll_u); -err0: - kfree(phy); - return ERR_PTR(err); + return status; } - -int tegra_usb_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd) +int tegra_usb_phy_suspend(struct tegra_usb_phy *phy) { - int ret = 0; - - const tegra_phy_fp power_on[] = { - utmi_phy_power_on, - ulpi_phy_power_on, - null_phy_power_on, - uhsic_phy_power_on, - }; + int err = 0; - if (phy->power_on) - return ret; + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); - if ((phy->instance == 0) && usb_phy_data[0].vbus_irq && - (phy->mode == TEGRA_USB_PHY_MODE_DEVICE)) - is_dpd = true; + if (phy->ops && phy->ops->suspend) + err = phy->ops->suspend(phy); - if (phy->reg_vdd && !phy->regulator_on) { - regulator_enable(phy->reg_vdd); - phy->regulator_on = 1; + if (!err && phy->pdata->u_data.host.power_off_on_suspend) { + if (phy->pdata->ops && phy->pdata->ops->pre_phy_off) + phy->pdata->ops->pre_phy_off(); + err = phy->ops->power_off(phy); + if (phy->pdata->ops && phy->pdata->ops->post_phy_off) + phy->pdata->ops->post_phy_off(); } - if (power_on[phy->usb_phy_type]) - ret = power_on[phy->usb_phy_type](phy, is_dpd); - - phy->power_on = true; - return ret; + return err; } - -void tegra_usb_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd) +int tegra_usb_phy_post_suspend(struct tegra_usb_phy *phy) { - const tegra_phy_fp power_off[] = { - utmi_phy_power_off, - ulpi_phy_power_off, - null_phy_power_off, - uhsic_phy_power_off, - }; + int status = 0; - if (!phy->power_on) - return; + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); - if ((phy->instance == 0) && usb_phy_data[0].vbus_irq && - (phy->mode == TEGRA_USB_PHY_MODE_DEVICE)) - is_dpd = true; + if (phy->ops && phy->ops->post_suspend) + status = phy->ops->post_suspend(phy); - if (power_off[phy->usb_phy_type]) - power_off[phy->usb_phy_type](phy, is_dpd); + if (phy->pdata->ops && phy->pdata->ops->post_suspend) + phy->pdata->ops->post_suspend(); - if (phy->reg_vdd && phy->regulator_on && is_dpd) { -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - if (tegra_get_revision() >= TEGRA_REVISION_A03) -#endif - regulator_disable(phy->reg_vdd); - phy->regulator_on = 0; - } - phy->power_on = false; + return status; } - -void tegra_usb_phy_preresume(struct tegra_usb_phy *phy, bool remote_wakeup) +int tegra_usb_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup) { - const tegra_phy_fp preresume[] = { - utmi_phy_preresume, - NULL, - NULL, - uhsic_phy_preresume, - }; + int status = 0; - if (preresume[phy->usb_phy_type]) - preresume[phy->usb_phy_type](phy, remote_wakeup); -} + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); -void tegra_usb_phy_postsuspend(struct tegra_usb_phy *phy, bool is_dpd) + if (phy->pdata->ops && phy->pdata->ops->pre_resume) + phy->pdata->ops->pre_resume(); -{ - const tegra_phy_fp postsuspend[] = { - NULL, - NULL, - NULL, - uhsic_phy_postsuspend, - }; + if (phy->ops && phy->ops->pre_resume) + status = phy->ops->pre_resume(phy, remote_wakeup); - if (postsuspend[phy->usb_phy_type]) - postsuspend[phy->usb_phy_type](phy, is_dpd); + return status; } - -void tegra_usb_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd) +int tegra_usb_phy_resume(struct tegra_usb_phy *phy) { - const tegra_phy_fp postresume[] = { - utmi_phy_postresume, - NULL, - NULL, - NULL, - }; + int err = 0; - usb_phy_set_tx_fill_tuning(phy, is_dpd); - - // If Phy type is utmi, call its post resume - if (phy->usb_phy_type == 0) - utmi_phy_postresume(phy, is_dpd); -} + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); -void tegra_ehci_pre_reset(struct tegra_usb_phy *phy, bool is_dpd) -{ - const tegra_phy_fp pre_reset[] = { - NULL, - NULL, - null_phy_pre_usbcmd_reset, - NULL, - }; + if (phy->pdata->u_data.host.power_off_on_suspend) { + if (phy->pdata->ops && phy->pdata->ops->pre_phy_on) + phy->pdata->ops->pre_phy_on(); + err = phy->ops->power_on(phy); + if (phy->pdata->ops && phy->pdata->ops->post_phy_on) + phy->pdata->ops->post_phy_on(); + } - if (pre_reset[phy->usb_phy_type]) - pre_reset[phy->usb_phy_type](phy, is_dpd); -} + if (!err && phy->ops && phy->ops->resume) + err = phy->ops->resume(phy); -void tegra_ehci_post_reset(struct tegra_usb_phy *phy, bool is_dpd) -{ - const tegra_phy_fp post_reset[] = { - NULL, - NULL, - null_phy_post_usbcmd_reset, - NULL, - }; + return err; - if (post_reset[phy->usb_phy_type]) - post_reset[phy->usb_phy_type](phy, is_dpd); } - -void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy, - enum tegra_usb_phy_port_speed port_speed) +int tegra_usb_phy_post_resume(struct tegra_usb_phy *phy) { - const tegra_phy_restore_start_fp phy_restore_start[] = { - utmi_phy_restore_start, - ulpi_phy_restore_start, - null_phy_restore_start, - NULL, - }; + int status = 0; - if (phy_restore_start[phy->usb_phy_type]) - phy_restore_start[phy->usb_phy_type](phy, port_speed); -} + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); -void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy) -{ - const tegra_phy_restore_end_fp phy_restore_end[] = { - utmi_phy_restore_end, - ulpi_phy_restore_end, - null_phy_restore_end, - NULL, - }; + if (phy->ops && phy->ops->post_resume) + status = phy->ops->post_resume(phy); - if (phy_restore_end[phy->usb_phy_type]) - phy_restore_end[phy->usb_phy_type](phy); -} + if (phy->pdata->ops && phy->pdata->ops->post_resume) + phy->pdata->ops->post_resume(); -void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy) -{ - if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) - utmi_phy_clk_disable(phy); + return status; } - -void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy) +int tegra_usb_phy_port_power(struct tegra_usb_phy *phy) { - if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) - utmi_phy_clk_enable(phy); -} + int status = 0; -void tegra_usb_phy_close(struct tegra_usb_phy *phy) -{ - if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) { - utmip_pad_close(phy); - utmip_phy_disable_pmc_bus_ctrl(phy); - } - else if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_LINK_ULPI && phy->clk) - clk_put(phy->clk); - if (phy->mode == TEGRA_USB_PHY_MODE_HOST) { - vbus_disable(phy); - } - clk_disable(phy->pll_u); - clk_put(phy->pll_u); - if (phy->reg_vbus) - regulator_put(phy->reg_vbus); - if (phy->reg_vdd) - regulator_put(phy->reg_vdd); - if (phy->instance == 0 && usb_phy_data[0].vbus_irq) - free_irq(usb_phy_data[0].vbus_irq, phy); - kfree(phy); -} + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); -int tegra_usb_phy_bus_connect(struct tegra_usb_phy *phy) -{ - unsigned long val; - void __iomem *base = phy->regs; - struct tegra_uhsic_config *uhsic_config = phy->config; - - if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC) { -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - val = readl(base + TEGRA_USB_USBMODE_REG_OFFSET); - val |= TEGRA_USB_USBMODE_HOST; - writel(val, base + TEGRA_USB_USBMODE_REG_OFFSET); - - /* Change the USB controller PHY type to HSIC */ - val = readl(base + HOSTPC1_DEVLC); - val &= ~HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK); - val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC); - val &= ~HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK); - val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED); - writel(val, base + HOSTPC1_DEVLC); -#endif - val = readl(base + UHSIC_MISC_CFG0); - val |= UHSIC_DETECT_SHORT_CONNECT; - writel(val, base + UHSIC_MISC_CFG0); - udelay(1); - - val = readl(base + UHSIC_MISC_CFG0); - val |= UHSIC_FORCE_XCVR_MODE; - writel(val, base + UHSIC_MISC_CFG0); + if (phy->ops && phy->ops->port_power) + status = phy->ops->port_power(phy); - val = readl(base + UHSIC_PADS_CFG1); - val &= ~UHSIC_RPD_STROBE; -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - val |= UHSIC_RPU_STROBE; -#endif - writel(val, base + UHSIC_PADS_CFG1); - - if (uhsic_config->usb_phy_ready && - uhsic_config->usb_phy_ready()) - return -EAGAIN; - - /* connect detect on T30 requires extra wait */ - if (utmi_wait_register_timeout(base + UHSIC_STAT_CFG0, - UHSIC_CONNECT_DETECT, UHSIC_CONNECT_DETECT, - CONNECT_DETECT_TIMEOUT) < 0) { - pr_err("%s: timeout waiting for hsic connect detect\n", __func__); - return -ETIMEDOUT; - } - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - if (utmi_wait_register(base + USB_PORTSC1, USB_PORTSC1_LS(2), USB_PORTSC1_LS(2)) < 0) { - pr_err("%s: timeout waiting for dplus state\n", __func__); - return -ETIMEDOUT; - } -#endif - } + if (phy->pdata->ops && phy->pdata->ops->port_power) + phy->pdata->ops->port_power(); - return 0; + return status; } - int tegra_usb_phy_bus_reset(struct tegra_usb_phy *phy) { - unsigned long val; - void __iomem *base = phy->regs; - - if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC) { -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - /* Change the USB controller PHY type to HSIC */ - val = readl(base + HOSTPC1_DEVLC); - val &= ~HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK); - val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC); - val &= ~HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK); - val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED); - writel(val, base + HOSTPC1_DEVLC); - /* wait here, otherwise HOSTPC1_DEVLC_PSPD will timeout */ - mdelay(5); -#endif - val = readl(base + USB_PORTSC1); - val |= USB_PORTSC1_PTC(5); - writel(val, base + USB_PORTSC1); - udelay(2); - - val = readl(base + USB_PORTSC1); - val &= ~USB_PORTSC1_PTC(~0); - writel(val, base + USB_PORTSC1); - udelay(2); - - if (utmi_wait_register(base + USB_PORTSC1, USB_PORTSC1_LS(0), 0) < 0) { - pr_err("%s: timeout waiting for SE0\n", __func__); - return -ETIMEDOUT; - } + int status = 0; - if (utmi_wait_register(base + USB_PORTSC1, USB_PORTSC1_CCS, USB_PORTSC1_CCS) < 0) { - pr_err("%s: timeout waiting for connection status\n", __func__); - return -ETIMEDOUT; - } + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); -#if defined(CONFIG_ARCH_TEGRA_2x_SOC) - if (utmi_wait_register(base + USB_PORTSC1, USB_PORTSC1_PSPD(2), USB_PORTSC1_PSPD(2)) < 0) { - pr_err("%s: timeout waiting hsic high speed configuration\n", __func__); - return -ETIMEDOUT; - } -#elif defined(CONFIG_ARCH_TEGRA_3x_SOC) - if (utmi_wait_register(base + HOSTPC1_DEVLC, - HOSTPC1_DEVLC_PSPD(2), - HOSTPC1_DEVLC_PSPD(2)) < 0) { - pr_err("%s: timeout waiting hsic high speed configuration\n", __func__); - return -ETIMEDOUT; - } -#endif - val = readl(base + USB_USBCMD); - val &= ~USB_USBCMD_RS; - writel(val, base + USB_USBCMD); - - if (utmi_wait_register(base + USB_USBSTS, USB_USBSTS_HCH, USB_USBSTS_HCH) < 0) { - pr_err("%s: timeout waiting for stopping the controller\n", __func__); - return -ETIMEDOUT; - } - - val = readl(base + UHSIC_PADS_CFG1); - val &= ~UHSIC_RPU_STROBE; - val |= UHSIC_RPD_STROBE; - writel(val, base + UHSIC_PADS_CFG1); - - mdelay(50); - - val = readl(base + UHSIC_PADS_CFG1); - val &= ~UHSIC_RPD_STROBE; - val |= UHSIC_RPU_STROBE; - writel(val, base + UHSIC_PADS_CFG1); - - val = readl(base + USB_USBCMD); - val |= USB_USBCMD_RS; - writel(val, base + USB_USBCMD); - - val = readl(base + UHSIC_PADS_CFG1); - val &= ~UHSIC_RPU_STROBE; - writel(val, base + UHSIC_PADS_CFG1); + if (phy->ops && phy->ops->bus_reset) + status = phy->ops->bus_reset(phy); - if (utmi_wait_register(base + USB_USBCMD, USB_USBCMD_RS, USB_USBCMD_RS) < 0) { - pr_err("%s: timeout waiting for starting the controller\n", __func__); - return -ETIMEDOUT; - } - } - - return 0; + return status; } -int tegra_usb_phy_bus_idle(struct tegra_usb_phy *phy) +bool tegra_usb_phy_charger_detected(struct tegra_usb_phy *phy) { - unsigned long val; - void __iomem *base = phy->regs; - struct tegra_uhsic_config *uhsic_config = phy->config; - - if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC) { - -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - val = readl(base + TEGRA_USB_USBMODE_REG_OFFSET); - val |= TEGRA_USB_USBMODE_HOST; - writel(val, base + TEGRA_USB_USBMODE_REG_OFFSET); - - /* Change the USB controller PHY type to HSIC */ - val = readl(base + HOSTPC1_DEVLC); - val &= ~HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK); - val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC); - val &= ~HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK); - val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED); - writel(val, base + HOSTPC1_DEVLC); -#endif - val = readl(base + UHSIC_MISC_CFG0); - val |= UHSIC_DETECT_SHORT_CONNECT; - writel(val, base + UHSIC_MISC_CFG0); - udelay(1); + bool status = 0; - val = readl(base + UHSIC_MISC_CFG0); - val |= UHSIC_FORCE_XCVR_MODE; - writel(val, base + UHSIC_MISC_CFG0); - - val = readl(base + UHSIC_PADS_CFG1); - val &= ~UHSIC_RPD_STROBE; - /* safe to enable RPU on STROBE at all times during idle */ - val |= UHSIC_RPU_STROBE; - writel(val, base + UHSIC_PADS_CFG1); - - val = readl(base + USB_USBCMD); - val &= ~USB_USBCMD_RS; - writel(val, base + USB_USBCMD); - - if (uhsic_config->usb_phy_ready && - uhsic_config->usb_phy_ready()) - return -EAGAIN; - - /* connect detect on T30 requires extra wait */ - if (utmi_wait_register_timeout(base + UHSIC_STAT_CFG0, - UHSIC_CONNECT_DETECT, UHSIC_CONNECT_DETECT, - CONNECT_DETECT_TIMEOUT) < 0) { - pr_err("%s: timeout waiting for hsic connect detect\n", - __func__); - return -ETIMEDOUT; - } - } - return 0; + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + if (phy->ops && phy->ops->charger_detect) + status = phy->ops->charger_detect(phy); + + return status; } -bool tegra_usb_phy_is_device_connected(struct tegra_usb_phy *phy) +bool tegra_usb_phy_hw_accessible(struct tegra_usb_phy *phy) { - void __iomem *base = phy->regs; + if (!phy->hw_accessible) + DBG("%s(%d) inst:[%d] Not Accessible\n", __func__, + __LINE__, phy->inst); - if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC) { - if (utmi_wait_register(base + UHSIC_STAT_CFG0, - UHSIC_CONNECT_DETECT, UHSIC_CONNECT_DETECT) < 0) { - pr_err("%s: no hsic connection\n", __func__); - return false; - } -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - if (utmi_wait_register(base + USB_PORTSC1, USB_PORTSC1_LS(2), USB_PORTSC1_LS(2)) < 0) { - pr_err("%s: timeout waiting for dplus state\n", __func__); - return false; - } -#endif - } - return true; + return phy->hw_accessible; } -bool tegra_usb_phy_charger_detect(struct tegra_usb_phy *phy) +bool tegra_usb_phy_remote_wakeup(struct tegra_usb_phy *phy) { - unsigned long val; - void __iomem *base = phy->regs; - bool status; - - if (phy->usb_phy_type != TEGRA_USB_PHY_TYPE_UTMIP) - { - /* Charger detection is not there for ULPI - * return Charger not available */ - return false; - } - - /* Enable charger detection logic */ - val = readl(base + UTMIP_BAT_CHRG_CFG0); - val |= UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN; - writel(val, base + UTMIP_BAT_CHRG_CFG0); - - /* Source should be on for 100 ms as per USB charging spec */ - msleep(TDP_SRC_ON_MS); - - val = readl(base + USB_PHY_VBUS_WAKEUP_ID); - /* If charger is not connected disable the interrupt */ - val &= ~VDAT_DET_INT_EN; - val |= VDAT_DET_CHG_DET; - writel(val,base + USB_PHY_VBUS_WAKEUP_ID); - - val = readl(base + USB_PHY_VBUS_WAKEUP_ID); - if (val & VDAT_DET_STS) - status = true; - else - status = false; - - /* Disable charger detection logic */ - val = readl(base + UTMIP_BAT_CHRG_CFG0); - val &= ~(UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN); - writel(val, base + UTMIP_BAT_CHRG_CFG0); - - /* Delay of 40 ms before we pull the D+ as per battery charger spec */ - msleep(TDPSRC_CON_MS); - - return status; + return phy->remote_wakeup; } -#ifndef CONFIG_ARCH_TEGRA_2x_SOC -void tegra_usb_phy_power_down_pmc(void) +bool tegra_usb_phy_has_hostpc(struct tegra_usb_phy *phy) { - unsigned long val; - void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); - - /* power down all 3 UTMIP interfaces */ - val = readl(pmc_base + PMC_UTMIP_MASTER_CONFIG); - val |= UTMIP_PWR(0) | UTMIP_PWR(1) | UTMIP_PWR(2); - writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG); - - /* turn on pad detectors */ - writel(PMC_POWER_DOWN_MASK, pmc_base + PMC_USB_AO); - - /* setup sleep walk fl all 3 usb controllers */ - val = UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A | UTMIP_HIGHZ_A | - UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_HIGHZ_B | - UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_HIGHZ_C | - UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_HIGHZ_D; - writel(val, pmc_base + PMC_SLEEPWALK_REG(0)); - writel(val, pmc_base + PMC_SLEEPWALK_REG(1)); - writel(val, pmc_base + PMC_SLEEPWALK_REG(2)); - - /* enable pull downs on HSIC PMC */ - val = UHSIC_STRB_RPD_A | UHSIC_DATA_RPD_A | UHSIC_STRB_RPD_B | - UHSIC_DATA_RPD_B | UHSIC_STRB_RPD_C | UHSIC_DATA_RPD_C | - UHSIC_STRB_RPD_D | UHSIC_DATA_RPD_D; - writel(val, pmc_base + UHSIC_SLEEPWALK_REG); - - /* Turn over pad configuration to PMC */ - val = readl(pmc_base + PMC_SLEEP_CFG); - val &= ~UTMIP_WAKE_VAL(0, ~0); - val &= ~UTMIP_WAKE_VAL(1, ~0); - val &= ~UTMIP_WAKE_VAL(2, ~0); - val &= ~UHSIC_WAKE_VAL_P0(~0); - val |= UTMIP_WAKE_VAL(0, WAKE_VAL_NONE) | UHSIC_WAKE_VAL_P0(WAKE_VAL_NONE) | - UTMIP_WAKE_VAL(1, WAKE_VAL_NONE) | UTMIP_WAKE_VAL(2, WAKE_VAL_NONE) | - UTMIP_RCTRL_USE_PMC(0) | UTMIP_RCTRL_USE_PMC(1) | UTMIP_RCTRL_USE_PMC(2) | - UTMIP_TCTRL_USE_PMC(0) | UTMIP_TCTRL_USE_PMC(1) | UTMIP_TCTRL_USE_PMC(2) | - UTMIP_FSLS_USE_PMC(0) | UTMIP_FSLS_USE_PMC(1) | UTMIP_FSLS_USE_PMC(2) | - UTMIP_MASTER_ENABLE(0) | UTMIP_MASTER_ENABLE(1) | UTMIP_MASTER_ENABLE(2) | - UHSIC_MASTER_ENABLE_P0; - writel(val, pmc_base + PMC_SLEEP_CFG); + return phy->pdata->has_hostpc; } -#endif -int __init tegra_usb_phy_init(struct usb_phy_plat_data *pdata, int size) +bool tegra_usb_phy_otg_supported(struct tegra_usb_phy *phy) { - if (pdata) { - int i; - - for (i = 0; i < size; i++, pdata++) { - usb_phy_data[pdata->instance].instance = pdata->instance; - usb_phy_data[pdata->instance].vbus_irq = pdata->vbus_irq; - usb_phy_data[pdata->instance].vbus_gpio = pdata->vbus_gpio; - usb_phy_data[pdata->instance].vbus_reg_supply = pdata->vbus_reg_supply; - } - } - -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - tegra_usb_phy_power_down_pmc(); -#endif - - return 0; + return phy->pdata->port_otg; } void tegra_usb_phy_memory_prefetch_on(struct tegra_usb_phy *phy) @@ -3197,7 +643,7 @@ void tegra_usb_phy_memory_prefetch_on(struct tegra_usb_phy *phy) void __iomem *ahb_gizmo = IO_ADDRESS(TEGRA_AHB_GIZMO_BASE); unsigned long val; - if (phy->instance == 0 && phy->mode == TEGRA_USB_PHY_MODE_DEVICE) { + if (phy->inst == 0 && phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) { val = readl(ahb_gizmo + AHB_MEM_PREFETCH_CFG1); val |= PREFETCH_ENB; writel(val, ahb_gizmo + AHB_MEM_PREFETCH_CFG1); @@ -3212,7 +658,7 @@ void tegra_usb_phy_memory_prefetch_off(struct tegra_usb_phy *phy) void __iomem *ahb_gizmo = IO_ADDRESS(TEGRA_AHB_GIZMO_BASE); unsigned long val; - if (phy->instance == 0 && phy->mode == TEGRA_USB_PHY_MODE_DEVICE) { + if (phy->inst == 0 && phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) { val = readl(ahb_gizmo + AHB_MEM_PREFETCH_CFG1); val &= ~(PREFETCH_ENB); writel(val, ahb_gizmo + AHB_MEM_PREFETCH_CFG1); @@ -3221,38 +667,3 @@ void tegra_usb_phy_memory_prefetch_off(struct tegra_usb_phy *phy) writel(val, ahb_gizmo + AHB_MEM_PREFETCH_CFG2); } } - -/* disable walk and wake events after resume from LP0 */ -bool tegra_usb_phy_is_remotewake_detected(struct tegra_usb_phy *phy) -{ -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); - void __iomem *base = phy->regs; - unsigned int inst = phy->instance; - u32 val; - - val = readl(base + UTMIP_PMC_WAKEUP0); - if (val & EVENT_INT_ENB) { - val = readl(pmc_base + UTMIP_UHSIC_STATUS); - if (UTMIP_WAKE_ALARM(inst) & val) { - val = readl(pmc_base + PMC_SLEEP_CFG); - val &= ~UTMIP_WAKE_VAL(inst, 0x0); - val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE); - writel(val, pmc_base + PMC_SLEEP_CFG); - - val = readl(pmc_base + PMC_TRIGGERS); - val |= UTMIP_CLR_WAKE_ALARM(inst) | - UTMIP_CLR_WALK_PTR(inst); - writel(val, pmc_base + PMC_TRIGGERS); - - val = readl(base + UTMIP_PMC_WAKEUP0); - val &= ~EVENT_INT_ENB; - writel(val, base + UTMIP_PMC_WAKEUP0); - phy->remote_wakeup = true; - return true; - } - } -#endif - return false; -} - |