diff options
109 files changed, 2956 insertions, 1125 deletions
diff --git a/arch/arm/configs/tegra3_android_defconfig b/arch/arm/configs/tegra3_android_defconfig index 2b4aee13812b..50da47699f9f 100644 --- a/arch/arm/configs/tegra3_android_defconfig +++ b/arch/arm/configs/tegra3_android_defconfig @@ -292,6 +292,7 @@ CONFIG_SPI_TEGRA=y CONFIG_SPI_SLAVE_TEGRA=y CONFIG_DEBUG_GPIO=y CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_RC5T583=y CONFIG_POWER_SUPPLY=y CONFIG_BATTERY_BQ20Z75=y CONFIG_BATTERY_BQ27x00=y @@ -307,6 +308,7 @@ CONFIG_MFD_TPS6586X=y CONFIG_MFD_TPS65910=y CONFIG_MFD_MAX77663=y CONFIG_MFD_TPS6591X=y +CONFIG_MFD_RC5T583=y CONFIG_MFD_TPS80031=y CONFIG_GPADC_TPS80031=y CONFIG_MFD_RICOH583=y @@ -317,6 +319,7 @@ CONFIG_REGULATOR_GPIO=y CONFIG_REGULATOR_USERSPACE_CONSUMER=y CONFIG_REGULATOR_MAX8973=y CONFIG_REGULATOR_MAX77663=y +CONFIG_REGULATOR_RC5T583=y CONFIG_REGULATOR_TPS6586X=y CONFIG_REGULATOR_TPS65910=y CONFIG_REGULATOR_TPS62360=y @@ -332,6 +335,7 @@ CONFIG_VIDEO_HELPER_CHIPS_AUTO=y # CONFIG_TEGRA_AVP is not set # CONFIG_TEGRA_MEDIASERVER is not set CONFIG_TEGRA_NVAVP=y +CONFIG_TEGRA_NVAVP_AUDIO=y CONFIG_VIDEO_OV5650=y CONFIG_VIDEO_OV5640=y CONFIG_VIDEO_OV9726=y @@ -441,7 +445,7 @@ CONFIG_EFI_PARTITION=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y -CONFIG_MAGIC_SYSRQ=y +# CONFIG_MAGIC_SYSRQ is not set CONFIG_DEBUG_SECTION_MISMATCH=y CONFIG_DEBUG_FS=y CONFIG_LOCKUP_DETECTOR=y diff --git a/arch/arm/configs/tegra_android_defconfig b/arch/arm/configs/tegra_android_defconfig index a129a8ee5a10..3cb78ad0741e 100644 --- a/arch/arm/configs/tegra_android_defconfig +++ b/arch/arm/configs/tegra_android_defconfig @@ -371,7 +371,6 @@ CONFIG_EFI_PARTITION=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y CONFIG_LOCKUP_DETECTOR=y # CONFIG_DETECT_HUNG_TASK is not set @@ -384,3 +383,4 @@ CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_TWOFISH=y # CONFIG_CRYPTO_ANSI_CPRNG is not set CONFIG_CRYPTO_DEV_TEGRA_AES=y +# CONFIG_MAGIC_SYSRQ is not set diff --git a/arch/arm/configs/tegra_p1852_gnu_linux_defconfig b/arch/arm/configs/tegra_p1852_gnu_linux_defconfig index 6a98b5b8fb49..243eaffccec3 100644 --- a/arch/arm/configs/tegra_p1852_gnu_linux_defconfig +++ b/arch/arm/configs/tegra_p1852_gnu_linux_defconfig @@ -31,6 +31,7 @@ CONFIG_ARCH_TEGRA_3x_SOC=y CONFIG_TEGRA_PCI=y CONFIG_MACH_P1852=y CONFIG_TEGRA_PWM=y +CONFIG_TEGRA_P1852_TDM=y # CONFIG_TEGRA_CPU_DVFS is not set CONFIG_TEGRA_CLOCK_DEBUG_WRITE=y # CONFIG_TEGRA_MC_EARLY_ACK is not set diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 82306bc4aff5..c11ea97941a2 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -24,6 +24,7 @@ config ARCH_TEGRA_2x_SOC select ARM_ERRATA_716044 select ARM_ERRATA_764369 if SMP select ARCH_HAS_SUSPEND_PAGETABLE + select NVMAP_CACHE_MAINT_BY_SET_WAYS help Support for NVIDIA Tegra AP20 and T20 processors, based on the ARM CortexA9MP CPU and the ARM PL310 L2 cache controller @@ -51,6 +52,7 @@ config ARCH_TEGRA_3x_SOC select TEGRA_LP2_ARM_TWD if HAVE_ARM_TWD && !TEGRA_RAIL_OFF_MULTIPLE_CPUS select CPA select ARCH_HAS_SUSPEND_PAGETABLE + select NVMAP_CACHE_MAINT_BY_SET_WAYS help Support for NVIDIA Tegra 3 family of SoCs, based upon the ARM CortexA9MP CPU and the ARM PL310 L2 cache controller @@ -254,6 +256,14 @@ config TEGRA_FIQ_DEBUGGER help Enables the FIQ serial debugger on Tegra +config TEGRA_P1852_TDM + bool "Enable TDM mode for P1852 SKUs" + default n + depends on MACH_P1852 + help + Enables TDM mode driver for P1852 SKUs. If this + is not defined then I2S mode is selected by default. + config TEGRA_CARDHU_DSI bool "Support DSI panel on Cardhu" depends on MACH_CARDHU diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 3153203c6efc..9acb8305a175 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra3_emc.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += wakeups-t2.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += wakeups-t3.o +obj-y += wakeups.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pm-t2.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += pm-t3.o diff --git a/arch/arm/mach-tegra/baseband-xmm-power.c b/arch/arm/mach-tegra/baseband-xmm-power.c index 4da5d412cf41..30aba86f02f1 100644 --- a/arch/arm/mach-tegra/baseband-xmm-power.c +++ b/arch/arm/mach-tegra/baseband-xmm-power.c @@ -187,10 +187,36 @@ static int baseband_modem_power_on(struct baseband_power_platform_data *data) /* set IPC_HSIC_ACTIVE active */ gpio_set_value(data->modem.xmm.ipc_hsic_active, 1); + /* wait 20 ms */ + mdelay(20); + /* reset / power on sequence */ - msleep(40); + mdelay(40); gpio_set_value(data->modem.xmm.bb_rst, 1); mdelay(1); + + gpio_set_value(data->modem.xmm.bb_on, 1); + udelay(70); + gpio_set_value(data->modem.xmm.bb_on, 0); + + return 0; +} + +/* this function can sleep, do not call in atomic context */ +static int baseband_modem_power_on_async( + struct baseband_power_platform_data *data) +{ + /* set IPC_HSIC_ACTIVE active */ + gpio_set_value(data->modem.xmm.ipc_hsic_active, 1); + + /* wait 20 ms */ + msleep(20); + + /* reset / power on sequence */ + msleep(40); + gpio_set_value(data->modem.xmm.bb_rst, 1); + usleep_range(1000, 2000); + gpio_set_value(data->modem.xmm.bb_on, 1); udelay(70); gpio_set_value(data->modem.xmm.bb_on, 0); @@ -251,8 +277,9 @@ static int xmm_power_on(struct platform_device *device) if (pdata->hsic_register) data->hsic_device = pdata->hsic_register(); /* turn on modem */ - pr_debug("%s call baseband_modem_power_on\n", __func__); - baseband_modem_power_on(pdata); + pr_debug("%s call baseband_modem_power_on_async\n", + __func__); + baseband_modem_power_on_async(pdata); } } ret = enable_irq_wake(gpio_to_irq(pdata->modem.xmm.ipc_ap_wake)); @@ -302,11 +329,12 @@ static int xmm_power_off(struct platform_device *device) gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0); /* wait 20 ms */ - mdelay(20); + msleep(20); /* drive bb_rst low */ gpio_set_value(pdata->modem.xmm.bb_rst, 0); - mdelay(1); + /* sleep 1ms */ + usleep_range(1000, 2000); baseband_xmm_powerstate = BBXMM_PS_UNINIT; modem_sleep_flag = false; @@ -484,6 +512,7 @@ EXPORT_SYMBOL_GPL(baseband_xmm_set_power_status); irqreturn_t xmm_power_ipc_ap_wake_irq(int irq, void *dev_id) { struct baseband_power_platform_data *data = xmm_power_drv_data.pdata; + struct xmm_power_data *drv = &xmm_power_drv_data; int value; value = gpio_get_value(data->modem.xmm.ipc_ap_wake); @@ -521,6 +550,12 @@ irqreturn_t xmm_power_ipc_ap_wake_irq(int irq, void *dev_id) /* modem wakeup part */ if (!value) { pr_debug("%s - falling\n", __func__); + if (drv->hostwake == 0) { + /* AP L2 to L0 wakeup */ + pr_debug("received wakeup ap l2->l0\n"); + drv->hostwake = 1; + wake_up_interruptible(&drv->bb_wait); + } /* First check it a CP ack or CP wake */ value = gpio_get_value(data->modem.xmm.ipc_bb_wake); if (value) { @@ -528,6 +563,7 @@ irqreturn_t xmm_power_ipc_ap_wake_irq(int irq, void *dev_id) ipc_ap_wake_state = IPC_AP_WAKE_L; return IRQ_HANDLED; } + spin_lock(&xmm_lock); wakeup_pending = true; if (system_suspending) { @@ -593,19 +629,19 @@ static void xmm_power_init1_work(struct work_struct *work) } /* wait 100 ms */ - mdelay(100); + msleep(100); /* set IPC_HSIC_ACTIVE low */ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0); /* wait 10 ms */ - mdelay(10); + usleep_range(10000, 11000); /* set IPC_HSIC_ACTIVE high */ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 1); /* wait 20 ms */ - mdelay(20); + msleep(20); pr_debug("%s }\n", __func__); } @@ -654,9 +690,11 @@ static void xmm_power_autopm_resume(struct work_struct *work) static void xmm_power_L2_resume(void) { struct baseband_power_platform_data *pdata = xmm_power_drv_data.pdata; + struct xmm_power_data *drv = &xmm_power_drv_data; int value; - int delay = 10000; /* maxmum delay in msec */ + int delay = 1000; /* maxmum delay in msec */ unsigned long flags; + int ret, rcount = 0; pr_debug("%s\n", __func__); @@ -680,22 +718,30 @@ static void xmm_power_L2_resume(void) pr_info("AP L2->L0\n"); value = gpio_get_value(pdata->modem.xmm.ipc_ap_wake); if (value) { - pr_debug("waiting for host wakeup from CP...\n"); + drv->hostwake = 0; /* wake bb */ gpio_set_value(pdata->modem.xmm.ipc_bb_wake, 1); - do { - mdelay(1); - value = gpio_get_value( - pdata->modem.xmm.ipc_ap_wake); - delay--; - } while ((value) && (delay)); - if (delay) - pr_debug("gpio host wakeup low <-\n"); - else +retry: + /* wait for cp */ + pr_debug("waiting for host wakeup from CP...\n"); + ret = wait_event_interruptible_timeout(drv->bb_wait, + drv->hostwake == 1, msecs_to_jiffies(delay)); + if (ret == 0) { pr_info("!!AP L2->L0 Failed\n"); - } else { + return; + } + if (ret == -ERESTARTSYS) { + if (rcount >= 5) { + pr_info("!!AP L2->L0 Failed\n"); + return; + } + pr_debug("%s: caught signal\n", __func__); + rcount++; + goto retry; + } + pr_debug("Get gpio host wakeup low <-\n"); + } else pr_info("CP already ready\n"); - } } } @@ -723,7 +769,7 @@ static void xmm_power_reset_on(struct baseband_power_platform_data *pdata) gpio_set_value(pdata->modem.xmm.bb_rst, 0); msleep(40); gpio_set_value(pdata->modem.xmm.bb_rst, 1); - mdelay(1); + usleep_range(1000, 2000); gpio_set_value(pdata->modem.xmm.bb_on, 1); udelay(70); gpio_set_value(pdata->modem.xmm.bb_on, 0); @@ -778,6 +824,7 @@ static void xmm_power_work_func(struct work_struct *work) * software directly. */ break; + case BBXMM_WORK_INIT_FLASHLESS_PM_STEP1: pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_STEP1\n"); pr_info("%s: flashless is not supported here\n", __func__); @@ -915,6 +962,10 @@ static int xmm_power_driver_probe(struct platform_device *device) /* save platform data */ xmm_power_drv_data.pdata = pdata; + /* init wait queue */ + xmm_power_drv_data.hostwake = 1; + init_waitqueue_head(&xmm_power_drv_data.bb_wait); + /* create device file */ err = device_create_file(dev, &dev_attr_xmm_onoff); if (err < 0) { @@ -1041,7 +1092,7 @@ static int xmm_power_driver_handle_resume( struct baseband_power_platform_data *pdata) { int value; - int delay = 1000; /* maxmum delay in msec */ + unsigned long timeout; unsigned long flags; pr_debug("%s\n", __func__); @@ -1064,29 +1115,30 @@ static int xmm_power_driver_handle_resume( value = gpio_get_value(pdata->modem.xmm.ipc_ap_wake); if (value) { pr_info("AP L3 -> L0\n"); - pr_debug("waiting for host wakeup...\n"); /* wake bb */ gpio_set_value(pdata->modem.xmm.ipc_bb_wake, 1); + + /* Wait for max 1 sec */ + timeout = jiffies + HZ; + pr_debug("Current: %lu: timeout %lu\n", jiffies, timeout); do { - mdelay(1); + udelay(100); value = gpio_get_value(pdata->modem.xmm.ipc_ap_wake); - delay--; - } while ((value) && (delay)); - if (delay) + if (!value) + break; + } while (time_before(jiffies, timeout)); + if (!value) pr_debug("gpio host wakeup low <-\n"); else pr_info("!!AP L3->L0 Failed\n"); - - } else { + } else pr_info("CP L3 -> L0\n"); - } + reenable_autosuspend = true; return 0; - } - #ifdef CONFIG_PM static int xmm_power_driver_suspend(struct device *dev) { diff --git a/arch/arm/mach-tegra/baseband-xmm-power.h b/arch/arm/mach-tegra/baseband-xmm-power.h index 1f08e3b6900c..69140891319d 100644 --- a/arch/arm/mach-tegra/baseband-xmm-power.h +++ b/arch/arm/mach-tegra/baseband-xmm-power.h @@ -84,6 +84,9 @@ struct xmm_power_data { struct baseband_power_platform_data *pdata; struct work_struct work; struct platform_device *hsic_device; + wait_queue_head_t bb_wait; + /* host wakeup gpio state*/ + unsigned int hostwake; }; enum baseband_xmm_powerstate_t { diff --git a/arch/arm/mach-tegra/board-aruba-power.c b/arch/arm/mach-tegra/board-aruba-power.c index 4391f6f19b51..b72b82fc144a 100644 --- a/arch/arm/mach-tegra/board-aruba-power.c +++ b/arch/arm/mach-tegra/board-aruba-power.c @@ -26,7 +26,6 @@ #include "pm.h" #include "board.h" -#include "wakeups-t3.h" static int ac_online(void) { 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 f0dc8afa56fe..9168d9719b7c 100644 --- a/arch/arm/mach-tegra/board-cardhu-pm298-power-rails.c +++ b/arch/arm/mach-tegra/board-cardhu-pm298-power-rails.c @@ -1,7 +1,7 @@ /* * arch/arm/mach-tegra/board-cardhu-pm298-power-rails.c * - * Copyright (C) 2011 NVIDIA, Inc. + * Copyright (C) 2011-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 version 2 as @@ -37,7 +37,6 @@ #include "board.h" #include "board-cardhu.h" #include "pm.h" -#include "wakeups-t3.h" #define PMC_CTRL 0x0 #define PMC_CTRL_INTR_LOW BIT(17) @@ -676,7 +675,6 @@ static struct platform_device *fixed_reg_devs_pm269[] = { int __init cardhu_pm298_gpio_switch_regulator_init(void) { - int i; struct board_info board_info; struct platform_device **fixed_reg_devs; int 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 6d4db73b6ecd..32f07599fea4 100644 --- a/arch/arm/mach-tegra/board-cardhu-pm299-power-rails.c +++ b/arch/arm/mach-tegra/board-cardhu-pm299-power-rails.c @@ -1,7 +1,7 @@ /* * arch/arm/mach-tegra/board-cardhu-pm299-power-rails.c * - * Copyright (C) 2011 NVIDIA, Inc. + * Copyright (C) 2011-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 version 2 as @@ -37,7 +37,6 @@ #include "gpio-names.h" #include "board.h" #include "board-cardhu.h" -#include "wakeups-t3.h" #define PMC_CTRL 0x0 #define PMC_CTRL_INTR_LOW (1 << 17) @@ -666,7 +665,6 @@ static struct platform_device *fixed_reg_devs_pm269[] = { int __init cardhu_pm299_gpio_switch_regulator_init(void) { - int i; struct board_info board_info; struct platform_device **fixed_reg_devs; int nfixreg_devs; diff --git a/arch/arm/mach-tegra/board-cardhu-power.c b/arch/arm/mach-tegra/board-cardhu-power.c index 61b5a15ed5c7..d517d8266204 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-2012 NVIDIA, Inc. + * Copyright (C) 2011-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 version 2 as @@ -42,7 +42,6 @@ #include "board.h" #include "board-cardhu.h" #include "pm.h" -#include "wakeups-t3.h" #include "tegra3_tsensor.h" #define PMC_CTRL 0x0 @@ -994,7 +993,6 @@ static struct platform_device *fixed_reg_devs_e1291_a04[] = { int __init cardhu_fixed_regulator_init(void) { - int i; struct board_info board_info; struct board_info pmu_board_info; struct board_info display_board_info; diff --git a/arch/arm/mach-tegra/board-cardhu-sdhci.c b/arch/arm/mach-tegra/board-cardhu-sdhci.c index cb0684bcc742..d8be9fe6747f 100644 --- a/arch/arm/mach-tegra/board-cardhu-sdhci.c +++ b/arch/arm/mach-tegra/board-cardhu-sdhci.c @@ -145,6 +145,7 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = { .embedded_sdio = &embedded_sdio_data2, #endif .built_in = 0, + .ocr_mask = MMC_OCR_1V8_MASK, }, #ifndef CONFIG_MMC_EMBEDDED_SDIO .pm_flags = MMC_PM_KEEP_POWER, diff --git a/arch/arm/mach-tegra/board-enterprise-baseband.c b/arch/arm/mach-tegra/board-enterprise-baseband.c index 9143103fd036..f2c94fda7727 100644 --- a/arch/arm/mach-tegra/board-enterprise-baseband.c +++ b/arch/arm/mach-tegra/board-enterprise-baseband.c @@ -69,11 +69,14 @@ static struct gpio modem_gpios[] = { static void baseband_phy_init(void); static void baseband_phy_on(void); -static void baseband_phy_off(void); +static void baseband_pre_phy_off(void); +static void baseband_post_phy_off(void); +static bool ap2mdm_ack_gpio_off = false; static struct tegra_usb_phy_platform_ops ulpi_null_plat_ops = { .init = baseband_phy_init, - .pre_phy_off = baseband_phy_off, + .pre_phy_off = baseband_pre_phy_off, + .post_phy_off = baseband_post_phy_off, .post_phy_on = baseband_phy_on, }; @@ -133,16 +136,65 @@ static void baseband_phy_init(void) pr_info("%s\n", __func__); } -static void baseband_phy_off(void) +static inline void null_phy_set_tristate(bool enable) +{ + int tristate = (enable) ? TEGRA_TRI_TRISTATE : TEGRA_TRI_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); +} + + +static void baseband_post_phy_off(void) +{ + null_phy_set_tristate(true); +} + + +static void baseband_pre_phy_off(void) { /* set AP2MDM_ACK2 high */ gpio_set_value(AP2MDM_ACK2, 1); + ap2mdm_ack_gpio_off = true; } static void baseband_phy_on(void) { - /* set AP2MDM_ACK2 low */ - gpio_set_value(AP2MDM_ACK2, 0); + if (ap2mdm_ack_gpio_off) { + + /* driving linestate using GPIO */ + gpio_set_value(ULPI_D0, 0); + gpio_set_value(ULPI_D1, 0); + + /* remove ULPI tristate */ + null_phy_set_tristate(false); + + gpio_set_value(AP2MDM_ACK2, 0); + + if (gpio_is_valid(MDM2AP_ACK2)) { + int retry = 20000; + while (retry) { + /* poll phy_restore_gpio high */ + if (gpio_get_value(MDM2AP_ACK2)) + break; + retry--; + } + + if (retry == 0) + pr_info("phy_restore_gpio timeout\n"); + } + ap2mdm_ack_gpio_off = false; + } } static void baseband_start(void) diff --git a/arch/arm/mach-tegra/board-enterprise-power.c b/arch/arm/mach-tegra/board-enterprise-power.c index c7598ab56139..f32365d808a7 100644 --- a/arch/arm/mach-tegra/board-enterprise-power.c +++ b/arch/arm/mach-tegra/board-enterprise-power.c @@ -44,7 +44,6 @@ #include "board.h" #include "board-enterprise.h" #include "pm.h" -#include "wakeups-t3.h" #include "tegra3_tsensor.h" #define PMC_CTRL 0x0 @@ -298,6 +297,7 @@ static struct tps80031_rtc_platform_data rtc_data = { .tm_min = 2, .tm_sec = 3, }, + .msecure_gpio = TEGRA_GPIO_PF7, }; int battery_charger_init(void *board_data) @@ -746,6 +746,8 @@ int __init enterprise_regulator_init(void) battery_gauge_data.battery_present = 0; } + tegra_gpio_enable(TEGRA_GPIO_PF7); + if (board_info.fab < BOARD_FAB_A03) { tps_platform.num_subdevs = ARRAY_SIZE(tps80031_devs_a02); tps_platform.subdevs = tps80031_devs_a02; diff --git a/arch/arm/mach-tegra/board-enterprise.c b/arch/arm/mach-tegra/board-enterprise.c index d92ac57dd054..e23a9a468081 100644 --- a/arch/arm/mach-tegra/board-enterprise.c +++ b/arch/arm/mach-tegra/board-enterprise.c @@ -684,7 +684,8 @@ static struct tegra_usb_platform_data tegra_udc_pdata = { .phy_intf = TEGRA_USB_PHY_INTF_UTMI, .op_mode = TEGRA_USB_OPMODE_DEVICE, .u_data.dev = { - .vbus_pmu_irq = 0, + .vbus_pmu_irq = ENT_TPS80031_IRQ_BASE + + TPS80031_INT_VBUS_DET, .vbus_gpio = -1, .charging_supported = false, .remote_wakeup_supported = false, diff --git a/arch/arm/mach-tegra/board-kai-kbc.c b/arch/arm/mach-tegra/board-kai-kbc.c index 928e5de707c9..e55383a1028b 100644 --- a/arch/arm/mach-tegra/board-kai-kbc.c +++ b/arch/arm/mach-tegra/board-kai-kbc.c @@ -90,13 +90,6 @@ int __init kai_keys_init(void) pr_info("Registering gpio keys\n"); - /* Enable gpio mode for other pins */ - for (i = 0; i < kai_keys_platform_data.nbuttons; i++) { - if (kai_keys_platform_data.buttons[i].gpio < 0) - continue; - tegra_gpio_enable(kai_keys_platform_data.buttons[i].gpio); - } - platform_device_register(&kai_keys_device); return 0; diff --git a/arch/arm/mach-tegra/board-kai-panel.c b/arch/arm/mach-tegra/board-kai-panel.c index 4073afe2fc8d..45333840ffb7 100644 --- a/arch/arm/mach-tegra/board-kai-panel.c +++ b/arch/arm/mach-tegra/board-kai-panel.c @@ -111,8 +111,6 @@ static int kai_backlight_init(struct device *dev) if (WARN_ON(ARRAY_SIZE(kai_bl_output_measured) != 256)) pr_err("bl_output array does not have 256 elements\n"); - tegra_gpio_disable(kai_bl_pwm); - ret = gpio_request(kai_bl_enb, "backlight_enb"); if (ret < 0) return ret; @@ -120,8 +118,6 @@ static int kai_backlight_init(struct device *dev) ret = gpio_direction_output(kai_bl_enb, 1); if (ret < 0) gpio_free(kai_bl_enb); - else - tegra_gpio_enable(kai_bl_enb); return ret; }; @@ -132,7 +128,6 @@ static void kai_backlight_exit(struct device *dev) /*ret = gpio_request(kai_bl_enb, "backlight_enb");*/ gpio_set_value(kai_bl_enb, 0); gpio_free(kai_bl_enb); - tegra_gpio_disable(kai_bl_enb); return; } @@ -654,35 +649,27 @@ int __init kai_panel_init(void) #endif gpio_request(kai_lvds_avdd_en, "lvds_avdd_en"); gpio_direction_output(kai_lvds_avdd_en, 1); - tegra_gpio_enable(kai_lvds_avdd_en); gpio_request(kai_lvds_stdby, "lvds_stdby"); gpio_direction_output(kai_lvds_stdby, 1); - tegra_gpio_enable(kai_lvds_stdby); gpio_request(kai_lvds_rst, "lvds_rst"); gpio_direction_output(kai_lvds_rst, 1); - tegra_gpio_enable(kai_lvds_rst); if (board_info.fab == BOARD_FAB_A00) { gpio_request(kai_lvds_rs_a00, "lvds_rs"); gpio_direction_output(kai_lvds_rs_a00, 0); - tegra_gpio_enable(kai_lvds_rs_a00); } else { gpio_request(kai_lvds_rs, "lvds_rs"); gpio_direction_output(kai_lvds_rs, 0); - tegra_gpio_enable(kai_lvds_rs); } gpio_request(kai_lvds_lr, "lvds_lr"); gpio_direction_output(kai_lvds_lr, 1); - tegra_gpio_enable(kai_lvds_lr); gpio_request(kai_lvds_shutdown, "lvds_shutdown"); gpio_direction_output(kai_lvds_shutdown, 1); - tegra_gpio_enable(kai_lvds_shutdown); - tegra_gpio_enable(kai_hdmi_hpd); gpio_request(kai_hdmi_hpd, "hdmi_hpd"); gpio_direction_input(kai_hdmi_hpd); diff --git a/arch/arm/mach-tegra/board-kai-pinmux.c b/arch/arm/mach-tegra/board-kai-pinmux.c index fa750f15ca7e..be11d4ef6698 100644 --- a/arch/arm/mach-tegra/board-kai-pinmux.c +++ b/arch/arm/mach-tegra/board-kai-pinmux.c @@ -449,13 +449,9 @@ static __initdata struct tegra_pingroup_config unused_pins_lowpower[] = { static void __init kai_pinmux_audio_init(void) { - tegra_gpio_enable(TEGRA_GPIO_CDC_IRQ); gpio_request(TEGRA_GPIO_CDC_IRQ, "rt5640"); gpio_direction_input(TEGRA_GPIO_CDC_IRQ); - tegra_gpio_enable(TEGRA_GPIO_HP_DET); - tegra_gpio_enable(TEGRA_GPIO_INT_MIC_EN); - tegra_gpio_enable(TEGRA_GPIO_EXT_MIC_EN); } /* We are disabling this code for now. */ @@ -551,7 +547,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-kai-power.c b/arch/arm/mach-tegra/board-kai-power.c index e89b2bd2246d..cc3b35608c98 100644 --- a/arch/arm/mach-tegra/board-kai-power.c +++ b/arch/arm/mach-tegra/board-kai-power.c @@ -40,7 +40,6 @@ #include "board.h" #include "board-kai.h" #include "pm.h" -#include "wakeups-t3.h" #include "tegra3_tsensor.h" #define PMC_CTRL 0x0 @@ -567,8 +566,6 @@ static int __init kai_fixed_regulator_init(void) fixed_reg_devs[i]->dev.platform_data; 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-kai-sdhci.c b/arch/arm/mach-tegra/board-kai-sdhci.c index 8d1d4a9bd4a8..0fa39ccf475d 100644 --- a/arch/arm/mach-tegra/board-kai-sdhci.c +++ b/arch/arm/mach-tegra/board-kai-sdhci.c @@ -106,6 +106,7 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = { .mmc_data = { .register_status_notify = kai_wifi_status_register, .built_in = 0, + .ocr_mask = MMC_OCR_1V8_MASK, }, #ifndef CONFIG_MMC_EMBEDDED_SDIO .pm_flags = MMC_PM_KEEP_POWER, @@ -243,9 +244,6 @@ static int __init kai_wifi_init(void) if (rc) pr_err("WLAN_IRQ gpio request failed:%d\n", rc); - tegra_gpio_enable(KAI_WLAN_EN); - tegra_gpio_enable(KAI_WLAN_IRQ); - rc = gpio_direction_output(KAI_WLAN_EN, 0); if (rc) pr_err("WLAN_EN gpio direction configuration failed:%d\n", rc); diff --git a/arch/arm/mach-tegra/board-kai-sensors.c b/arch/arm/mach-tegra/board-kai-sensors.c index 9564aaf0cfde..c545b2d0d786 100644 --- a/arch/arm/mach-tegra/board-kai-sensors.c +++ b/arch/arm/mach-tegra/board-kai-sensors.c @@ -135,9 +135,6 @@ static int kai_nct1008_init(void) pr_err("%s: set gpio to input failed\n", __func__); gpio_free(KAI_TEMP_ALERT_GPIO); } - else - tegra_gpio_enable(KAI_TEMP_ALERT_GPIO); - return ret; } @@ -158,7 +155,6 @@ static int kai_camera_init(void) { int ret; - tegra_gpio_enable(CAM2_POWER_DWN_GPIO); ret = gpio_request(CAM2_POWER_DWN_GPIO, "cam2_power_en"); if (ret < 0) { pr_err("%s: gpio_request failed for gpio %s\n", @@ -168,7 +164,6 @@ static int kai_camera_init(void) gpio_direction_output(CAM2_POWER_DWN_GPIO, 1); mdelay(10); - tegra_gpio_enable(CAM2_RST_GPIO); ret = gpio_request(CAM2_RST_GPIO, "cam2_reset"); if (ret < 0) { pr_err("%s: gpio_request failed for gpio %s\n", @@ -314,7 +309,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); @@ -331,7 +325,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-kai.c b/arch/arm/mach-tegra/board-kai.c index 193d68632d52..86374cf27271 100644 --- a/arch/arm/mach-tegra/board-kai.c +++ b/arch/arm/mach-tegra/board-kai.c @@ -108,7 +108,6 @@ static noinline void __init kai_bt_st(void) platform_device_register(&wl128x_device); platform_device_register(&btwilink_device); - tegra_gpio_enable(TEGRA_GPIO_PU0); } static struct resource kai_bluesleep_resources[] = { @@ -620,9 +619,6 @@ static int __init kai_touch_init(void) { int touch_id; - tegra_gpio_enable(KAI_TS_ID1); - tegra_gpio_enable(KAI_TS_ID2); - gpio_request(KAI_TS_ID1, "touch-id1"); gpio_direction_input(KAI_TS_ID1); @@ -764,10 +760,6 @@ static void kai_modem_init(void) { int ret; - tegra_gpio_enable(TEGRA_GPIO_W_DISABLE); - tegra_gpio_enable(TEGRA_GPIO_MODEM_RSVD1); - tegra_gpio_enable(TEGRA_GPIO_MODEM_RSVD2); - ret = gpio_request(TEGRA_GPIO_W_DISABLE, "w_disable_gpio"); if (ret < 0) pr_err("%s: gpio_request failed for gpio %d\n", @@ -813,13 +805,6 @@ static void kai_audio_init(void) } } -static void kai_nfc_init(void) -{ - tegra_gpio_enable(TEGRA_GPIO_PX0); - tegra_gpio_enable(TEGRA_GPIO_PS7); - tegra_gpio_enable(TEGRA_GPIO_PR3); -} - static void __init tegra_kai_init(void) { tegra_thermal_init(&thermal_data); @@ -843,7 +828,6 @@ static void __init tegra_kai_init(void) kai_panel_init(); kai_bt_st(); kai_tegra_setup_tibluesleep(); - kai_nfc_init(); kai_sensors_init(); kai_pins_state_init(); kai_emc_init(); diff --git a/arch/arm/mach-tegra/board-p1852-pinmux.c b/arch/arm/mach-tegra/board-p1852-pinmux.c index 1503c80c8269..9133c7daa972 100644 --- a/arch/arm/mach-tegra/board-p1852-pinmux.c +++ b/arch/arm/mach-tegra/board-p1852-pinmux.c @@ -63,14 +63,21 @@ /* !!!FIXME!!!! Update drive strength with characterized value */ static __initdata struct tegra_drive_pingroup_config p1852_drive_pinmux[] = { - SET_DRIVE(DAP2, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), + /* ATC1 CFG */ + SET_DRIVE(AT1, ENABLE, ENABLE, DIV_1, 0, 0, SLOWEST, SLOWEST), + /* ATC2 CFG */ + SET_DRIVE(AT2, ENABLE, ENABLE, DIV_1, 0, 0, SLOWEST, SLOWEST), + /* ATC3 CFG */ + SET_DRIVE(AT3, ENABLE, ENABLE, DIV_1, 0, 0, SLOWEST, SLOWEST), + /* ATC4 CFG */ + SET_DRIVE(AT4, DISABLE, DISABLE, DIV_1, 0, 0, SLOWEST, SLOWEST), /* All I2C pins are driven to maximum drive strength */ /* GEN1 I2C */ SET_DRIVE(DBG, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), /* GEN2 I2C */ - SET_DRIVE(AT5, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), + SET_DRIVE(AT5, DISABLE, ENABLE, DIV_1, 12, 30, FASTEST, FASTEST), /* DDC I2C */ SET_DRIVE(DDC, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), @@ -83,6 +90,48 @@ static __initdata struct tegra_drive_pingroup_config p1852_drive_pinmux[] = { SET_DRIVE(GMF, DISABLE, ENABLE, DIV_1, 0, 0, SLOWEST, SLOWEST), SET_DRIVE(GMG, DISABLE, ENABLE, DIV_1, 15, 6, SLOWEST, SLOWEST), SET_DRIVE(GMH, DISABLE, ENABLE, DIV_1, 12, 6, SLOWEST, SLOWEST), + + /* LCD */ + SET_DRIVE(LCD1, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), + SET_DRIVE(LCD2, DISABLE, ENABLE, DIV_1, 2, 2, FASTEST, FASTEST), + + /* DAP2 */ + SET_DRIVE(DAP2, ENABLE, ENABLE, DIV_1, 0, 0, SLOWEST, SLOWEST), + /* DAP4 */ + SET_DRIVE(DAP4, ENABLE, ENABLE, DIV_1, 0, 0, SLOWEST, SLOWEST), + /* DBG */ + SET_DRIVE(DBG, ENABLE, ENABLE, DIV_1, 20, 0, SLOWEST, SLOWEST), + /* SPI */ + SET_DRIVE(SPI, ENABLE, ENABLE, DIV_1, 0, 0, SLOWEST, SLOWEST), + /* UAA */ + SET_DRIVE(UAA, DISABLE, DISABLE, DIV_1, 0, 0, SLOWEST, SLOWEST), + /* UART2 */ + SET_DRIVE(UART2, ENABLE, ENABLE, DIV_1, 0, 0, SLOWEST, SLOWEST), + /* UART3 */ + SET_DRIVE(UART3, ENABLE, ENABLE, DIV_1, 0, 0, SLOWEST, SLOWEST), + /* GME */ + SET_DRIVE(GME, DISABLE, ENABLE, DIV_1, 1, 4, SLOWEST, SLOWEST), + /* GMF */ + SET_DRIVE(GMF, DISABLE, ENABLE, DIV_1, 0, 0, SLOWEST, SLOWEST), + /* GMG */ + SET_DRIVE(GMG, DISABLE, ENABLE, DIV_1, 3, 0, SLOWEST, SLOWEST), + /* GMH */ + SET_DRIVE(GMH, DISABLE, ENABLE, DIV_1, 0, 12, SLOWEST, SLOWEST), + + /* I2S/TDM */ +#ifdef CONFIG_TEGRA_MODS + SET_DRIVE(DAP1, ENABLE, ENABLE, DIV_1, 20, 20, SLOWEST, SLOWEST), + SET_DRIVE(DAP3, ENABLE, ENABLE, DIV_1, 20, 20, SLOWEST, SLOWEST), +#else + SET_DRIVE(DAP1, ENABLE, ENABLE, DIV_1, 3, 3, SLOWEST, SLOWEST), + SET_DRIVE(DAP3, ENABLE, ENABLE, DIV_1, 3, 3, SLOWEST, SLOWEST), +#endif + + /* SPI */ + SET_DRIVE(UAD, DISABLE, ENABLE, DIV_1, 4, 1, SLOWEST, SLOWEST), + SET_DRIVE(UAB, DISABLE, ENABLE, DIV_1, 4, 1, SLOWEST, SLOWEST), + SET_DRIVE(SDIO3, DISABLE, ENABLE, DIV_8, 4, 1, FASTEST, FASTEST), + }; #define DEFAULT_PINMUX(_pingroup, _mux, _pupd, _tri, _io) \ diff --git a/arch/arm/mach-tegra/board-p1852.c b/arch/arm/mach-tegra/board-p1852.c index 71c12756539d..eebbb24a9871 100644 --- a/arch/arm/mach-tegra/board-p1852.c +++ b/arch/arm/mach-tegra/board-p1852.c @@ -200,12 +200,14 @@ static void __init p1852_uart_init(void) ARRAY_SIZE(p1852_uart_devices)); } -static struct tegra_p1852_platform_data p1852_audio_pdata = { +#if defined(CONFIG_TEGRA_P1852_TDM) +static struct tegra_p1852_platform_data p1852_audio_tdm_pdata = { .codec_info[0] = { .codec_dai_name = "dit-hifi", .cpu_dai_name = "tegra30-i2s.0", .codec_name = "spdif-dit.0", .name = "tegra-i2s-1", + .pcm_driver = "tegra-tdm-pcm-audio", .i2s_format = format_tdm, .master = 1, .num_slots = 4, @@ -218,6 +220,7 @@ static struct tegra_p1852_platform_data p1852_audio_pdata = { .cpu_dai_name = "tegra30-i2s.4", .codec_name = "spdif-dit.1", .name = "tegra-i2s-2", + .pcm_driver = "tegra-tdm-pcm-audio", .i2s_format = format_tdm, .master = 1, .num_slots = 8, @@ -225,9 +228,29 @@ static struct tegra_p1852_platform_data p1852_audio_pdata = { .tx_mask = 0xff, .rx_mask = 0xff, }, - }; - +#else +static struct tegra_p1852_platform_data p1852_audio_i2s_pdata = { + .codec_info[0] = { + .codec_dai_name = "dit-hifi", + .cpu_dai_name = "tegra30-i2s.0", + .codec_name = "spdif-dit.0", + .name = "tegra-i2s-1", + .pcm_driver = "tegra-pcm-audio", + .i2s_format = format_i2s, + .master = 1, + }, + .codec_info[1] = { + .codec_dai_name = "dit-hifi", + .cpu_dai_name = "tegra30-i2s.4", + .codec_name = "spdif-dit.1", + .name = "tegra-i2s-2", + .pcm_driver = "tegra-pcm-audio", + .i2s_format = format_i2s, + .master = 0, + }, +}; +#endif static struct platform_device generic_codec_1 = { .name = "spdif-dit", .id = 0, @@ -241,13 +264,18 @@ static struct platform_device tegra_snd_p1852 = { .name = "tegra-snd-p1852", .id = 0, .dev = { - .platform_data = &p1852_audio_pdata, +#if defined(CONFIG_TEGRA_P1852_TDM) + .platform_data = &p1852_audio_tdm_pdata, +#else + .platform_data = &p1852_audio_i2s_pdata, +#endif }, }; static void p1852_i2s_audio_init(void) { platform_device_register(&tegra_pcm_device); + platform_device_register(&tegra_tdm_pcm_device); platform_device_register(&generic_codec_1); platform_device_register(&generic_codec_2); platform_device_register(&tegra_i2s_device0); diff --git a/arch/arm/mach-tegra/board-ventana-panel.c b/arch/arm/mach-tegra/board-ventana-panel.c index f396557411b8..e848441ef7e0 100644 --- a/arch/arm/mach-tegra/board-ventana-panel.c +++ b/arch/arm/mach-tegra/board-ventana-panel.c @@ -1,7 +1,7 @@ /* * arch/arm/mach-tegra/board-ventana-panel.c * - * 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 @@ -63,8 +63,6 @@ static int ventana_backlight_init(struct device *dev) { ret = gpio_direction_output(ventana_bl_enb, 1); if (ret < 0) gpio_free(ventana_bl_enb); - else - tegra_gpio_enable(ventana_bl_enb); return ret; }; @@ -72,7 +70,6 @@ static int ventana_backlight_init(struct device *dev) { static void ventana_backlight_exit(struct device *dev) { gpio_set_value(ventana_bl_enb, 0); gpio_free(ventana_bl_enb); - tegra_gpio_disable(ventana_bl_enb); } static int ventana_backlight_notify(struct device *unused, int brightness) @@ -392,13 +389,10 @@ int __init ventana_panel_init(void) gpio_request(ventana_lvds_shutdown, "lvds_shdn"); gpio_direction_output(ventana_lvds_shutdown, 1); - tegra_gpio_enable(ventana_lvds_shutdown); - tegra_gpio_enable(ventana_hdmi_enb); gpio_request(ventana_hdmi_enb, "hdmi_5v_en"); gpio_direction_output(ventana_hdmi_enb, 1); - tegra_gpio_enable(ventana_hdmi_hpd); gpio_request(ventana_hdmi_hpd, "hdmi_hpd"); gpio_direction_input(ventana_hdmi_hpd); diff --git a/arch/arm/mach-tegra/board-ventana-power.c b/arch/arm/mach-tegra/board-ventana-power.c index 2acfdfed28e4..aa6f4be203ad 100644 --- a/arch/arm/mach-tegra/board-ventana-power.c +++ b/arch/arm/mach-tegra/board-ventana-power.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2012 NVIDIA, Inc. + * 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 version 2 as @@ -34,7 +34,6 @@ #include "gpio-names.h" #include "fuse.h" #include "pm.h" -#include "wakeups-t2.h" #include "board.h" #include "board-ventana.h" @@ -47,7 +46,6 @@ int __init ventana_charge_init(void) { gpio_request(CHARGING_DISABLE, "chg_disable"); gpio_direction_output(CHARGING_DISABLE, 0); - tegra_gpio_enable(CHARGING_DISABLE); return 0; } @@ -255,14 +253,6 @@ static struct platform_device *fixed_voltage_regulators[] __initdata = { int __init ventana_fixed_voltage_regulator_init(void) { - int i; - - for (i = 0; i < ARRAY_SIZE(fixed_voltage_regulators); ++i) { - struct fixed_voltage_config *fixed_voltage_regulators_pdata = - fixed_voltage_regulators[i]->dev.platform_data; - if (fixed_voltage_regulators_pdata->gpio < TEGRA_NR_GPIOS) - tegra_gpio_enable(fixed_voltage_regulators_pdata->gpio); - } return platform_add_devices(fixed_voltage_regulators, ARRAY_SIZE(fixed_voltage_regulators)); } @@ -317,7 +307,6 @@ static struct platform_device ventana_charger_device = { int __init ventana_charger_init(void) { - tegra_gpio_enable(AC_PRESENT_GPIO); platform_device_register(&ventana_charger_device); return 0; } diff --git a/arch/arm/mach-tegra/board-ventana-sdhci.c b/arch/arm/mach-tegra/board-ventana-sdhci.c index 188335ac98c5..9d426aadff79 100644 --- a/arch/arm/mach-tegra/board-ventana-sdhci.c +++ b/arch/arm/mach-tegra/board-ventana-sdhci.c @@ -1,7 +1,6 @@ /* - * arch/arm/mach-tegra/board-harmony-sdhci.c - * * Copyright (C) 2010 Google, Inc. + * Copyright (C) 2010-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 @@ -132,6 +131,7 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = { .embedded_sdio = &embedded_sdio_data0, #endif .built_in = 0, + .ocr_mask = MMC_OCR_1V8_MASK, }, #ifndef CONFIG_MMC_EMBEDDED_SDIO .pm_flags = MMC_PM_KEEP_POWER, @@ -257,10 +257,6 @@ static int __init ventana_wifi_init(void) gpio_request(VENTANA_WLAN_RST, "wlan_rst"); gpio_request(VENTANA_WLAN_WOW, "bcmsdh_sdmmc"); - tegra_gpio_enable(VENTANA_WLAN_PWR); - tegra_gpio_enable(VENTANA_WLAN_RST); - tegra_gpio_enable(VENTANA_WLAN_WOW); - gpio_direction_output(VENTANA_WLAN_PWR, 0); gpio_direction_output(VENTANA_WLAN_RST, 0); gpio_direction_input(VENTANA_WLAN_WOW); @@ -274,11 +270,6 @@ static int __init ventana_wifi_init(void) } int __init ventana_sdhci_init(void) { - tegra_gpio_enable(tegra_sdhci_platform_data2.power_gpio); - tegra_gpio_enable(tegra_sdhci_platform_data2.cd_gpio); - tegra_gpio_enable(tegra_sdhci_platform_data2.wp_gpio); - tegra_gpio_enable(tegra_sdhci_platform_data3.power_gpio); - platform_device_register(&tegra_sdhci_device3); platform_device_register(&tegra_sdhci_device2); platform_device_register(&tegra_sdhci_device0); diff --git a/arch/arm/mach-tegra/board-ventana-sensors.c b/arch/arm/mach-tegra/board-ventana-sensors.c index 574bdb25fc2a..be7c179dfad9 100644 --- a/arch/arm/mach-tegra/board-ventana-sensors.c +++ b/arch/arm/mach-tegra/board-ventana-sensors.c @@ -186,7 +186,6 @@ static struct ssl3250a_platform_data ventana_ssl3250a_pdata = { static void ventana_isl29018_init(void) { - tegra_gpio_enable(ISL29018_IRQ_GPIO); gpio_request(ISL29018_IRQ_GPIO, "isl29018"); gpio_direction_input(ISL29018_IRQ_GPIO); } @@ -194,7 +193,6 @@ static void ventana_isl29018_init(void) #ifdef CONFIG_SENSORS_AK8975 static void ventana_akm8975_init(void) { - tegra_gpio_enable(AKM8975_IRQ_GPIO); gpio_request(AKM8975_IRQ_GPIO, "akm8975"); gpio_direction_input(AKM8975_IRQ_GPIO); } @@ -202,7 +200,6 @@ static void ventana_akm8975_init(void) static void ventana_nct1008_init(void) { - tegra_gpio_enable(NCT1008_THERM2_GPIO); gpio_request(NCT1008_THERM2_GPIO, "temp_alert"); gpio_direction_input(NCT1008_THERM2_GPIO); } @@ -379,7 +376,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); @@ -396,7 +392,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); @@ -465,37 +460,35 @@ int __init ventana_sensors_init(void) struct tegra_camera_gpios { const char *name; int gpio; - bool tegra_internal_gpio; int enabled; }; -#define TEGRA_CAMERA_GPIO(_name, _gpio, _tegra_internal_gpio, _enabled) \ +#define TEGRA_CAMERA_GPIO(_name, _gpio, _enabled) \ { \ .name = _name, \ .gpio = _gpio, \ - .tegra_internal_gpio = _tegra_internal_gpio, \ .enabled = _enabled, \ } static struct tegra_camera_gpios ventana_camera_gpio_keys[] = { - [0] = TEGRA_CAMERA_GPIO("camera_power_en", CAMERA_POWER_GPIO, true, 1), - [1] = TEGRA_CAMERA_GPIO("camera_csi_sel", CAMERA_CSI_MUX_SEL_GPIO, true, 0), - [2] = TEGRA_CAMERA_GPIO("torch_gpio_act", CAMERA_FLASH_ACT_GPIO, true, 0), + [0] = TEGRA_CAMERA_GPIO("camera_power_en", CAMERA_POWER_GPIO, 1), + [1] = TEGRA_CAMERA_GPIO("camera_csi_sel", CAMERA_CSI_MUX_SEL_GPIO, 0), + [2] = TEGRA_CAMERA_GPIO("torch_gpio_act", CAMERA_FLASH_ACT_GPIO, 0), - [3] = TEGRA_CAMERA_GPIO("en_avdd_csi", AVDD_DSI_CSI_ENB_GPIO, false, 1), - [4] = TEGRA_CAMERA_GPIO("cam_i2c_mux_rst_lo", CAM_I2C_MUX_RST_GPIO, false, 1), + [3] = TEGRA_CAMERA_GPIO("en_avdd_csi", AVDD_DSI_CSI_ENB_GPIO, 1), + [4] = TEGRA_CAMERA_GPIO("cam_i2c_mux_rst_lo", CAM_I2C_MUX_RST_GPIO, 1), - [5] = TEGRA_CAMERA_GPIO("cam2_af_pwdn_lo", CAM2_AF_PWR_DN_L_GPIO, false, 0), - [6] = TEGRA_CAMERA_GPIO("cam2_pwdn", CAM2_PWR_DN_GPIO, false, 0), - [7] = TEGRA_CAMERA_GPIO("cam2_rst_lo", CAM2_RST_L_GPIO, false, 1), + [5] = TEGRA_CAMERA_GPIO("cam2_af_pwdn_lo", CAM2_AF_PWR_DN_L_GPIO, 0), + [6] = TEGRA_CAMERA_GPIO("cam2_pwdn", CAM2_PWR_DN_GPIO, 0), + [7] = TEGRA_CAMERA_GPIO("cam2_rst_lo", CAM2_RST_L_GPIO, 1), - [8] = TEGRA_CAMERA_GPIO("cam3_af_pwdn_lo", CAM3_AF_PWR_DN_L_GPIO, false, 0), - [9] = TEGRA_CAMERA_GPIO("cam3_pwdn", CAM3_PWR_DN_GPIO, false, 0), - [10] = TEGRA_CAMERA_GPIO("cam3_rst_lo", CAM3_RST_L_GPIO, false, 1), + [8] = TEGRA_CAMERA_GPIO("cam3_af_pwdn_lo", CAM3_AF_PWR_DN_L_GPIO, 0), + [9] = TEGRA_CAMERA_GPIO("cam3_pwdn", CAM3_PWR_DN_GPIO, 0), + [10] = TEGRA_CAMERA_GPIO("cam3_rst_lo", CAM3_RST_L_GPIO, 1), - [11] = TEGRA_CAMERA_GPIO("cam1_af_pwdn_lo", CAM1_AF_PWR_DN_L_GPIO, false, 0), - [12] = TEGRA_CAMERA_GPIO("cam1_pwdn", CAM1_PWR_DN_GPIO, false, 0), - [13] = TEGRA_CAMERA_GPIO("cam1_rst_lo", CAM1_RST_L_GPIO, false, 1), + [11] = TEGRA_CAMERA_GPIO("cam1_af_pwdn_lo", CAM1_AF_PWR_DN_L_GPIO, 0), + [12] = TEGRA_CAMERA_GPIO("cam1_pwdn", CAM1_PWR_DN_GPIO, 0), + [13] = TEGRA_CAMERA_GPIO("cam1_rst_lo", CAM1_RST_L_GPIO, 1), }; int __init ventana_camera_late_init(void) @@ -522,10 +515,6 @@ int __init ventana_camera_late_init(void) i2c_new_device(i2c_get_adapter(3), ventana_i2c3_board_info_tca6416); for (i = 0; i < ARRAY_SIZE(ventana_camera_gpio_keys); i++) { - - if (ventana_camera_gpio_keys[i].tegra_internal_gpio) - tegra_gpio_enable(ventana_camera_gpio_keys[i].gpio); - ret = gpio_request(ventana_camera_gpio_keys[i].gpio, ventana_camera_gpio_keys[i].name); if (ret < 0) { diff --git a/arch/arm/mach-tegra/board-ventana.c b/arch/arm/mach-tegra/board-ventana.c index 779ffdba0f65..942ca44e2a13 100644 --- a/arch/arm/mach-tegra/board-ventana.c +++ b/arch/arm/mach-tegra/board-ventana.c @@ -1,7 +1,7 @@ /* * arch/arm/mach-tegra/board-ventana.c * - * Copyright (c) 2010-2011, NVIDIA Corporation. + * Copyright (c) 2010-2011 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 @@ -119,8 +119,6 @@ static struct platform_device ventana_bluesleep_device = { static void __init ventana_setup_bluesleep(void) { platform_device_register(&ventana_bluesleep_device); - tegra_gpio_enable(TEGRA_GPIO_PU6); - tegra_gpio_enable(TEGRA_GPIO_PU1); return; } @@ -326,7 +324,8 @@ static int ventana_wakeup_key(void) unsigned long status = readl(IO_ADDRESS(TEGRA_PMC_BASE) + PMC_WAKE_STATUS); - return status & TEGRA_WAKE_GPIO_PV2 ? KEY_POWER : KEY_RESERVED; + return (status & (1 << TEGRA_WAKE_GPIO_PV2)) ? + KEY_POWER : KEY_RESERVED; } static struct gpio_keys_platform_data ventana_keys_platform_data = { @@ -342,14 +341,6 @@ static struct platform_device ventana_keys_device = { .platform_data = &ventana_keys_platform_data, }, }; - -static void ventana_keys_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ventana_keys); i++) - tegra_gpio_enable(ventana_keys[i].gpio); -} #endif static struct platform_device tegra_camera = { @@ -625,10 +616,6 @@ static void __init tegra_ventana_init(void) ventana_touch_init_panjit(); } -#ifdef CONFIG_KEYBOARD_GPIO - ventana_keys_init(); -#endif - ventana_usb_init(); ventana_gps_init(); ventana_panel_init(); diff --git a/arch/arm/mach-tegra/board-whistler-baseband.c b/arch/arm/mach-tegra/board-whistler-baseband.c index eb50fb2f8237..b602cd3f44c1 100644 --- a/arch/arm/mach-tegra/board-whistler-baseband.c +++ b/arch/arm/mach-tegra/board-whistler-baseband.c @@ -26,8 +26,9 @@ static void baseband_phy_init(void); static void baseband_phy_on(void); -static void baseband_phy_off(void); - +static void baseband_pre_phy_off(void); +static void baseband_post_phy_off(void); +static bool ap2mdm_ack_gpio_off = false; static struct wake_lock mdm_wake_lock; static struct gpio modem_gpios[] = { @@ -58,13 +59,14 @@ static __initdata struct tegra_pingroup_config whistler_null_ulpi_pinmux[] = { static struct tegra_usb_phy_platform_ops ulpi_null_plat_ops = { .init = baseband_phy_init, - .pre_phy_off = baseband_phy_off, + .pre_phy_off = baseband_pre_phy_off, + .post_phy_off = baseband_post_phy_off, .post_phy_on = baseband_phy_on, }; static struct tegra_usb_platform_data tegra_ehci2_ulpi_null_pdata = { .port_otg = false, - .has_hostpc = true, + .has_hostpc = false, .phy_intf = TEGRA_USB_PHY_INTF_ULPI_NULL, .op_mode = TEGRA_USB_OPMODE_HOST, .u_data.host = { @@ -105,6 +107,15 @@ static irqreturn_t mdm_start_thread(int irq, void *data) return IRQ_HANDLED; } +static inline void null_phy_set_tristate(bool enable) +{ + int tristate = (enable) ? TEGRA_TRI_TRISTATE : TEGRA_TRI_NORMAL; + + tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, tristate); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, tristate); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, tristate); +} + static void baseband_phy_init(void) { static bool phy_init; @@ -117,18 +128,51 @@ static void baseband_phy_init(void) pr_info("%s\n", __func__); } -static void baseband_phy_off(void) +static void baseband_pre_phy_off(void) { /* set AP2MDM_ACK2 high */ gpio_set_value(AP2MDM_ACK2, 1); + ap2mdm_ack_gpio_off = true; +} + +static void baseband_post_phy_off(void) +{ + null_phy_set_tristate(true); } -static void baseband_phy_on (void) +static void baseband_phy_on(void) { - /* set AP2MDM_ACK2 low */ - gpio_set_value(AP2MDM_ACK2, 0); + if (ap2mdm_ack_gpio_off) { + + /* driving linestate using GPIO */ + gpio_set_value(ULPI_D0, 0); + gpio_set_value(ULPI_D1, 0); + + /* driving DIR high */ + gpio_set_value(ULPI_DIR, 1); + + /* remove ULPI tristate */ + null_phy_set_tristate(false); + + gpio_set_value(AP2MDM_ACK2, 0); + + if (gpio_is_valid(MDM2AP_ACK2)) { + int retry = 20000; + while (retry) { + /* poll phy_restore_gpio high */ + if (gpio_get_value(MDM2AP_ACK2)) + break; + retry--; + } + + if (retry == 0) + pr_info("phy_restore_gpio timeout\n"); + } + ap2mdm_ack_gpio_off = false; + } } + static void baseband_start(void) { /* diff --git a/arch/arm/mach-tegra/board-whistler-power.c b/arch/arm/mach-tegra/board-whistler-power.c index a0eb6686b0db..67663252e0d9 100644 --- a/arch/arm/mach-tegra/board-whistler-power.c +++ b/arch/arm/mach-tegra/board-whistler-power.c @@ -31,7 +31,6 @@ #include "gpio-names.h" #include "fuse.h" #include "pm.h" -#include "wakeups-t2.h" #include "board.h" #define PMC_CTRL 0x0 diff --git a/arch/arm/mach-tegra/board-whistler-sdhci.c b/arch/arm/mach-tegra/board-whistler-sdhci.c index 2d2a9c8c01f8..491688052858 100644 --- a/arch/arm/mach-tegra/board-whistler-sdhci.c +++ b/arch/arm/mach-tegra/board-whistler-sdhci.c @@ -168,6 +168,7 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data1 = { .embedded_sdio = &embedded_sdio_data1, #endif .built_in = 0, + .ocr_mask = MMC_OCR_1V8_MASK, }, #ifndef CONFIG_MMC_EMBEDDED_SDIO .pm_flags = MMC_PM_KEEP_POWER, diff --git a/arch/arm/mach-tegra/board-whistler.c b/arch/arm/mach-tegra/board-whistler.c index 874ef18900e7..6156c8a8e51d 100644 --- a/arch/arm/mach-tegra/board-whistler.c +++ b/arch/arm/mach-tegra/board-whistler.c @@ -441,7 +441,7 @@ static struct tegra_usb_platform_data tegra_udc_pdata = { .phy_intf = TEGRA_USB_PHY_INTF_UTMI, .op_mode = TEGRA_USB_OPMODE_DEVICE, .u_data.dev = { - .vbus_pmu_irq = 0, + .vbus_pmu_irq = MAX8907C_INT_BASE + MAX8907C_IRQ_VCHG_DC_R, .vbus_gpio = -1, .charging_supported = false, .remote_wakeup_supported = false, diff --git a/arch/arm/mach-tegra/cpu-tegra3.c b/arch/arm/mach-tegra/cpu-tegra3.c index 86a0b1364b3d..5b9ac4f770a2 100644 --- a/arch/arm/mach-tegra/cpu-tegra3.c +++ b/arch/arm/mach-tegra/cpu-tegra3.c @@ -230,7 +230,8 @@ static void tegra_auto_hotplug_work_func(struct work_struct *work) cpu = tegra_get_slowest_cpu_n(); if (cpu < nr_cpu_ids) { up = false; - } else if (!is_lp_cluster() && !no_lp) { + } else if (!is_lp_cluster() && !no_lp && + !pm_qos_request(PM_QOS_MIN_ONLINE_CPUS)) { if(!clk_set_parent(cpu_clk, cpu_lp_clk)) { hp_stats_update(CONFIG_NR_CPUS, true); hp_stats_update(0, false); @@ -299,10 +300,10 @@ static int min_cpus_notify(struct notifier_block *nb, unsigned long n, void *p) { mutex_lock(tegra3_cpu_lock); - if ((n >= 2) && is_lp_cluster()) { + if ((n >= 1) && is_lp_cluster()) { /* make sure cpu rate is within g-mode range before switching */ - unsigned int speed = max( - tegra_getspeed(0), clk_get_min_rate(cpu_g_clk) / 1000); + unsigned int speed = max((unsigned long)tegra_getspeed(0), + clk_get_min_rate(cpu_g_clk) / 1000); tegra_update_cpu_speed(speed); if (!clk_set_parent(cpu_clk, cpu_g_clk)) { diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c index 377772ff4291..44afd0e63fe4 100644 --- a/arch/arm/mach-tegra/devices.c +++ b/arch/arm/mach-tegra/devices.c @@ -1166,6 +1166,11 @@ struct platform_device tegra_pcm_device = { .id = -1, }; +struct platform_device tegra_tdm_pcm_device = { + .name = "tegra-tdm-pcm-audio", + .id = -1, +}; + static struct resource w1_resources[] = { [0] = { .start = INT_OWR, diff --git a/arch/arm/mach-tegra/devices.h b/arch/arm/mach-tegra/devices.h index 97a0c53ccfce..3d0734d1c688 100644 --- a/arch/arm/mach-tegra/devices.h +++ b/arch/arm/mach-tegra/devices.h @@ -69,6 +69,7 @@ extern struct platform_device spdif_dit_device; extern struct platform_device bluetooth_dit_device; extern struct platform_device baseband_dit_device; extern struct platform_device tegra_pcm_device; +extern struct platform_device tegra_tdm_pcm_device; extern struct platform_device tegra_w1_device; extern struct platform_device tegra_udc_device; extern struct platform_device tegra_ehci1_device; diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h index 71f1be769507..87af9441c28c 100644 --- a/arch/arm/mach-tegra/include/mach/dc.h +++ b/arch/arm/mach-tegra/include/mach/dc.h @@ -551,7 +551,6 @@ struct tegra_dc_pwm_params { void tegra_dc_config_pwm(struct tegra_dc *dc, struct tegra_dc_pwm_params *cfg); int tegra_dsi_send_panel_short_cmd(struct tegra_dc *dc, u8 *pdata, u8 data_len); -void tegra_dc_host_trigger(struct tegra_dc *dc); int tegra_dc_update_csc(struct tegra_dc *dc, int win_index); diff --git a/arch/arm/mach-tegra/include/mach/sdhci.h b/arch/arm/mach-tegra/include/mach/sdhci.h index 5dc8cd2ddf76..e307506eb40b 100644 --- a/arch/arm/mach-tegra/include/mach/sdhci.h +++ b/arch/arm/mach-tegra/include/mach/sdhci.h @@ -20,6 +20,14 @@ #include <linux/mmc/host.h> #include <asm/mach/mmc.h> +/* + * MMC_OCR_1V8_MASK will be used in board sdhci file + * Example for cardhu it will be used in board-cardhu-sdhci.c + * for built_in = 0 devices enabling ocr_mask to MMC_OCR_1V8_MASK + * sets the voltage to 1.8V + */ +#define MMC_OCR_1V8_MASK 0x8 + struct tegra_sdhci_platform_data { int cd_gpio; int wp_gpio; diff --git a/arch/arm/mach-tegra/include/mach/tegra_p1852_pdata.h b/arch/arm/mach-tegra/include/mach/tegra_p1852_pdata.h index 6bea4e50b915..501d815b881b 100644 --- a/arch/arm/mach-tegra/include/mach/tegra_p1852_pdata.h +++ b/arch/arm/mach-tegra/include/mach/tegra_p1852_pdata.h @@ -35,6 +35,7 @@ struct codec_info_s { char *cpu_dai_name; char *codec_name; /* Name of the Codec Driver */ char *name; /* Name of the Codec-Dai-Link */ + char *pcm_driver; /* Name of the PCM driver */ enum i2s_data_format i2s_format; int master; /* Codec is Master or Slave */ /* TDM format setttings */ diff --git a/arch/arm/mach-tegra/p852/board-p852.h b/arch/arm/mach-tegra/p852/board-p852.h index bb43febb4a2c..8e8f1444029c 100644 --- a/arch/arm/mach-tegra/p852/board-p852.h +++ b/arch/arm/mach-tegra/p852/board-p852.h @@ -55,7 +55,6 @@ #include "../pm.h" #include "../devices.h" #include "../gpio-names.h" -#include "../wakeups-t2.h" #define P852_SKU3 0x030000UL diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c index 80a9a121f193..68e0fda385ae 100644 --- a/arch/arm/mach-tegra/pcie.c +++ b/arch/arm/mach-tegra/pcie.c @@ -36,6 +36,8 @@ #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> +#include <linux/workqueue.h> +#include <linux/gpio.h> #include <asm/sizes.h> #include <asm/mach/pci.h> @@ -308,6 +310,7 @@ struct tegra_pcie_port { char mem_space_name[16]; char prefetch_space_name[20]; struct resource res[3]; + struct pci_bus* bus; }; struct tegra_pcie_info { @@ -319,6 +322,7 @@ struct tegra_pcie_info { struct resource res_mmio; int power_rails_enabled; int pcie_power_enabled; + struct work_struct hotplug_detect; struct regulator *regulator_hvdd; struct regulator *regulator_pexio; @@ -333,8 +337,6 @@ struct tegra_pcie_info { #define pmc_readl(reg) \ __raw_readl((u32)reg_pmc_base + (reg)) -static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); - static struct tegra_pcie_info tegra_pcie = { .res_mmio = { .name = "PCI IO", @@ -620,6 +622,31 @@ static struct hw_pci tegra_pcie_hw = { .map_irq = tegra_pcie_map_irq, }; +static void work_hotplug_handler(struct work_struct *work) +{ + struct tegra_pcie_info *pcie_driver = + container_of(work, struct tegra_pcie_info, hotplug_detect); + int val; + + if (pcie_driver->plat_data->gpio == -1) + return; + val = gpio_get_value(pcie_driver->plat_data->gpio); + if (val == 0) { + pr_info("Pcie Dock Connected but hotplug functionality not supported yet\n"); + } else { + struct pci_dev *dev = NULL; + + pr_info("Pcie Dock DisConnected\n"); + for_each_pci_dev(dev) + pci_stop_bus_device(dev); + } +} + +static irqreturn_t gpio_pcie_detect_isr(int irq, void *arg) +{ + schedule_work(&tegra_pcie.hotplug_detect); + return IRQ_HANDLED; +} static irqreturn_t tegra_pcie_isr(int irq, void *arg) { @@ -1169,6 +1196,8 @@ static int tegra_pcie_init(void) pcibios_min_mem = 0x03000000ul; pcibios_min_io = 0x10000000ul; #endif + + INIT_WORK(&tegra_pcie.hotplug_detect, work_hotplug_handler); err = tegra_pcie_get_resources(); if (err) return err; @@ -1184,11 +1213,36 @@ static int tegra_pcie_init(void) } tegra_pcie.pcie_power_enabled = 1; + if (tegra_pcie.plat_data->use_dock_detect) { + unsigned int irq; + + pr_info("acquiring dock_detect = %d\n", + tegra_pcie.plat_data->gpio); + gpio_request(tegra_pcie.plat_data->gpio, "pcie_dock_detect"); + gpio_direction_input(tegra_pcie.plat_data->gpio); + irq = gpio_to_irq(tegra_pcie.plat_data->gpio); + if (irq < 0) { + pr_err("Unable to get irq number for dock_detect\n"); + goto err_irq; + } + err = request_irq(irq, + gpio_pcie_detect_isr, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "pcie_dock_detect", + (void *)tegra_pcie.plat_data); + if (err < 0) { + pr_err("Unable to claim irq number for dock_detect\n"); + goto err_irq; + } + } + if (tegra_pcie.num_ports) pci_common_init(&tegra_pcie_hw); else err = tegra_pcie_power_off(); +err_irq: + return err; } diff --git a/arch/arm/mach-tegra/pinmux-t3-tables.c b/arch/arm/mach-tegra/pinmux-t3-tables.c index 5e50fede625d..90dbf757b909 100644 --- a/arch/arm/mach-tegra/pinmux-t3-tables.c +++ b/arch/arm/mach-tegra/pinmux-t3-tables.c @@ -3,7 +3,7 @@ * * Common pinmux configurations for Tegra 3 SoCs * - * 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 @@ -64,11 +64,16 @@ const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[TEGRA_MAX_DRIVE_PINGROUP] = { DEFAULT_DRIVE_PINGROUP(AO1, 0x868), DEFAULT_DRIVE_PINGROUP(AO2, 0x86c), - DEFAULT_DRIVE_PINGROUP(AT1, 0x870), - DEFAULT_DRIVE_PINGROUP(AT2, 0x874), - DEFAULT_DRIVE_PINGROUP(AT3, 0x878), - DEFAULT_DRIVE_PINGROUP(AT4, 0x87c), - DEFAULT_DRIVE_PINGROUP(AT5, 0x880), + SET_DRIVE_PINGROUP(AT1, 0x870, 14, 0x1f, 19, 0x1f, + 24, 0x3, 28, 0x3), + SET_DRIVE_PINGROUP(AT2, 0x874, 14, 0x1f, 19, 0x1f, + 24, 0x3, 28, 0x3), + SET_DRIVE_PINGROUP(AT3, 0x878, 14, 0x1f, 19, 0x1f, + 28, 0x3, 30, 0x3), + SET_DRIVE_PINGROUP(AT4, 0x87c, 14, 0x1f, 19, 0x1f, + 28, 0x3, 30, 0x3), + SET_DRIVE_PINGROUP(AT5, 0x880, 14, 0x1f, 19, 0x1f, + 28, 0x3, 30, 0x3), DEFAULT_DRIVE_PINGROUP(CDEV1, 0x884), DEFAULT_DRIVE_PINGROUP(CDEV2, 0x888), DEFAULT_DRIVE_PINGROUP(CSUS, 0x88c), @@ -101,10 +106,14 @@ const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[TEGRA_MAX_DRIVE 24, 0xf, 28, 0xf), SET_DRIVE_PINGROUP(GMD, 0x90c, 14, 0x1f, 19, 0x1f, 24, 0xf, 28, 0xf), - DEFAULT_DRIVE_PINGROUP(GME, 0x910), - DEFAULT_DRIVE_PINGROUP(GMF, 0x914), - DEFAULT_DRIVE_PINGROUP(GMG, 0x918), - DEFAULT_DRIVE_PINGROUP(GMH, 0x91c), + SET_DRIVE_PINGROUP(GME, 0x910, 14, 0x1f, 19, 0x1f, + 28, 0x3, 30, 0x3), + SET_DRIVE_PINGROUP(GMF, 0x914, 14, 0x1f, 19, 0x1f, + 28, 0x3, 30, 0x3), + SET_DRIVE_PINGROUP(GMG, 0x918, 14, 0x1f, 19, 0x1f, + 28, 0x3, 30, 0x3), + SET_DRIVE_PINGROUP(GMH, 0x91c, 14, 0x1f, 19, 0x1f, + 28, 0x3, 30, 0x3), DEFAULT_DRIVE_PINGROUP(OWR, 0x920), DEFAULT_DRIVE_PINGROUP(UAD, 0x924), DEFAULT_DRIVE_PINGROUP(GPV, 0x928), diff --git a/arch/arm/mach-tegra/pm-irq.c b/arch/arm/mach-tegra/pm-irq.c index 57d21361ca14..9b205f86f8b9 100644 --- a/arch/arm/mach-tegra/pm-irq.c +++ b/arch/arm/mach-tegra/pm-irq.c @@ -29,6 +29,7 @@ #include <mach/iomap.h> #include "pm-irq.h" +#include "wakeups.h" #define PMC_CTRL 0x0 #define PMC_CTRL_LATCH_WAKEUPS (1 << 5) diff --git a/arch/arm/mach-tegra/pm-irq.h b/arch/arm/mach-tegra/pm-irq.h index 8e87b4bba246..639bfe9c4cc9 100644 --- a/arch/arm/mach-tegra/pm-irq.h +++ b/arch/arm/mach-tegra/pm-irq.h @@ -22,8 +22,6 @@ int tegra_pm_irq_set_wake(int irq, int enable); int tegra_pm_irq_set_wake_type(int irq, int flow_type); bool tegra_pm_irq_lp0_allowed(void); -int tegra_irq_to_wake(int irq); -int tegra_wake_to_irq(int wake); #else static inline int tegra_pm_irq_set_wake_type(int irq, int flow_type) { diff --git a/arch/arm/mach-tegra/tegra2_usb_phy.c b/arch/arm/mach-tegra/tegra2_usb_phy.c index 819721c49a29..7b18333cc77c 100644 --- a/arch/arm/mach-tegra/tegra2_usb_phy.c +++ b/arch/arm/mach-tegra/tegra2_usb_phy.c @@ -1545,6 +1545,189 @@ static int ulpi_link_phy_resume(struct tegra_usb_phy *phy) return status; } + +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; + } + + phy->phy_clk_on = false; + phy->hw_accessible = false; + + 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_lp0_resume(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + 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); + + 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; + } + + /* Enable Port Power */ + val = readl(base + USB_PORTSC); + val |= USB_PORTSC_PP; + writel(val, base + USB_PORTSC); + udelay(10); + + /* disable ULPI pinmux bypass */ + val = readl(base + ULPI_TIMING_CTRL_0); + val &= ~ULPI_OUTPUT_PINMUX_BYP; + writel(val, base + ULPI_TIMING_CTRL_0); + + 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; + } + + 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); + 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); + + 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; + } else { + if (!readl(base + USB_ASYNCLISTADDR)) + ulpi_null_phy_lp0_resume(phy); + } + udelay(10); + + phy->phy_clk_on = true; + phy->hw_accessible = true; + + return 0; +} + + +static 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 int ulpi_null_phy_resume(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + if (!readl(base + USB_ASYNCLISTADDR)) { + /* enable ULPI CLK output pad */ + val = readl(base + ULPI_TIMING_CTRL_0); + val |= ULPI_CLK_PADOUT_ENA; + writel(val, base + ULPI_TIMING_CTRL_0); + + /* enable ULPI pinmux bypass */ + val = readl(base + ULPI_TIMING_CTRL_0); + val |= ULPI_OUTPUT_PINMUX_BYP; + writel(val, base + ULPI_TIMING_CTRL_0); + udelay(5); + } + + return 0; +} + + + static struct tegra_usb_phy_ops utmi_phy_ops = { .open = utmi_phy_open, .close = utmi_phy_close, @@ -1578,7 +1761,14 @@ static struct tegra_usb_phy_ops ulpi_link_phy_ops = { .resume = ulpi_link_phy_resume, }; -static struct tegra_usb_phy_ops ulpi_null_phy_ops; +static struct tegra_usb_phy_ops ulpi_null_phy_ops = { + .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, + .resume = ulpi_null_phy_resume, +}; + static struct tegra_usb_phy_ops icusb_phy_ops; diff --git a/arch/arm/mach-tegra/tegra3_dvfs.c b/arch/arm/mach-tegra/tegra3_dvfs.c index 657a6cfd6510..f36bfa774577 100644 --- a/arch/arm/mach-tegra/tegra3_dvfs.c +++ b/arch/arm/mach-tegra/tegra3_dvfs.c @@ -1,7 +1,7 @@ /* * arch/arm/mach-tegra/tegra3_dvfs.c * - * Copyright (C) 2010-2011 NVIDIA Corporation. + * Copyright (C) 2010-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 @@ -783,8 +783,6 @@ static void core_cap_update(void) static void core_cap_enable(bool enable) { - int i; - if (enable) tegra3_core_cap.refcnt++; else if (tegra3_core_cap.refcnt) diff --git a/arch/arm/mach-tegra/tegra3_usb_phy.c b/arch/arm/mach-tegra/tegra3_usb_phy.c index 5b3e51974d3b..8ada255cad55 100644 --- a/arch/arm/mach-tegra/tegra3_usb_phy.c +++ b/arch/arm/mach-tegra/tegra3_usb_phy.c @@ -888,6 +888,7 @@ static void uhsic_powerup_pmc_wake_detect(struct tegra_usb_phy *phy) mdelay(1); } +#ifdef KERNEL_WARNING static void usb_phy_power_down_pmc(void) { unsigned long val; @@ -931,6 +932,7 @@ static void usb_phy_power_down_pmc(void) UHSIC_MASTER_ENABLE_P0; writel(val, pmc_base + PMC_SLEEP_CFG); } +#endif static int usb_phy_bringup_host_controller(struct tegra_usb_phy *phy) { @@ -1142,10 +1144,6 @@ static void utmi_phy_close(struct tegra_usb_phy *phy) 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); } @@ -1341,16 +1339,20 @@ static int utmi_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup) unsigned int inst = phy->inst; DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); - - val = (readl(base + HOSTPC1_DEVLC) >> 25) & + phy->port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) & HOSTPC1_DEVLC_PSPD_MASK; - if (val == USB_PHY_PORT_SPEED_HIGH) { + + if (phy->port_speed == 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); + 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__); + } } val = readl(pmc_base + PMC_SLEEP_CFG); @@ -1388,6 +1390,21 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy) val |= UTMIP_PD_CHRG; writel(val, base + UTMIP_BAT_CHRG_CFG0); } else { + phy->port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) & + HOSTPC1_DEVLC_PSPD_MASK; + + /* 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); + + 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__); + } utmip_setup_pmc_wake_detect(phy); } @@ -1409,9 +1426,6 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy) 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 @@ -1776,7 +1790,7 @@ static int uhsic_phy_power_on(struct tegra_usb_phy *phy) DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); - utmip_powerup_pmc_wake_detect(phy); + uhsic_powerup_pmc_wake_detect(phy); if (phy->phy_clk_on) { DBG("%s(%d) inst:[%d] phy clk is already On\n", @@ -1897,7 +1911,7 @@ static int uhsic_phy_power_off(struct tegra_usb_phy *phy) writel(val, base + USB_SUSP_CTRL); udelay(30); - utmip_powerdown_pmc_wake_detect(phy); + uhsic_powerdown_pmc_wake_detect(phy); phy->phy_clk_on = false; phy->hw_accessible = false; @@ -2153,31 +2167,6 @@ static void ulpi_set_host(void __iomem *base) } - -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); @@ -2188,8 +2177,6 @@ static int ulpi_null_phy_power_off(struct tegra_usb_phy *phy) return 0; } - null_phy_set_tristate(true); - phy->phy_clk_on = false; phy->hw_accessible = false; @@ -2241,6 +2228,52 @@ static int ulpi_null_phy_cmd_reset(struct tegra_usb_phy *phy) return 0; } +static int ulpi_null_phy_lp0_resume(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + ulpi_null_phy_init(phy); + + 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); + + ulpi_null_phy_cmd_reset(phy); + + 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; + } + + /* Enable Port Power */ + val = readl(base + USB_PORTSC); + val |= USB_PORTSC_PP; + writel(val, base + USB_PORTSC); + udelay(10); + + /* disable ULPI pinmux bypass */ + val = readl(base + ULPI_TIMING_CTRL_0); + val &= ~ULPI_OUTPUT_PINMUX_BYP; + writel(val, base + ULPI_TIMING_CTRL_0); + + return 0; +} + static int ulpi_null_phy_power_on(struct tegra_usb_phy *phy) { unsigned long val; @@ -2334,6 +2367,9 @@ static int ulpi_null_phy_power_on(struct tegra_usb_phy *phy) val |= ULPI_CLK_PADOUT_ENA; writel(val, base + ULPI_TIMING_CTRL_0); cold_boot = false; + } else { + if (!readl(base + USB_ASYNCLISTADDR)) + ulpi_null_phy_lp0_resume(phy); } udelay(10); @@ -2352,6 +2388,32 @@ int ulpi_null_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup) return 0; } +static int ulpi_null_phy_resume(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + if (!readl(base + USB_ASYNCLISTADDR)) { + /* enable ULPI CLK output pad */ + val = readl(base + ULPI_TIMING_CTRL_0); + val |= ULPI_CLK_PADOUT_ENA; + writel(val, base + ULPI_TIMING_CTRL_0); + + /* enable ULPI pinmux bypass */ + val = readl(base + ULPI_TIMING_CTRL_0); + val |= ULPI_OUTPUT_PINMUX_BYP; + writel(val, base + ULPI_TIMING_CTRL_0); + udelay(5); +#ifndef CONFIG_ARCH_TEGRA_2x_SOC + /* remove DIR tristate */ + tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DIR, TEGRA_TRI_NORMAL); +#endif + } + return 0; +} + + + static struct tegra_usb_phy_ops utmi_phy_ops = { .open = utmi_phy_open, .close = utmi_phy_close, @@ -2382,6 +2444,7 @@ static struct tegra_usb_phy_ops ulpi_null_phy_ops = { .power_on = ulpi_null_phy_power_on, .power_off = ulpi_null_phy_power_off, .pre_resume = ulpi_null_phy_pre_resume, + .resume = ulpi_null_phy_resume, .reset = ulpi_null_phy_cmd_reset, }; diff --git a/arch/arm/mach-tegra/tegra_usb_phy.h b/arch/arm/mach-tegra/tegra_usb_phy.h index 36b88db94f52..0375b5aac812 100644 --- a/arch/arm/mach-tegra/tegra_usb_phy.h +++ b/arch/arm/mach-tegra/tegra_usb_phy.h @@ -89,6 +89,7 @@ struct tegra_usb_phy { void __iomem *regs; int inst; bool phy_clk_on; + bool ctrl_clk_on; /* used only for pmu irq */ bool phy_power_on; bool remote_wakeup; bool hw_accessible; diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c index 6f568fd2cd29..bfb9abae2c94 100644 --- a/arch/arm/mach-tegra/usb_phy.c +++ b/arch/arm/mach-tegra/usb_phy.c @@ -131,15 +131,25 @@ int tegra_usb_phy_init_ops(struct tegra_usb_phy *phy) static irqreturn_t usb_phy_dev_vbus_pmu_irq_thr(int irq, void *pdata) { - /* FIXME : Need to enable pmu vbus handling */ + struct tegra_usb_phy *phy = pdata; - return IRQ_NONE; + /* clk is disabled during phy power off and not here*/ + if (!phy->ctrl_clk_on) { + clk_enable(phy->ctrlr_clk); + phy->ctrl_clk_on = true; + } + + return IRQ_HANDLED; } static void tegra_usb_phy_release_clocks(struct tegra_usb_phy *phy) { clk_put(phy->emc_clk); clk_put(phy->sys_clk); + if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) + if (phy->pdata->u_data.host.hot_plug || + phy->pdata->u_data.host.remote_wakeup_supported) + clk_disable(phy->ctrlr_clk); clk_put(phy->ctrlr_clk); clk_disable(phy->pllu_clk); clk_put(phy->pllu_clk); @@ -164,6 +174,11 @@ static int tegra_usb_phy_get_clocks(struct tegra_usb_phy *phy) goto fail_ctrlr_clk; } + if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) + if (phy->pdata->u_data.host.hot_plug || + phy->pdata->u_data.host.remote_wakeup_supported) + clk_enable(phy->ctrlr_clk); + 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"); @@ -273,6 +288,8 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct platform_device *pdev) phy->inst); goto fail_init; } + } else { + clk_enable(phy->ctrlr_clk); } } else { if (phy->pdata->u_data.host.vbus_reg) { @@ -365,6 +382,8 @@ void tegra_usb_phy_close(struct tegra_usb_phy *phy) 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 + clk_disable(phy->ctrlr_clk); } else { usb_host_vbus_enable(phy, false); @@ -379,8 +398,6 @@ void tegra_usb_phy_close(struct tegra_usb_phy *phy) } } - tegra_usb_phy_release_clocks(phy); - if (phy->vdd_reg) { regulator_disable(phy->vdd_reg); regulator_put(phy->vdd_reg); @@ -392,6 +409,8 @@ void tegra_usb_phy_close(struct tegra_usb_phy *phy) if (phy->pdata->ops && phy->pdata->ops->close) phy->pdata->ops->close(); + tegra_usb_phy_release_clocks(phy); + kfree(phy->pdata); kfree(phy); } @@ -439,7 +458,19 @@ int tegra_usb_phy_power_off(struct tegra_usb_phy *phy) clk_disable(phy->emc_clk); clk_disable(phy->sys_clk); - clk_disable(phy->ctrlr_clk); + if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) { + if (!phy->pdata->u_data.host.hot_plug && + !phy->pdata->u_data.host.remote_wakeup_supported) + clk_disable(phy->ctrlr_clk); + } else { + /* In device mode clock is turned on by pmu irq handler + * if pmu irq is not available clocks will not be turned off/on + */ + if (phy->pdata->u_data.dev.vbus_pmu_irq) { + clk_disable(phy->ctrlr_clk); + phy->ctrl_clk_on = false; + } + } phy->phy_power_on = false; @@ -455,7 +486,20 @@ int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) if (phy->phy_power_on) return status; - clk_enable(phy->ctrlr_clk); + /* In device mode clock is turned on by pmu irq handler + * if pmu irq is not available clocks will not be turned off/on + */ + if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) { + if (!phy->pdata->u_data.host.hot_plug && + !phy->pdata->u_data.host.remote_wakeup_supported) + clk_enable(phy->ctrlr_clk); + } else { + if (phy->pdata->u_data.dev.vbus_pmu_irq && + !phy->ctrl_clk_on) { + clk_enable(phy->ctrlr_clk); + phy->ctrl_clk_on = true; + } + } clk_enable(phy->sys_clk); clk_enable(phy->emc_clk); @@ -506,11 +550,7 @@ int tegra_usb_phy_suspend(struct tegra_usb_phy *phy) err = phy->ops->suspend(phy); 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(); + tegra_usb_phy_power_off(phy); } return err; @@ -550,11 +590,7 @@ int tegra_usb_phy_resume(struct tegra_usb_phy *phy) DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); 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(); + tegra_usb_phy_power_on(phy); } if (!err && phy->ops && phy->ops->resume) diff --git a/arch/arm/mach-tegra/wakeups-t2.c b/arch/arm/mach-tegra/wakeups-t2.c index 7c5d12ac60d4..8079e6820145 100644 --- a/arch/arm/mach-tegra/wakeups-t2.c +++ b/arch/arm/mach-tegra/wakeups-t2.c @@ -22,8 +22,9 @@ #include <mach/gpio.h> #include "gpio-names.h" +#include "wakeups.h" -static int tegra_wake_event_irq[] = { +static int tegra_wake_event_irq_t2[] = { [0] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO5), [1] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV3), [2] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PL1), @@ -57,55 +58,5 @@ static int tegra_wake_event_irq[] = { [30] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN2), }; -int tegra_irq_to_wake(int irq) -{ - int i; - int wake_irq; - int search_gpio; - static int last_wake = -1; - - /* Two level wake irq search for gpio based wakeups - - * 1. check for GPIO irq(based on tegra_wake_event_irq table) - * e.g. for a board, wake7 based on GPIO PU6 and irq==358 done first - * 2. check for gpio bank irq assuming search for GPIO irq - * preceded this search. - * e.g. in this step check for gpio bank irq GPIO6 irq==119 - */ - for (i = 0; i < ARRAY_SIZE(tegra_wake_event_irq); i++) { - /* return if step 1 matches */ - if (tegra_wake_event_irq[i] == irq) { - pr_info("Wake%d for irq=%d\n", i, irq); - last_wake = i; - return i; - } - - /* step 2 below uses saved last_wake from step 1 - * in previous call */ - search_gpio = irq_to_gpio( - tegra_wake_event_irq[i]); - if (search_gpio < 0) - continue; - wake_irq = tegra_gpio_get_bank_int_nr(search_gpio); - if (wake_irq < 0) - continue; - if ((last_wake == i) && - (wake_irq == irq)) { - pr_info("gpio bank wake found: wake%d for irq=%d\n", - i, irq); - return i; - } - } - - return -EINVAL; -} - -int tegra_wake_to_irq(int wake) -{ - if (wake < 0) - return -EINVAL; - - if (wake >= ARRAY_SIZE(tegra_wake_event_irq)) - return -EINVAL; - - return tegra_wake_event_irq[wake]; -} +int *tegra_wake_event_irq = tegra_wake_event_irq_t2; +unsigned int tegra_wake_event_irq_size = ARRAY_SIZE(tegra_wake_event_irq_t2); diff --git a/arch/arm/mach-tegra/wakeups-t2.h b/arch/arm/mach-tegra/wakeups-t2.h index eb193c0aaf9e..955b351a71fa 100644 --- a/arch/arm/mach-tegra/wakeups-t2.h +++ b/arch/arm/mach-tegra/wakeups-t2.h @@ -30,36 +30,36 @@ int tegra_irq_to_wake(int irq); int tegra_wake_to_irq(int wake); -#define TEGRA_WAKE_GPIO_PO5 (1 << 0) -#define TEGRA_WAKE_GPIO_PV3 (1 << 1) -#define TEGRA_WAKE_GPIO_PL1 (1 << 2) -#define TEGRA_WAKE_GPIO_PB6 (1 << 3) -#define TEGRA_WAKE_GPIO_PN7 (1 << 4) -#define TEGRA_WAKE_GPIO_PA0 (1 << 5) -#define TEGRA_WAKE_GPIO_PU5 (1 << 6) -#define TEGRA_WAKE_GPIO_PU6 (1 << 7) -#define TEGRA_WAKE_GPIO_PC7 (1 << 8) -#define TEGRA_WAKE_GPIO_PS2 (1 << 9) -#define TEGRA_WAKE_GPIO_PAA1 (1 << 10) -#define TEGRA_WAKE_GPIO_PW3 (1 << 11) -#define TEGRA_WAKE_GPIO_PW2 (1 << 12) -#define TEGRA_WAKE_GPIO_PY6 (1 << 13) -#define TEGRA_WAKE_GPIO_PV6 (1 << 14) -#define TEGRA_WAKE_GPIO_PJ7 (1 << 15) -#define TEGRA_WAKE_RTC_ALARM (1 << 16) -#define TEGRA_WAKE_KBC_EVENT (1 << 17) -#define TEGRA_WAKE_PWR_INT (1 << 18) -#define TEGRA_WAKE_USB1_VBUS (1 << 19) -#define TEGRA_WAKE_USB3_VBUS (1 << 20) -#define TEGRA_WAKE_USB1_ID (1 << 21) -#define TEGRA_WAKE_USB3_ID (1 << 22) -#define TEGRA_WAKE_GPIO_PI5 (1 << 23) -#define TEGRA_WAKE_GPIO_PV2 (1 << 24) -#define TEGRA_WAKE_GPIO_PS4 (1 << 25) -#define TEGRA_WAKE_GPIO_PS5 (1 << 26) -#define TEGRA_WAKE_GPIO_PS0 (1 << 27) -#define TEGRA_WAKE_GPIO_PQ6 (1 << 28) -#define TEGRA_WAKE_GPIO_PQ7 (1 << 29) -#define TEGRA_WAKE_GPIO_PN2 (1 << 30) +#define TEGRA_WAKE_GPIO_PO5 0 +#define TEGRA_WAKE_GPIO_PV3 1 +#define TEGRA_WAKE_GPIO_PL1 2 +#define TEGRA_WAKE_GPIO_PB6 3 +#define TEGRA_WAKE_GPIO_PN7 4 +#define TEGRA_WAKE_GPIO_PA0 5 +#define TEGRA_WAKE_GPIO_PU5 6 +#define TEGRA_WAKE_GPIO_PU6 7 +#define TEGRA_WAKE_GPIO_PC7 8 +#define TEGRA_WAKE_GPIO_PS2 9 +#define TEGRA_WAKE_GPIO_PAA1 10 +#define TEGRA_WAKE_GPIO_PW3 11 +#define TEGRA_WAKE_GPIO_PW2 12 +#define TEGRA_WAKE_GPIO_PY6 13 +#define TEGRA_WAKE_GPIO_PV6 14 +#define TEGRA_WAKE_GPIO_PJ7 15 +#define TEGRA_WAKE_RTC_ALARM 16 +#define TEGRA_WAKE_KBC_EVENT 17 +#define TEGRA_WAKE_PWR_INT 18 +#define TEGRA_WAKE_USB1_VBUS 19 +#define TEGRA_WAKE_USB3_VBUS 20 +#define TEGRA_WAKE_USB1_ID 21 +#define TEGRA_WAKE_USB3_ID 22 +#define TEGRA_WAKE_GPIO_PI5 23 +#define TEGRA_WAKE_GPIO_PV2 24 +#define TEGRA_WAKE_GPIO_PS4 25 +#define TEGRA_WAKE_GPIO_PS5 26 +#define TEGRA_WAKE_GPIO_PS0 27 +#define TEGRA_WAKE_GPIO_PQ6 28 +#define TEGRA_WAKE_GPIO_PQ7 29 +#define TEGRA_WAKE_GPIO_PN2 30 #endif diff --git a/arch/arm/mach-tegra/wakeups-t3.c b/arch/arm/mach-tegra/wakeups-t3.c index 823736204362..33dfb12f7211 100644 --- a/arch/arm/mach-tegra/wakeups-t3.c +++ b/arch/arm/mach-tegra/wakeups-t3.c @@ -22,8 +22,9 @@ #include <mach/gpio.h> #include "gpio-names.h" +#include "wakeups.h" -static int tegra_wake_event_irq[] = { +static int tegra_wake_event_irq_t3[] = { TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO5), /* wake0 */ TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV1), /* wake1 */ TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PL1), /* wake2 */ @@ -68,55 +69,5 @@ static int tegra_wake_event_irq[] = { INT_USB3, /* TEGRA_USB3_UTMIP, */ /* wake41 */ }; -int tegra_irq_to_wake(int irq) -{ - int i; - int wake_irq; - int search_gpio; - static int last_wake = -1; - - /* Two level wake irq search for gpio based wakeups - - * 1. check for GPIO irq(based on tegra_wake_event_irq table) - * e.g. for a board, wake7 based on GPIO PU6 and irq==390 done first - * 2. check for gpio bank irq assuming search for GPIO irq - * preceded this search. - * e.g. in this step check for gpio bank irq GPIO6 irq==119 - */ - for (i = 0; i < ARRAY_SIZE(tegra_wake_event_irq); i++) { - /* return if step 1 matches */ - if (tegra_wake_event_irq[i] == irq) { - pr_info("Wake%d for irq=%d\n", i, irq); - last_wake = i; - return i; - } - - /* step 2 below uses saved last_wake from step 1 - * in previous call */ - search_gpio = irq_to_gpio( - tegra_wake_event_irq[i]); - if (search_gpio < 0) - continue; - wake_irq = tegra_gpio_get_bank_int_nr(search_gpio); - if (wake_irq < 0) - continue; - if ((last_wake == i) && - (wake_irq == irq)) { - pr_info("gpio bank wake found: wake%d for irq=%d\n", - i, irq); - return i; - } - } - - return -EINVAL; -} - -int tegra_wake_to_irq(int wake) -{ - if (wake < 0) - return -EINVAL; - - if (wake >= ARRAY_SIZE(tegra_wake_event_irq)) - return -EINVAL; - - return tegra_wake_event_irq[wake]; -} +int *tegra_wake_event_irq = tegra_wake_event_irq_t3; +unsigned int tegra_wake_event_irq_size = ARRAY_SIZE(tegra_wake_event_irq_t3); diff --git a/arch/arm/mach-tegra/wakeups-t3.h b/arch/arm/mach-tegra/wakeups-t3.h index f811d8939387..6c051270cc93 100644 --- a/arch/arm/mach-tegra/wakeups-t3.h +++ b/arch/arm/mach-tegra/wakeups-t3.h @@ -27,45 +27,45 @@ #error "Tegra 3 wakeup sources valid only for CONFIG_ARCH_TEGRA_3x_SOC" #endif -#define TEGRA_WAKE_GPIO_PO5 (1ull << 0) -#define TEGRA_WAKE_GPIO_PV1 (1ull << 1) -#define TEGRA_WAKE_GPIO_PL1 (1ull << 2) -#define TEGRA_WAKE_GPIO_PB6 (1ull << 3) -#define TEGRA_WAKE_GPIO_PN7 (1ull << 4) -#define TEGRA_WAKE_GPIO_PBB6 (1ull << 5) -#define TEGRA_WAKE_GPIO_PU5 (1ull << 6) -#define TEGRA_WAKE_GPIO_PU6 (1ull << 7) -#define TEGRA_WAKE_GPIO_PC7 (1ull << 8) -#define TEGRA_WAKE_GPIO_PS2 (1ull << 9) -#define TEGRA_WAKE_GPIO_PAA1 (1ull << 10) -#define TEGRA_WAKE_GPIO_PW3 (1ull << 11) -#define TEGRA_WAKE_GPIO_PW2 (1ull << 12) -#define TEGRA_WAKE_GPIO_PY6 (1ull << 13) -#define TEGRA_WAKE_GPIO_PDD3 (1ull << 14) -#define TEGRA_WAKE_GPIO_PJ2 (1ull << 15) -#define TEGRA_WAKE_RTC_ALARM (1ull << 16) -#define TEGRA_WAKE_KBC_EVENT (1ull << 17) -#define TEGRA_WAKE_PWR_INT (1ull << 18) -#define TEGRA_WAKE_USB1_VBUS (1ull << 19) -#define TEGRA_WAKE_USB2_VBUS (1ull << 20) -#define TEGRA_WAKE_USB1_ID (1ull << 21) -#define TEGRA_WAKE_USB2_ID (1ull << 22) -#define TEGRA_WAKE_GPIO_PI5 (1ull << 23) -#define TEGRA_WAKE_GPIO_PV0 (1ull << 24) -#define TEGRA_WAKE_GPIO_PS4 (1ull << 25) -#define TEGRA_WAKE_GPIO_PS5 (1ull << 26) -#define TEGRA_WAKE_GPIO_PS0 (1ull << 27) -#define TEGRA_WAKE_GPIO_PS6 (1ull << 28) -#define TEGRA_WAKE_GPIO_PS7 (1ull << 29) -#define TEGRA_WAKE_GPIO_PN2 (1ull << 30) +#define TEGRA_WAKE_GPIO_PO5 0 +#define TEGRA_WAKE_GPIO_PV1 1 +#define TEGRA_WAKE_GPIO_PL1 2 +#define TEGRA_WAKE_GPIO_PB6 3 +#define TEGRA_WAKE_GPIO_PN7 4 +#define TEGRA_WAKE_GPIO_PBB6 5 +#define TEGRA_WAKE_GPIO_PU5 6 +#define TEGRA_WAKE_GPIO_PU6 7 +#define TEGRA_WAKE_GPIO_PC7 8 +#define TEGRA_WAKE_GPIO_PS2 9 +#define TEGRA_WAKE_GPIO_PAA1 10 +#define TEGRA_WAKE_GPIO_PW3 11 +#define TEGRA_WAKE_GPIO_PW2 12 +#define TEGRA_WAKE_GPIO_PY6 13 +#define TEGRA_WAKE_GPIO_PDD3 14 +#define TEGRA_WAKE_GPIO_PJ2 15 +#define TEGRA_WAKE_RTC_ALARM 16 +#define TEGRA_WAKE_KBC_EVENT 17 +#define TEGRA_WAKE_PWR_INT 18 +#define TEGRA_WAKE_USB1_VBUS 19 +#define TEGRA_WAKE_USB2_VBUS 20 +#define TEGRA_WAKE_USB1_ID 21 +#define TEGRA_WAKE_USB2_ID 22 +#define TEGRA_WAKE_GPIO_PI5 23 +#define TEGRA_WAKE_GPIO_PV0 24 +#define TEGRA_WAKE_GPIO_PS4 25 +#define TEGRA_WAKE_GPIO_PS5 26 +#define TEGRA_WAKE_GPIO_PS0 27 +#define TEGRA_WAKE_GPIO_PS6 28 +#define TEGRA_WAKE_GPIO_PS7 29 +#define TEGRA_WAKE_GPIO_PN2 30 /* bit 31 is unused */ -#define TEGRA_WAKE_GPIO_PO4 (1ull << 32) -#define TEGRA_WAKE_GPIO_PJ0 (1ull << 33) -#define TEGRA_WAKE_GPIO_PK2 (1ull << 34) -#define TEGRA_WAKE_GPIO_PI6 (1ull << 35) -#define TEGRA_WAKE_GPIO_PBB1 (1ull << 36) -#define TEGRA_WAKE_USB3_ID (1ull << 37) -#define TEGRA_WAKE_USB3_VBUS (1ull << 38) +#define TEGRA_WAKE_GPIO_PO4 32 +#define TEGRA_WAKE_GPIO_PJ0 33 +#define TEGRA_WAKE_GPIO_PK2 34 +#define TEGRA_WAKE_GPIO_PI6 35 +#define TEGRA_WAKE_GPIO_PBB1 36 +#define TEGRA_WAKE_USB3_ID 37 +#define TEGRA_WAKE_USB3_VBUS 38 #endif diff --git a/arch/arm/mach-tegra/wakeups.c b/arch/arm/mach-tegra/wakeups.c new file mode 100644 index 000000000000..d53563cf22ba --- /dev/null +++ b/arch/arm/mach-tegra/wakeups.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/kernel.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/interrupt.h> + +#include <mach/iomap.h> +#include <mach/irqs.h> +#include <mach/gpio.h> + +#include "gpio-names.h" +#include "wakeups.h" + +extern int *tegra_wake_event_irq; +extern unsigned int tegra_wake_event_irq_size; + +int tegra_irq_to_wake(int irq) +{ + int i; + int wake_irq; + int search_gpio; + static int last_wake = -1; + + /* Two level wake irq search for gpio based wakeups - + * 1. check for GPIO irq(based on tegra_wake_event_irq table) + * e.g. for a board, wake7 based on GPIO PU6 and irq==390 done first + * 2. check for gpio bank irq assuming search for GPIO irq + * preceded this search. + * e.g. in this step check for gpio bank irq GPIO6 irq==119 + */ + for (i = 0; i < tegra_wake_event_irq_size; i++) { + /* return if step 1 matches */ + if (tegra_wake_event_irq[i] == irq) { + pr_info("Wake%d for irq=%d\n", i, irq); + last_wake = i; + return i; + } + + /* step 2 below uses saved last_wake from step 1 + * in previous call */ + search_gpio = irq_to_gpio( + tegra_wake_event_irq[i]); + if (search_gpio < 0) + continue; + wake_irq = tegra_gpio_get_bank_int_nr(search_gpio); + if (wake_irq < 0) + continue; + if ((last_wake == i) && + (wake_irq == irq)) { + pr_info("gpio bank wake found: wake%d for irq=%d\n", + i, irq); + return i; + } + } + + return -EINVAL; +} + +int tegra_wake_to_irq(int wake) +{ + if (wake < 0) + return -EINVAL; + + if (wake >= tegra_wake_event_irq_size) + return -EINVAL; + + return tegra_wake_event_irq[wake]; +} + diff --git a/arch/arm/mach-tegra/wakeups.h b/arch/arm/mach-tegra/wakeups.h new file mode 100644 index 000000000000..ab113649d534 --- /dev/null +++ b/arch/arm/mach-tegra/wakeups.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __WAKEUPS_H_ +#define __WAKEUPS_H_ + +/* + * given irq number returns wake source index or negative value for error + */ +int tegra_irq_to_wake(int irq); +/* + * given wake source index, returns irq number or negative value for error + */ +int tegra_wake_to_irq(int wake); + +#endif /* end __WAKEUPS_H_ */ diff --git a/drivers/crypto/tegra-se.c b/drivers/crypto/tegra-se.c index 3d2e9187b949..83324162a09f 100644 --- a/drivers/crypto/tegra-se.c +++ b/drivers/crypto/tegra-se.c @@ -622,9 +622,12 @@ static int tegra_se_count_sgs(struct scatterlist *sl, u32 total_bytes) return 0; do { - total_bytes -= min(sl[i].length, total_bytes); + if (!sl->length) + return 0; + total_bytes -= min(sl->length, total_bytes); i++; - } while (total_bytes); + sl = sg_next(sl); + } while (total_bytes && sl); return i; } @@ -846,7 +849,7 @@ static int tegra_se_aes_queue_req(struct ablkcipher_request *req) bool idle = true; int err = 0; - if (!req->nbytes) + if (!tegra_se_count_sgs(req->src, req->nbytes)) return -EINVAL; spin_lock_irqsave(&se_dev->lock, flags); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d539efd96d4b..9b304f254f98 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -271,6 +271,15 @@ config GPIO_PCF857X This driver provides an in-kernel interface to those GPIOs using platform-neutral GPIO calls. +config GPIO_RC5T583 + bool "RICOH RC5T583 GPIO" + depends on MFD_RC5T583 + help + Select this option to enable GPIO driver for the Ricoh RC5T583 + chip family. + This driver provides the support for driving/reading the gpio pins + of RC5T583 device through standard gpio library. + config GPIO_SX150X bool "Semtech SX150x I2C GPIO expander" depends on I2C=y diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 9588948c96f0..4ef6785f446b 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o obj-$(CONFIG_GPIO_PCH) += gpio-pch.o obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o +obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o obj-$(CONFIG_GPIO_PLAT_SAMSUNG) += gpio-plat-samsung.o diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c new file mode 100644 index 000000000000..08428bf17718 --- /dev/null +++ b/drivers/gpio/gpio-rc5t583.c @@ -0,0 +1,180 @@ +/* + * GPIO driver for RICOH583 power management chip. + * + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * Author: Laxman dewangan <ldewangan@nvidia.com> + * + * Based on code + * Copyright (C) 2011 RICOH COMPANY,LTD + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/gpio.h> +#include <linux/mfd/rc5t583.h> + +struct rc5t583_gpio { + struct gpio_chip gpio_chip; + struct rc5t583 *rc5t583; +}; + +static inline struct rc5t583_gpio *to_rc5t583_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct rc5t583_gpio, gpio_chip); +} + +static int rc5t583_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc); + struct device *parent = rc5t583_gpio->rc5t583->dev; + uint8_t val = 0; + int ret; + + ret = rc5t583_read(parent, RC5T583_GPIO_MON_IOIN, &val); + if (ret < 0) + return ret; + + return !!(val & BIT(offset)); +} + +static void rc5t583_gpio_set(struct gpio_chip *gc, unsigned int offset, int val) +{ + struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc); + struct device *parent = rc5t583_gpio->rc5t583->dev; + if (val) + rc5t583_set_bits(parent, RC5T583_GPIO_IOOUT, BIT(offset)); + else + rc5t583_clear_bits(parent, RC5T583_GPIO_IOOUT, BIT(offset)); +} + +static int rc5t583_gpio_dir_input(struct gpio_chip *gc, unsigned int offset) +{ + struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc); + struct device *parent = rc5t583_gpio->rc5t583->dev; + int ret; + + ret = rc5t583_clear_bits(parent, RC5T583_GPIO_IOSEL, BIT(offset)); + if (ret < 0) + return ret; + + /* Set pin to gpio mode */ + return rc5t583_clear_bits(parent, RC5T583_GPIO_PGSEL, BIT(offset)); +} + +static int rc5t583_gpio_dir_output(struct gpio_chip *gc, unsigned offset, + int value) +{ + struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc); + struct device *parent = rc5t583_gpio->rc5t583->dev; + int ret; + + rc5t583_gpio_set(gc, offset, value); + ret = rc5t583_set_bits(parent, RC5T583_GPIO_IOSEL, BIT(offset)); + if (ret < 0) + return ret; + + /* Set pin to gpio mode */ + return rc5t583_clear_bits(parent, RC5T583_GPIO_PGSEL, BIT(offset)); +} + +static int rc5t583_gpio_to_irq(struct gpio_chip *gc, unsigned offset) +{ + struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc); + + if ((offset >= 0) && (offset < 8)) + return rc5t583_gpio->rc5t583->irq_base + + RC5T583_IRQ_GPIO0 + offset; + return -EINVAL; +} + +static void rc5t583_gpio_free(struct gpio_chip *gc, unsigned offset) +{ + struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc); + struct device *parent = rc5t583_gpio->rc5t583->dev; + + rc5t583_set_bits(parent, RC5T583_GPIO_PGSEL, BIT(offset)); +} + +static int __devinit rc5t583_gpio_probe(struct platform_device *pdev) +{ + struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent); + struct rc5t583_platform_data *pdata = dev_get_platdata(rc5t583->dev); + struct rc5t583_gpio *rc5t583_gpio; + + rc5t583_gpio = devm_kzalloc(&pdev->dev, sizeof(*rc5t583_gpio), + GFP_KERNEL); + if (!rc5t583_gpio) { + dev_warn(&pdev->dev, "Mem allocation for rc5t583_gpio failed"); + return -ENOMEM; + } + + rc5t583_gpio->gpio_chip.label = "gpio-rc5t583", + rc5t583_gpio->gpio_chip.owner = THIS_MODULE, + rc5t583_gpio->gpio_chip.free = rc5t583_gpio_free, + rc5t583_gpio->gpio_chip.direction_input = rc5t583_gpio_dir_input, + rc5t583_gpio->gpio_chip.direction_output = rc5t583_gpio_dir_output, + rc5t583_gpio->gpio_chip.set = rc5t583_gpio_set, + rc5t583_gpio->gpio_chip.get = rc5t583_gpio_get, + rc5t583_gpio->gpio_chip.to_irq = rc5t583_gpio_to_irq, + rc5t583_gpio->gpio_chip.ngpio = RC5T583_MAX_GPIO, + rc5t583_gpio->gpio_chip.can_sleep = 1, + rc5t583_gpio->gpio_chip.dev = &pdev->dev; + rc5t583_gpio->gpio_chip.base = -1; + rc5t583_gpio->rc5t583 = rc5t583; + + if (pdata && pdata->gpio_base) + rc5t583_gpio->gpio_chip.base = pdata->gpio_base; + + platform_set_drvdata(pdev, rc5t583_gpio); + + return gpiochip_add(&rc5t583_gpio->gpio_chip); +} + +static int __devexit rc5t583_gpio_remove(struct platform_device *pdev) +{ + struct rc5t583_gpio *rc5t583_gpio = platform_get_drvdata(pdev); + + return gpiochip_remove(&rc5t583_gpio->gpio_chip); +} + +static struct platform_driver rc5t583_gpio_driver = { + .driver = { + .name = "rc5t583-gpio", + .owner = THIS_MODULE, + }, + .probe = rc5t583_gpio_probe, + .remove = __devexit_p(rc5t583_gpio_remove), +}; + +static int __init rc5t583_gpio_init(void) +{ + return platform_driver_register(&rc5t583_gpio_driver); +} +subsys_initcall(rc5t583_gpio_init); + +static void __exit rc5t583_gpio_exit(void) +{ + platform_driver_unregister(&rc5t583_gpio_driver); +} +module_exit(rc5t583_gpio_exit); + +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_DESCRIPTION("GPIO interface for RC5T583"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:rc5t583-gpio"); diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c index 7eef648a3351..af6dc837ffca 100644 --- a/drivers/gpio/gpio-tps65910.c +++ b/drivers/gpio/gpio-tps65910.c @@ -18,14 +18,26 @@ #include <linux/errno.h> #include <linux/gpio.h> #include <linux/i2c.h> +#include <linux/platform_device.h> #include <linux/mfd/tps65910.h> +struct tps65910_gpio { + struct gpio_chip gpio_chip; + struct tps65910 *tps65910; +}; + +static inline struct tps65910_gpio *to_tps65910_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct tps65910_gpio, gpio_chip); +} + static int tps65910_gpio_get(struct gpio_chip *gc, unsigned offset) { - struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio); - uint8_t val; + struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc); + struct tps65910 *tps65910 = tps65910_gpio->tps65910; + unsigned int val; - tps65910->read(tps65910, TPS65910_GPIO0 + offset, 1, &val); + tps65910_reg_read(tps65910, TPS65910_GPIO0 + offset, &val); if (val & GPIO_STS_MASK) return 1; @@ -36,83 +48,135 @@ static int tps65910_gpio_get(struct gpio_chip *gc, unsigned offset) static void tps65910_gpio_set(struct gpio_chip *gc, unsigned offset, int value) { - struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio); + struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc); + struct tps65910 *tps65910 = tps65910_gpio->tps65910; if (value) - tps65910_set_bits(tps65910, TPS65910_GPIO0 + offset, + tps65910_reg_set_bits(tps65910, TPS65910_GPIO0 + offset, GPIO_SET_MASK); else - tps65910_clear_bits(tps65910, TPS65910_GPIO0 + offset, + tps65910_reg_clear_bits(tps65910, TPS65910_GPIO0 + offset, GPIO_SET_MASK); } static int tps65910_gpio_output(struct gpio_chip *gc, unsigned offset, int value) { - struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio); + struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc); + struct tps65910 *tps65910 = tps65910_gpio->tps65910; /* Set the initial value */ tps65910_gpio_set(gc, offset, value); - return tps65910_set_bits(tps65910, TPS65910_GPIO0 + offset, + return tps65910_reg_set_bits(tps65910, TPS65910_GPIO0 + offset, GPIO_CFG_MASK); } static int tps65910_gpio_input(struct gpio_chip *gc, unsigned offset) { - struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio); + struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc); + struct tps65910 *tps65910 = tps65910_gpio->tps65910; - return tps65910_clear_bits(tps65910, TPS65910_GPIO0 + offset, + return tps65910_reg_clear_bits(tps65910, TPS65910_GPIO0 + offset, GPIO_CFG_MASK); } -void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base) +static int __devinit tps65910_gpio_probe(struct platform_device *pdev) { + struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); + struct tps65910_board *pdata = dev_get_platdata(tps65910->dev); + struct tps65910_gpio *tps65910_gpio; int ret; - struct tps65910_board *board_data; + int i; + + tps65910_gpio = devm_kzalloc(&pdev->dev, + sizeof(*tps65910_gpio), GFP_KERNEL); + if (!tps65910_gpio) { + dev_err(&pdev->dev, "Could not allocate tps65910_gpio\n"); + return -ENOMEM; + } - if (!gpio_base) - return; + tps65910_gpio->tps65910 = tps65910; - tps65910->gpio.owner = THIS_MODULE; - tps65910->gpio.label = tps65910->i2c_client->name; - tps65910->gpio.dev = tps65910->dev; - tps65910->gpio.base = gpio_base; + tps65910_gpio->gpio_chip.owner = THIS_MODULE; + tps65910_gpio->gpio_chip.label = tps65910->i2c_client->name; switch(tps65910_chip_id(tps65910)) { case TPS65910: - tps65910->gpio.ngpio = TPS65910_NUM_GPIO; + tps65910_gpio->gpio_chip.ngpio = TPS65910_NUM_GPIO; break; case TPS65911: - tps65910->gpio.ngpio = TPS65911_NUM_GPIO; + tps65910_gpio->gpio_chip.ngpio = TPS65911_NUM_GPIO; break; default: - return; + return -EINVAL; } - tps65910->gpio.can_sleep = 1; - - tps65910->gpio.direction_input = tps65910_gpio_input; - tps65910->gpio.direction_output = tps65910_gpio_output; - tps65910->gpio.set = tps65910_gpio_set; - tps65910->gpio.get = tps65910_gpio_get; - - /* Configure sleep control for gpios */ - board_data = dev_get_platdata(tps65910->dev); - if (board_data) { - int i; - for (i = 0; i < tps65910->gpio.ngpio; ++i) { - if (board_data->en_gpio_sleep[i]) { - ret = tps65910_set_bits(tps65910, - TPS65910_GPIO0 + i, GPIO_SLEEP_MASK); - if (ret < 0) - dev_warn(tps65910->dev, - "GPIO Sleep setting failed\n"); - } - } + tps65910_gpio->gpio_chip.can_sleep = 1; + tps65910_gpio->gpio_chip.direction_input = tps65910_gpio_input; + tps65910_gpio->gpio_chip.direction_output = tps65910_gpio_output; + tps65910_gpio->gpio_chip.set = tps65910_gpio_set; + tps65910_gpio->gpio_chip.get = tps65910_gpio_get; + tps65910_gpio->gpio_chip.dev = &pdev->dev; + if (pdata && pdata->gpio_base) + tps65910_gpio->gpio_chip.base = pdata->gpio_base; + else + tps65910_gpio->gpio_chip.base = -1; + + if (!pdata) + goto skip_init; + + /* Configure sleep control for gpios if provided */ + for (i = 0; i < tps65910_gpio->gpio_chip.ngpio; ++i) { + if (!pdata->en_gpio_sleep[i]) + continue; + + ret = tps65910_reg_set_bits(tps65910, + TPS65910_GPIO0 + i, GPIO_SLEEP_MASK); + if (ret < 0) + dev_warn(tps65910->dev, + "GPIO Sleep setting failed with err %d\n", ret); + } + +skip_init: + ret = gpiochip_add(&tps65910_gpio->gpio_chip); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); + return ret; } - ret = gpiochip_add(&tps65910->gpio); + platform_set_drvdata(pdev, tps65910_gpio); - if (ret) - dev_warn(tps65910->dev, "GPIO registration failed: %d\n", ret); + return ret; } + +static int __devexit tps65910_gpio_remove(struct platform_device *pdev) +{ + struct tps65910_gpio *tps65910_gpio = platform_get_drvdata(pdev); + + return gpiochip_remove(&tps65910_gpio->gpio_chip); +} + +static struct platform_driver tps65910_gpio_driver = { + .driver.name = "tps65910-gpio", + .driver.owner = THIS_MODULE, + .probe = tps65910_gpio_probe, + .remove = __devexit_p(tps65910_gpio_remove), +}; + +static int __init tps65910_gpio_init(void) +{ + return platform_driver_register(&tps65910_gpio_driver); +} +subsys_initcall(tps65910_gpio_init); + +static void __exit tps65910_gpio_exit(void) +{ + platform_driver_unregister(&tps65910_gpio_driver); +} +module_exit(tps65910_gpio_exit); + +MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>"); +MODULE_AUTHOR("Jorge Eduardo Candelaria jedu@slimlogic.co.uk>"); +MODULE_DESCRIPTION("GPIO interface for TPS65910/TPS6511 PMICs"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:tps65910-gpio"); diff --git a/drivers/media/video/tegra/ad5816.c b/drivers/media/video/tegra/ad5816.c index d95368f43cf6..ed113b3a187c 100644 --- a/drivers/media/video/tegra/ad5816.c +++ b/drivers/media/video/tegra/ad5816.c @@ -249,9 +249,8 @@ static int ad5816_i2c_wr16(struct ad5816_info *info, u8 reg, u16 val) return 0; } -static int ad5816_gpio_wr(struct ad5816_info *info, - enum ad5816_gpio_types i, - int val) /* val: 0=deassert, 1=assert */ +static int ad5816_gpio_wr(struct ad5816_info *info, ad5816_gpio_types i, + int val) /* val: 0=deassert, 1=assert */ { int err = -EINVAL; if (info->gpio[i].valid) { @@ -370,8 +369,7 @@ static void ad5816_gpio_init(struct ad5816_info *info) } } -static int ad5816_vreg_dis(struct ad5816_info *info, - enum ad5816_vreg i) +static int ad5816_vreg_dis(struct ad5816_info *info, ad5816_vreg i) { int err = 0; if (info->vreg[i].vreg_flag && (info->vreg[i].vreg != NULL)) { @@ -396,8 +394,7 @@ static int ad5816_vreg_dis_all(struct ad5816_info *info) return err; } -static int ad5816_vreg_en(struct ad5816_info *info, - enum ad5816_vreg i) +static int ad5816_vreg_en(struct ad5816_info *info, ad5816_vreg i) { int err = 0; if (!info->vreg[i].vreg_flag && (info->vreg[i].vreg != NULL)) { diff --git a/drivers/media/video/tegra/nvavp/Kconfig b/drivers/media/video/tegra/nvavp/Kconfig index 2d3af3f79fb3..294253a0de49 100644 --- a/drivers/media/video/tegra/nvavp/Kconfig +++ b/drivers/media/video/tegra/nvavp/Kconfig @@ -8,3 +8,14 @@ config TEGRA_NVAVP /dev/tegra_avpchannel. If unsure, say N + +config TEGRA_NVAVP_AUDIO + bool "Enable Audio Channel support for Tegra NVAVP driver" + depends on TEGRA_NVAVP + default n + help + Enables support for the push-buffer mechanism based driver for the Tegra + audio multimedia framework. Exports the Tegra nvavp interface on device node + /dev/tegra_audio_avpchannel. + + If unsure, say N diff --git a/drivers/media/video/tegra/nvavp/nvavp_dev.c b/drivers/media/video/tegra/nvavp/nvavp_dev.c index 012f50b7a5f4..b695aa16af59 100644 --- a/drivers/media/video/tegra/nvavp/nvavp_dev.c +++ b/drivers/media/video/tegra/nvavp/nvavp_dev.c @@ -72,6 +72,34 @@ /* AVP behavior params */ #define NVAVP_OS_IDLE_TIMEOUT 100 /* milli-seconds */ +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) +/* Two control channels: Audio and Video channels */ +#define NVAVP_NUM_CHANNELS 2 + +#define NVAVP_AUDIO_CHANNEL 1 + +#define IS_AUDIO_CHANNEL_ID(channel_id) (channel_id == NVAVP_AUDIO_CHANNEL ? 1: 0) +#else +#define NVAVP_NUM_CHANNELS 1 +#endif + +/* Channel ID 0 represents the Video channel control area */ +#define NVAVP_VIDEO_CHANNEL 0 +/* Channel ID 1 represents the Audio channel control area */ + +#define IS_VIDEO_CHANNEL_ID(channel_id) (channel_id == NVAVP_VIDEO_CHANNEL ? 1: 0) + + +struct nvavp_channel { + struct mutex pushbuffer_lock; + struct nvmap_handle_ref *pushbuf_handle; + unsigned long pushbuf_phys; + u8 *pushbuf_data; + u32 pushbuf_index; + u32 pushbuf_fence; + struct nv_e276_control *os_control; +}; + struct nvavp_info { u32 clk_enabled; struct clk *bsev_clk; @@ -88,8 +116,10 @@ struct nvavp_info { struct mutex open_lock; int refcount; - int initialized; - + int video_initialized; +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) + int audio_initialized; +#endif struct work_struct clock_disable_work; /* os information */ @@ -101,22 +131,19 @@ struct nvavp_info { /* client for driver allocations, persistent */ struct nvmap_client *nvmap; - struct mutex pushbuffer_lock; - struct nvmap_handle_ref *pushbuf_handle; - unsigned long pushbuf_phys; - u8 *pushbuf_data; - u32 pushbuf_index; - u32 pushbuf_fence; bool pending; - struct nv_e276_control *os_control; + struct nvavp_channel channel_info[NVAVP_NUM_CHANNELS]; struct nvhost_syncpt *nvhost_syncpt; u32 syncpt_id; u32 syncpt_value; struct nvhost_device *nvhost_dev; - struct miscdevice misc_dev; + struct miscdevice video_misc_dev; +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) + struct miscdevice audio_misc_dev; +#endif atomic_t clock_stay_on_refcount; }; @@ -128,8 +155,77 @@ struct nvavp_clientctx { int num_relocs; struct nvavp_info *nvavp; int clock_stay_on; + int channel_id; }; +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) +static int nvavp_get_audio_init_status(struct nvavp_info *nvavp) +{ + return nvavp->audio_initialized; +} + +static void nvavp_set_audio_init_status(struct nvavp_info *nvavp, int status) +{ + nvavp->audio_initialized = status; +} +#endif + +static void nvavp_set_video_init_status(struct nvavp_info *nvavp, int status) +{ + nvavp->video_initialized = status; +} + +static int nvavp_get_video_init_status(struct nvavp_info *nvavp) +{ + return nvavp->video_initialized; +} + +static struct nvavp_channel *nvavp_get_channel_info(struct nvavp_info *nvavp, int channel_id) +{ + return &nvavp->channel_info[channel_id]; +} + +static void nvavp_set_channel_control_area(struct nvavp_info *nvavp, int channel_id) +{ + struct nv_e276_control *control; + struct nvavp_os_info *os = &nvavp->os_info; + u32 temp; + void *ptr; + struct nvavp_channel *channel_info; + + ptr = os->data + os->control_offset + (sizeof(struct nv_e276_control) * channel_id); + + channel_info = nvavp_get_channel_info(nvavp, channel_id); + channel_info->os_control = (struct nv_e276_control *)ptr; + + control = channel_info->os_control; + + /* init get and put pointers */ + writel(0x0, &control->put); + writel(0x0, &control->get); + + pr_debug("nvavp_set_channel_control_area for channel_id (%d):\ + control->put (0x%x) control->get (0x%x)\n", + channel_id, &control->put, &control->get); + + /* enable avp VDE clock control and disable iram clock gating */ + writel(0x0, &control->idle_clk_enable); + writel(0x0, &control->iram_clk_gating); + + /* enable avp idle timeout interrupt */ + writel(0x1, &control->idle_notify_enable); + writel(NVAVP_OS_IDLE_TIMEOUT, &control->idle_notify_delay); + + /* init dma start and end pointers */ + writel(channel_info->pushbuf_phys, &control->dma_start); + writel((channel_info->pushbuf_phys + NVAVP_PUSHBUFFER_SIZE), + &control->dma_end); + + writel(0x00, &channel_info->pushbuf_index); + temp = NVAVP_PUSHBUFFER_SIZE - NVAVP_PUSHBUFFER_MIN_UPDATE_SPACE; + writel(temp, &channel_info->pushbuf_fence); +} + static struct clk *nvavp_clk_get(struct nvavp_info *nvavp, int id) { if (!nvavp) @@ -175,7 +271,8 @@ static void nvavp_clks_disable(struct nvavp_info *nvavp) static u32 nvavp_check_idle(struct nvavp_info *nvavp) { - struct nv_e276_control *control = nvavp->os_control; + struct nvavp_channel *channel_info = nvavp_get_channel_info(nvavp, NVAVP_VIDEO_CHANNEL); + struct nv_e276_control *control = channel_info->os_control; return ((control->put == control->get) && (!atomic_read(&nvavp->clock_stay_on_refcount))) ? 1 : 0; } @@ -183,18 +280,20 @@ static u32 nvavp_check_idle(struct nvavp_info *nvavp) static void clock_disable_handler(struct work_struct *work) { struct nvavp_info *nvavp; + struct nvavp_channel *channel_info; nvavp = container_of(work, struct nvavp_info, clock_disable_work); + channel_info = nvavp_get_channel_info(nvavp, NVAVP_VIDEO_CHANNEL); - mutex_lock(&nvavp->pushbuffer_lock); + mutex_lock(&channel_info->pushbuffer_lock); mutex_lock(&nvavp->open_lock); if (nvavp_check_idle(nvavp) && nvavp->pending) { nvavp->pending = false; nvavp_clks_disable(nvavp); } mutex_unlock(&nvavp->open_lock); - mutex_unlock(&nvavp->pushbuffer_lock); + mutex_unlock(&channel_info->pushbuffer_lock); } static int nvavp_service(struct nvavp_info *nvavp) @@ -212,6 +311,10 @@ static int nvavp_service(struct nvavp_info *nvavp) if (inbox & NVE276_OS_INTERRUPT_VIDEO_IDLE) schedule_work(&nvavp->clock_disable_work); +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) + if (inbox & NVE276_OS_INTERRUPT_AUDIO_IDLE) + pr_debug("nvavp_service NVE276_OS_INTERRUPT_AUDIO_IDLE\n"); +#endif if (inbox & NVE276_OS_INTERRUPT_DEBUG_STRING) { /* Should only occur with debug AVP OS builds */ debug_print = os->data; @@ -337,99 +440,91 @@ static int nvavp_reset_vde(struct nvavp_info *nvavp) return 0; } -static int nvavp_pushbuffer_alloc(struct nvavp_info *nvavp) +static int nvavp_pushbuffer_alloc(struct nvavp_info *nvavp, int channel_id) { int ret = 0; - nvavp->pushbuf_handle = nvmap_alloc(nvavp->nvmap, NVAVP_PUSHBUFFER_SIZE, - SZ_1M, NVMAP_HANDLE_UNCACHEABLE, 0); - if (IS_ERR(nvavp->pushbuf_handle)) { + struct nvavp_channel *channel_info = nvavp_get_channel_info( + nvavp, channel_id); + + channel_info->pushbuf_handle = nvmap_alloc(nvavp->nvmap, + NVAVP_PUSHBUFFER_SIZE, + SZ_1M, NVMAP_HANDLE_UNCACHEABLE, + 0); + if (IS_ERR(channel_info->pushbuf_handle)) { dev_err(&nvavp->nvhost_dev->dev, "cannot create pushbuffer handle\n"); - ret = PTR_ERR(nvavp->pushbuf_handle); + ret = PTR_ERR(channel_info->pushbuf_handle); goto err_pushbuf_alloc; } - nvavp->pushbuf_data = (u8 *)nvmap_mmap(nvavp->pushbuf_handle); - if (!nvavp->pushbuf_data) { + channel_info->pushbuf_data = (u8 *)nvmap_mmap( + channel_info->pushbuf_handle); + + if (!channel_info->pushbuf_data) { dev_err(&nvavp->nvhost_dev->dev, "cannot map pushbuffer handle\n"); ret = -ENOMEM; goto err_pushbuf_mmap; } - nvavp->pushbuf_phys = nvmap_pin(nvavp->nvmap, nvavp->pushbuf_handle); - if (IS_ERR((void *)nvavp->pushbuf_phys)) { + channel_info->pushbuf_phys = nvmap_pin(nvavp->nvmap, + channel_info->pushbuf_handle); + if (IS_ERR((void *)channel_info->pushbuf_phys)) { dev_err(&nvavp->nvhost_dev->dev, "cannot pin pushbuffer handle\n"); - ret = PTR_ERR((void *)nvavp->pushbuf_phys); + ret = PTR_ERR((void *)channel_info->pushbuf_phys); goto err_pushbuf_pin; } - memset(nvavp->pushbuf_data, 0, NVAVP_PUSHBUFFER_SIZE); + memset(channel_info->pushbuf_data, 0, NVAVP_PUSHBUFFER_SIZE); return 0; err_pushbuf_pin: - nvmap_munmap(nvavp->pushbuf_handle, nvavp->pushbuf_data); + nvmap_munmap(channel_info->pushbuf_handle, channel_info->pushbuf_data); err_pushbuf_mmap: - nvmap_free(nvavp->nvmap, nvavp->pushbuf_handle); + nvmap_free(nvavp->nvmap, channel_info->pushbuf_handle); err_pushbuf_alloc: return ret; } static void nvavp_pushbuffer_free(struct nvavp_info *nvavp) { - nvmap_unpin(nvavp->nvmap, nvavp->pushbuf_handle); - nvmap_munmap(nvavp->pushbuf_handle, nvavp->pushbuf_data); - nvmap_free(nvavp->nvmap, nvavp->pushbuf_handle); + int channel_id; + + for (channel_id = 0; channel_id < NVAVP_NUM_CHANNELS; channel_id++) { + if (nvavp->channel_info[channel_id].pushbuf_data) { + nvmap_unpin(nvavp->nvmap, + nvavp->channel_info[channel_id].pushbuf_handle); + nvmap_munmap( + nvavp->channel_info[channel_id].pushbuf_handle, + nvavp->channel_info[channel_id].pushbuf_data); + nvmap_free(nvavp->nvmap, + nvavp->channel_info[channel_id].pushbuf_handle); + } + } } + static int nvavp_pushbuffer_init(struct nvavp_info *nvavp) { - void *ptr; - struct nvavp_os_info *os = &nvavp->os_info; - struct nv_e276_control *control; - u32 temp; - int ret; + int ret, channel_id; - ret = nvavp_pushbuffer_alloc(nvavp); - if (ret) { - dev_err(&nvavp->nvhost_dev->dev, - "unable to alloc pushbuffer\n"); - return ret; - } - - ptr = os->data; - ptr += os->control_offset; - nvavp->os_control = (struct nv_e276_control *)ptr; - - control = nvavp->os_control; - memset(control, 0, sizeof(struct nvavp_os_info)); - - /* init get and put pointers */ - writel(0x0, &control->put); - writel(0x0, &control->get); - - /* enable avp VDE clock control and disable iram clock gating */ - writel(0x0, &control->idle_clk_enable); - writel(0x0, &control->iram_clk_gating); - - /* enable avp idle timeout interrupt */ - writel(0x1, &control->idle_notify_enable); - writel(NVAVP_OS_IDLE_TIMEOUT, &control->idle_notify_delay); - - /* init dma start and end pointers */ - writel(nvavp->pushbuf_phys, &control->dma_start); - writel((nvavp->pushbuf_phys + NVAVP_PUSHBUFFER_SIZE), - &control->dma_end); - - writel(0x00, &nvavp->pushbuf_index); - temp = NVAVP_PUSHBUFFER_SIZE - NVAVP_PUSHBUFFER_MIN_UPDATE_SPACE; - writel(temp, &nvavp->pushbuf_fence); - - nvavp->syncpt_id = NVSYNCPT_AVP_0; - nvavp->syncpt_value = nvhost_syncpt_read(nvavp->nvhost_syncpt, - nvavp->syncpt_id); + for (channel_id = 0; channel_id < NVAVP_NUM_CHANNELS; channel_id++) { + ret = nvavp_pushbuffer_alloc(nvavp, channel_id); + if (ret) { + dev_err(&nvavp->nvhost_dev->dev, + "unable to alloc pushbuffer\n"); + return ret; + } + nvavp_set_channel_control_area(nvavp, channel_id); + if (IS_VIDEO_CHANNEL_ID(channel_id)) { + nvavp->syncpt_id = NVSYNCPT_AVP_0; + nvavp->syncpt_value = nvhost_syncpt_read( + nvavp->nvhost_syncpt, + nvavp->syncpt_id); + } + } return 0; } @@ -440,37 +535,47 @@ static void nvavp_pushbuffer_deinit(struct nvavp_info *nvavp) static int nvavp_pushbuffer_update(struct nvavp_info *nvavp, u32 phys_addr, u32 gather_count, struct nvavp_syncpt *syncpt, - u32 ext_ucode_flag) + u32 ext_ucode_flag, int channel_id) { - struct nv_e276_control *control = nvavp->os_control; + struct nvavp_channel *channel_info; + struct nv_e276_control *control; u32 gather_cmd, setucode_cmd, sync = 0; u32 wordcount = 0; u32 index, value = -1; - mutex_lock(&nvavp->pushbuffer_lock); + channel_info = nvavp_get_channel_info(nvavp, channel_id); + + control = channel_info->os_control; + pr_debug("nvavp_pushbuffer_update for channel_id (%d):\ + control->put (0x%x) control->get (0x%x)\n", + channel_id, &control->put, &control->get); + + mutex_lock(&channel_info->pushbuffer_lock); /* check for pushbuffer wrapping */ - if (nvavp->pushbuf_index >= nvavp->pushbuf_fence) - nvavp->pushbuf_index = 0; + if (channel_info->pushbuf_index >= channel_info->pushbuf_fence) + channel_info->pushbuf_index = 0; if (!ext_ucode_flag) { setucode_cmd = NVE26E_CH_OPCODE_INCR(NVE276_SET_MICROCODE_A, 3); - index = wordcount + nvavp->pushbuf_index; - writel(setucode_cmd, (nvavp->pushbuf_data + index)); + index = wordcount + channel_info->pushbuf_index; + writel(setucode_cmd, (channel_info->pushbuf_data + index)); wordcount += sizeof(u32); - index = wordcount + nvavp->pushbuf_index; - writel(0, (nvavp->pushbuf_data + index)); + index = wordcount + channel_info->pushbuf_index; + writel(0, (channel_info->pushbuf_data + index)); wordcount += sizeof(u32); - index = wordcount + nvavp->pushbuf_index; - writel(nvavp->ucode_info.phys, (nvavp->pushbuf_data + index)); + index = wordcount + channel_info->pushbuf_index; + writel(nvavp->ucode_info.phys, + (channel_info->pushbuf_data + index)); wordcount += sizeof(u32); - index = wordcount + nvavp->pushbuf_index; - writel(nvavp->ucode_info.size, (nvavp->pushbuf_data + index)); + index = wordcount + channel_info->pushbuf_index; + writel(nvavp->ucode_info.size, + (channel_info->pushbuf_data + index)); wordcount += sizeof(u32); } @@ -485,44 +590,58 @@ static int nvavp_pushbuffer_update(struct nvavp_info *nvavp, u32 phys_addr, } /* write commands out */ - index = wordcount + nvavp->pushbuf_index; - writel(gather_cmd, (nvavp->pushbuf_data + index)); + index = wordcount + channel_info->pushbuf_index; + writel(gather_cmd, (channel_info->pushbuf_data + index)); wordcount += sizeof(u32); - index = wordcount + nvavp->pushbuf_index; - writel(phys_addr, (nvavp->pushbuf_data + index)); + index = wordcount + channel_info->pushbuf_index; + writel(phys_addr, (channel_info->pushbuf_data + index)); wordcount += sizeof(u32); if (syncpt) { - index = wordcount + nvavp->pushbuf_index; - writel(sync, (nvavp->pushbuf_data + index)); + index = wordcount + channel_info->pushbuf_index; + writel(sync, (channel_info->pushbuf_data + index)); wordcount += sizeof(u32); } /* enable clocks to VDE/BSEV */ - mutex_lock(&nvavp->open_lock); - if (!nvavp->pending) { - nvavp_clks_enable(nvavp); - nvavp->pending = true; + if (IS_VIDEO_CHANNEL_ID(channel_id)) { + mutex_lock(&nvavp->open_lock); + if (!nvavp->pending) { + nvavp_clks_enable(nvavp); + nvavp->pending = true; + } + mutex_unlock(&nvavp->open_lock); } - mutex_unlock(&nvavp->open_lock); /* update put pointer */ - nvavp->pushbuf_index = (nvavp->pushbuf_index + wordcount) & + channel_info->pushbuf_index = (channel_info->pushbuf_index + wordcount)& (NVAVP_PUSHBUFFER_SIZE - 1); - writel(nvavp->pushbuf_index, &control->put); + + writel(channel_info->pushbuf_index, &control->put); wmb(); /* wake up avp */ - writel(0xA0000001, NVAVP_OS_OUTBOX); + if (IS_VIDEO_CHANNEL_ID(channel_id)) { + pr_debug("Wake up Video Channel\n"); + writel(0xA0000001, NVAVP_OS_OUTBOX); + } + else { +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) + if (IS_AUDIO_CHANNEL_ID(channel_id)) { + pr_debug("Wake up Audio Channel\n"); + writel(0xA0000002, NVAVP_OS_OUTBOX); + } +#endif + } /* Fill out fence struct */ if (syncpt) { syncpt->id = nvavp->syncpt_id; syncpt->value = value; } - mutex_unlock(&nvavp->pushbuffer_lock); + mutex_unlock(&channel_info->pushbuffer_lock); return 0; } @@ -547,14 +666,14 @@ static int nvavp_load_ucode(struct nvavp_info *nvavp) sprintf(fw_ucode_file, "nvavp_vid_ucode.bin"); ret = request_firmware(&nvavp_ucode_fw, fw_ucode_file, - nvavp->misc_dev.this_device); + nvavp->video_misc_dev.this_device); if (ret) { /* Try alternative version */ sprintf(fw_ucode_file, "nvavp_vid_ucode_alt.bin"); ret = request_firmware(&nvavp_ucode_fw, fw_ucode_file, - nvavp->misc_dev.this_device); + nvavp->video_misc_dev.this_device); if (ret) { dev_err(&nvavp->nvhost_dev->dev, @@ -652,7 +771,7 @@ static int nvavp_load_os(struct nvavp_info *nvavp, char *fw_os_file) if (!os_info->os_bin) { ret = request_firmware(&nvavp_os_fw, fw_os_file, - nvavp->misc_dev.this_device); + nvavp->video_misc_dev.this_device); if (ret) { dev_err(&nvavp->nvhost_dev->dev, "cannot read os firmware '%s'\n", fw_os_file); @@ -717,14 +836,28 @@ err_req_fw: return ret; } -static int nvavp_init(struct nvavp_info *nvavp) + +static int nvavp_os_init(struct nvavp_info *nvavp) { char fw_os_file[32]; int ret = 0; + int video_initialized, audio_initialized = 0; - if (nvavp->initialized) + video_initialized = nvavp_get_video_init_status(nvavp); + +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) + audio_initialized = nvavp_get_audio_init_status(nvavp); +#endif + pr_debug("video_initialized(%d) audio_initialized(%d)\n", + video_initialized, audio_initialized); + + /* Video and Audio both are initialized */ + if (video_initialized || audio_initialized) return ret; + /* Video or Audio both are uninitialized */ + pr_debug("video_initialized == audio_initialized (%d)\n", + nvavp->video_initialized); #if defined(CONFIG_TEGRA_AVP_KERNEL_ON_MMU) /* Tegra2 with AVP MMU */ /* paddr is any address returned from nvmap_pin */ /* vaddr is AVP_KERNEL_VIRT_BASE */ @@ -768,7 +901,6 @@ static int nvavp_init(struct nvavp_info *nvavp) nvavp->os_info.reset_addr = nvavp->os_info.phys; nvavp->os_info.data = ioremap(nvavp->os_info.phys, SZ_1M); #endif - ret = nvavp_load_os(nvavp, fw_os_file); if (ret) { dev_err(&nvavp->nvhost_dev->dev, @@ -782,21 +914,45 @@ static int nvavp_init(struct nvavp_info *nvavp) "unable to init pushbuffer\n"); goto err_exit; } + tegra_init_legacy_irq_cop(); + enable_irq(nvavp->mbox_from_avp_pend_irq); +err_exit: + return ret; +} - ret = nvavp_load_ucode(nvavp); +static int nvavp_init(struct nvavp_info *nvavp, int channel_id) +{ + int ret = 0; + + ret = nvavp_os_init(nvavp); if (ret) { dev_err(&nvavp->nvhost_dev->dev, - "unable to load ucode\n"); - goto err_exit; + "unable to load os firmware and allocate buffers\n"); } - tegra_init_legacy_irq_cop(); + if (IS_VIDEO_CHANNEL_ID(channel_id) && + (!nvavp_get_video_init_status(nvavp)) ) { + pr_debug("nvavp_init : channel_ID (%d)\n", channel_id); + ret = nvavp_load_ucode(nvavp); + if (ret) { + dev_err(&nvavp->nvhost_dev->dev, + "unable to load ucode\n"); + goto err_exit; + } - nvavp_reset_vde(nvavp); - nvavp_reset_avp(nvavp, nvavp->os_info.reset_addr); - enable_irq(nvavp->mbox_from_avp_pend_irq); + nvavp_reset_vde(nvavp); + nvavp_reset_avp(nvavp, nvavp->os_info.reset_addr); - nvavp->initialized = 1; + nvavp_set_video_init_status(nvavp, 1); + } +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) + if (IS_AUDIO_CHANNEL_ID(channel_id) && + (!nvavp_get_audio_init_status(nvavp))) { + pr_debug("nvavp_init : channel_ID (%d)\n", channel_id); + nvavp_reset_avp(nvavp, nvavp->os_info.reset_addr); + nvavp_set_audio_init_status(nvavp, 1); + } +#endif err_exit: return ret; @@ -804,22 +960,48 @@ err_exit: static void nvavp_uninit(struct nvavp_info *nvavp) { - if (!nvavp->initialized) + int video_initialized, audio_initialized = 0; + + video_initialized = nvavp_get_video_init_status(nvavp); + +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) + audio_initialized = nvavp_get_audio_init_status(nvavp); +#endif + + pr_debug("nvavp_uninit video_initialized(%d) audio_initialized(%d)\n", + video_initialized, audio_initialized); + + /* Video and Audio both are uninitialized */ + if (!video_initialized && !audio_initialized) return; - disable_irq(nvavp->mbox_from_avp_pend_irq); + if (video_initialized) { + pr_debug("nvavp_uninit nvavp->video_initialized\n"); + cancel_work_sync(&nvavp->clock_disable_work); - cancel_work_sync(&nvavp->clock_disable_work); + nvavp_halt_vde(nvavp); - nvavp_pushbuffer_deinit(nvavp); + clk_disable(nvavp->sclk); + clk_disable(nvavp->emc_clk); - nvavp_halt_vde(nvavp); - nvavp_halt_avp(nvavp); + nvavp_set_video_init_status(nvavp, 0); + video_initialized = 0; + } - clk_disable(nvavp->sclk); - clk_disable(nvavp->emc_clk); +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) + if (audio_initialized) { + nvavp_set_audio_init_status(nvavp, 0); + audio_initialized = 0; + } +#endif - nvavp->initialized = 0; + /* Video and Audio both becomes uninitialized */ + if (video_initialized == audio_initialized) { + pr_debug("nvavp_uninit both channels unitialized\n"); + disable_irq(nvavp->mbox_from_avp_pend_irq); + nvavp_pushbuffer_deinit(nvavp); + nvavp_halt_avp(nvavp); + } } static int nvavp_set_clock_ioctl(struct file *filp, unsigned int cmd, @@ -1010,7 +1192,8 @@ static int nvavp_pushbuffer_submit_ioctl(struct file *filp, unsigned int cmd, ret = nvavp_pushbuffer_update(nvavp, (phys_addr + hdr.cmdbuf.offset), hdr.cmdbuf.words, &syncpt, - (hdr.flags & NVAVP_UCODE_EXT)); + (hdr.flags & NVAVP_UCODE_EXT), + clientctx->channel_id); if (copy_to_user((void __user *)user_hdr->syncpt, &syncpt, sizeof(struct nvavp_syncpt))) { @@ -1021,7 +1204,8 @@ static int nvavp_pushbuffer_submit_ioctl(struct file *filp, unsigned int cmd, ret = nvavp_pushbuffer_update(nvavp, (phys_addr + hdr.cmdbuf.offset), hdr.cmdbuf.words, NULL, - (hdr.flags & NVAVP_UCODE_EXT)); + (hdr.flags & NVAVP_UCODE_EXT), + clientctx->channel_id); } err_reloc_info: @@ -1075,7 +1259,7 @@ static int nvavp_force_clock_stay_on_ioctl(struct file *filp, unsigned int cmd, return 0; } -static int tegra_nvavp_open(struct inode *inode, struct file *filp) +static int tegra_nvavp_open(struct inode *inode, struct file *filp, int channel_id) { struct miscdevice *miscdev = filp->private_data; struct nvavp_info *nvavp = dev_get_drvdata(miscdev->parent); @@ -1092,8 +1276,11 @@ static int tegra_nvavp_open(struct inode *inode, struct file *filp) mutex_lock(&nvavp->open_lock); - if (!nvavp->refcount) - ret = nvavp_init(nvavp); + pr_debug("tegra_nvavp_open channel_id (%d)\n", channel_id); + + clientctx->channel_id = channel_id; + + ret = nvavp_init(nvavp, channel_id); if (!ret) nvavp->refcount++; @@ -1109,6 +1296,20 @@ static int tegra_nvavp_open(struct inode *inode, struct file *filp) return ret; } +static int tegra_nvavp_video_open(struct inode *inode, struct file *filp) +{ + pr_debug("tegra_nvavp_video_open NVAVP_VIDEO_CHANNEL\n"); + return tegra_nvavp_open(inode, filp, NVAVP_VIDEO_CHANNEL); +} + +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) +static int tegra_nvavp_audio_open(struct inode *inode, struct file *filp) +{ + pr_debug("tegra_nvavp_audio_open NVAVP_AUDIO_CHANNEL\n"); + return tegra_nvavp_open(inode, filp, NVAVP_AUDIO_CHANNEL); +} +#endif + static int tegra_nvavp_release(struct inode *inode, struct file *filp) { struct nvavp_clientctx *clientctx = filp->private_data; @@ -1181,13 +1382,22 @@ static long tegra_nvavp_ioctl(struct file *filp, unsigned int cmd, return ret; } -static const struct file_operations tegra_nvavp_fops = { +static const struct file_operations tegra_video_nvavp_fops = { .owner = THIS_MODULE, - .open = tegra_nvavp_open, + .open = tegra_nvavp_video_open, .release = tegra_nvavp_release, .unlocked_ioctl = tegra_nvavp_ioctl, }; +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) +static const struct file_operations tegra_audio_nvavp_fops = { + .owner = THIS_MODULE, + .open = tegra_nvavp_audio_open, + .release = tegra_nvavp_release, + .unlocked_ioctl = tegra_nvavp_ioctl, +}; +#endif + static int tegra_nvavp_probe(struct nvhost_device *ndev, struct nvhost_device_id *id_table) { @@ -1195,7 +1405,7 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev, int irq; unsigned int heap_mask; u32 iovmm_addr; - int ret = 0; + int ret = 0, channel_id; irq = nvhost_get_irq_byname(ndev, "mbox_from_nvavp_pending"); if (irq < 0) { @@ -1306,7 +1516,9 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev, nvavp->mbox_from_avp_pend_irq = irq; mutex_init(&nvavp->open_lock); - mutex_init(&nvavp->pushbuffer_lock); + + for (channel_id = 0; channel_id < NVAVP_NUM_CHANNELS; channel_id++) + mutex_init(&nvavp->channel_info[channel_id].pushbuffer_lock); /* TODO DO NOT USE NVAVP DEVICE */ nvavp->cop_clk = clk_get(&ndev->dev, "cop"); @@ -1349,18 +1561,32 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev, INIT_WORK(&nvavp->clock_disable_work, clock_disable_handler); - nvavp->misc_dev.minor = MISC_DYNAMIC_MINOR; - nvavp->misc_dev.name = "tegra_avpchannel"; - nvavp->misc_dev.fops = &tegra_nvavp_fops; - nvavp->misc_dev.mode = S_IRWXUGO; - nvavp->misc_dev.parent = &ndev->dev; + nvavp->video_misc_dev.minor = MISC_DYNAMIC_MINOR; + nvavp->video_misc_dev.name = "tegra_avpchannel"; + nvavp->video_misc_dev.fops = &tegra_video_nvavp_fops; + nvavp->video_misc_dev.mode = S_IRWXUGO; + nvavp->video_misc_dev.parent = &ndev->dev; - ret = misc_register(&nvavp->misc_dev); + ret = misc_register(&nvavp->video_misc_dev); if (ret) { dev_err(&ndev->dev, "unable to register misc device!\n"); goto err_misc_reg; } +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) + nvavp->audio_misc_dev.minor = MISC_DYNAMIC_MINOR; + nvavp->audio_misc_dev.name = "tegra_audio_avpchannel"; + nvavp->audio_misc_dev.fops = &tegra_audio_nvavp_fops; + nvavp->audio_misc_dev.mode = S_IRWXUGO; + nvavp->audio_misc_dev.parent = &ndev->dev; + + ret = misc_register(&nvavp->audio_misc_dev); + if (ret) { + dev_err(&ndev->dev, "unable to register misc device!\n"); + goto err_audio_misc_reg; + } +#endif + ret = request_irq(irq, nvavp_mbox_pending_isr, 0, TEGRA_NVAVP_NAME, nvavp); if (ret) { @@ -1375,7 +1601,11 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev, return 0; err_req_irq_pend: - misc_deregister(&nvavp->misc_dev); +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) + misc_deregister(&nvavp->audio_misc_dev); +err_audio_misc_reg: +#endif + misc_deregister(&nvavp->video_misc_dev); err_misc_reg: clk_put(nvavp->emc_clk); err_get_emc_clk: @@ -1421,8 +1651,11 @@ static int tegra_nvavp_remove(struct nvhost_device *ndev) nvavp_unload_ucode(nvavp); nvavp_unload_os(nvavp); - misc_deregister(&nvavp->misc_dev); + misc_deregister(&nvavp->video_misc_dev); +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) + misc_deregister(&nvavp->audio_misc_dev); +#endif clk_put(nvavp->bsev_clk); clk_put(nvavp->vde_clk); clk_put(nvavp->cop_clk); @@ -1463,7 +1696,7 @@ static int tegra_nvavp_resume(struct nvhost_device *ndev) mutex_lock(&nvavp->open_lock); if (nvavp->refcount) - nvavp_init(nvavp); + nvavp_init(nvavp, NVAVP_VIDEO_CHANNEL); mutex_unlock(&nvavp->open_lock); diff --git a/drivers/media/video/tegra/ov2710.c b/drivers/media/video/tegra/ov2710.c index 5e8eaa123124..293cb8932dfb 100644 --- a/drivers/media/video/tegra/ov2710.c +++ b/drivers/media/video/tegra/ov2710.c @@ -21,6 +21,8 @@ #include <linux/uaccess.h> #include <media/ov2710.h> +#define SIZEOF_I2C_TRANSBUF 32 + struct ov2710_reg { u16 addr; u16 val; @@ -30,6 +32,7 @@ struct ov2710_info { int mode; struct i2c_client *i2c_client; struct ov2710_platform_data *pdata; + u8 i2c_trans_buf[SIZEOF_I2C_TRANSBUF]; }; #define OV2710_TABLE_WAIT_MS 0 @@ -152,7 +155,7 @@ static struct ov2710_reg mode_1920x1080[] = { {0x3704, 0x44}, {0x3801, 0xd2}, - {0x3503, 0x17}, + {0x3503, 0x33}, {0x3500, 0x00}, {0x3501, 0x00}, {0x3502, 0x00}, @@ -283,7 +286,7 @@ static struct ov2710_reg mode_1280x720[] = { {0x3704, 0x40}, {0x3801, 0xbc}, - {0x3503, 0x17}, + {0x3503, 0x33}, {0x3500, 0x00}, {0x3501, 0x00}, {0x3502, 0x00}, @@ -400,14 +403,39 @@ static int ov2710_write_reg(struct i2c_client *client, u16 addr, u8 val) return err; } -static int ov2710_write_table(struct i2c_client *client, +static int ov2710_write_bulk_reg(struct i2c_client *client, u8 *data, int len) +{ + int err; + struct i2c_msg msg; + + if (!client->adapter) + return -ENODEV; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = len; + msg.buf = data; + + err = i2c_transfer(client->adapter, &msg, 1); + if (err == 1) + return 0; + + pr_err("ov2710: i2c bulk transfer failed at %x\n", + (int)data[0] << 8 | data[1]); + + return err; +} + +static int ov2710_write_table(struct ov2710_info *info, const struct ov2710_reg table[], const struct ov2710_reg override_list[], int num_override_regs) { int err; - const struct ov2710_reg *next; - int i; + const struct ov2710_reg *next, *n_next; + u8 *b_ptr = info->i2c_trans_buf; + unsigned int buf_filled = 0; + unsigned int i; u16 val; for (next = table; next->addr != OV2710_TABLE_END; next++) { @@ -416,9 +444,7 @@ static int ov2710_write_table(struct i2c_client *client, continue; } - val = next->val; - /* When an override list is passed in, replace the reg */ /* value to write if the reg is in the list */ if (override_list) { @@ -430,9 +456,28 @@ static int ov2710_write_table(struct i2c_client *client, } } - err = ov2710_write_reg(client, next->addr, val); + if (!buf_filled) { + b_ptr = info->i2c_trans_buf; + *b_ptr++ = next->addr >> 8; + *b_ptr++ = next->addr & 0xff; + buf_filled = 2; + } + *b_ptr++ = val; + buf_filled++; + + n_next = next + 1; + if (n_next->addr != OV2710_TABLE_END && + n_next->addr != OV2710_TABLE_WAIT_MS && + buf_filled < SIZEOF_I2C_TRANSBUF && + n_next->addr == next->addr + 1) { + continue; + } + + err = ov2710_write_bulk_reg(info->i2c_client, + info->i2c_trans_buf, buf_filled); if (err) return err; + buf_filled = 0; } return 0; } @@ -463,7 +508,7 @@ static int ov2710_set_mode(struct ov2710_info *info, struct ov2710_mode *mode) ov2710_get_coarse_time_regs(reg_list + 2, mode->coarse_time); ov2710_get_gain_reg(reg_list + 5, mode->gain); - err = ov2710_write_table(info->i2c_client, mode_table[sensor_mode], + err = ov2710_write_table(info, mode_table[sensor_mode], reg_list, 6); if (err) return err; @@ -474,51 +519,37 @@ static int ov2710_set_mode(struct ov2710_info *info, struct ov2710_mode *mode) static int ov2710_set_frame_length(struct ov2710_info *info, u32 frame_length) { - struct ov2710_reg reg_list[2]; - int i = 0; int ret; + struct ov2710_reg reg_list[2]; + u8 *b_ptr = info->i2c_trans_buf; ov2710_get_frame_length_regs(reg_list, frame_length); - for (i = 0; i < 2; i++) { - ret = ov2710_write_reg(info->i2c_client, reg_list[i].addr, - reg_list[i].val); - if (ret) - return ret; - } + *b_ptr++ = reg_list[0].addr >> 8; + *b_ptr++ = reg_list[0].addr & 0xff; + *b_ptr++ = reg_list[0].val & 0xff; + *b_ptr++ = reg_list[1].val & 0xff; + ret = ov2710_write_bulk_reg(info->i2c_client, info->i2c_trans_buf, 4); - return 0; + return ret; } static int ov2710_set_coarse_time(struct ov2710_info *info, u32 coarse_time) { int ret; - struct ov2710_reg reg_list[3]; - int i = 0; + u8 *b_ptr = info->i2c_trans_buf; ov2710_get_coarse_time_regs(reg_list, coarse_time); - ret = ov2710_write_reg(info->i2c_client, 0x3212, 0x01); - if (ret) - return ret; - - for (i = 0; i < 3; i++) { - ret = ov2710_write_reg(info->i2c_client, reg_list[i].addr, - reg_list[i].val); - if (ret) - return ret; - } - - ret = ov2710_write_reg(info->i2c_client, 0x3212, 0x11); - if (ret) - return ret; + *b_ptr++ = reg_list[0].addr >> 8; + *b_ptr++ = reg_list[0].addr & 0xff; + *b_ptr++ = reg_list[0].val & 0xff; + *b_ptr++ = reg_list[1].val & 0xff; + *b_ptr++ = reg_list[2].val & 0xff; + ret = ov2710_write_bulk_reg(info->i2c_client, info->i2c_trans_buf, 5); - ret = ov2710_write_reg(info->i2c_client, 0x3212, 0xa1); - if (ret) - return ret; - - return 0; + return ret; } static int ov2710_set_gain(struct ov2710_info *info, u16 gain) @@ -533,6 +564,48 @@ static int ov2710_set_gain(struct ov2710_info *info, u16 gain) return ret; } +static int ov2710_set_group_hold(struct ov2710_info *info, struct ov2710_ae *ae) +{ + int ret; + int count = 0; + bool groupHoldEnabled = false; + + if (ae->gain_enable) + count++; + if (ae->coarse_time_enable) + count++; + if (ae->frame_length_enable) + count++; + if (count >= 2) + groupHoldEnabled = true; + + if (groupHoldEnabled) { + ret = ov2710_write_reg(info->i2c_client, 0x3212, 0x01); + if (ret) + return ret; + } + + if (ae->gain_enable) + ov2710_set_gain(info, ae->gain); + if (ae->coarse_time_enable) + ov2710_set_coarse_time(info, ae->coarse_time); + if (ae->frame_length_enable) + ov2710_set_frame_length(info, ae->frame_length); + + if (groupHoldEnabled) { + ret = ov2710_write_reg(info->i2c_client, 0x3212, 0x11); + if (ret) + return ret; + + ret = ov2710_write_reg(info->i2c_client, 0x3212, 0xa1); + if (ret) + return ret; + } + + return 0; +} + + static int ov2710_get_status(struct ov2710_info *info, u8 *status) { int err; @@ -567,6 +640,17 @@ static long ov2710_ioctl(struct file *file, return ov2710_set_coarse_time(info, (u32)arg); case OV2710_IOCTL_SET_GAIN: return ov2710_set_gain(info, (u16)arg); + case OV2710_IOCTL_SET_GROUP_HOLD: + { + struct ov2710_ae ae; + if (copy_from_user(&ae, + (const void __user *)arg, + sizeof(struct ov2710_ae))) { + pr_info("%s %d\n", __func__, __LINE__); + return -EFAULT; + } + return ov2710_set_group_hold(info, &ae); + } case OV2710_IOCTL_GET_STATUS: { u8 status; diff --git a/drivers/media/video/tegra/sh532u.c b/drivers/media/video/tegra/sh532u.c index f41b44ce9530..4c7ef5aeaeab 100644 --- a/drivers/media/video/tegra/sh532u.c +++ b/drivers/media/video/tegra/sh532u.c @@ -532,7 +532,7 @@ static int sh532u_vreg_init(struct sh532u_info *info) else dev_info(&info->i2c_client->dev, "%s no regulator found for %s. " - "This board may not have an" + "This board may not have an " "independent %s regulator.\n", __func__, info->vreg[j].vreg_name, info->vreg[j].vreg_name); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index f89c3eedee36..a4931c756205 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -175,7 +175,6 @@ config MFD_TPS65910 bool "TPS65910 Power Management chip" depends on I2C=y && GPIOLIB select MFD_CORE - select GPIO_TPS65910 select REGMAP_I2C help if you say yes here you get support for the TPS65910 series of diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c index 99ef944c621d..cdc1df7fa0e9 100644 --- a/drivers/mfd/rc5t583.c +++ b/drivers/mfd/rc5t583.c @@ -75,49 +75,12 @@ static struct deepsleep_control_data deepsleep_data[] = { (RC5T583_EXT_PWRREQ1_CONTROL | RC5T583_EXT_PWRREQ2_CONTROL) static struct mfd_cell rc5t583_subdevs[] = { + {.name = "rc5t583-gpio",}, {.name = "rc5t583-regulator",}, {.name = "rc5t583-rtc", }, {.name = "rc5t583-key", } }; -int rc5t583_write(struct device *dev, uint8_t reg, uint8_t val) -{ - struct rc5t583 *rc5t583 = dev_get_drvdata(dev); - return regmap_write(rc5t583->regmap, reg, val); -} - -int rc5t583_read(struct device *dev, uint8_t reg, uint8_t *val) -{ - struct rc5t583 *rc5t583 = dev_get_drvdata(dev); - unsigned int ival; - int ret; - ret = regmap_read(rc5t583->regmap, reg, &ival); - if (!ret) - *val = (uint8_t)ival; - return ret; -} - -int rc5t583_set_bits(struct device *dev, unsigned int reg, - unsigned int bit_mask) -{ - struct rc5t583 *rc5t583 = dev_get_drvdata(dev); - return regmap_update_bits(rc5t583->regmap, reg, bit_mask, bit_mask); -} - -int rc5t583_clear_bits(struct device *dev, unsigned int reg, - unsigned int bit_mask) -{ - struct rc5t583 *rc5t583 = dev_get_drvdata(dev); - return regmap_update_bits(rc5t583->regmap, reg, bit_mask, 0); -} - -int rc5t583_update(struct device *dev, unsigned int reg, - unsigned int val, unsigned int mask) -{ - struct rc5t583 *rc5t583 = dev_get_drvdata(dev); - return regmap_update_bits(rc5t583->regmap, reg, mask, val); -} - static int __rc5t583_set_ext_pwrreq1_control(struct device *dev, int id, int ext_pwr, int slots) { @@ -197,6 +160,7 @@ int rc5t583_ext_power_req_config(struct device *dev, int ds_id, ds_id, ext_pwr_req); return 0; } +EXPORT_SYMBOL(rc5t583_ext_power_req_config); static int rc5t583_clear_ext_power_req(struct rc5t583 *rc5t583, struct rc5t583_platform_data *pdata) @@ -304,7 +268,7 @@ static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c, rc5t583->dev = &i2c->dev; i2c_set_clientdata(i2c, rc5t583); - rc5t583->regmap = regmap_init_i2c(i2c, &rc5t583_regmap_config); + rc5t583->regmap = devm_regmap_init_i2c(i2c, &rc5t583_regmap_config); if (IS_ERR(rc5t583->regmap)) { ret = PTR_ERR(rc5t583->regmap); dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret); @@ -313,7 +277,7 @@ static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c, ret = rc5t583_clear_ext_power_req(rc5t583, pdata); if (ret < 0) - goto err_irq_init; + return ret; if (i2c->irq) { ret = rc5t583_irq_init(rc5t583, i2c->irq, pdata->irq_base); @@ -336,8 +300,6 @@ static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c, err_add_devs: if (irq_init_success) rc5t583_irq_exit(rc5t583); -err_irq_init: - regmap_exit(rc5t583->regmap); return ret; } @@ -347,7 +309,6 @@ static int __devexit rc5t583_i2c_remove(struct i2c_client *i2c) mfd_remove_devices(rc5t583->dev); rc5t583_irq_exit(rc5t583); - regmap_exit(rc5t583->regmap); return 0; } diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c index c9ed5c00a621..0f1ff7fbdc74 100644 --- a/drivers/mfd/tps65910-irq.c +++ b/drivers/mfd/tps65910-irq.c @@ -41,28 +41,28 @@ static inline int irq_to_tps65910_irq(struct tps65910 *tps65910, static irqreturn_t tps65910_irq(int irq, void *irq_data) { struct tps65910 *tps65910 = irq_data; + unsigned int reg; u32 irq_sts; u32 irq_mask; - u8 reg; int i; - tps65910->read(tps65910, TPS65910_INT_STS, 1, ®); + tps65910_reg_read(tps65910, TPS65910_INT_STS, ®); irq_sts = reg; - tps65910->read(tps65910, TPS65910_INT_STS2, 1, ®); + tps65910_reg_read(tps65910, TPS65910_INT_STS2, ®); irq_sts |= reg << 8; switch (tps65910_chip_id(tps65910)) { case TPS65911: - tps65910->read(tps65910, TPS65910_INT_STS3, 1, ®); + tps65910_reg_read(tps65910, TPS65910_INT_STS3, ®); irq_sts |= reg << 16; } - tps65910->read(tps65910, TPS65910_INT_MSK, 1, ®); + tps65910_reg_read(tps65910, TPS65910_INT_MSK, ®); irq_mask = reg; - tps65910->read(tps65910, TPS65910_INT_MSK2, 1, ®); + tps65910_reg_read(tps65910, TPS65910_INT_MSK2, ®); irq_mask |= reg << 8; switch (tps65910_chip_id(tps65910)) { case TPS65911: - tps65910->read(tps65910, TPS65910_INT_MSK3, 1, ®); + tps65910_reg_read(tps65910, TPS65910_INT_MSK3, ®); irq_mask |= reg << 16; } @@ -82,13 +82,13 @@ static irqreturn_t tps65910_irq(int irq, void *irq_data) /* Write the STS register back to clear IRQs we handled */ reg = irq_sts & 0xFF; irq_sts >>= 8; - tps65910->write(tps65910, TPS65910_INT_STS, 1, ®); + tps65910_reg_write(tps65910, TPS65910_INT_STS, reg); reg = irq_sts & 0xFF; - tps65910->write(tps65910, TPS65910_INT_STS2, 1, ®); + tps65910_reg_write(tps65910, TPS65910_INT_STS2, reg); switch (tps65910_chip_id(tps65910)) { case TPS65911: reg = irq_sts >> 8; - tps65910->write(tps65910, TPS65910_INT_STS3, 1, ®); + tps65910_reg_write(tps65910, TPS65910_INT_STS3, reg); } return IRQ_HANDLED; @@ -105,27 +105,27 @@ static void tps65910_irq_sync_unlock(struct irq_data *data) { struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); u32 reg_mask; - u8 reg; + unsigned int reg; - tps65910->read(tps65910, TPS65910_INT_MSK, 1, ®); + tps65910_reg_read(tps65910, TPS65910_INT_MSK, ®); reg_mask = reg; - tps65910->read(tps65910, TPS65910_INT_MSK2, 1, ®); + tps65910_reg_read(tps65910, TPS65910_INT_MSK2, ®); reg_mask |= reg << 8; switch (tps65910_chip_id(tps65910)) { case TPS65911: - tps65910->read(tps65910, TPS65910_INT_MSK3, 1, ®); + tps65910_reg_read(tps65910, TPS65910_INT_MSK3, ®); reg_mask |= reg << 16; } if (tps65910->irq_mask != reg_mask) { reg = tps65910->irq_mask & 0xFF; - tps65910->write(tps65910, TPS65910_INT_MSK, 1, ®); + tps65910_reg_write(tps65910, TPS65910_INT_MSK, reg); reg = tps65910->irq_mask >> 8 & 0xFF; - tps65910->write(tps65910, TPS65910_INT_MSK2, 1, ®); + tps65910_reg_write(tps65910, TPS65910_INT_MSK2, reg); switch (tps65910_chip_id(tps65910)) { case TPS65911: reg = tps65910->irq_mask >> 16; - tps65910->write(tps65910, TPS65910_INT_MSK3, 1, ®); + tps65910_reg_write(tps65910, TPS65910_INT_MSK3, reg); } } mutex_unlock(&tps65910->irq_lock); diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 1c4f53efee74..18b30cf45e5b 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -19,13 +19,16 @@ #include <linux/err.h> #include <linux/slab.h> #include <linux/i2c.h> -#include <linux/gpio.h> #include <linux/mfd/core.h> #include <linux/regmap.h> #include <linux/mfd/tps65910.h> +#include <linux/of_device.h> static struct mfd_cell tps65910s[] = { { + .name = "tps65910-gpio", + }, + { .name = "tps65910-pmic", }, { @@ -37,30 +40,6 @@ static struct mfd_cell tps65910s[] = { }; -static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg, - int bytes, void *dest) -{ - return regmap_bulk_read(tps65910->regmap, reg, dest, bytes); -} - -static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg, - int bytes, void *src) -{ - return regmap_bulk_write(tps65910->regmap, reg, src, bytes); -} - -int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask) -{ - return regmap_update_bits(tps65910->regmap, reg, mask, mask); -} -EXPORT_SYMBOL_GPL(tps65910_set_bits); - -int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask) -{ - return regmap_update_bits(tps65910->regmap, reg, mask, 0); -} -EXPORT_SYMBOL_GPL(tps65910_clear_bits); - static bool is_volatile_reg(struct device *dev, unsigned int reg) { struct tps65910 *tps65910 = dev_get_drvdata(dev); @@ -81,84 +60,212 @@ static bool is_volatile_reg(struct device *dev, unsigned int reg) return true; } -static const struct regmap_config rc5t583_regmap_config = { +static const struct regmap_config tps65910_regmap_config = { .reg_bits = 8, .val_bits = 8, .volatile_reg = is_volatile_reg, - .max_register = TPS65910_MAX_REGISTER, - .num_reg_defaults_raw = TPS65910_MAX_REGISTER, + .max_register = TPS65910_MAX_REGISTER - 1, .cache_type = REGCACHE_RBTREE, }; -static int tps65910_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int __devinit tps65910_sleepinit(struct tps65910 *tps65910, + struct tps65910_board *pmic_pdata) +{ + struct device *dev = NULL; + int ret = 0; + + dev = tps65910->dev; + + if (!pmic_pdata->en_dev_slp) + return 0; + + /* enabling SLEEP device state */ + ret = tps65910_reg_set_bits(tps65910, TPS65910_DEVCTRL, + DEVCTRL_DEV_SLP_MASK); + if (ret < 0) { + dev_err(dev, "set dev_slp failed: %d\n", ret); + goto err_sleep_init; + } + + /* Return if there is no sleep keepon data. */ + if (!pmic_pdata->slp_keepon) + return 0; + + if (pmic_pdata->slp_keepon->therm_keepon) { + ret = tps65910_reg_set_bits(tps65910, + TPS65910_SLEEP_KEEP_RES_ON, + SLEEP_KEEP_RES_ON_THERM_KEEPON_MASK); + if (ret < 0) { + dev_err(dev, "set therm_keepon failed: %d\n", ret); + goto disable_dev_slp; + } + } + + if (pmic_pdata->slp_keepon->clkout32k_keepon) { + ret = tps65910_reg_set_bits(tps65910, + TPS65910_SLEEP_KEEP_RES_ON, + SLEEP_KEEP_RES_ON_CLKOUT32K_KEEPON_MASK); + if (ret < 0) { + dev_err(dev, "set clkout32k_keepon failed: %d\n", ret); + goto disable_dev_slp; + } + } + + if (pmic_pdata->slp_keepon->i2chs_keepon) { + ret = tps65910_reg_set_bits(tps65910, + TPS65910_SLEEP_KEEP_RES_ON, + SLEEP_KEEP_RES_ON_I2CHS_KEEPON_MASK); + if (ret < 0) { + dev_err(dev, "set i2chs_keepon failed: %d\n", ret); + goto disable_dev_slp; + } + } + + return 0; + +disable_dev_slp: + tps65910_reg_clear_bits(tps65910, TPS65910_DEVCTRL, + DEVCTRL_DEV_SLP_MASK); + +err_sleep_init: + return ret; +} + +#ifdef CONFIG_OF +static struct of_device_id tps65910_of_match[] = { + { .compatible = "ti,tps65910", .data = (void *)TPS65910}, + { .compatible = "ti,tps65911", .data = (void *)TPS65911}, + { }, +}; +MODULE_DEVICE_TABLE(of, tps65910_of_match); + +static struct tps65910_board *tps65910_parse_dt(struct i2c_client *client, + int *chip_id) +{ + struct device_node *np = client->dev.of_node; + struct tps65910_board *board_info; + unsigned int prop; + const struct of_device_id *match; + unsigned int prop_array[TPS6591X_MAX_NUM_GPIO]; + int ret = 0; + int idx; + + match = of_match_device(tps65910_of_match, &client->dev); + if (!match) { + dev_err(&client->dev, "Failed to find matching dt id\n"); + return NULL; + } + + *chip_id = (int)match->data; + + board_info = devm_kzalloc(&client->dev, sizeof(*board_info), + GFP_KERNEL); + if (!board_info) { + dev_err(&client->dev, "Failed to allocate pdata\n"); + return NULL; + } + + ret = of_property_read_u32(np, "ti,vmbch-threshold", &prop); + if (!ret) + board_info->vmbch_threshold = prop; + else if (*chip_id == TPS65911) + dev_warn(&client->dev, "VMBCH-Threshold not specified"); + + ret = of_property_read_u32(np, "ti,vmbch2-threshold", &prop); + if (!ret) + board_info->vmbch2_threshold = prop; + else if (*chip_id == TPS65911) + dev_warn(&client->dev, "VMBCH2-Threshold not specified"); + + ret = of_property_read_u32_array(np, "ti,en-gpio-sleep", + prop_array, TPS6591X_MAX_NUM_GPIO); + if (!ret) + for (idx = 0; idx < ARRAY_SIZE(prop_array); idx++) + board_info->en_gpio_sleep[idx] = (prop_array[idx] != 0); + else if (ret != -EINVAL) { + dev_err(&client->dev, + "error reading property ti,en-gpio-sleep: %d\n.", ret); + return NULL; + } + + + board_info->irq = client->irq; + board_info->irq_base = -1; + board_info->gpio_base = -1; + + return board_info; +} +#else +static inline +struct tps65910_board *tps65910_parse_dt(struct i2c_client *client, + int *chip_id) +{ + return NULL; +} +#endif + +static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct tps65910 *tps65910; struct tps65910_board *pmic_plat_data; struct tps65910_platform_data *init_data; int ret = 0; + int chip_id = id->driver_data; pmic_plat_data = dev_get_platdata(&i2c->dev); + + if (!pmic_plat_data && i2c->dev.of_node) + pmic_plat_data = tps65910_parse_dt(i2c, &chip_id); + if (!pmic_plat_data) return -EINVAL; - init_data = kzalloc(sizeof(struct tps65910_platform_data), GFP_KERNEL); + init_data = devm_kzalloc(&i2c->dev, sizeof(*init_data), GFP_KERNEL); if (init_data == NULL) return -ENOMEM; - tps65910 = kzalloc(sizeof(struct tps65910), GFP_KERNEL); - if (tps65910 == NULL) { - kfree(init_data); + tps65910 = devm_kzalloc(&i2c->dev, sizeof(*tps65910), GFP_KERNEL); + if (tps65910 == NULL) return -ENOMEM; - } i2c_set_clientdata(i2c, tps65910); tps65910->dev = &i2c->dev; tps65910->i2c_client = i2c; - tps65910->id = id->driver_data; - tps65910->read = tps65910_i2c_read; - tps65910->write = tps65910_i2c_write; + tps65910->id = chip_id; mutex_init(&tps65910->io_mutex); - tps65910->regmap = regmap_init_i2c(i2c, &rc5t583_regmap_config); + tps65910->regmap = devm_regmap_init_i2c(i2c, &tps65910_regmap_config); if (IS_ERR(tps65910->regmap)) { ret = PTR_ERR(tps65910->regmap); dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret); - goto regmap_err; + return ret; } ret = mfd_add_devices(tps65910->dev, -1, tps65910s, ARRAY_SIZE(tps65910s), NULL, 0); - if (ret < 0) - goto err; + if (ret < 0) { + dev_err(&i2c->dev, "mfd_add_devices failed: %d\n", ret); + return ret; + } init_data->irq = pmic_plat_data->irq; init_data->irq_base = pmic_plat_data->irq_base; - tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base); - tps65910_irq_init(tps65910, init_data->irq, init_data); - kfree(init_data); - return ret; + tps65910_sleepinit(tps65910, pmic_plat_data); -err: - regmap_exit(tps65910->regmap); -regmap_err: - kfree(tps65910); - kfree(init_data); return ret; } -static int tps65910_i2c_remove(struct i2c_client *i2c) +static __devexit int tps65910_i2c_remove(struct i2c_client *i2c) { struct tps65910 *tps65910 = i2c_get_clientdata(i2c); tps65910_irq_exit(tps65910); mfd_remove_devices(tps65910->dev); - regmap_exit(tps65910->regmap); - kfree(tps65910); return 0; } @@ -175,9 +282,10 @@ static struct i2c_driver tps65910_i2c_driver = { .driver = { .name = "tps65910", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tps65910_of_match), }, .probe = tps65910_i2c_probe, - .remove = tps65910_i2c_remove, + .remove = __devexit_p(tps65910_i2c_remove), .id_table = tps65910_i2c_id, }; diff --git a/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c b/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c index ed44cdefe43b..8a60be2298c8 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c @@ -1082,7 +1082,7 @@ woal_cfg80211_assoc(moal_private * priv, void *sme) goto done; } - if (channel) { + if (mode == MLAN_BSS_MODE_IBSS && channel) { /* Get the secondary channel offset */ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg)); if (req == NULL) { diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 67093e3f1cd7..28c58a1c19b1 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -257,6 +257,16 @@ config REGULATOR_AB3100 AB3100 analog baseband dealing with power regulators for the system. +config REGULATOR_RC5T583 + tristate "RICOH RC5T583 Power regulators" + depends on MFD_RC5T583 + help + Select this option to enable the power regulator of RICOH + PMIC RC5T583. + This driver supports the control of different power rails of device + through regulator interface. The device supports multiple DCDC/LDO + outputs which can be controlled by i2c communication. + config REGULATOR_TPS6105X tristate "TI TPS6105X Power regulators" depends on TPS6105X diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 7642d39fb8d3..a25ff34afcbc 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o +obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c new file mode 100644 index 000000000000..81a03b281fa0 --- /dev/null +++ b/drivers/regulator/rc5t583-regulator.c @@ -0,0 +1,363 @@ +/* + * Regulator driver for RICOH RC5T583 power management chip. + * + * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved. + * Author: Laxman dewangan <ldewangan@nvidia.com> + * + * based on code + * Copyright (C) 2011 RICOH COMPANY,LTD + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/gpio.h> +#include <linux/mfd/rc5t583.h> + +struct rc5t583_regulator_info { + int deepsleep_id; + + /* Regulator register address.*/ + uint8_t reg_en_reg; + uint8_t en_bit; + uint8_t reg_disc_reg; + uint8_t disc_bit; + uint8_t vout_reg; + uint8_t vout_mask; + uint8_t deepsleep_reg; + + /* Chip constraints on regulator behavior */ + int min_uV; + int max_uV; + int step_uV; + + /* Regulator specific turn-on delay and voltage settling time*/ + int enable_uv_per_us; + int change_uv_per_us; + + /* Used by regulator core */ + struct regulator_desc desc; +}; + +struct rc5t583_regulator { + struct rc5t583_regulator_info *reg_info; + + /* Devices */ + struct device *dev; + struct rc5t583 *mfd; + struct regulator_dev *rdev; +}; + +static int rc5t583_reg_is_enabled(struct regulator_dev *rdev) +{ + struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); + struct rc5t583_regulator_info *ri = reg->reg_info; + uint8_t control; + int ret; + + ret = rc5t583_read(reg->mfd->dev, ri->reg_en_reg, &control); + if (ret < 0) { + dev_err(&rdev->dev, + "Error in reading the control register 0x%02x\n", + ri->reg_en_reg); + return ret; + } + return !!(control & BIT(ri->en_bit)); +} + +static int rc5t583_reg_enable(struct regulator_dev *rdev) +{ + struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); + struct rc5t583_regulator_info *ri = reg->reg_info; + int ret; + + ret = rc5t583_set_bits(reg->mfd->dev, ri->reg_en_reg, + (1 << ri->en_bit)); + if (ret < 0) { + dev_err(&rdev->dev, + "Error in setting bit of STATE register 0x%02x\n", + ri->reg_en_reg); + return ret; + } + return ret; +} + +static int rc5t583_reg_disable(struct regulator_dev *rdev) +{ + struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); + struct rc5t583_regulator_info *ri = reg->reg_info; + int ret; + + ret = rc5t583_clear_bits(reg->mfd->dev, ri->reg_en_reg, + (1 << ri->en_bit)); + if (ret < 0) + dev_err(&rdev->dev, + "Error in clearing bit of STATE register 0x%02x\n", + ri->reg_en_reg); + + return ret; +} + +static int rc5t583_list_voltage(struct regulator_dev *rdev, unsigned selector) +{ + struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); + struct rc5t583_regulator_info *ri = reg->reg_info; + return ri->min_uV + (ri->step_uV * selector); +} + +static int rc5t583_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) +{ + struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); + struct rc5t583_regulator_info *ri = reg->reg_info; + int ret; + if (selector >= rdev->desc->n_voltages) { + dev_err(&rdev->dev, "Invalid selector 0x%02x\n", selector); + return -EINVAL; + } + + ret = rc5t583_update(reg->mfd->dev, ri->vout_reg, + selector, ri->vout_mask); + if (ret < 0) + dev_err(&rdev->dev, + "Error in update voltage register 0x%02x\n", ri->vout_reg); + return ret; +} + +static int rc5t583_get_voltage_sel(struct regulator_dev *rdev) +{ + struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); + struct rc5t583_regulator_info *ri = reg->reg_info; + uint8_t vsel; + int ret; + ret = rc5t583_read(reg->mfd->dev, ri->vout_reg, &vsel); + if (ret < 0) { + dev_err(&rdev->dev, + "Error in reading voltage register 0x%02x\n", ri->vout_reg); + return ret; + } + return vsel & ri->vout_mask; +} + +static int rc5t583_regulator_enable_time(struct regulator_dev *rdev) +{ + struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); + int vsel = rc5t583_get_voltage_sel(rdev); + int curr_uV = rc5t583_list_voltage(rdev, vsel); + return DIV_ROUND_UP(curr_uV, reg->reg_info->enable_uv_per_us); +} + +static int rc5t583_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, unsigned int new_selector) +{ + struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); + int old_uV, new_uV; + old_uV = rc5t583_list_voltage(rdev, old_selector); + + if (old_uV < 0) + return old_uV; + + new_uV = rc5t583_list_voltage(rdev, new_selector); + if (new_uV < 0) + return new_uV; + + return DIV_ROUND_UP(abs(old_uV - new_uV), + reg->reg_info->change_uv_per_us); +} + + +static struct regulator_ops rc5t583_ops = { + .is_enabled = rc5t583_reg_is_enabled, + .enable = rc5t583_reg_enable, + .disable = rc5t583_reg_disable, + .enable_time = rc5t583_regulator_enable_time, + .get_voltage_sel = rc5t583_get_voltage_sel, + .set_voltage_sel = rc5t583_set_voltage_sel, + .list_voltage = rc5t583_list_voltage, + .set_voltage_time_sel = rc5t583_set_voltage_time_sel, +}; + +#define RC5T583_REG(_id, _en_reg, _en_bit, _disc_reg, _disc_bit, _vout_reg, \ + _vout_mask, _ds_reg, _min_mv, _max_mv, _step_uV, _enable_mv) \ +{ \ + .reg_en_reg = RC5T583_REG_##_en_reg, \ + .en_bit = _en_bit, \ + .reg_disc_reg = RC5T583_REG_##_disc_reg, \ + .disc_bit = _disc_bit, \ + .vout_reg = RC5T583_REG_##_vout_reg, \ + .vout_mask = _vout_mask, \ + .deepsleep_reg = RC5T583_REG_##_ds_reg, \ + .min_uV = _min_mv * 1000, \ + .max_uV = _max_mv * 1000, \ + .step_uV = _step_uV, \ + .enable_uv_per_us = _enable_mv * 1000, \ + .change_uv_per_us = 40 * 1000, \ + .deepsleep_id = RC5T583_DS_##_id, \ + .desc = { \ + .name = "rc5t583-regulator-"#_id, \ + .id = RC5T583_REGULATOR_##_id, \ + .n_voltages = (_max_mv - _min_mv) * 1000 / _step_uV + 1, \ + .ops = &rc5t583_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + }, \ +} + +static struct rc5t583_regulator_info rc5t583_reg_info[RC5T583_REGULATOR_MAX] = { + RC5T583_REG(DC0, DC0CTL, 0, DC0CTL, 1, DC0DAC, 0x7F, DC0DAC_DS, + 700, 1500, 12500, 4), + RC5T583_REG(DC1, DC1CTL, 0, DC1CTL, 1, DC1DAC, 0x7F, DC1DAC_DS, + 700, 1500, 12500, 14), + RC5T583_REG(DC2, DC2CTL, 0, DC2CTL, 1, DC2DAC, 0x7F, DC2DAC_DS, + 900, 2400, 12500, 14), + RC5T583_REG(DC3, DC3CTL, 0, DC3CTL, 1, DC3DAC, 0x7F, DC3DAC_DS, + 900, 2400, 12500, 14), + RC5T583_REG(LDO0, LDOEN2, 0, LDODIS2, 0, LDO0DAC, 0x7F, LDO0DAC_DS, + 900, 3400, 25000, 160), + RC5T583_REG(LDO1, LDOEN2, 1, LDODIS2, 1, LDO1DAC, 0x7F, LDO1DAC_DS, + 900, 3400, 25000, 160), + RC5T583_REG(LDO2, LDOEN2, 2, LDODIS2, 2, LDO2DAC, 0x7F, LDO2DAC_DS, + 900, 3400, 25000, 160), + RC5T583_REG(LDO3, LDOEN2, 3, LDODIS2, 3, LDO3DAC, 0x7F, LDO3DAC_DS, + 900, 3400, 25000, 160), + RC5T583_REG(LDO4, LDOEN2, 4, LDODIS2, 4, LDO4DAC, 0x3F, LDO4DAC_DS, + 750, 1500, 12500, 133), + RC5T583_REG(LDO5, LDOEN2, 5, LDODIS2, 5, LDO5DAC, 0x7F, LDO5DAC_DS, + 900, 3400, 25000, 267), + RC5T583_REG(LDO6, LDOEN2, 6, LDODIS2, 6, LDO6DAC, 0x7F, LDO6DAC_DS, + 900, 3400, 25000, 133), + RC5T583_REG(LDO7, LDOEN2, 7, LDODIS2, 7, LDO7DAC, 0x7F, LDO7DAC_DS, + 900, 3400, 25000, 233), + RC5T583_REG(LDO8, LDOEN1, 0, LDODIS1, 0, LDO8DAC, 0x7F, LDO8DAC_DS, + 900, 3400, 25000, 233), + RC5T583_REG(LDO9, LDOEN1, 1, LDODIS1, 1, LDO9DAC, 0x7F, LDO9DAC_DS, + 900, 3400, 25000, 133), +}; + +static int __devinit rc5t583_regulator_probe(struct platform_device *pdev) +{ + struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent); + struct rc5t583_platform_data *pdata = dev_get_platdata(rc5t583->dev); + struct regulator_init_data *reg_data; + struct rc5t583_regulator *reg = NULL; + struct rc5t583_regulator *regs; + struct regulator_dev *rdev; + struct rc5t583_regulator_info *ri; + int ret; + int id; + + if (!pdata) { + dev_err(&pdev->dev, "No platform data, exiting...\n"); + return -ENODEV; + } + + regs = devm_kzalloc(&pdev->dev, RC5T583_REGULATOR_MAX * + sizeof(struct rc5t583_regulator), GFP_KERNEL); + if (!regs) { + dev_err(&pdev->dev, "Memory allocation failed exiting..\n"); + return -ENOMEM; + } + + + for (id = 0; id < RC5T583_REGULATOR_MAX; ++id) { + reg_data = pdata->reg_init_data[id]; + + /* No need to register if there is no regulator data */ + if (!reg_data) + continue; + + reg = ®s[id]; + ri = &rc5t583_reg_info[id]; + reg->reg_info = ri; + reg->mfd = rc5t583; + reg->dev = &pdev->dev; + + if (ri->deepsleep_id == RC5T583_DS_NONE) + goto skip_ext_pwr_config; + + ret = rc5t583_ext_power_req_config(rc5t583->dev, + ri->deepsleep_id, + pdata->regulator_ext_pwr_control[id], + pdata->regulator_deepsleep_slot[id]); + /* + * Configuring external control is not a major issue, + * just give warning. + */ + if (ret < 0) + dev_warn(&pdev->dev, + "Failed to configure ext control %d\n", id); + +skip_ext_pwr_config: + rdev = regulator_register(&ri->desc, &pdev->dev, reg_data, reg); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "Failed to register regulator %s\n", + ri->desc.name); + ret = PTR_ERR(rdev); + goto clean_exit; + } + reg->rdev = rdev; + } + platform_set_drvdata(pdev, regs); + return 0; + +clean_exit: + while (--id >= 0) + regulator_unregister(regs[id].rdev); + + return ret; +} + +static int __devexit rc5t583_regulator_remove(struct platform_device *pdev) +{ + struct rc5t583_regulator *regs = platform_get_drvdata(pdev); + int id; + + for (id = 0; id < RC5T583_REGULATOR_MAX; ++id) + regulator_unregister(regs[id].rdev); + return 0; +} + +static struct platform_driver rc5t583_regulator_driver = { + .driver = { + .name = "rc5t583-regulator", + .owner = THIS_MODULE, + }, + .probe = rc5t583_regulator_probe, + .remove = __devexit_p(rc5t583_regulator_remove), +}; + +static int __init rc5t583_regulator_init(void) +{ + return platform_driver_register(&rc5t583_regulator_driver); +} +subsys_initcall(rc5t583_regulator_init); + +static void __exit rc5t583_regulator_exit(void) +{ + platform_driver_unregister(&rc5t583_regulator_driver); +} +module_exit(rc5t583_regulator_exit); + +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_DESCRIPTION("RC5T583 regulator driver"); +MODULE_ALIAS("platform:rc5t583-regulator"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index 7eaf08275376..7db148202436 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -1,7 +1,7 @@ /* * tps62360.c -- TI tps62360 * - * Driver for processor core supply tps62360 and tps62361B + * Driver for processor core supply tps62360, tps62361B, tps62362 and tps62363. * * Copyright (c) 2012, NVIDIA Corporation. * @@ -46,20 +46,20 @@ #define REG_RAMPCTRL 6 #define REG_CHIPID 8 -enum chips {TPS62360, TPS62361}; +#define FORCE_PWM_ENABLE BIT(7) -#define TPS62360_BASE_VOLTAGE 770 +enum chips {TPS62360, TPS62361, TPS62362, TPS62363}; + +#define TPS62360_BASE_VOLTAGE 770000 #define TPS62360_N_VOLTAGES 64 -#define TPS62361_BASE_VOLTAGE 500 +#define TPS62361_BASE_VOLTAGE 500000 #define TPS62361_N_VOLTAGES 128 /* tps 62360 chip information */ struct tps62360_chip { - const char *name; struct device *dev; struct regulator_desc desc; - struct i2c_client *client; struct regulator_dev *rdev; struct regmap *regmap; int chip_id; @@ -68,12 +68,12 @@ struct tps62360_chip { int voltage_base; u8 voltage_reg_mask; bool en_internal_pulldn; - bool en_force_pwm; bool en_discharge; bool valid_gpios; int lru_index[4]; int curr_vset_vsel[4]; int curr_vset_id; + int change_uv_per_us; }; /* @@ -99,6 +99,7 @@ static bool find_voltage_set_register(struct tps62360_chip *tps, bool found = false; int new_vset_reg = tps->lru_index[3]; int found_index = 3; + for (i = 0; i < 4; ++i) { if (tps->curr_vset_vsel[tps->lru_index[i]] == req_vsel) { new_vset_reg = tps->lru_index[i]; @@ -117,7 +118,7 @@ update_lru_index: return found; } -static int tps62360_dcdc_get_voltage(struct regulator_dev *dev) +static int tps62360_dcdc_get_voltage_sel(struct regulator_dev *dev) { struct tps62360_chip *tps = rdev_get_drvdata(dev); int vsel; @@ -126,12 +127,12 @@ static int tps62360_dcdc_get_voltage(struct regulator_dev *dev) ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data); if (ret < 0) { - dev_err(tps->dev, "%s: Error in reading register %d\n", - __func__, REG_VSET0 + tps->curr_vset_id); + dev_err(tps->dev, "%s(): register %d read failed with err %d\n", + __func__, REG_VSET0 + tps->curr_vset_id, ret); return ret; } vsel = (int)data & tps->voltage_reg_mask; - return (tps->voltage_base + vsel * 10) * 1000; + return vsel; } static int tps62360_dcdc_set_voltage(struct regulator_dev *dev, @@ -143,17 +144,13 @@ static int tps62360_dcdc_set_voltage(struct regulator_dev *dev, bool found = false; int new_vset_id = tps->curr_vset_id; - if (max_uV < min_uV) - return -EINVAL; - - if (min_uV > - ((tps->voltage_base + (tps->desc.n_voltages - 1) * 10) * 1000)) + if ((max_uV < min_uV) || (max_uV < tps->voltage_base)) return -EINVAL; - if (max_uV < tps->voltage_base * 1000) + if (min_uV > (tps->voltage_base + (tps->desc.n_voltages - 1) * 10000)) return -EINVAL; - vsel = DIV_ROUND_UP(min_uV - (tps->voltage_base * 1000), 10000); + vsel = DIV_ROUND_UP(min_uV - tps->voltage_base, 10000); if (selector) *selector = (vsel & tps->voltage_reg_mask); @@ -168,8 +165,9 @@ static int tps62360_dcdc_set_voltage(struct regulator_dev *dev, ret = regmap_update_bits(tps->regmap, REG_VSET0 + new_vset_id, tps->voltage_reg_mask, vsel); if (ret < 0) { - dev_err(tps->dev, "%s: Error in updating register %d\n", - __func__, REG_VSET0 + new_vset_id); + dev_err(tps->dev, + "%s(): register %d update failed with err %d\n", + __func__, REG_VSET0 + new_vset_id, ret); return ret; } tps->curr_vset_id = new_vset_id; @@ -178,8 +176,7 @@ static int tps62360_dcdc_set_voltage(struct regulator_dev *dev, /* Select proper VSET register vio gpios */ if (tps->valid_gpios) { - gpio_set_value_cansleep(tps->vsel0_gpio, - new_vset_id & 0x1); + gpio_set_value_cansleep(tps->vsel0_gpio, new_vset_id & 0x1); gpio_set_value_cansleep(tps->vsel1_gpio, (new_vset_id >> 1) & 0x1); } @@ -191,82 +188,146 @@ static int tps62360_dcdc_list_voltage(struct regulator_dev *dev, { struct tps62360_chip *tps = rdev_get_drvdata(dev); - if ((selector < 0) || (selector >= tps->desc.n_voltages)) + if (selector >= tps->desc.n_voltages) return -EINVAL; - return (tps->voltage_base + selector * 10) * 1000; + + return tps->voltage_base + selector * 10000; } -static struct regulator_ops tps62360_dcdc_ops = { - .get_voltage = tps62360_dcdc_get_voltage, - .set_voltage = tps62360_dcdc_set_voltage, - .list_voltage = tps62360_dcdc_list_voltage, -}; +static int tps62360_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, unsigned int new_selector) +{ + struct tps62360_chip *tps = rdev_get_drvdata(rdev); + int old_uV, new_uV; -static int tps62360_init_force_pwm(struct tps62360_chip *tps, - struct tps62360_regulator_platform_data *pdata, - int vset_id) + old_uV = tps62360_dcdc_list_voltage(rdev, old_selector); + if (old_uV < 0) + return old_uV; + + new_uV = tps62360_dcdc_list_voltage(rdev, new_selector); + if (new_uV < 0) + return new_uV; + + return DIV_ROUND_UP(abs(old_uV - new_uV), tps->change_uv_per_us); +} + +static int tps62360_set_mode(struct regulator_dev *rdev, unsigned int mode) { + struct tps62360_chip *tps = rdev_get_drvdata(rdev); + int i; + int val; + int ret; + + /* Enable force PWM mode in FAST mode only. */ + switch (mode) { + case REGULATOR_MODE_FAST: + val = FORCE_PWM_ENABLE; + break; + + case REGULATOR_MODE_NORMAL: + val = 0; + break; + + default: + return -EINVAL; + } + + if (!tps->valid_gpios) { + ret = regmap_update_bits(tps->regmap, + REG_VSET0 + tps->curr_vset_id, FORCE_PWM_ENABLE, val); + if (ret < 0) + dev_err(tps->dev, + "%s(): register %d update failed with err %d\n", + __func__, REG_VSET0 + tps->curr_vset_id, ret); + return ret; + } + + /* If gpios are valid then all register set need to be control */ + for (i = 0; i < 4; ++i) { + ret = regmap_update_bits(tps->regmap, + REG_VSET0 + i, FORCE_PWM_ENABLE, val); + if (ret < 0) { + dev_err(tps->dev, + "%s(): register %d update failed with err %d\n", + __func__, REG_VSET0 + i, ret); + return ret; + } + } + return ret; +} + +static unsigned int tps62360_get_mode(struct regulator_dev *rdev) +{ + struct tps62360_chip *tps = rdev_get_drvdata(rdev); unsigned int data; int ret; - ret = regmap_read(tps->regmap, REG_VSET0 + vset_id, &data); + + ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data); if (ret < 0) { - dev_err(tps->dev, "%s() fails in writing reg %d\n", - __func__, REG_VSET0 + vset_id); + dev_err(tps->dev, "%s(): register %d read failed with err %d\n", + __func__, REG_VSET0 + tps->curr_vset_id, ret); return ret; } - tps->curr_vset_vsel[vset_id] = data & tps->voltage_reg_mask; - if (pdata->en_force_pwm) - data |= BIT(7); - else - data &= ~BIT(7); - ret = regmap_write(tps->regmap, REG_VSET0 + vset_id, data); - if (ret < 0) - dev_err(tps->dev, "%s() fails in writing reg %d\n", - __func__, REG_VSET0 + vset_id); - return ret; + return (data & FORCE_PWM_ENABLE) ? + REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL; } -static int tps62360_init_dcdc(struct tps62360_chip *tps, +static struct regulator_ops tps62360_dcdc_ops = { + .get_voltage_sel = tps62360_dcdc_get_voltage_sel, + .set_voltage = tps62360_dcdc_set_voltage, + .list_voltage = tps62360_dcdc_list_voltage, + .set_voltage_time_sel = tps62360_set_voltage_time_sel, + .set_mode = tps62360_set_mode, + .get_mode = tps62360_get_mode, +}; + +static int __devinit tps62360_init_dcdc(struct tps62360_chip *tps, struct tps62360_regulator_platform_data *pdata) { int ret; - int i; + unsigned int ramp_ctrl; - /* Initailize internal pull up/down control */ + /* Initialize internal pull up/down control */ if (tps->en_internal_pulldn) ret = regmap_write(tps->regmap, REG_CONTROL, 0xE0); else ret = regmap_write(tps->regmap, REG_CONTROL, 0x0); if (ret < 0) { - dev_err(tps->dev, "%s() fails in writing reg %d\n", - __func__, REG_CONTROL); + dev_err(tps->dev, + "%s(): register %d write failed with err %d\n", + __func__, REG_CONTROL, ret); return ret; } - /* Initailize force PWM mode */ - if (tps->valid_gpios) { - for (i = 0; i < 4; ++i) { - ret = tps62360_init_force_pwm(tps, pdata, i); - if (ret < 0) - return ret; - } - } else { - ret = tps62360_init_force_pwm(tps, pdata, tps->curr_vset_id); - if (ret < 0) - return ret; - } - /* Reset output discharge path to reduce power consumption */ ret = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), 0); - if (ret < 0) - dev_err(tps->dev, "%s() fails in updating reg %d\n", - __func__, REG_RAMPCTRL); + if (ret < 0) { + dev_err(tps->dev, + "%s(): register %d update failed with err %d\n", + __func__, REG_RAMPCTRL, ret); + return ret; + } + + /* Get ramp value from ramp control register */ + ret = regmap_read(tps->regmap, REG_RAMPCTRL, &ramp_ctrl); + if (ret < 0) { + dev_err(tps->dev, + "%s(): register %d read failed with err %d\n", + __func__, REG_RAMPCTRL, ret); + return ret; + } + ramp_ctrl = (ramp_ctrl >> 4) & 0x7; + + /* ramp mV/us = 32/(2^ramp_ctrl) */ + tps->change_uv_per_us = DIV_ROUND_UP(32000, BIT(ramp_ctrl)); return ret; } static const struct regmap_config tps62360_regmap_config = { - .reg_bits = 8, - .val_bits = 8, + .reg_bits = 8, + .val_bits = 8, + .max_register = REG_CHIPID, + .cache_type = REGCACHE_RBTREE, }; static int __devinit tps62360_probe(struct i2c_client *client, @@ -280,42 +341,52 @@ static int __devinit tps62360_probe(struct i2c_client *client, pdata = client->dev.platform_data; if (!pdata) { - dev_err(&client->dev, "%s() Err: Platform data not found\n", + dev_err(&client->dev, "%s(): Platform data not found\n", __func__); return -EIO; } tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); if (!tps) { - dev_err(&client->dev, "%s() Err: Memory allocation fails\n", + dev_err(&client->dev, "%s(): Memory allocation failed\n", __func__); return -ENOMEM; } - tps->en_force_pwm = pdata->en_force_pwm; tps->en_discharge = pdata->en_discharge; tps->en_internal_pulldn = pdata->en_internal_pulldn; tps->vsel0_gpio = pdata->vsel0_gpio; tps->vsel1_gpio = pdata->vsel1_gpio; - tps->client = client; tps->dev = &client->dev; - tps->name = id->name; - tps->voltage_base = (id->driver_data == TPS62360) ? - TPS62360_BASE_VOLTAGE : TPS62361_BASE_VOLTAGE; - tps->voltage_reg_mask = (id->driver_data == TPS62360) ? 0x3F : 0x7F; + + switch (id->driver_data) { + case TPS62360: + case TPS62362: + tps->voltage_base = TPS62360_BASE_VOLTAGE; + tps->voltage_reg_mask = 0x3F; + tps->desc.n_voltages = TPS62360_N_VOLTAGES; + break; + case TPS62361: + case TPS62363: + tps->voltage_base = TPS62361_BASE_VOLTAGE; + tps->voltage_reg_mask = 0x7F; + tps->desc.n_voltages = TPS62361_N_VOLTAGES; + break; + default: + return -ENODEV; + } tps->desc.name = id->name; tps->desc.id = 0; - tps->desc.n_voltages = (id->driver_data == TPS62360) ? - TPS62360_N_VOLTAGES : TPS62361_N_VOLTAGES; tps->desc.ops = &tps62360_dcdc_ops; tps->desc.type = REGULATOR_VOLTAGE; tps->desc.owner = THIS_MODULE; - tps->regmap = regmap_init_i2c(client, &tps62360_regmap_config); + tps->regmap = devm_regmap_init_i2c(client, &tps62360_regmap_config); if (IS_ERR(tps->regmap)) { ret = PTR_ERR(tps->regmap); - dev_err(&client->dev, "%s() Err: Failed to allocate register" - "map: %d\n", __func__, ret); + dev_err(&client->dev, + "%s(): regmap allocation failed with err %d\n", + __func__, ret); return ret; } i2c_set_clientdata(client, tps); @@ -326,35 +397,26 @@ static int __devinit tps62360_probe(struct i2c_client *client, tps->valid_gpios = false; if (gpio_is_valid(tps->vsel0_gpio) && gpio_is_valid(tps->vsel1_gpio)) { - ret = gpio_request(tps->vsel0_gpio, "tps62360-vsel0"); + int gpio_flags; + gpio_flags = (pdata->vsel0_def_state) ? + GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + ret = gpio_request_one(tps->vsel0_gpio, + gpio_flags, "tps62360-vsel0"); if (ret) { dev_err(&client->dev, - "Err: Could not obtain vsel0 GPIO %d: %d\n", - tps->vsel0_gpio, ret); - goto err_gpio0; - } - ret = gpio_direction_output(tps->vsel0_gpio, - pdata->vsel0_def_state); - if (ret) { - dev_err(&client->dev, "Err: Could not set direction of" - "vsel0 GPIO %d: %d\n", tps->vsel0_gpio, ret); - gpio_free(tps->vsel0_gpio); + "%s(): Could not obtain vsel0 GPIO %d: %d\n", + __func__, tps->vsel0_gpio, ret); goto err_gpio0; } - ret = gpio_request(tps->vsel1_gpio, "tps62360-vsel1"); + gpio_flags = (pdata->vsel1_def_state) ? + GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + ret = gpio_request_one(tps->vsel1_gpio, + gpio_flags, "tps62360-vsel1"); if (ret) { dev_err(&client->dev, - "Err: Could not obtain vsel1 GPIO %d: %d\n", - tps->vsel1_gpio, ret); - goto err_gpio1; - } - ret = gpio_direction_output(tps->vsel1_gpio, - pdata->vsel1_def_state); - if (ret) { - dev_err(&client->dev, "Err: Could not set direction of" - "vsel1 GPIO %d: %d\n", tps->vsel1_gpio, ret); - gpio_free(tps->vsel1_gpio); + "%s(): Could not obtain vsel1 GPIO %d: %d\n", + __func__, tps->vsel1_gpio, ret); goto err_gpio1; } tps->valid_gpios = true; @@ -371,7 +433,7 @@ static int __devinit tps62360_probe(struct i2c_client *client, ret = tps62360_init_dcdc(tps, pdata); if (ret < 0) { - dev_err(tps->dev, "%s() Err: Init fails with = %d\n", + dev_err(tps->dev, "%s(): Init failed with err = %d\n", __func__, ret); goto err_init; } @@ -380,8 +442,9 @@ static int __devinit tps62360_probe(struct i2c_client *client, rdev = regulator_register(&tps->desc, &client->dev, &pdata->reg_init_data, tps); if (IS_ERR(rdev)) { - dev_err(tps->dev, "%s() Err: Failed to register %s\n", - __func__, id->name); + dev_err(tps->dev, + "%s(): regulator register failed with err %s\n", + __func__, id->name); ret = PTR_ERR(rdev); goto err_init; } @@ -396,7 +459,6 @@ err_gpio1: if (gpio_is_valid(tps->vsel0_gpio)) gpio_free(tps->vsel0_gpio); err_gpio0: - regmap_exit(tps->regmap); return ret; } @@ -417,7 +479,6 @@ static int __devexit tps62360_remove(struct i2c_client *client) gpio_free(tps->vsel0_gpio); regulator_unregister(tps->rdev); - regmap_exit(tps->regmap); return 0; } @@ -432,13 +493,16 @@ static void tps62360_shutdown(struct i2c_client *client) /* Configure the output discharge path */ st = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), BIT(2)); if (st < 0) - dev_err(tps->dev, "%s() fails in updating reg %d\n", - __func__, REG_RAMPCTRL); + dev_err(tps->dev, + "%s(): register %d update failed with err %d\n", + __func__, REG_RAMPCTRL, st); } static const struct i2c_device_id tps62360_id[] = { {.name = "tps62360", .driver_data = TPS62360}, {.name = "tps62361", .driver_data = TPS62361}, + {.name = "tps62362", .driver_data = TPS62362}, + {.name = "tps62363", .driver_data = TPS62363}, {}, }; @@ -468,5 +532,5 @@ static void __exit tps62360_cleanup(void) module_exit(tps62360_cleanup); MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); -MODULE_DESCRIPTION("TPS62360 voltage regulator driver"); +MODULE_DESCRIPTION("TPS6236x voltage regulator driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index fe2f1a8412b7..a2fef3880065 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -331,21 +331,16 @@ struct tps65910_reg { static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg) { - u8 val; + unsigned int val; int err; - err = pmic->mfd->read(pmic->mfd, reg, 1, &val); + err = tps65910_reg_read(pmic->mfd, reg, &val); if (err) return err; return val; } -static inline int tps65910_write(struct tps65910_reg *pmic, u8 reg, u8 val) -{ - return pmic->mfd->write(pmic->mfd, reg, 1, &val); -} - static int tps65910_modify_bits(struct tps65910_reg *pmic, u8 reg, u8 set_mask, u8 clear_mask) { @@ -362,7 +357,7 @@ static int tps65910_modify_bits(struct tps65910_reg *pmic, u8 reg, data &= ~clear_mask; data |= set_mask; - err = tps65910_write(pmic, reg, data); + err = tps65910_reg_write(pmic->mfd, reg, data); if (err) dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg); @@ -371,7 +366,7 @@ out: return err; } -static int tps65910_reg_read(struct tps65910_reg *pmic, u8 reg) +static int tps65910_reg_read_locked(struct tps65910_reg *pmic, u8 reg) { int data; @@ -385,13 +380,13 @@ static int tps65910_reg_read(struct tps65910_reg *pmic, u8 reg) return data; } -static int tps65910_reg_write(struct tps65910_reg *pmic, u8 reg, u8 val) +static int tps65910_reg_write_locked(struct tps65910_reg *pmic, u8 reg, u8 val) { int err; mutex_lock(&pmic->mutex); - err = tps65910_write(pmic, reg, val); + err = tps65910_reg_write(pmic->mfd, reg, val); if (err < 0) dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg); @@ -476,7 +471,7 @@ static int tps65910_is_enabled(struct regulator_dev *dev) if (reg < 0) return reg; - value = tps65910_reg_read(pmic, reg); + value = tps65910_reg_read_locked(pmic, reg); if (value < 0) return value; @@ -493,7 +488,7 @@ static int tps65910_enable(struct regulator_dev *dev) if (reg < 0) return reg; - return tps65910_set_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED); + return tps65910_reg_set_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED); } static int tps65910_disable(struct regulator_dev *dev) @@ -506,7 +501,7 @@ static int tps65910_disable(struct regulator_dev *dev) if (reg < 0) return reg; - return tps65910_clear_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED); + return tps65910_reg_clear_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED); } static int tps65910_enable_time(struct regulator_dev *dev) @@ -532,9 +527,9 @@ static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode) LDO_ST_MODE_BIT); case REGULATOR_MODE_IDLE: value = LDO_ST_ON_BIT | LDO_ST_MODE_BIT; - return tps65910_set_bits(mfd, reg, value); + return tps65910_reg_set_bits(mfd, reg, value); case REGULATOR_MODE_STANDBY: - return tps65910_clear_bits(mfd, reg, LDO_ST_ON_BIT); + return tps65910_reg_clear_bits(mfd, reg, LDO_ST_ON_BIT); } return -EINVAL; @@ -549,7 +544,7 @@ static unsigned int tps65910_get_mode(struct regulator_dev *dev) if (reg < 0) return reg; - value = tps65910_reg_read(pmic, reg); + value = tps65910_reg_read_locked(pmic, reg); if (value < 0) return value; @@ -569,28 +564,28 @@ static int tps65910_get_voltage_dcdc_sel(struct regulator_dev *dev) switch (id) { case TPS65910_REG_VDD1: - opvsel = tps65910_reg_read(pmic, TPS65910_VDD1_OP); - mult = tps65910_reg_read(pmic, TPS65910_VDD1); + opvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD1_OP); + mult = tps65910_reg_read_locked(pmic, TPS65910_VDD1); mult = (mult & VDD1_VGAIN_SEL_MASK) >> VDD1_VGAIN_SEL_SHIFT; - srvsel = tps65910_reg_read(pmic, TPS65910_VDD1_SR); + srvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD1_SR); sr = opvsel & VDD1_OP_CMD_MASK; opvsel &= VDD1_OP_SEL_MASK; srvsel &= VDD1_SR_SEL_MASK; vselmax = 75; break; case TPS65910_REG_VDD2: - opvsel = tps65910_reg_read(pmic, TPS65910_VDD2_OP); - mult = tps65910_reg_read(pmic, TPS65910_VDD2); + opvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD2_OP); + mult = tps65910_reg_read_locked(pmic, TPS65910_VDD2); mult = (mult & VDD2_VGAIN_SEL_MASK) >> VDD2_VGAIN_SEL_SHIFT; - srvsel = tps65910_reg_read(pmic, TPS65910_VDD2_SR); + srvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD2_SR); sr = opvsel & VDD2_OP_CMD_MASK; opvsel &= VDD2_OP_SEL_MASK; srvsel &= VDD2_SR_SEL_MASK; vselmax = 75; break; case TPS65911_REG_VDDCTRL: - opvsel = tps65910_reg_read(pmic, TPS65911_VDDCTRL_OP); - srvsel = tps65910_reg_read(pmic, TPS65911_VDDCTRL_SR); + opvsel = tps65910_reg_read_locked(pmic, TPS65911_VDDCTRL_OP); + srvsel = tps65910_reg_read_locked(pmic, TPS65911_VDDCTRL_SR); sr = opvsel & VDDCTRL_OP_CMD_MASK; opvsel &= VDDCTRL_OP_SEL_MASK; srvsel &= VDDCTRL_SR_SEL_MASK; @@ -630,7 +625,7 @@ static int tps65910_get_voltage(struct regulator_dev *dev) if (reg < 0) return reg; - value = tps65910_reg_read(pmic, reg); + value = tps65910_reg_read_locked(pmic, reg); if (value < 0) return value; @@ -669,7 +664,7 @@ static int tps65911_get_voltage(struct regulator_dev *dev) reg = pmic->get_ctrl_reg(id); - value = tps65910_reg_read(pmic, reg); + value = tps65910_reg_read_locked(pmic, reg); switch (id) { case TPS65911_REG_LDO1: @@ -728,7 +723,7 @@ static int tps65910_set_voltage_dcdc_sel(struct regulator_dev *dev, tps65910_modify_bits(pmic, TPS65910_VDD1, (dcdc_mult << VDD1_VGAIN_SEL_SHIFT), VDD1_VGAIN_SEL_MASK); - tps65910_reg_write(pmic, TPS65910_VDD1_OP, vsel); + tps65910_reg_write_locked(pmic, TPS65910_VDD1_OP, vsel); break; case TPS65910_REG_VDD2: dcdc_mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1; @@ -739,11 +734,11 @@ static int tps65910_set_voltage_dcdc_sel(struct regulator_dev *dev, tps65910_modify_bits(pmic, TPS65910_VDD2, (dcdc_mult << VDD2_VGAIN_SEL_SHIFT), VDD1_VGAIN_SEL_MASK); - tps65910_reg_write(pmic, TPS65910_VDD2_OP, vsel); + tps65910_reg_write_locked(pmic, TPS65910_VDD2_OP, vsel); break; case TPS65911_REG_VDDCTRL: vsel = selector + 3; - tps65910_reg_write(pmic, TPS65911_VDDCTRL_OP, vsel); + tps65910_reg_write_locked(pmic, TPS65911_VDDCTRL_OP, vsel); } return 0; @@ -994,10 +989,10 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic, /* External EN1 control */ if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1) - ret = tps65910_set_bits(mfd, + ret = tps65910_reg_set_bits(mfd, TPS65910_EN1_LDO_ASS + regoffs, bit_pos); else - ret = tps65910_clear_bits(mfd, + ret = tps65910_reg_clear_bits(mfd, TPS65910_EN1_LDO_ASS + regoffs, bit_pos); if (ret < 0) { dev_err(mfd->dev, @@ -1007,10 +1002,10 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic, /* External EN2 control */ if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2) - ret = tps65910_set_bits(mfd, + ret = tps65910_reg_set_bits(mfd, TPS65910_EN2_LDO_ASS + regoffs, bit_pos); else - ret = tps65910_clear_bits(mfd, + ret = tps65910_reg_clear_bits(mfd, TPS65910_EN2_LDO_ASS + regoffs, bit_pos); if (ret < 0) { dev_err(mfd->dev, @@ -1022,10 +1017,10 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic, if ((tps65910_chip_id(mfd) == TPS65910) && (id >= TPS65910_REG_VDIG1)) { if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3) - ret = tps65910_set_bits(mfd, + ret = tps65910_reg_set_bits(mfd, TPS65910_EN3_LDO_ASS + regoffs, bit_pos); else - ret = tps65910_clear_bits(mfd, + ret = tps65910_reg_clear_bits(mfd, TPS65910_EN3_LDO_ASS + regoffs, bit_pos); if (ret < 0) { dev_err(mfd->dev, @@ -1037,10 +1032,10 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic, /* Return if no external control is selected */ if (!(ext_sleep_config & EXT_SLEEP_CONTROL)) { /* Clear all sleep controls */ - ret = tps65910_clear_bits(mfd, + ret = tps65910_reg_clear_bits(mfd, TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos); if (!ret) - ret = tps65910_clear_bits(mfd, + ret = tps65910_reg_clear_bits(mfd, TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); if (ret < 0) dev_err(mfd->dev, @@ -1059,32 +1054,33 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic, (tps65910_chip_id(mfd) == TPS65911))) { int op_reg_add = pmic->get_ctrl_reg(id) + 1; int sr_reg_add = pmic->get_ctrl_reg(id) + 2; - int opvsel = tps65910_reg_read(pmic, op_reg_add); - int srvsel = tps65910_reg_read(pmic, sr_reg_add); + int opvsel = tps65910_reg_read_locked(pmic, op_reg_add); + int srvsel = tps65910_reg_read_locked(pmic, sr_reg_add); if (opvsel & VDD1_OP_CMD_MASK) { u8 reg_val = srvsel & VDD1_OP_SEL_MASK; - ret = tps65910_reg_write(pmic, op_reg_add, reg_val); + ret = tps65910_reg_write_locked(pmic, op_reg_add, + reg_val); if (ret < 0) { dev_err(mfd->dev, "Error in configuring op register\n"); return ret; } } - ret = tps65910_reg_write(pmic, sr_reg_add, 0); + ret = tps65910_reg_write_locked(pmic, sr_reg_add, 0); if (ret < 0) { dev_err(mfd->dev, "Error in settting sr register\n"); return ret; } } - ret = tps65910_clear_bits(mfd, + ret = tps65910_reg_clear_bits(mfd, TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos); if (!ret) { if (ext_sleep_config & TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP) - ret = tps65910_set_bits(mfd, + ret = tps65910_reg_set_bits(mfd, TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); else - ret = tps65910_clear_bits(mfd, + ret = tps65910_reg_clear_bits(mfd, TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); } if (ret < 0) @@ -1117,7 +1113,7 @@ static __devinit int tps65910_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pmic); /* Give control of all register to control port */ - tps65910_set_bits(pmic->mfd, TPS65910_DEVCTRL, + tps65910_reg_set_bits(pmic->mfd, TPS65910_DEVCTRL, DEVCTRL_SR_CTL_I2C_SEL_MASK); switch(tps65910_chip_id(tps65910)) { diff --git a/drivers/rtc/rtc-tps80031.c b/drivers/rtc/rtc-tps80031.c index 70d6734a5708..b2b9d04171c5 100644 --- a/drivers/rtc/rtc-tps80031.c +++ b/drivers/rtc/rtc-tps80031.c @@ -31,6 +31,7 @@ #include <linux/platform_device.h> #include <linux/rtc.h> #include <linux/slab.h> +#include <linux/gpio.h> #define RTC_CTRL 0x10 #define RTC_STATUS 0x11 @@ -65,8 +66,25 @@ struct tps80031_rtc { int irq; struct rtc_device *rtc; u8 alarm_irq_enabled; + int msecure_gpio; }; +static inline void tps80031_enable_rtc_write(struct device *dev) +{ + struct tps80031_rtc *rtc = dev_get_drvdata(dev); + + if (rtc->msecure_gpio >= 0) + gpio_set_value(rtc->msecure_gpio, 1); +} + +static inline void tps80031_disable_rtc_write(struct device *dev) +{ + struct tps80031_rtc *rtc = dev_get_drvdata(dev); + + if (rtc->msecure_gpio >= 0) + gpio_set_value(rtc->msecure_gpio, 0); +} + static int tps80031_read_regs(struct device *dev, int reg, int len, uint8_t *val) { @@ -93,13 +111,16 @@ static int tps80031_write_regs(struct device *dev, int reg, int len, uint8_t *val) { int ret; + + tps80031_enable_rtc_write(dev); ret = tps80031_writes(dev->parent, 1, reg, len, val); if (ret < 0) { + tps80031_disable_rtc_write(dev); dev_err(dev->parent, "failed writing reg: %d\n", reg); WARN_ON(1); return ret; } - + tps80031_disable_rtc_write(dev); return 0; } @@ -150,18 +171,24 @@ static int tps80031_rtc_read_time(struct device *dev, struct rtc_time *tm) static int tps80031_rtc_stop(struct device *dev) { int err; + + tps80031_enable_rtc_write(dev); err = tps80031_clr_bits(dev->parent, 1, RTC_CTRL, STOP_RTC); if (err < 0) dev_err(dev->parent, "failed to stop RTC. err: %d\n", err); + tps80031_disable_rtc_write(dev); return err; } static int tps80031_rtc_start(struct device *dev) { int err; + + tps80031_enable_rtc_write(dev); err = tps80031_set_bits(dev->parent, 1, RTC_CTRL, STOP_RTC); if (err < 0) dev_err(dev->parent, "failed to start RTC. err: %d\n", err); + tps80031_disable_rtc_write(dev); return err; } @@ -262,7 +289,9 @@ static int tps80031_rtc_alarm_irq_enable(struct device *dev, if (rtc->alarm_irq_enabled) return 0; + tps80031_enable_rtc_write(dev); err = tps80031_set_bits(p, 1, RTC_INT, ENABLE_ALARM_INT); + tps80031_disable_rtc_write(dev); if (err < 0) { dev_err(p, "failed to set ALRM int. err: %d\n", err); return err; @@ -271,7 +300,9 @@ static int tps80031_rtc_alarm_irq_enable(struct device *dev, } else { if(!rtc->alarm_irq_enabled) return 0; + tps80031_enable_rtc_write(dev); err = tps80031_clr_bits(p, 1, RTC_INT, ENABLE_ALARM_INT); + tps80031_disable_rtc_write(dev); if (err < 0) { dev_err(p, "failed to clear ALRM int. err: %d\n", err); return err; @@ -303,8 +334,10 @@ static irqreturn_t tps80031_rtc_irq(int irq, void *data) return -EBUSY; } + tps80031_enable_rtc_write(dev); err = tps80031_force_update(dev->parent, 1, RTC_STATUS, ALARM_INT_STATUS, ALARM_INT_STATUS); + tps80031_disable_rtc_write(dev); if (err) { dev_err(dev->parent, "unable to set Alarm INT\n"); return -EBUSY; @@ -335,8 +368,19 @@ static int __devinit tps80031_rtc_probe(struct platform_device *pdev) if (pdata->irq < 0) dev_err(&pdev->dev, "no IRQ specified, wakeup is disabled\n"); + rtc->msecure_gpio = -1; + if (gpio_is_valid(pdata->msecure_gpio)) { + err = gpio_request(pdata->msecure_gpio, "tps80031 msecure"); + if (err == 0) { + rtc->msecure_gpio = pdata->msecure_gpio; + gpio_direction_output(rtc->msecure_gpio, 0); + } else + dev_warn(&pdev->dev, "could not get msecure GPIO\n"); + } + rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &tps80031_rtc_ops, THIS_MODULE); + dev_set_drvdata(&pdev->dev, rtc); if (IS_ERR(rtc->rtc)) { err = PTR_ERR(rtc->rtc); @@ -379,7 +423,9 @@ static int __devinit tps80031_rtc_probe(struct platform_device *pdev) return -EBUSY; } + tps80031_enable_rtc_write(&pdev->dev); err = tps80031_set_bits(pdev->dev.parent, 1, RTC_INT, ENABLE_ALARM_INT); + tps80031_disable_rtc_write(&pdev->dev); if (err) { dev_err(&pdev->dev, "unable to program Interrupt Mask reg\n"); err = -EBUSY; @@ -388,7 +434,6 @@ static int __devinit tps80031_rtc_probe(struct platform_device *pdev) } else rtc->alarm_irq_enabled = 1; - dev_set_drvdata(&pdev->dev, rtc); if (pdata && (pdata->irq >= 0)) { rtc->irq = pdata->irq; err = request_threaded_irq(pdata->irq, NULL, tps80031_rtc_irq, diff --git a/drivers/tty/serial/tegra_hsuart.c b/drivers/tty/serial/tegra_hsuart.c index 8b65e20c4d3e..484e228dc044 100644 --- a/drivers/tty/serial/tegra_hsuart.c +++ b/drivers/tty/serial/tegra_hsuart.c @@ -1263,6 +1263,12 @@ static void tegra_set_termios(struct uart_port *u, struct ktermios *termios, if (t->rts_active) set_rts(t, false); + /* Clear all interrupts as configuration is going to be change */ + uart_writeb(t, t->ier_shadow | UART_IER_RDI, UART_IER); + uart_readb(t, UART_IER); + uart_writeb(t, 0, UART_IER); + uart_readb(t, UART_IER); + /* Parity */ lcr = t->lcr_shadow; lcr &= ~UART_LCR_PARITY; @@ -1335,6 +1341,13 @@ static void tegra_set_termios(struct uart_port *u, struct ktermios *termios, /* update the port timeout based on new settings */ uart_update_timeout(u, termios->c_cflag, baud); + /* Make sure all write has completed */ + uart_readb(t, UART_IER); + + /* Reenable interrupt */ + uart_writeb(t, t->ier_shadow, UART_IER); + uart_readb(t, UART_IER); + spin_unlock_irqrestore(&u->lock, flags); dev_vdbg(t->uport.dev, "-tegra_set_termios\n"); return; diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index c5fa8160bffe..98f3d5106a38 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -224,7 +224,7 @@ static int tegra_ehci_hub_control( status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1]; /* Ensure the port PORT_SUSPEND and PORT_RESUME has cleared */ if (handshake(ehci, status_reg, (PORT_SUSPEND | PORT_RESUME), 0, 25000)) { - pr_err("%s: timeout waiting for SUSPEND to clear\n", __func__); + EHCI_DBG("%s: timeout waiting for SUSPEND to clear\n", __func__); } tegra_usb_phy_post_resume(tegra->phy); tegra->port_resuming = 0; @@ -241,6 +241,11 @@ static int tegra_ehci_hub_control( if (wValue == USB_PORT_FEAT_SUSPEND) { tegra_usb_phy_pre_resume(tegra->phy, false); tegra->port_resuming = 1; + } else if (wValue == USB_PORT_FEAT_ENABLE) { + u32 temp; + temp = ehci_readl(ehci, &ehci->regs->port_status[0]) & ~PORT_RWC_BITS; + ehci_writel(ehci, temp & ~PORT_PE, &ehci->regs->port_status[0]); + return retval; } break; } @@ -264,6 +269,12 @@ static int tegra_ehci_hub_control( tegra_usb_phy_port_power(tegra->phy); } break; + case ClearPortFeature: + if (wValue == USB_PORT_FEAT_SUSPEND) { + /* tegra USB controller needs 25 ms to resume the port */ + ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25); + } + break; } } diff --git a/drivers/usb/otg/tegra-otg.c b/drivers/usb/otg/tegra-otg.c index 4c590076f73e..b5106faf68bd 100644 --- a/drivers/usb/otg/tegra-otg.c +++ b/drivers/usb/otg/tegra-otg.c @@ -375,10 +375,8 @@ static ssize_t store_host_en(struct device *dev, struct device_attribute *attr, unsigned long host; int err; - err = kstrtoul(buf, 10, &host); - if (err < 0) { - return err; - } + if (sscanf(buf, "%d", &host) != 1 || host < 0 || host > 1) + return -EINVAL; if (host) { enable_interrupt(tegra, false); @@ -474,6 +472,8 @@ static int tegra_otg_probe(struct platform_device *pdev) goto err_irq; } + clk_disable(tegra->clk); + return 0; err_irq: diff --git a/drivers/video/tegra/Kconfig b/drivers/video/tegra/Kconfig index 59e27788680d..15c2acfa8cc7 100644 --- a/drivers/video/tegra/Kconfig +++ b/drivers/video/tegra/Kconfig @@ -102,6 +102,15 @@ config NVMAP_PAGE_POOL_SIZE hex default 0x0 +config NVMAP_CACHE_MAINT_BY_SET_WAYS + bool "Enalbe cache maintenance by set/ways" + depends on TEGRA_NVMAP + help + Say Y here to reduce cache maintenance overhead by MVA. + This helps in reducing cache maintenance overhead in the systems, + where inner cache includes only L1. For the systems, where inner cache + includes L1 and L2, keep this option disabled. + config NVMAP_VPR bool "Enable VPR Heap." depends on TEGRA_NVMAP diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index df54578a5b5a..5c960f9e45c0 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -2146,23 +2146,6 @@ static void tegra_dc_vblank(struct work_struct *work) } } -/* Must acquire dc lock and dc one-shot lock before invoking this function. - * Acquire dc one-shot lock first and then dc lock. */ -void tegra_dc_host_trigger(struct tegra_dc *dc) -{ - /* We release the lock here to prevent deadlock between - * cancel_delayed_work_sync and one-shot work. */ - mutex_unlock(&dc->lock); - - cancel_delayed_work_sync(&dc->one_shot_work); - mutex_lock(&dc->lock); - - schedule_delayed_work(&dc->one_shot_work, - msecs_to_jiffies(dc->one_shot_delay_ms)); - tegra_dc_program_bandwidth(dc); - tegra_dc_writel(dc, NC_HOST_TRIG, DC_CMD_STATE_CONTROL); -} - static void tegra_dc_one_shot_worker(struct work_struct *work) { struct tegra_dc *dc = container_of( diff --git a/drivers/video/tegra/dc/dc_config.h b/drivers/video/tegra/dc/dc_config.h index f513cd06dc45..314cd11e77f9 100644 --- a/drivers/video/tegra/dc/dc_config.h +++ b/drivers/video/tegra/dc/dc_config.h @@ -129,13 +129,13 @@ enum tegra_dc_feature_option { }; struct tegra_dc_feature_entry { - int window_index; - enum tegra_dc_feature_option option; + u32 window_index; + u32 option; long arg[ENTRY_SIZE]; }; struct tegra_dc_feature { - unsigned num_entries; + u32 num_entries; struct tegra_dc_feature_entry *entries; }; diff --git a/drivers/video/tegra/dc/dsi.c b/drivers/video/tegra/dc/dsi.c index e402c416b779..6624a8e8f52c 100644 --- a/drivers/video/tegra/dc/dsi.c +++ b/drivers/video/tegra/dc/dsi.c @@ -1625,7 +1625,7 @@ static void tegra_dsi_pad_calibration(struct tegra_dc_dsi_data *dsi) tegra_vi_csi_writel(val, CSI_CIL_PAD_CONFIG); } -static void tegra_dsi_panelB_enable() +static void tegra_dsi_panelB_enable(void) { unsigned int val; @@ -2751,8 +2751,8 @@ static int tegra_dc_dsi_cp_info(struct tegra_dc_dsi_data *dsi, struct tegra_dsi_out *p_dsi) { struct tegra_dsi_cmd *p_init_cmd; - struct tegra_dsi_cmd *p_early_suspend_cmd; - struct tegra_dsi_cmd *p_late_resume_cmd; + struct tegra_dsi_cmd *p_early_suspend_cmd = NULL; + struct tegra_dsi_cmd *p_late_resume_cmd = NULL; struct tegra_dsi_cmd *p_suspend_cmd; int err; diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c index c349a4720d2e..a8de7a7a26e0 100644 --- a/drivers/video/tegra/dc/ext/dev.c +++ b/drivers/video/tegra/dc/ext/dev.c @@ -708,6 +708,21 @@ static int tegra_dc_ext_get_status(struct tegra_dc_ext_user *user, return 0; } +static int tegra_dc_ext_get_feature(struct tegra_dc_ext_user *user, + struct tegra_dc_ext_feature *feature) +{ + struct tegra_dc *dc = user->ext->dc; + struct tegra_dc_feature *table = dc->feature; + + if (dc->enabled && feature->entries) { + feature->length = table->num_entries; + memcpy(feature->entries, table->entries, table->num_entries * + sizeof(struct tegra_dc_feature_entry)); + } + + return 0; +} + static long tegra_dc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -805,6 +820,22 @@ static long tegra_dc_ioctl(struct file *filp, unsigned int cmd, return tegra_dc_ext_set_lut(user, &args); } + case TEGRA_DC_EXT_GET_FEATURES: + { + struct tegra_dc_ext_feature args; + int ret; + + if (copy_from_user(&args, user_arg, sizeof(args))) + return -EFAULT; + + ret = tegra_dc_ext_get_feature(user, &args); + + if (copy_to_user(user_arg, &args, sizeof(args))) + return -EFAULT; + + return ret; + } + default: return -EINVAL; } diff --git a/drivers/video/tegra/dc/nvsd.c b/drivers/video/tegra/dc/nvsd.c index 65d518759243..860dd8dab1fd 100644 --- a/drivers/video/tegra/dc/nvsd.c +++ b/drivers/video/tegra/dc/nvsd.c @@ -378,7 +378,10 @@ void nvsd_init(struct tegra_dc *dc, struct tegra_dc_sd_settings *settings) val = tegra_dc_readl(dc, DC_DISP_SD_CONTROL); if (val & SD_ENABLE_NORMAL) - i = tegra_dc_readl(dc, DC_DISP_SD_HW_K_VALUES); + if (settings->phase_in_adjustments) + i = tegra_dc_readl(dc, DC_DISP_SD_MAN_K_VALUES); + else + i = tegra_dc_readl(dc, DC_DISP_SD_HW_K_VALUES); else i = 0; /* 0 values for RGB = 1.0, i.e. non-affected */ diff --git a/drivers/video/tegra/host/Makefile b/drivers/video/tegra/host/Makefile index d47c97571286..f228a3ad0396 100644 --- a/drivers/video/tegra/host/Makefile +++ b/drivers/video/tegra/host/Makefile @@ -17,7 +17,6 @@ obj-$(CONFIG_TEGRA_GRHOST) += gr3d/ obj-$(CONFIG_TEGRA_GRHOST) += host1x/ obj-$(CONFIG_TEGRA_GRHOST) += t20/ obj-$(CONFIG_TEGRA_GRHOST) += t30/ -obj-$(CONFIG_TEGRA_GRHOST) += dsi/ obj-$(CONFIG_TEGRA_GRHOST) += gr2d/ obj-$(CONFIG_TEGRA_GRHOST) += isp/ obj-$(CONFIG_TEGRA_GRHOST) += vi/ diff --git a/drivers/video/tegra/host/bus_client.c b/drivers/video/tegra/host/bus_client.c index 87aa9c64d363..6bfce9a3cb2a 100644 --- a/drivers/video/tegra/host/bus_client.c +++ b/drivers/video/tegra/host/bus_client.c @@ -50,10 +50,28 @@ #include "nvhost_job.h" #include "nvhost_hwctx.h" -void nvhost_read_module_regs(struct nvhost_device *ndev, +static int validate_reg(struct nvhost_device *ndev, u32 offset, int count) +{ + struct resource *r = nvhost_get_resource(ndev, IORESOURCE_MEM, 0); + int err = 0; + + if (offset + 4 * count > resource_size(r) + || (offset + 4 * count < offset)) + err = -EPERM; + + return err; +} + +int nvhost_read_module_regs(struct nvhost_device *ndev, u32 offset, int count, u32 *values) { void __iomem *p = ndev->aperture + offset; + int err; + + /* verify offset */ + err = validate_reg(ndev, offset, count); + if (err) + return err; nvhost_module_busy(ndev); while (count--) { @@ -62,12 +80,20 @@ void nvhost_read_module_regs(struct nvhost_device *ndev, } rmb(); nvhost_module_idle(ndev); + + return 0; } -void nvhost_write_module_regs(struct nvhost_device *ndev, +int nvhost_write_module_regs(struct nvhost_device *ndev, u32 offset, int count, const u32 *values) { void __iomem *p = ndev->aperture + offset; + int err; + + /* verify offset */ + err = validate_reg(ndev, offset, count); + if (err) + return err; nvhost_module_busy(ndev); while (count--) { @@ -76,6 +102,8 @@ void nvhost_write_module_regs(struct nvhost_device *ndev, } wmb(); nvhost_module_idle(ndev); + + return 0; } struct nvhost_channel_userctx { @@ -140,7 +168,9 @@ static int nvhost_channelopen(struct inode *inode, struct file *filp) priv->priority = NVHOST_PRIORITY_MEDIUM; priv->clientid = atomic_add_return(1, &nvhost_get_host(ch->dev)->clientid); - priv->timeout = MAX_STUCK_CHECK_COUNT * SYNCPT_CHECK_PERIOD; + priv->timeout = + jiffies_to_msecs(MAX_STUCK_CHECK_COUNT * SYNCPT_CHECK_PERIOD); + return 0; fail: nvhost_channelrelease(inode, filp); @@ -149,14 +179,17 @@ fail: static int set_submit(struct nvhost_channel_userctx *ctx) { - struct device *device = &ctx->ch->dev->dev; + struct nvhost_device *ndev = ctx->ch->dev; + struct nvhost_master *host = nvhost_get_host(ndev); /* submit should have at least 1 cmdbuf */ - if (!ctx->hdr.num_cmdbufs) + if (!ctx->hdr.num_cmdbufs || + !nvhost_syncpt_is_valid(&host->syncpt, + ctx->hdr.syncpt_id)) return -EIO; if (!ctx->nvmap) { - dev_err(device, "no nvmap context set\n"); + dev_err(&ndev->dev, "no nvmap context set\n"); return -EFAULT; } @@ -182,6 +215,11 @@ static void reset_submit(struct nvhost_channel_userctx *ctx) ctx->hdr.num_relocs = 0; ctx->num_relocshifts = 0; ctx->hdr.num_waitchks = 0; + + if (ctx->job) { + nvhost_job_put(ctx->job); + ctx->job = NULL; + } } static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf, @@ -367,11 +405,10 @@ static long nvhost_channelctl(struct file *filp, if ((_IOC_TYPE(cmd) != NVHOST_IOCTL_MAGIC) || (_IOC_NR(cmd) == 0) || - (_IOC_NR(cmd) > NVHOST_IOCTL_CHANNEL_LAST)) + (_IOC_NR(cmd) > NVHOST_IOCTL_CHANNEL_LAST) || + (_IOC_SIZE(cmd) > NVHOST_IOCTL_CHANNEL_MAX_ARG_SIZE)) return -EFAULT; - BUG_ON(_IOC_SIZE(cmd) > NVHOST_IOCTL_CHANNEL_MAX_ARG_SIZE); - if (_IOC_DIR(cmd) & _IOC_WRITE) { if (copy_from_user(buf, (void __user *)arg, _IOC_SIZE(cmd))) return -EFAULT; diff --git a/drivers/video/tegra/host/bus_client.h b/drivers/video/tegra/host/bus_client.h index adc3a704ea5d..e95ea0bc3401 100644 --- a/drivers/video/tegra/host/bus_client.h +++ b/drivers/video/tegra/host/bus_client.h @@ -24,10 +24,10 @@ #include <linux/types.h> struct nvhost_device; -void nvhost_read_module_regs(struct nvhost_device *ndev, +int nvhost_read_module_regs(struct nvhost_device *ndev, u32 offset, int count, u32 *values); -void nvhost_write_module_regs(struct nvhost_device *ndev, +int nvhost_write_module_regs(struct nvhost_device *ndev, u32 offset, int count, const u32 *values); int nvhost_client_user_init(struct nvhost_device *dev); diff --git a/drivers/video/tegra/host/dev.c b/drivers/video/tegra/host/dev.c index ca73528fbeeb..2c05fbfb7477 100644 --- a/drivers/video/tegra/host/dev.c +++ b/drivers/video/tegra/host/dev.c @@ -205,6 +205,7 @@ static int nvhost_ioctl_ctrl_module_regrdwr(struct nvhost_ctrl_userctx *ctx, return -EINVAL; while (num_offsets--) { + int err; int remaining = args->block_size >> 2; u32 offs; if (get_user(offs, offsets)) @@ -216,17 +217,21 @@ static int nvhost_ioctl_ctrl_module_regrdwr(struct nvhost_ctrl_userctx *ctx, if (copy_from_user(vals, values, batch*sizeof(u32))) return -EFAULT; - nvhost_write_module_regs(ndev, + err = nvhost_write_module_regs(ndev, offs, batch, vals); + if (err) + return err; } else { - nvhost_read_module_regs(ndev, + err = nvhost_read_module_regs(ndev, offs, batch, vals); + if (err) + return err; if (copy_to_user(values, vals, batch*sizeof(u32))) return -EFAULT; } remaining -= batch; - offs += batch; + offs += batch*sizeof(u32); values += batch; } } @@ -250,11 +255,10 @@ static long nvhost_ctrlctl(struct file *filp, if ((_IOC_TYPE(cmd) != NVHOST_IOCTL_MAGIC) || (_IOC_NR(cmd) == 0) || - (_IOC_NR(cmd) > NVHOST_IOCTL_CTRL_LAST)) + (_IOC_NR(cmd) > NVHOST_IOCTL_CTRL_LAST) || + (_IOC_SIZE(cmd) > NVHOST_IOCTL_CTRL_MAX_ARG_SIZE)) return -EFAULT; - BUG_ON(_IOC_SIZE(cmd) > NVHOST_IOCTL_CTRL_MAX_ARG_SIZE); - if (_IOC_DIR(cmd) & _IOC_WRITE) { if (copy_from_user(buf, (void __user *)arg, _IOC_SIZE(cmd))) return -EFAULT; diff --git a/drivers/video/tegra/host/dsi/Makefile b/drivers/video/tegra/host/dsi/Makefile deleted file mode 100644 index eb94d3ec4928..000000000000 --- a/drivers/video/tegra/host/dsi/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -GCOV_PROFILE := y -EXTRA_CFLAGS += -Idrivers/video/tegra/host - -nvhost-dsi-objs = \ - dsi.o - -obj-$(CONFIG_TEGRA_GRHOST) += nvhost-dsi.o diff --git a/drivers/video/tegra/host/dsi/dsi.c b/drivers/video/tegra/host/dsi/dsi.c deleted file mode 100644 index 87da8a6f1b8a..000000000000 --- a/drivers/video/tegra/host/dsi/dsi.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * drivers/video/tegra/host/dsi/dsi.c - * - * Tegra Graphics DSI - * - * Copyright (c) 2012, NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "dev.h" -#include "bus_client.h" - -static int dsi_probe(struct nvhost_device *dev, - struct nvhost_device_id *id_table) -{ - return nvhost_client_device_init(dev); -} - -static int __exit dsi_remove(struct nvhost_device *dev) -{ - /* Add clean-up */ - return 0; -} - -static int dsi_suspend(struct nvhost_device *dev, pm_message_t state) -{ - return nvhost_client_device_suspend(dev); -} - -static int dsi_resume(struct nvhost_device *dev) -{ - dev_info(&dev->dev, "resuming\n"); - return 0; -} - -struct nvhost_device *dsi_device; - -static struct nvhost_driver dsi_driver = { - .probe = dsi_probe, - .remove = __exit_p(dsi_remove), -#ifdef CONFIG_PM - .suspend = dsi_suspend, - .resume = dsi_resume, -#endif - .driver = { - .owner = THIS_MODULE, - .name = "dsi", - } -}; - -static int __init dsi_init(void) -{ - int err; - - dsi_device = nvhost_get_device("dsi"); - if (!dsi_device) - return -ENXIO; - - err = nvhost_device_register(dsi_device); - if (err) - return err; - - return nvhost_driver_register(&dsi_driver); -} - -static void __exit dsi_exit(void) -{ - nvhost_driver_unregister(&dsi_driver); -} - -module_init(dsi_init); -module_exit(dsi_exit); diff --git a/drivers/video/tegra/host/gr3d/gr3d_t30.c b/drivers/video/tegra/host/gr3d/gr3d_t30.c index 57f4c779eff8..4bc7c9f92bb5 100644 --- a/drivers/video/tegra/host/gr3d/gr3d_t30.c +++ b/drivers/video/tegra/host/gr3d/gr3d_t30.c @@ -427,6 +427,8 @@ struct nvhost_hwctx_handler *nvhost_gr3d_t30_ctxhandler_init( setup_save(p, save_ptr); + nvmap_munmap(p->save_buf, save_ptr); + p->h.alloc = ctx3d_alloc_v1; p->h.save_push = save_push_v1; p->h.save_service = NULL; diff --git a/drivers/video/tegra/host/nvhost_acm.c b/drivers/video/tegra/host/nvhost_acm.c index 6d96bd023d81..dfd84328307b 100644 --- a/drivers/video/tegra/host/nvhost_acm.c +++ b/drivers/video/tegra/host/nvhost_acm.c @@ -134,7 +134,11 @@ static void to_state_running_locked(struct nvhost_device *dev) for (i = 0; i < dev->num_clks; i++) { int err = clk_enable(dev->clk[i]); - BUG_ON(err); + if (err) { + dev_err(&dev->dev, "Cannot turn on clock %s", + dev->clocks[i].name); + return; + } } if (prev_state == NVHOST_POWER_STATE_POWERGATED @@ -369,7 +373,11 @@ int nvhost_module_init(struct nvhost_device *dev) snprintf(devname, MAX_DEVID_LENGTH, "tegra_%s", dev->name); c = clk_get_sys(devname, dev->clocks[i].name); - BUG_ON(IS_ERR_OR_NULL(c)); + if (IS_ERR_OR_NULL(c)) { + dev_err(&dev->dev, "Cannot get clock %s\n", + dev->clocks[i].name); + continue; + } rate = clk_round_rate(c, rate); clk_enable(c); diff --git a/drivers/video/tegra/host/nvhost_syncpt.h b/drivers/video/tegra/host/nvhost_syncpt.h index b58921bffa9c..fcc9fce72071 100644 --- a/drivers/video/tegra/host/nvhost_syncpt.h +++ b/drivers/video/tegra/host/nvhost_syncpt.h @@ -140,6 +140,11 @@ int nvhost_syncpt_patch_wait(struct nvhost_syncpt *sp, void *patch_addr); void nvhost_syncpt_debug(struct nvhost_syncpt *sp); +static inline int nvhost_syncpt_is_valid(struct nvhost_syncpt *sp, u32 id) +{ + return id != NVSYNCPT_INVALID && id < sp->nb_pts; +} + int nvhost_mutex_try_lock(struct nvhost_syncpt *sp, int idx); void nvhost_mutex_unlock(struct nvhost_syncpt *sp, int idx); diff --git a/drivers/video/tegra/nvmap/nvmap_ioctl.c b/drivers/video/tegra/nvmap/nvmap_ioctl.c index 14787154523f..7a10231982c1 100644 --- a/drivers/video/tegra/nvmap/nvmap_ioctl.c +++ b/drivers/video/tegra/nvmap/nvmap_ioctl.c @@ -540,6 +540,7 @@ static bool fast_cache_maint(struct nvmap_client *client, struct nvmap_handle *h { int ret = false; +#if defined(CONFIG_NVMAP_CACHE_MAINT_BY_SET_WAYS) if ((op == NVMAP_CACHE_OP_INV) || ((end - start) < FLUSH_CLEAN_BY_SET_WAY_THRESHOLD)) goto out; @@ -559,6 +560,7 @@ static bool fast_cache_maint(struct nvmap_client *client, struct nvmap_handle *h } ret = true; out: +#endif return ret; } diff --git a/include/linux/mfd/rc5t583.h b/include/linux/mfd/rc5t583.h index a2c61609d21d..3661c59aa1e9 100644 --- a/include/linux/mfd/rc5t583.h +++ b/include/linux/mfd/rc5t583.h @@ -26,6 +26,7 @@ #include <linux/mutex.h> #include <linux/types.h> +#include <linux/regmap.h> #define RC5T583_MAX_REGS 0xF8 @@ -249,6 +250,26 @@ enum { RC5T583_EXT_PWRREQ2_CONTROL = 0x2, }; +enum { + RC5T583_REGULATOR_DC0, + RC5T583_REGULATOR_DC1, + RC5T583_REGULATOR_DC2, + RC5T583_REGULATOR_DC3, + RC5T583_REGULATOR_LDO0, + RC5T583_REGULATOR_LDO1, + RC5T583_REGULATOR_LDO2, + RC5T583_REGULATOR_LDO3, + RC5T583_REGULATOR_LDO4, + RC5T583_REGULATOR_LDO5, + RC5T583_REGULATOR_LDO6, + RC5T583_REGULATOR_LDO7, + RC5T583_REGULATOR_LDO8, + RC5T583_REGULATOR_LDO9, + + /* Should be last entry */ + RC5T583_REGULATOR_MAX, +}; + struct rc5t583 { struct device *dev; struct regmap *regmap; @@ -271,22 +292,63 @@ struct rc5t583 { * rc5t583_platform_data: Platform data for ricoh rc5t583 pmu. * The board specific data is provided through this structure. * @irq_base: Irq base number on which this device registers their interrupts. + * @gpio_base: GPIO base from which gpio of this device will start. * @enable_shutdown: Enable shutdown through the input pin "shutdown". + * @regulator_deepsleep_slot: The slot number on which device goes to sleep + * in device sleep mode. + * @regulator_ext_pwr_control: External power request regulator control. The + * regulator output enable/disable is controlled by the external + * power request input state. + * @reg_init_data: Regulator init data. */ struct rc5t583_platform_data { int irq_base; + int gpio_base; bool enable_shutdown; + int regulator_deepsleep_slot[RC5T583_REGULATOR_MAX]; + unsigned long regulator_ext_pwr_control[RC5T583_REGULATOR_MAX]; + struct regulator_init_data *reg_init_data[RC5T583_REGULATOR_MAX]; }; -int rc5t583_write(struct device *dev, u8 reg, uint8_t val); -int rc5t583_read(struct device *dev, uint8_t reg, uint8_t *val); -int rc5t583_set_bits(struct device *dev, unsigned int reg, - unsigned int bit_mask); -int rc5t583_clear_bits(struct device *dev, unsigned int reg, - unsigned int bit_mask); -int rc5t583_update(struct device *dev, unsigned int reg, - unsigned int val, unsigned int mask); +static inline int rc5t583_write(struct device *dev, uint8_t reg, uint8_t val) +{ + struct rc5t583 *rc5t583 = dev_get_drvdata(dev); + return regmap_write(rc5t583->regmap, reg, val); +} + +static inline int rc5t583_read(struct device *dev, uint8_t reg, uint8_t *val) +{ + struct rc5t583 *rc5t583 = dev_get_drvdata(dev); + unsigned int ival; + int ret; + ret = regmap_read(rc5t583->regmap, reg, &ival); + if (!ret) + *val = (uint8_t)ival; + return ret; +} + +static inline int rc5t583_set_bits(struct device *dev, unsigned int reg, + unsigned int bit_mask) +{ + struct rc5t583 *rc5t583 = dev_get_drvdata(dev); + return regmap_update_bits(rc5t583->regmap, reg, bit_mask, bit_mask); +} + +static inline int rc5t583_clear_bits(struct device *dev, unsigned int reg, + unsigned int bit_mask) +{ + struct rc5t583 *rc5t583 = dev_get_drvdata(dev); + return regmap_update_bits(rc5t583->regmap, reg, bit_mask, 0); +} + +static inline int rc5t583_update(struct device *dev, unsigned int reg, + unsigned int val, unsigned int mask) +{ + struct rc5t583 *rc5t583 = dev_get_drvdata(dev); + return regmap_update_bits(rc5t583->regmap, reg, mask, val); +} + int rc5t583_ext_power_req_config(struct device *dev, int deepsleep_id, int ext_pwr_req, int deepsleep_slot_nr); int rc5t583_irq_init(struct rc5t583 *rc5t583, int irq, int irq_base); diff --git a/include/linux/mfd/tps65910.h b/include/linux/mfd/tps65910.h index f6021cc9d911..7e4395a2c21b 100644 --- a/include/linux/mfd/tps65910.h +++ b/include/linux/mfd/tps65910.h @@ -17,6 +17,9 @@ #ifndef __LINUX_MFD_TPS65910_H #define __LINUX_MFD_TPS65910_H +#include <linux/gpio.h> +#include <linux/regmap.h> + /* TPS chip id list */ #define TPS65910 0 #define TPS65911 1 @@ -781,6 +784,18 @@ #define TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 0x4 #define TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP 0x8 +/* + * Sleep keepon data: Maintains the state in sleep mode + * @therm_keepon: Keep on the thermal monitoring in sleep state. + * @clkout32k_keepon: Keep on the 32KHz clock output in sleep state. + * @i2chs_keepon: Keep on high speed internal clock in sleep state. + */ +struct tps65910_sleep_keepon_data { + unsigned therm_keepon:1; + unsigned clkout32k_keepon:1; + unsigned i2chs_keepon:1; +}; + /** * struct tps65910_board * Board platform data may be used to initialize regulators. @@ -792,6 +807,8 @@ struct tps65910_board { int irq_base; int vmbch_threshold; int vmbch2_threshold; + bool en_dev_slp; + struct tps65910_sleep_keepon_data *slp_keepon; unsigned long regulator_ext_sleep_control[TPS65910_NUM_REGS]; bool en_gpio_sleep[TPS6591X_MAX_NUM_GPIO]; struct regulator_init_data *tps65910_pmic_init_data[TPS65910_NUM_REGS]; @@ -807,17 +824,12 @@ struct tps65910 { struct regmap *regmap; struct mutex io_mutex; unsigned int id; - int (*read)(struct tps65910 *tps65910, u8 reg, int size, void *dest); - int (*write)(struct tps65910 *tps65910, u8 reg, int size, void *src); /* Client devices */ struct tps65910_pmic *pmic; struct tps65910_rtc *rtc; struct tps65910_power *power; - /* GPIO Handling */ - struct gpio_chip gpio; - /* IRQ Handling */ struct mutex irq_lock; int chip_irq; @@ -831,9 +843,6 @@ struct tps65910_platform_data { int irq_base; }; -int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask); -int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask); -void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base); int tps65910_irq_init(struct tps65910 *tps65910, int irq, struct tps65910_platform_data *pdata); int tps65910_irq_exit(struct tps65910 *tps65910); @@ -843,4 +852,28 @@ static inline int tps65910_chip_id(struct tps65910 *tps65910) return tps65910->id; } +static inline int tps65910_reg_read(struct tps65910 *tps65910, u8 reg, + unsigned int *val) +{ + return regmap_read(tps65910->regmap, reg, val); +} + +static inline int tps65910_reg_write(struct tps65910 *tps65910, u8 reg, + unsigned int val) +{ + return regmap_write(tps65910->regmap, reg, val); +} + +static inline int tps65910_reg_set_bits(struct tps65910 *tps65910, u8 reg, + u8 mask) +{ + return regmap_update_bits(tps65910->regmap, reg, mask, mask); +} + +static inline int tps65910_reg_clear_bits(struct tps65910 *tps65910, u8 reg, + u8 mask) +{ + return regmap_update_bits(tps65910->regmap, reg, mask, 0); +} + #endif /* __LINUX_MFD_TPS65910_H */ diff --git a/include/linux/mfd/tps80031.h b/include/linux/mfd/tps80031.h index 9623a873d311..b3b9480ce596 100644 --- a/include/linux/mfd/tps80031.h +++ b/include/linux/mfd/tps80031.h @@ -165,6 +165,7 @@ struct tps80031_subdev_info { struct tps80031_rtc_platform_data { int irq; struct rtc_time time; + int msecure_gpio; }; struct tps80031_clk32k_init_data { diff --git a/include/linux/of.h b/include/linux/of.h index 9180dc5cb00b..c4b5b52a7515 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -235,6 +235,7 @@ extern void of_attach_node(struct device_node *); extern void of_detach_node(struct device_node *); #endif +#define of_match_ptr(_ptr) (_ptr) #else /* CONFIG_OF */ static inline bool of_have_populated_dt(void) @@ -263,6 +264,7 @@ static inline const void *of_get_property(const struct device_node *node, return NULL; } +#define of_match_ptr(_ptr) NULL #endif /* CONFIG_OF */ static inline int of_property_read_u32(const struct device_node *np, diff --git a/include/linux/pm_qos_params.h b/include/linux/pm_qos_params.h index 5a536cbb25b8..be63f01630a3 100644 --- a/include/linux/pm_qos_params.h +++ b/include/linux/pm_qos_params.h @@ -28,7 +28,7 @@ enum { #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC) #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC) #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0 -#define PM_QOS_MIN_ONLINE_CPUS_DEFAULT_VALUE 1 +#define PM_QOS_MIN_ONLINE_CPUS_DEFAULT_VALUE 0 #define PM_QOS_MAX_ONLINE_CPUS_DEFAULT_VALUE LONG_MAX #define PM_QOS_CPU_FREQ_MIN_DEFAULT_VALUE 0 #define PM_QOS_CPU_FREQ_MAX_DEFAULT_VALUE LONG_MAX diff --git a/include/linux/regulator/tps62360.h b/include/linux/regulator/tps62360.h index 6a5c1b2c751e..6475cd029c42 100644 --- a/include/linux/regulator/tps62360.h +++ b/include/linux/regulator/tps62360.h @@ -32,7 +32,6 @@ * struct tps62360_regulator_platform_data - tps62360 regulator platform data. * * @reg_init_data: The regulator init data. - * @en_force_pwm: Enable force pwm or not. * @en_discharge: Enable discharge the output capacitor via internal * register. * @en_internal_pulldn: internal pull down enable or not. @@ -45,7 +44,6 @@ */ struct tps62360_regulator_platform_data { struct regulator_init_data reg_init_data; - bool en_force_pwm; bool en_discharge; bool en_internal_pulldn; int vsel0_gpio; diff --git a/include/linux/tegra_audio.h b/include/linux/tegra_audio.h index 3975913a5206..ddc9c93498a0 100644 --- a/include/linux/tegra_audio.h +++ b/include/linux/tegra_audio.h @@ -76,7 +76,7 @@ struct dam_srate { #define I2S_MODE_I2S _IOW(TEGRA_AUDIO_MAGIC, 18, unsigned int *) #ifdef CONFIG_SND_SOC_TEGRA -extern bool tegra_is_voice_call_active(); +extern bool tegra_is_voice_call_active(void); #else static inline bool tegra_is_voice_call_active() { diff --git a/include/media/ad5816.h b/include/media/ad5816.h index bfea25ffaddf..c51417ca472b 100644 --- a/include/media/ad5816.h +++ b/include/media/ad5816.h @@ -22,21 +22,19 @@ #include <media/nvc_focus.h> #include <media/nvc.h> -typedef enum ad5816_vreg -{ +typedef enum { AD5816_VREG_VDD = 0, AD5816_VREG_VDD_AF, AD5816_VREG_VDD_I2C -}; +} ad5816_vreg; -typedef enum ad5816_gpio_types -{ +typedef enum { AD5816_GPIO_RESET = 0, AD5816_GPIO_I2CMUX, AD5816_GPIO_GP1, AD5816_GPIO_GP2, AD5816_GPIO_GP3 -}; +} ad5816_gpio_types; struct ad5816_platform_data { @@ -78,4 +76,4 @@ struct ad5816_pdata_info { #endif -/* __AD5816_H__ */
\ No newline at end of file +/* __AD5816_H__ */ diff --git a/include/media/ov2710.h b/include/media/ov2710.h index e3d43056d700..aeeaea8849e0 100644 --- a/include/media/ov2710.h +++ b/include/media/ov2710.h @@ -27,6 +27,7 @@ #define OV2710_IOCTL_SET_COARSE_TIME _IOW('o', 3, __u32) #define OV2710_IOCTL_SET_GAIN _IOW('o', 4, __u16) #define OV2710_IOCTL_GET_STATUS _IOR('o', 5, __u8) +#define OV2710_IOCTL_SET_GROUP_HOLD _IOW('o', 6, struct ov2710_ae) struct ov2710_mode { int xres; @@ -35,6 +36,16 @@ struct ov2710_mode { __u32 coarse_time; __u16 gain; }; + +struct ov2710_ae { + __u32 frame_length; + __u8 frame_length_enable; + __u32 coarse_time; + __u8 coarse_time_enable; + __s32 gain; + __u8 gain_enable; +}; + #ifdef __KERNEL__ struct ov2710_platform_data { int (*power_on)(void); diff --git a/include/video/tegra_dc_ext.h b/include/video/tegra_dc_ext.h index 76bb34b01af1..8f9d0423f516 100644 --- a/include/video/tegra_dc_ext.h +++ b/include/video/tegra_dc_ext.h @@ -211,6 +211,11 @@ struct tegra_dc_ext_status { __u32 pad[3]; }; +struct tegra_dc_ext_feature { + __u32 length; + __u32 *entries; +}; + #define TEGRA_DC_EXT_SET_NVMAP_FD \ _IOW('D', 0x00, __s32) @@ -247,6 +252,9 @@ struct tegra_dc_ext_status { #define TEGRA_DC_EXT_SET_LUT \ _IOW('D', 0x0A, struct tegra_dc_ext_lut) +#define TEGRA_DC_EXT_GET_FEATURES \ + _IOW('D', 0x0B, struct tegra_dc_ext_feature) + enum tegra_dc_ext_control_output_type { TEGRA_DC_EXT_DSI, TEGRA_DC_EXT_LVDS, diff --git a/sound/soc/codecs/rt5639.c b/sound/soc/codecs/rt5639.c index c9b14e9f0bc1..13190e21404b 100644 --- a/sound/soc/codecs/rt5639.c +++ b/sound/soc/codecs/rt5639.c @@ -105,6 +105,18 @@ static int rt5639_reg_init(struct snd_soc_codec *codec) } #endif +static int rt5639_index_sync(struct snd_soc_codec *codec) +{ + int i; + + for (i = 0; i < RT5639_INIT_REG_LEN; i++) + if (RT5639_PRIV_INDEX == init_list[i].reg || + RT5639_PRIV_DATA == init_list[i].reg) + snd_soc_write(codec, init_list[i].reg, + init_list[i].val); + return 0; +} + static const u16 rt5639_reg[RT5639_VENDOR_ID2 + 1] = { [RT5639_RESET] = 0x0008, [RT5639_SPK_VOL] = 0xc8c8, @@ -2213,7 +2225,9 @@ static int rt5639_set_bias_level(struct snd_soc_codec *codec, RT5639_PWR_FV1 | RT5639_PWR_FV2, RT5639_PWR_FV1 | RT5639_PWR_FV2); codec->cache_only = false; + codec->cache_sync = 1; snd_soc_cache_sync(codec); + rt5639_index_sync(codec); } break; @@ -2311,13 +2325,23 @@ static int rt5639_remove(struct snd_soc_codec *codec) #ifdef CONFIG_PM static int rt5639_suspend(struct snd_soc_codec *codec, pm_message_t state) { + rt5639_reset(codec); rt5639_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } static int rt5639_resume(struct snd_soc_codec *codec) { + int ret = 0 ; + + codec->cache_sync = 1; + ret = snd_soc_cache_sync(codec); + if (ret) { + dev_err(codec->dev,"Failed to sync cache: %d\n", ret); + return ret; + } rt5639_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + return 0; } #else diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 8407c638cf8a..49256e2d151d 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -106,6 +106,18 @@ static int rt5640_reg_init(struct snd_soc_codec *codec) } #endif +static int rt5640_index_sync(struct snd_soc_codec *codec) +{ + int i; + + for (i = 0; i < RT5640_INIT_REG_LEN; i++) + if (RT5640_PRIV_INDEX == init_list[i].reg || + RT5640_PRIV_DATA == init_list[i].reg) + snd_soc_write(codec, init_list[i].reg, + init_list[i].val); + return 0; +} + static const u16 rt5640_reg[RT5640_VENDOR_ID2 + 1] = { [RT5640_RESET] = 0x000c, [RT5640_SPK_VOL] = 0xc8c8, @@ -2269,7 +2281,9 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec, RT5640_PWR_FV1 | RT5640_PWR_FV2, RT5640_PWR_FV1 | RT5640_PWR_FV2); codec->cache_only = false; + codec->cache_sync = 1; snd_soc_cache_sync(codec); + rt5640_index_sync(codec); } break; @@ -2381,6 +2395,7 @@ static int rt5640_remove(struct snd_soc_codec *codec) #ifdef CONFIG_PM static int rt5640_suspend(struct snd_soc_codec *codec, pm_message_t state) { + rt5640_reset(codec); rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF); snd_soc_write(codec, RT5640_PWR_ANLG1, 0); @@ -2389,6 +2404,14 @@ static int rt5640_suspend(struct snd_soc_codec *codec, pm_message_t state) static int rt5640_resume(struct snd_soc_codec *codec) { + int ret = 0 ; + + codec->cache_sync = 1; + ret = snd_soc_cache_sync(codec); + if (ret) { + dev_err(codec->dev,"Failed to sync cache: %d\n", ret); + return ret; + } rt5640_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 449359837efb..8be00b840fb5 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -418,6 +418,10 @@ static int tegra30_i2s_tdm_hw_params(struct snd_pcm_substream *substream, i2s_client_bits = TEGRA30_AUDIOCIF_BITS_32; i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_32; break; + default: + dev_err(dev, "unknown slot_width %d\n", + i2s->dsp_config.slot_width); + return -EINVAL; } val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | diff --git a/sound/soc/tegra/tegra_p1852.c b/sound/soc/tegra/tegra_p1852.c index 85b4cee30c5f..199bb8046636 100644 --- a/sound/soc/tegra/tegra_p1852.c +++ b/sound/soc/tegra/tegra_p1852.c @@ -227,6 +227,9 @@ static __devinit int tegra_p1852_driver_probe(struct platform_device *pdev) pdata->codec_info[i].codec_dai_name; tegra_p1852_dai_link[i].name = pdata->codec_info[i].name; + if (pdata->codec_info[i].pcm_driver) + tegra_p1852_dai_link[i].platform_name = + pdata->codec_info[i].pcm_driver; } ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card); |