diff options
241 files changed, 5119 insertions, 1047 deletions
@@ -1823,6 +1823,11 @@ S: Kattreinstr 38 S: D-64295 S: Germany +N: Avi Kivity +E: avi.kivity@gmail.com +D: Kernel-based Virtual Machine (KVM) +S: Ra'annana, Israel + N: Andi Kleen E: andi@firstfloor.org U: http://www.halobates.de diff --git a/Documentation/devicetree/bindings/net/mdio-gpio.txt b/Documentation/devicetree/bindings/net/mdio-gpio.txt index bc9549529014..c79bab025369 100644 --- a/Documentation/devicetree/bindings/net/mdio-gpio.txt +++ b/Documentation/devicetree/bindings/net/mdio-gpio.txt @@ -8,9 +8,16 @@ gpios property as described in section VIII.1 in the following order: MDC, MDIO. +Note: Each gpio-mdio bus should have an alias correctly numbered in "aliases" +node. + Example: -mdio { +aliases { + mdio-gpio0 = <&mdio0>; +}; + +mdio0: mdio { compatible = "virtual,mdio-gpio"; #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/regulator/gpio-regulator.txt b/Documentation/devicetree/bindings/regulator/gpio-regulator.txt new file mode 100644 index 000000000000..63c659800c03 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/gpio-regulator.txt @@ -0,0 +1,37 @@ +GPIO controlled regulators + +Required properties: +- compatible : Must be "regulator-gpio". +- states : Selection of available voltages and GPIO configs. + if there are no states, then use a fixed regulator + +Optional properties: +- enable-gpio : GPIO to use to enable/disable the regulator. +- gpios : GPIO group used to control voltage. +- startup-delay-us : Startup time in microseconds. +- enable-active-high : Polarity of GPIO is active high (default is low). + +Any property defined as part of the core regulator binding defined in +regulator.txt can also be used. + +Example: + + mmciv: gpio-regulator { + compatible = "regulator-gpio"; + + regulator-name = "mmci-gpio-supply"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2600000>; + regulator-boot-on; + + enable-gpio = <&gpio0 23 0x4>; + gpios = <&gpio0 24 0x4 + &gpio0 25 0x4>; + states = <1800000 0x3 + 2200000 0x2 + 2600000 0x1 + 2900000 0x0>; + + startup-delay-us = <100000>; + enable-active-high; + }; diff --git a/Documentation/devicetree/bindings/regulator/max8925-regulator.txt b/Documentation/devicetree/bindings/regulator/max8925-regulator.txt new file mode 100644 index 000000000000..0057695aae8f --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/max8925-regulator.txt @@ -0,0 +1,40 @@ +Max8925 Voltage regulators + +Required nodes: +-nodes: + - SDV1 for SDV SDV1 + - SDV2 for SDV SDV2 + - SDV3 for SDV SDV3 + - LDO1 for LDO LDO1 + - LDO2 for LDO LDO2 + - LDO3 for LDO LDO3 + - LDO4 for LDO LDO4 + - LDO5 for LDO LDO5 + - LDO6 for LDO LDO6 + - LDO7 for LDO LDO7 + - LDO8 for LDO LDO8 + - LDO9 for LDO LDO9 + - LDO10 for LDO LDO10 + - LDO11 for LDO LDO11 + - LDO12 for LDO LDO12 + - LDO13 for LDO LDO13 + - LDO14 for LDO LDO14 + - LDO15 for LDO LDO15 + - LDO16 for LDO LDO16 + - LDO17 for LDO LDO17 + - LDO18 for LDO LDO18 + - LDO19 for LDO LDO19 + - LDO20 for LDO LDO20 + +Optional properties: +- Any optional property defined in bindings/regulator/regulator.txt + +Example: + + SDV1 { + regulator-min-microvolt = <637500>; + regulator-max-microvolt = <1425000>; + regulator-boot-on; + regulator-always-on; + }; + diff --git a/Documentation/devicetree/bindings/regulator/vexpress.txt b/Documentation/devicetree/bindings/regulator/vexpress.txt new file mode 100644 index 000000000000..d775f72487aa --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/vexpress.txt @@ -0,0 +1,32 @@ +Versatile Express voltage regulators +------------------------------------ + +Requires node properties: +- "compatible" value: "arm,vexpress-volt" +- "arm,vexpress-sysreg,func" when controlled via vexpress-sysreg + (see Documentation/devicetree/bindings/arm/vexpress-sysreg.txt + for more details) + +Required regulator properties: +- "regulator-name" +- "regulator-always-on" + +Optional regulator properties: +- "regulator-min-microvolt" +- "regulator-max-microvolt" + +See Documentation/devicetree/bindings/regulator/regulator.txt +for more details about the regulator properties. + +When no "regulator-[min|max]-microvolt" properties are defined, +the device is treated as fixed (or rather "read-only") regulator. + +Example: + volt@0 { + compatible = "arm,vexpress-volt"; + arm,vexpress-sysreg,func = <2 0>; + regulator-name = "Cores"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1050000>; + regulator-always-on; + }; diff --git a/Documentation/networking/vxlan.txt b/Documentation/networking/vxlan.txt index 5b34b762d7d5..6d993510f091 100644 --- a/Documentation/networking/vxlan.txt +++ b/Documentation/networking/vxlan.txt @@ -32,7 +32,7 @@ no entry is in the forwarding table. # ip link delete vxlan0 3. Show vxlan info - # ip -d show vxlan0 + # ip -d link show vxlan0 It is possible to create, destroy and display the vxlan forwarding table using the new bridge command. @@ -41,7 +41,7 @@ forwarding table using the new bridge command. # bridge fdb add to 00:17:42:8a:b4:05 dst 192.19.0.2 dev vxlan0 2. Delete forwarding table entry - # bridge fdb delete 00:17:42:8a:b4:05 + # bridge fdb delete 00:17:42:8a:b4:05 dev vxlan0 3. Show forwarding table # bridge fdb show dev vxlan0 diff --git a/MAINTAINERS b/MAINTAINERS index bb0b27db673f..9386a63ea8f6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -526,17 +526,17 @@ F: drivers/video/geode/ F: arch/x86/include/asm/geode.h AMD IOMMU (AMD-VI) -M: Joerg Roedel <joerg.roedel@amd.com> +M: Joerg Roedel <joro@8bytes.org> L: iommu@lists.linux-foundation.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git -S: Supported +S: Maintained F: drivers/iommu/amd_iommu*.[ch] F: include/linux/amd-iommu.h AMD MICROCODE UPDATE SUPPORT -M: Andreas Herrmann <andreas.herrmann3@amd.com> +M: Andreas Herrmann <herrmann.der.user@googlemail.com> L: amd64-microcode@amd64.org -S: Supported +S: Maintained F: arch/x86/kernel/microcode_amd.c AMS (Apple Motion Sensor) DRIVER @@ -841,6 +841,14 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/kristoffer/linux-hpc.git F: arch/arm/mach-sa1100/jornada720.c F: arch/arm/mach-sa1100/include/mach/jornada720.h +ARM/IGEP MACHINE SUPPORT +M: Enric Balletbo i Serra <eballetbo@gmail.com> +M: Javier Martinez Canillas <javier@dowhile0.org> +L: linux-omap@vger.kernel.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +S: Maintained +F: arch/arm/mach-omap2/board-igep0020.c + ARM/INCOME PXA270 SUPPORT M: Marek Vasut <marek.vasut@gmail.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -2708,10 +2716,10 @@ F: include/linux/edac.h EDAC-AMD64 M: Doug Thompson <dougthompson@xmission.com> -M: Borislav Petkov <borislav.petkov@amd.com> +M: Borislav Petkov <bp@alien8.de> L: linux-edac@vger.kernel.org W: bluesmoke.sourceforge.net -S: Supported +S: Maintained F: drivers/edac/amd64_edac* EDAC-E752X @@ -3753,7 +3761,7 @@ S: Maintained F: drivers/platform/x86/ideapad-laptop.c IDE/ATAPI DRIVERS -M: Borislav Petkov <petkovbb@gmail.com> +M: Borislav Petkov <bp@alien8.de> L: linux-ide@vger.kernel.org S: Maintained F: Documentation/cdrom/ide-cd @@ -4280,8 +4288,8 @@ F: include/linux/lockd/ F: include/linux/sunrpc/ KERNEL VIRTUAL MACHINE (KVM) -M: Avi Kivity <avi@redhat.com> M: Marcelo Tosatti <mtosatti@redhat.com> +M: Gleb Natapov <gleb@redhat.com> L: kvm@vger.kernel.org W: http://kvm.qumranet.com S: Supported @@ -5413,7 +5421,7 @@ S: Maintained F: sound/drivers/opl4/ OPROFILE -M: Robert Richter <robert.richter@amd.com> +M: Robert Richter <rric@kernel.org> L: oprofile-list@lists.sf.net S: Maintained F: arch/*/include/asm/oprofile*.h @@ -8198,7 +8206,7 @@ F: drivers/platform/x86 X86 MCE INFRASTRUCTURE M: Tony Luck <tony.luck@intel.com> -M: Borislav Petkov <bp@amd64.org> +M: Borislav Petkov <bp@alien8.de> L: linux-edac@vger.kernel.org S: Maintained F: arch/x86/kernel/cpu/mcheck/* @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 7 SUBLEVEL = 0 -EXTRAVERSION = -rc6 +EXTRAVERSION = -rc7 NAME = Terrified Chipmunk # *DOCUMENTATION* diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 1e6956a90608..14db93e4c8a8 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -445,7 +445,7 @@ struct procfs_args { * unhappy with OSF UFS. [CHECKME] */ static int -osf_ufs_mount(char *dirname, struct ufs_args __user *args, int flags) +osf_ufs_mount(const char *dirname, struct ufs_args __user *args, int flags) { int retval; struct cdfs_args tmp; @@ -465,7 +465,7 @@ osf_ufs_mount(char *dirname, struct ufs_args __user *args, int flags) } static int -osf_cdfs_mount(char *dirname, struct cdfs_args __user *args, int flags) +osf_cdfs_mount(const char *dirname, struct cdfs_args __user *args, int flags) { int retval; struct cdfs_args tmp; @@ -485,7 +485,7 @@ osf_cdfs_mount(char *dirname, struct cdfs_args __user *args, int flags) } static int -osf_procfs_mount(char *dirname, struct procfs_args __user *args, int flags) +osf_procfs_mount(const char *dirname, struct procfs_args __user *args, int flags) { struct procfs_args tmp; diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index cd0c8b1e1ecf..14e9947bad6e 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -713,8 +713,7 @@ static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type, break; case VPBE_ENC_CUSTOM_TIMINGS: if (pclock <= 27000000) { - v |= DM644X_VPSS_MUXSEL_PLL2_MODE | - DM644X_VPSS_DACCLKEN; + v |= DM644X_VPSS_DACCLKEN; writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL)); } else { /* diff --git a/arch/arm/mach-exynos/dma.c b/arch/arm/mach-exynos/dma.c index 21d568b3b149..87e07d6fc615 100644 --- a/arch/arm/mach-exynos/dma.c +++ b/arch/arm/mach-exynos/dma.c @@ -275,6 +275,9 @@ static int __init exynos_dma_init(void) exynos_pdma1_pdata.nr_valid_peri = ARRAY_SIZE(exynos4210_pdma1_peri); exynos_pdma1_pdata.peri_id = exynos4210_pdma1_peri; + + if (samsung_rev() == EXYNOS4210_REV_0) + exynos_mdma1_device.res.start = EXYNOS4_PA_S_MDMA1; } else if (soc_is_exynos4212() || soc_is_exynos4412()) { exynos_pdma0_pdata.nr_valid_peri = ARRAY_SIZE(exynos4212_pdma0_peri); diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h index 8480849affb9..ed4da4544cd2 100644 --- a/arch/arm/mach-exynos/include/mach/map.h +++ b/arch/arm/mach-exynos/include/mach/map.h @@ -90,6 +90,7 @@ #define EXYNOS4_PA_MDMA0 0x10810000 #define EXYNOS4_PA_MDMA1 0x12850000 +#define EXYNOS4_PA_S_MDMA1 0x12840000 #define EXYNOS4_PA_PDMA0 0x12680000 #define EXYNOS4_PA_PDMA1 0x12690000 #define EXYNOS5_PA_MDMA0 0x10800000 diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c index 48d5e41dfbfa..378590694447 100644 --- a/arch/arm/mach-omap2/board-igep0020.c +++ b/arch/arm/mach-omap2/board-igep0020.c @@ -580,6 +580,11 @@ static void __init igep_wlan_bt_init(void) } else return; + /* Make sure that the GPIO pins are muxed correctly */ + omap_mux_init_gpio(igep_wlan_bt_gpios[0].gpio, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(igep_wlan_bt_gpios[1].gpio, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(igep_wlan_bt_gpios[2].gpio, OMAP_PIN_OUTPUT); + err = gpio_request_array(igep_wlan_bt_gpios, ARRAY_SIZE(igep_wlan_bt_gpios)); if (err) { diff --git a/arch/arm/mach-omap2/common-board-devices.c b/arch/arm/mach-omap2/common-board-devices.c index 48daac2581b4..84551f205e46 100644 --- a/arch/arm/mach-omap2/common-board-devices.c +++ b/arch/arm/mach-omap2/common-board-devices.c @@ -64,30 +64,36 @@ void __init omap_ads7846_init(int bus_num, int gpio_pendown, int gpio_debounce, struct spi_board_info *spi_bi = &ads7846_spi_board_info; int err; - err = gpio_request_one(gpio_pendown, GPIOF_IN, "TSPenDown"); - if (err) { - pr_err("Couldn't obtain gpio for TSPenDown: %d\n", err); - return; - } + /* + * If a board defines get_pendown_state() function, request the pendown + * GPIO and set the GPIO debounce time. + * If a board does not define the get_pendown_state() function, then + * the ads7846 driver will setup the pendown GPIO itself. + */ + if (board_pdata && board_pdata->get_pendown_state) { + err = gpio_request_one(gpio_pendown, GPIOF_IN, "TSPenDown"); + if (err) { + pr_err("Couldn't obtain gpio for TSPenDown: %d\n", err); + return; + } - if (gpio_debounce) - gpio_set_debounce(gpio_pendown, gpio_debounce); + if (gpio_debounce) + gpio_set_debounce(gpio_pendown, gpio_debounce); + + gpio_export(gpio_pendown, 0); + } spi_bi->bus_num = bus_num; spi_bi->irq = gpio_to_irq(gpio_pendown); + ads7846_config.gpio_pendown = gpio_pendown; + if (board_pdata) { board_pdata->gpio_pendown = gpio_pendown; + board_pdata->gpio_pendown_debounce = gpio_debounce; spi_bi->platform_data = board_pdata; - if (board_pdata->get_pendown_state) - gpio_export(gpio_pendown, 0); - } else { - ads7846_config.gpio_pendown = gpio_pendown; } - if (!board_pdata || (board_pdata && !board_pdata->get_pendown_state)) - gpio_free(gpio_pendown); - spi_register_board_info(&ads7846_spi_board_info, 1); } #else diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c index 44c42057b61c..a256135d8e48 100644 --- a/arch/arm/mach-omap2/twl-common.c +++ b/arch/arm/mach-omap2/twl-common.c @@ -73,6 +73,7 @@ void __init omap4_pmic_init(const char *pmic_type, { /* PMIC part*/ omap_mux_init_signal("sys_nirq1", OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE); + omap_mux_init_signal("fref_clk0_out.sys_drm_msecure", OMAP_PIN_OUTPUT); omap_pmic_init(1, 400, pmic_type, 7 + OMAP44XX_IRQ_GIC_START, pmic_data); /* Register additional devices on i2c1 bus if needed */ diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c index a5683a84c6ee..6013831a043e 100644 --- a/arch/arm/plat-omap/i2c.c +++ b/arch/arm/plat-omap/i2c.c @@ -26,12 +26,14 @@ #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/i2c.h> +#include <linux/i2c-omap.h> #include <linux/slab.h> #include <linux/err.h> #include <linux/clk.h> #include <mach/irqs.h> #include <plat/i2c.h> +#include <plat/omap-pm.h> #include <plat/omap_device.h> #define OMAP_I2C_SIZE 0x3f @@ -127,6 +129,16 @@ static inline int omap1_i2c_add_bus(int bus_id) #ifdef CONFIG_ARCH_OMAP2PLUS +/* + * XXX This function is a temporary compatibility wrapper - only + * needed until the I2C driver can be converted to call + * omap_pm_set_max_dev_wakeup_lat() and handle a return code. + */ +static void omap_pm_set_max_mpu_wakeup_lat_compat(struct device *dev, long t) +{ + omap_pm_set_max_mpu_wakeup_lat(dev, t); +} + static inline int omap2_i2c_add_bus(int bus_id) { int l; @@ -158,6 +170,15 @@ static inline int omap2_i2c_add_bus(int bus_id) dev_attr = (struct omap_i2c_dev_attr *)oh->dev_attr; pdata->flags = dev_attr->flags; + /* + * When waiting for completion of a i2c transfer, we need to + * set a wake up latency constraint for the MPU. This is to + * ensure quick enough wakeup from idle, when transfer + * completes. + * Only omap3 has support for constraints + */ + if (cpu_is_omap34xx()) + pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat; pdev = omap_device_build(name, bus_id, oh, pdata, sizeof(struct omap_i2c_bus_platform_data), NULL, 0, 0); diff --git a/arch/m68k/include/asm/signal.h b/arch/m68k/include/asm/signal.h index 67e489d8d1bd..2df26b57c26a 100644 --- a/arch/m68k/include/asm/signal.h +++ b/arch/m68k/include/asm/signal.h @@ -41,7 +41,7 @@ struct k_sigaction { static inline void sigaddset(sigset_t *set, int _sig) { asm ("bfset %0{%1,#1}" - : "+od" (*set) + : "+o" (*set) : "id" ((_sig - 1) ^ 31) : "cc"); } @@ -49,7 +49,7 @@ static inline void sigaddset(sigset_t *set, int _sig) static inline void sigdelset(sigset_t *set, int _sig) { asm ("bfclr %0{%1,#1}" - : "+od" (*set) + : "+o" (*set) : "id" ((_sig - 1) ^ 31) : "cc"); } @@ -65,7 +65,7 @@ static inline int __gen_sigismember(sigset_t *set, int _sig) int ret; asm ("bfextu %1{%2,#1},%0" : "=d" (ret) - : "od" (*set), "id" ((_sig-1) ^ 31) + : "o" (*set), "id" ((_sig-1) ^ 31) : "cc"); return ret; } diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index a53f8ec37aac..290dc6a1d7a3 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -79,7 +79,7 @@ static struct resource data_resource = { .name = "Kernel data", }; void __init add_memory_region(phys_t start, phys_t size, long type) { int x = boot_mem_map.nr_map; - struct boot_mem_map_entry *prev = boot_mem_map.map + x - 1; + int i; /* Sanity check */ if (start + size < start) { @@ -88,15 +88,29 @@ void __init add_memory_region(phys_t start, phys_t size, long type) } /* - * Try to merge with previous entry if any. This is far less than - * perfect but is sufficient for most real world cases. + * Try to merge with existing entry, if any. */ - if (x && prev->addr + prev->size == start && prev->type == type) { - prev->size += size; + for (i = 0; i < boot_mem_map.nr_map; i++) { + struct boot_mem_map_entry *entry = boot_mem_map.map + i; + unsigned long top; + + if (entry->type != type) + continue; + + if (start + size < entry->addr) + continue; /* no overlap */ + + if (entry->addr + entry->size < start) + continue; /* no overlap */ + + top = max(entry->addr + entry->size, start + size); + entry->addr = min(entry->addr, start); + entry->size = top - entry->addr; + return; } - if (x == BOOT_MEM_MAP_MAX) { + if (boot_mem_map.nr_map == BOOT_MEM_MAP_MAX) { pr_err("Ooops! Too many entries in the memory map!\n"); return; } diff --git a/arch/mips/lib/mips-atomic.c b/arch/mips/lib/mips-atomic.c index e091430dbeb1..cd160be3ce4d 100644 --- a/arch/mips/lib/mips-atomic.c +++ b/arch/mips/lib/mips-atomic.c @@ -56,7 +56,7 @@ __asm__( " .set pop \n" " .endm \n"); -void arch_local_irq_disable(void) +notrace void arch_local_irq_disable(void) { preempt_disable(); __asm__ __volatile__( @@ -93,7 +93,7 @@ __asm__( " .set pop \n" " .endm \n"); -unsigned long arch_local_irq_save(void) +notrace unsigned long arch_local_irq_save(void) { unsigned long flags; preempt_disable(); @@ -135,7 +135,7 @@ __asm__( " .set pop \n" " .endm \n"); -void arch_local_irq_restore(unsigned long flags) +notrace void arch_local_irq_restore(unsigned long flags) { unsigned long __tmp1; @@ -159,7 +159,7 @@ void arch_local_irq_restore(unsigned long flags) EXPORT_SYMBOL(arch_local_irq_restore); -void __arch_local_irq_restore(unsigned long flags) +notrace void __arch_local_irq_restore(unsigned long flags) { unsigned long __tmp1; diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c index fd49aeda9eb8..5dede04f2f3e 100644 --- a/arch/parisc/kernel/signal32.c +++ b/arch/parisc/kernel/signal32.c @@ -65,7 +65,8 @@ put_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz) { compat_sigset_t s; - if (sz != sizeof *set) panic("put_sigset32()"); + if (sz != sizeof *set) + return -EINVAL; sigset_64to32(&s, set); return copy_to_user(up, &s, sizeof s); @@ -77,7 +78,8 @@ get_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz) compat_sigset_t s; int r; - if (sz != sizeof *set) panic("put_sigset32()"); + if (sz != sizeof *set) + return -EINVAL; if ((r = copy_from_user(&s, up, sz)) == 0) { sigset_32to64(set, &s); diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index 7426e40699bd..f76c10863c62 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c @@ -73,6 +73,8 @@ static unsigned long get_shared_area(struct address_space *mapping, struct vm_area_struct *vma; int offset = mapping ? get_offset(mapping) : 0; + offset = (offset + (pgoff << PAGE_SHIFT)) & 0x3FF000; + addr = DCACHE_ALIGN(addr - offset) + offset; for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) { diff --git a/arch/powerpc/boot/dts/mpc5200b.dtsi b/arch/powerpc/boot/dts/mpc5200b.dtsi index 7ab286ab5300..39ed65a44c5f 100644 --- a/arch/powerpc/boot/dts/mpc5200b.dtsi +++ b/arch/powerpc/boot/dts/mpc5200b.dtsi @@ -231,6 +231,12 @@ interrupts = <2 7 0>; }; + sclpc@3c00 { + compatible = "fsl,mpc5200-lpbfifo"; + reg = <0x3c00 0x60>; + interrupts = <2 23 0>; + }; + i2c@3d00 { #address-cells = <1>; #size-cells = <0>; diff --git a/arch/powerpc/boot/dts/o2d.dtsi b/arch/powerpc/boot/dts/o2d.dtsi index 3444eb8f0ade..24f668039295 100644 --- a/arch/powerpc/boot/dts/o2d.dtsi +++ b/arch/powerpc/boot/dts/o2d.dtsi @@ -86,12 +86,6 @@ reg = <0>; }; }; - - sclpc@3c00 { - compatible = "fsl,mpc5200-lpbfifo"; - reg = <0x3c00 0x60>; - interrupts = <3 23 0>; - }; }; localbus { diff --git a/arch/powerpc/boot/dts/pcm030.dts b/arch/powerpc/boot/dts/pcm030.dts index 9e354997eb7e..96512c058033 100644 --- a/arch/powerpc/boot/dts/pcm030.dts +++ b/arch/powerpc/boot/dts/pcm030.dts @@ -59,7 +59,7 @@ #gpio-cells = <2>; }; - psc@2000 { /* PSC1 in ac97 mode */ + audioplatform: psc@2000 { /* PSC1 in ac97 mode */ compatible = "mpc5200b-psc-ac97","fsl,mpc5200b-psc-ac97"; cell-index = <0>; }; @@ -134,4 +134,9 @@ localbus { status = "disabled"; }; + + sound { + compatible = "phytec,pcm030-audio-fabric"; + asoc-platform = <&audioplatform>; + }; }; diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index 8520b58a5e9a..b89ef65392dc 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -372,10 +372,11 @@ static int mpc52xx_irqhost_map(struct irq_domain *h, unsigned int virq, case MPC52xx_IRQ_L1_MAIN: irqchip = &mpc52xx_main_irqchip; break; case MPC52xx_IRQ_L1_PERP: irqchip = &mpc52xx_periph_irqchip; break; case MPC52xx_IRQ_L1_SDMA: irqchip = &mpc52xx_sdma_irqchip; break; - default: - pr_err("%s: invalid irq: virq=%i, l1=%i, l2=%i\n", - __func__, virq, l1irq, l2irq); - return -EINVAL; + case MPC52xx_IRQ_L1_CRIT: + pr_warn("%s: Critical IRQ #%d is unsupported! Nopping it.\n", + __func__, l2irq); + irq_set_chip(virq, &no_irq_chip); + return 0; } irq_set_chip_and_handler(virq, irqchip, handle_level_irq); diff --git a/arch/powerpc/platforms/pseries/eeh_pe.c b/arch/powerpc/platforms/pseries/eeh_pe.c index 797cd181dc3f..d16c8ded1084 100644 --- a/arch/powerpc/platforms/pseries/eeh_pe.c +++ b/arch/powerpc/platforms/pseries/eeh_pe.c @@ -449,7 +449,7 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe) if (list_empty(&pe->edevs)) { cnt = 0; list_for_each_entry(child, &pe->child_list, child) { - if (!(pe->type & EEH_PE_INVALID)) { + if (!(child->type & EEH_PE_INVALID)) { cnt++; break; } diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index d19f4977c834..e5b084723131 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -220,7 +220,8 @@ static struct device_node *find_pe_dn(struct pci_dev *dev, int *total) /* Get the top level device in the PE */ edev = of_node_to_eeh_dev(dn); - edev = list_first_entry(&edev->pe->edevs, struct eeh_dev, list); + if (edev->pe) + edev = list_first_entry(&edev->pe->edevs, struct eeh_dev, list); dn = eeh_dev_to_of_node(edev); if (!dn) return NULL; diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h index f93003123bce..67c62578d170 100644 --- a/arch/sparc/include/asm/prom.h +++ b/arch/sparc/include/asm/prom.h @@ -63,10 +63,13 @@ extern char *of_console_options; extern void irq_trans_init(struct device_node *dp); extern char *build_path_component(struct device_node *dp); -/* SPARC has a local implementation */ +/* SPARC has local implementations */ extern int of_address_to_resource(struct device_node *dev, int index, struct resource *r); #define of_address_to_resource of_address_to_resource +void __iomem *of_iomap(struct device_node *node, int index); +#define of_iomap of_iomap + #endif /* __KERNEL__ */ #endif /* _SPARC_PROM_H */ diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index 867de2f8189c..689e1ba62809 100644 --- a/arch/sparc/kernel/signal_64.c +++ b/arch/sparc/kernel/signal_64.c @@ -295,9 +295,7 @@ void do_rt_sigreturn(struct pt_regs *regs) err |= restore_fpu_state(regs, fpu_save); err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t)); - err |= do_sigaltstack(&sf->stack, NULL, (unsigned long)sf); - - if (err) + if (err || do_sigaltstack(&sf->stack, NULL, (unsigned long)sf) == -EFAULT) goto segv; err |= __get_user(rwin_save, &sf->rwin_save); diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index c760e073963e..e87b0cac14b5 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -12,6 +12,8 @@ #include <asm/setup.h> #include <asm/desc.h> +#undef memcpy /* Use memcpy from misc.c */ + #include "eboot.h" static efi_system_table_t *sys_table; diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S index 2a017441b8b2..8c132a625b94 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S @@ -476,6 +476,3 @@ die: setup_corrupt: .byte 7 .string "No setup signature found...\n" - - .data -dummy: .long 0 diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h index dcfde52979c3..19f16ebaf4fa 100644 --- a/arch/x86/include/asm/ptrace.h +++ b/arch/x86/include/asm/ptrace.h @@ -205,21 +205,14 @@ static inline bool user_64bit_mode(struct pt_regs *regs) } #endif -/* - * X86_32 CPUs don't save ss and esp if the CPU is already in kernel mode - * when it traps. The previous stack will be directly underneath the saved - * registers, and 'sp/ss' won't even have been saved. Thus the '®s->sp'. - * - * This is valid only for kernel mode traps. - */ -static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) -{ #ifdef CONFIG_X86_32 - return (unsigned long)(®s->sp); +extern unsigned long kernel_stack_pointer(struct pt_regs *regs); #else +static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) +{ return regs->sp; -#endif } +#endif #define GET_IP(regs) ((regs)->ip) #define GET_FP(regs) ((regs)->bp) diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index f7e98a2c0d12..1b7d1656a042 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -631,6 +631,20 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) } } + /* + * The way access filter has a performance penalty on some workloads. + * Disable it on the affected CPUs. + */ + if ((c->x86 == 0x15) && + (c->x86_model >= 0x02) && (c->x86_model < 0x20)) { + u64 val; + + if (!rdmsrl_safe(0xc0011021, &val) && !(val & 0x1E)) { + val |= 0x1E; + wrmsrl_safe(0xc0011021, val); + } + } + cpu_detect_cache_sizes(c); /* Multi core CPU? */ diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index 698b6ec12e0f..1ac581f38dfa 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -6,7 +6,7 @@ * * Written by Jacob Shin - AMD, Inc. * - * Support: borislav.petkov@amd.com + * Maintained by: Borislav Petkov <bp@alien8.de> * * April 2006 * - added support for AMD Family 0x10 processors diff --git a/arch/x86/kernel/cpu/mcheck/mce_intel.c b/arch/x86/kernel/cpu/mcheck/mce_intel.c index 5f88abf07e9c..4f9a3cbfc4a3 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_intel.c +++ b/arch/x86/kernel/cpu/mcheck/mce_intel.c @@ -285,34 +285,39 @@ void cmci_clear(void) raw_spin_unlock_irqrestore(&cmci_discover_lock, flags); } +static long cmci_rediscover_work_func(void *arg) +{ + int banks; + + /* Recheck banks in case CPUs don't all have the same */ + if (cmci_supported(&banks)) + cmci_discover(banks); + + return 0; +} + /* * After a CPU went down cycle through all the others and rediscover * Must run in process context. */ void cmci_rediscover(int dying) { - int banks; - int cpu; - cpumask_var_t old; + int cpu, banks; if (!cmci_supported(&banks)) return; - if (!alloc_cpumask_var(&old, GFP_KERNEL)) - return; - cpumask_copy(old, ¤t->cpus_allowed); for_each_online_cpu(cpu) { if (cpu == dying) continue; - if (set_cpus_allowed_ptr(current, cpumask_of(cpu))) + + if (cpu == smp_processor_id()) { + cmci_rediscover_work_func(NULL); continue; - /* Recheck banks in case CPUs don't all have the same */ - if (cmci_supported(&banks)) - cmci_discover(banks); - } + } - set_cpus_allowed_ptr(current, old); - free_cpumask_var(old); + work_on_cpu(cpu, cmci_rediscover_work_func, NULL); + } } /* diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index b51b2c7ee51f..1328fe49a3f1 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -995,8 +995,8 @@ END(interrupt) */ .p2align CONFIG_X86_L1_CACHE_SHIFT common_interrupt: - ASM_CLAC XCPT_FRAME + ASM_CLAC addq $-0x80,(%rsp) /* Adjust vector to [-256,-1] range */ interrupt do_IRQ /* 0(%rsp): old_rsp-ARGOFFSET */ @@ -1135,8 +1135,8 @@ END(common_interrupt) */ .macro apicinterrupt num sym do_sym ENTRY(\sym) - ASM_CLAC INTR_FRAME + ASM_CLAC pushq_cfi $~(\num) .Lcommon_\sym: interrupt \do_sym @@ -1190,8 +1190,8 @@ apicinterrupt IRQ_WORK_VECTOR \ */ .macro zeroentry sym do_sym ENTRY(\sym) - ASM_CLAC INTR_FRAME + ASM_CLAC PARAVIRT_ADJUST_EXCEPTION_FRAME pushq_cfi $-1 /* ORIG_RAX: no syscall to restart */ subq $ORIG_RAX-R15, %rsp @@ -1208,8 +1208,8 @@ END(\sym) .macro paranoidzeroentry sym do_sym ENTRY(\sym) - ASM_CLAC INTR_FRAME + ASM_CLAC PARAVIRT_ADJUST_EXCEPTION_FRAME pushq_cfi $-1 /* ORIG_RAX: no syscall to restart */ subq $ORIG_RAX-R15, %rsp @@ -1227,8 +1227,8 @@ END(\sym) #define INIT_TSS_IST(x) PER_CPU_VAR(init_tss) + (TSS_ist + ((x) - 1) * 8) .macro paranoidzeroentry_ist sym do_sym ist ENTRY(\sym) - ASM_CLAC INTR_FRAME + ASM_CLAC PARAVIRT_ADJUST_EXCEPTION_FRAME pushq_cfi $-1 /* ORIG_RAX: no syscall to restart */ subq $ORIG_RAX-R15, %rsp @@ -1247,8 +1247,8 @@ END(\sym) .macro errorentry sym do_sym ENTRY(\sym) - ASM_CLAC XCPT_FRAME + ASM_CLAC PARAVIRT_ADJUST_EXCEPTION_FRAME subq $ORIG_RAX-R15, %rsp CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15 @@ -1266,8 +1266,8 @@ END(\sym) /* error code is on the stack already */ .macro paranoiderrorentry sym do_sym ENTRY(\sym) - ASM_CLAC XCPT_FRAME + ASM_CLAC PARAVIRT_ADJUST_EXCEPTION_FRAME subq $ORIG_RAX-R15, %rsp CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15 diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c index 7720ff5a9ee2..efdec7cd8e01 100644 --- a/arch/x86/kernel/microcode_amd.c +++ b/arch/x86/kernel/microcode_amd.c @@ -8,8 +8,8 @@ * Tigran Aivazian <tigran@aivazian.fsnet.co.uk> * * Maintainers: - * Andreas Herrmann <andreas.herrmann3@amd.com> - * Borislav Petkov <borislav.petkov@amd.com> + * Andreas Herrmann <herrmann.der.user@googlemail.com> + * Borislav Petkov <bp@alien8.de> * * This driver allows to upgrade microcode on F10h AMD * CPUs and later. @@ -190,6 +190,7 @@ static unsigned int verify_patch_size(int cpu, u32 patch_size, #define F1XH_MPB_MAX_SIZE 2048 #define F14H_MPB_MAX_SIZE 1824 #define F15H_MPB_MAX_SIZE 4096 +#define F16H_MPB_MAX_SIZE 3458 switch (c->x86) { case 0x14: @@ -198,6 +199,9 @@ static unsigned int verify_patch_size(int cpu, u32 patch_size, case 0x15: max_size = F15H_MPB_MAX_SIZE; break; + case 0x16: + max_size = F16H_MPB_MAX_SIZE; + break; default: max_size = F1XH_MPB_MAX_SIZE; break; diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index b00b33a18390..5e0596b0632e 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -22,6 +22,7 @@ #include <linux/perf_event.h> #include <linux/hw_breakpoint.h> #include <linux/rcupdate.h> +#include <linux/module.h> #include <asm/uaccess.h> #include <asm/pgtable.h> @@ -166,6 +167,35 @@ static inline bool invalid_selector(u16 value) #define FLAG_MASK FLAG_MASK_32 +/* + * X86_32 CPUs don't save ss and esp if the CPU is already in kernel mode + * when it traps. The previous stack will be directly underneath the saved + * registers, and 'sp/ss' won't even have been saved. Thus the '®s->sp'. + * + * Now, if the stack is empty, '®s->sp' is out of range. In this + * case we try to take the previous stack. To always return a non-null + * stack pointer we fall back to regs as stack if no previous stack + * exists. + * + * This is valid only for kernel mode traps. + */ +unsigned long kernel_stack_pointer(struct pt_regs *regs) +{ + unsigned long context = (unsigned long)regs & ~(THREAD_SIZE - 1); + unsigned long sp = (unsigned long)®s->sp; + struct thread_info *tinfo; + + if (context == (sp & ~(THREAD_SIZE - 1))) + return sp; + + tinfo = (struct thread_info *)context; + if (tinfo->previous_esp) + return tinfo->previous_esp; + + return (unsigned long)regs; +} +EXPORT_SYMBOL_GPL(kernel_stack_pointer); + static unsigned long *pt_regs_access(struct pt_regs *regs, unsigned long regno) { BUILD_BUG_ON(offsetof(struct pt_regs, bx) != 0); diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 0777f042e400..60f926cd8b0e 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -197,7 +197,7 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, } if (end == TLB_FLUSH_ALL || tlb_flushall_shift == -1 - || vmflag == VM_HUGETLB) { + || vmflag & VM_HUGETLB) { local_flush_tlb(); goto flush_all; } diff --git a/arch/x86/pci/ce4100.c b/arch/x86/pci/ce4100.c index 41bd2a2d2c50..b914e20b5a00 100644 --- a/arch/x86/pci/ce4100.c +++ b/arch/x86/pci/ce4100.c @@ -115,6 +115,16 @@ static void sata_revid_read(struct sim_dev_reg *reg, u32 *value) reg_read(reg, value); } +static void reg_noirq_read(struct sim_dev_reg *reg, u32 *value) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&pci_config_lock, flags); + /* force interrupt pin value to 0 */ + *value = reg->sim_reg.value & 0xfff00ff; + raw_spin_unlock_irqrestore(&pci_config_lock, flags); +} + static struct sim_dev_reg bus1_fixups[] = { DEFINE_REG(2, 0, 0x10, (16*MB), reg_init, reg_read, reg_write) DEFINE_REG(2, 0, 0x14, (256), reg_init, reg_read, reg_write) @@ -144,6 +154,7 @@ static struct sim_dev_reg bus1_fixups[] = { DEFINE_REG(11, 5, 0x10, (64*KB), reg_init, reg_read, reg_write) DEFINE_REG(11, 6, 0x10, (256), reg_init, reg_read, reg_write) DEFINE_REG(11, 7, 0x10, (64*KB), reg_init, reg_read, reg_write) + DEFINE_REG(11, 7, 0x3c, 256, reg_init, reg_noirq_read, reg_write) DEFINE_REG(12, 0, 0x10, (128*KB), reg_init, reg_read, reg_write) DEFINE_REG(12, 0, 0x14, (256), reg_init, reg_read, reg_write) DEFINE_REG(12, 1, 0x10, (1024), reg_init, reg_read, reg_write) @@ -161,8 +172,10 @@ static struct sim_dev_reg bus1_fixups[] = { DEFINE_REG(16, 0, 0x10, (64*KB), reg_init, reg_read, reg_write) DEFINE_REG(16, 0, 0x14, (64*MB), reg_init, reg_read, reg_write) DEFINE_REG(16, 0, 0x18, (64*MB), reg_init, reg_read, reg_write) + DEFINE_REG(16, 0, 0x3c, 256, reg_init, reg_noirq_read, reg_write) DEFINE_REG(17, 0, 0x10, (128*KB), reg_init, reg_read, reg_write) DEFINE_REG(18, 0, 0x10, (1*KB), reg_init, reg_read, reg_write) + DEFINE_REG(18, 0, 0x3c, 256, reg_init, reg_noirq_read, reg_write) }; static void __init init_sim_regs(void) diff --git a/arch/x86/platform/ce4100/ce4100.c b/arch/x86/platform/ce4100/ce4100.c index 4c61b52191eb..92525cb8e54c 100644 --- a/arch/x86/platform/ce4100/ce4100.c +++ b/arch/x86/platform/ce4100/ce4100.c @@ -21,12 +21,25 @@ #include <asm/i8259.h> #include <asm/io.h> #include <asm/io_apic.h> +#include <asm/emergency-restart.h> static int ce4100_i8042_detect(void) { return 0; } +/* + * The CE4100 platform has an internal 8051 Microcontroller which is + * responsible for signaling to the external Power Management Unit the + * intention to reset, reboot or power off the system. This 8051 device has + * its command register mapped at I/O port 0xcf9 and the value 0x4 is used + * to power off the system. + */ +static void ce4100_power_off(void) +{ + outb(0x4, 0xcf9); +} + #ifdef CONFIG_SERIAL_8250 static unsigned int mem_serial_in(struct uart_port *p, int offset) @@ -139,8 +152,19 @@ void __init x86_ce4100_early_setup(void) x86_init.mpparse.find_smp_config = x86_init_noop; x86_init.pci.init = ce4100_pci_init; + /* + * By default, the reboot method is ACPI which is supported by the + * CE4100 bootloader CEFDK using FADT.ResetReg Address and ResetValue + * the bootloader will however issue a system power off instead of + * reboot. By using BOOT_KBD we ensure proper system reboot as + * expected. + */ + reboot_type = BOOT_KBD; + #ifdef CONFIG_X86_IO_APIC x86_init.pci.init_irq = sdv_pci_init; x86_init.mpparse.setup_ioapic_ids = setup_ioapic_ids_from_mpc_nocheck; #endif + + pm_power_off = ce4100_power_off; } diff --git a/block/blk-exec.c b/block/blk-exec.c index 8b6dc5bd4dd0..f71eac35c1b9 100644 --- a/block/blk-exec.c +++ b/block/blk-exec.c @@ -52,11 +52,17 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk, rq_end_io_fn *done) { int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK; + bool is_pm_resume; WARN_ON(irqs_disabled()); rq->rq_disk = bd_disk; rq->end_io = done; + /* + * need to check this before __blk_run_queue(), because rq can + * be freed before that returns. + */ + is_pm_resume = rq->cmd_type == REQ_TYPE_PM_RESUME; spin_lock_irq(q->queue_lock); @@ -71,7 +77,7 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk, __elv_add_request(q, rq, where); __blk_run_queue(q); /* the queue is stopped so it won't be run */ - if (rq->cmd_type == REQ_TYPE_PM_RESUME) + if (is_pm_resume) q->request_fn(q); spin_unlock_irq(q->queue_lock); } diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index b1ae48054dc5..b7078afddb74 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -238,7 +238,7 @@ static int __devexit ahci_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int ahci_suspend(struct device *dev) { struct ahci_platform_data *pdata = dev_get_platdata(dev); diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index fd9ecf74e631..5b0ba3f20edc 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -1105,10 +1105,15 @@ static int ata_acpi_bind_device(struct ata_port *ap, struct scsi_device *sdev, struct acpi_device *acpi_dev; struct acpi_device_power_state *states; - if (ap->flags & ATA_FLAG_ACPI_SATA) - ata_dev = &ap->link.device[sdev->channel]; - else + if (ap->flags & ATA_FLAG_ACPI_SATA) { + if (!sata_pmp_attached(ap)) + ata_dev = &ap->link.device[sdev->id]; + else + ata_dev = &ap->pmp_link[sdev->channel].device[sdev->id]; + } + else { ata_dev = &ap->link.device[sdev->id]; + } *handle = ata_dev_acpi_handle(ata_dev); diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 3cc7096cfda7..f46fbd3bd3fb 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2942,6 +2942,10 @@ const struct ata_timing *ata_timing_find_mode(u8 xfer_mode) if (xfer_mode == t->mode) return t; + + WARN_ONCE(true, "%s: unable to find timing for xfer_mode 0x%x\n", + __func__, xfer_mode); + return NULL; } diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index e3bda074fa12..a6df6a351d6e 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1052,6 +1052,8 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev) { sdev->use_10_for_rw = 1; sdev->use_10_for_ms = 1; + sdev->no_report_opcodes = 1; + sdev->no_write_same = 1; /* Schedule policy is determined by ->qc_defer() callback and * it needs to see every deferred qc. Set dev_blocked to 1 to diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c index 26201ebef3ca..371fd2c698b7 100644 --- a/drivers/ata/pata_arasan_cf.c +++ b/drivers/ata/pata_arasan_cf.c @@ -317,6 +317,12 @@ static int cf_init(struct arasan_cf_dev *acdev) return ret; } + ret = clk_set_rate(acdev->clk, 166000000); + if (ret) { + dev_warn(acdev->host->dev, "clock set rate failed"); + return ret; + } + spin_lock_irqsave(&acdev->host->lock, flags); /* configure CF interface clock */ writel((pdata->cf_if_clk <= CF_IF_CLK_200M) ? pdata->cf_if_clk : @@ -908,7 +914,7 @@ static int __devexit arasan_cf_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int arasan_cf_suspend(struct device *dev) { struct ata_host *host = dev_get_drvdata(dev); diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c index 0d7c4c2cd26f..400bf1c3e982 100644 --- a/drivers/ata/sata_highbank.c +++ b/drivers/ata/sata_highbank.c @@ -260,7 +260,7 @@ static const struct of_device_id ahci_of_match[] = { }; MODULE_DEVICE_TABLE(of, ahci_of_match); -static int __init ahci_highbank_probe(struct platform_device *pdev) +static int __devinit ahci_highbank_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ahci_host_priv *hpriv; @@ -378,7 +378,7 @@ static int __devexit ahci_highbank_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int ahci_highbank_suspend(struct device *dev) { struct ata_host *host = dev_get_drvdata(dev); diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index 44a4256533e1..08608de87e4e 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -142,6 +142,39 @@ static int k2_sata_scr_write(struct ata_link *link, return 0; } +static int k2_sata_softreset(struct ata_link *link, + unsigned int *class, unsigned long deadline) +{ + u8 dmactl; + void __iomem *mmio = link->ap->ioaddr.bmdma_addr; + + dmactl = readb(mmio + ATA_DMA_CMD); + + /* Clear the start bit */ + if (dmactl & ATA_DMA_START) { + dmactl &= ~ATA_DMA_START; + writeb(dmactl, mmio + ATA_DMA_CMD); + } + + return ata_sff_softreset(link, class, deadline); +} + +static int k2_sata_hardreset(struct ata_link *link, + unsigned int *class, unsigned long deadline) +{ + u8 dmactl; + void __iomem *mmio = link->ap->ioaddr.bmdma_addr; + + dmactl = readb(mmio + ATA_DMA_CMD); + + /* Clear the start bit */ + if (dmactl & ATA_DMA_START) { + dmactl &= ~ATA_DMA_START; + writeb(dmactl, mmio + ATA_DMA_CMD); + } + + return sata_sff_hardreset(link, class, deadline); +} static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) { @@ -346,6 +379,8 @@ static struct scsi_host_template k2_sata_sht = { static struct ata_port_operations k2_sata_ops = { .inherits = &ata_bmdma_port_ops, + .softreset = k2_sata_softreset, + .hardreset = k2_sata_hardreset, .sff_tf_load = k2_sata_tf_load, .sff_tf_read = k2_sata_tf_read, .sff_check_status = k2_stat_check_status, diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 74a67e0019a2..fbbd4ed2edf2 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -451,7 +451,7 @@ int dev_pm_qos_add_ancestor_request(struct device *dev, if (ancestor) error = dev_pm_qos_add_request(ancestor, req, value); - if (error) + if (error < 0) req->dev = NULL; return error; diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 3804a0af3ef1..9fe4f1865558 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -935,7 +935,7 @@ aoe_end_request(struct aoedev *d, struct request *rq, int fastfail) /* cf. http://lkml.org/lkml/2006/10/31/28 */ if (!fastfail) - q->request_fn(q); + __blk_run_queue(q); } static void diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 1c49d7173966..2ddd64a9ffde 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4330,6 +4330,7 @@ out_unreg_region: out_unreg_blkdev: unregister_blkdev(FLOPPY_MAJOR, "fd"); out_put_disk: + destroy_workqueue(floppy_wq); for (drive = 0; drive < N_DRIVE; drive++) { if (!disks[drive]) break; @@ -4340,7 +4341,6 @@ out_put_disk: } put_disk(disks[drive]); } - destroy_workqueue(floppy_wq); return err; } @@ -4555,6 +4555,8 @@ static void __exit floppy_module_exit(void) unregister_blkdev(FLOPPY_MAJOR, "fd"); platform_driver_unregister(&floppy_driver); + destroy_workqueue(floppy_wq); + for (drive = 0; drive < N_DRIVE; drive++) { del_timer_sync(&motor_off_timer[drive]); @@ -4578,7 +4580,6 @@ static void __exit floppy_module_exit(void) cancel_delayed_work_sync(&fd_timeout); cancel_delayed_work_sync(&fd_timer); - destroy_workqueue(floppy_wq); if (atomic_read(&usage_count)) floppy_release_irq_and_dma(); diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index adc6f36564cf..9694dd99bbbc 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -559,7 +559,7 @@ static void mtip_timeout_function(unsigned long int data) struct mtip_cmd *command; int tag, cmdto_cnt = 0; unsigned int bit, group; - unsigned int num_command_slots = port->dd->slot_groups * 32; + unsigned int num_command_slots; unsigned long to, tagaccum[SLOTBITS_IN_LONGS]; if (unlikely(!port)) @@ -572,6 +572,7 @@ static void mtip_timeout_function(unsigned long int data) } /* clear the tag accumulator */ memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long)); + num_command_slots = port->dd->slot_groups * 32; for (tag = 0; tag < num_command_slots; tag++) { /* @@ -2218,8 +2219,8 @@ static int exec_drive_taskfile(struct driver_data *dd, fis.device); /* check for erase mode support during secure erase.*/ - if ((fis.command == ATA_CMD_SEC_ERASE_UNIT) - && (outbuf[0] & MTIP_SEC_ERASE_MODE)) { + if ((fis.command == ATA_CMD_SEC_ERASE_UNIT) && outbuf && + (outbuf[0] & MTIP_SEC_ERASE_MODE)) { erasemode = 1; } @@ -2439,7 +2440,7 @@ static int mtip_hw_ioctl(struct driver_data *dd, unsigned int cmd, * return value * None */ -static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, +static void mtip_hw_submit_io(struct driver_data *dd, sector_t sector, int nsect, int nents, int tag, void *callback, void *data, int dir) { @@ -2447,6 +2448,7 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, struct mtip_port *port = dd->port; struct mtip_cmd *command = &port->commands[tag]; int dma_dir = (dir == READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + u64 start = sector; /* Map the scatter list for DMA access */ nents = dma_map_sg(&dd->pdev->dev, command->sg, nents, dma_dir); @@ -2465,8 +2467,12 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, fis->opts = 1 << 7; fis->command = (dir == READ ? ATA_CMD_FPDMA_READ : ATA_CMD_FPDMA_WRITE); - *((unsigned int *) &fis->lba_low) = (start & 0xFFFFFF); - *((unsigned int *) &fis->lba_low_ex) = ((start >> 24) & 0xFFFFFF); + fis->lba_low = start & 0xFF; + fis->lba_mid = (start >> 8) & 0xFF; + fis->lba_hi = (start >> 16) & 0xFF; + fis->lba_low_ex = (start >> 24) & 0xFF; + fis->lba_mid_ex = (start >> 32) & 0xFF; + fis->lba_hi_ex = (start >> 40) & 0xFF; fis->device = 1 << 6; fis->features = nsect & 0xFF; fis->features_ex = (nsect >> 8) & 0xFF; diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h index 5f4a917bd8bb..b1742640556a 100644 --- a/drivers/block/mtip32xx/mtip32xx.h +++ b/drivers/block/mtip32xx/mtip32xx.h @@ -34,7 +34,7 @@ #define PCIE_CONFIG_EXT_DEVICE_CONTROL_OFFSET 0x48 /* check for erase mode support during secure erase */ -#define MTIP_SEC_ERASE_MODE 0x3 +#define MTIP_SEC_ERASE_MODE 0x2 /* # of times to retry timed out/failed IOs */ #define MTIP_MAX_RETRIES 2 @@ -155,14 +155,14 @@ enum { MTIP_DDF_REBUILD_FAILED_BIT = 8, }; -__packed struct smart_attr{ +struct smart_attr { u8 attr_id; u16 flags; u8 cur; u8 worst; u32 data; u8 res[3]; -}; +} __packed; /* Register Frame Information Structure (FIS), host to device. */ struct host_to_dev_fis { diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 8d4804732bac..8c4139647efc 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -33,7 +33,7 @@ * detection. The mods to Rev F required more family * information detection. * - * Changes/Fixes by Borislav Petkov <borislav.petkov@amd.com>: + * Changes/Fixes by Borislav Petkov <bp@alien8.de>: * - misc fixes and code cleanups * * This module is based on the following documents diff --git a/drivers/edac/edac_stub.c b/drivers/edac/edac_stub.c index 6c86f6e54558..351945fa2ecd 100644 --- a/drivers/edac/edac_stub.c +++ b/drivers/edac/edac_stub.c @@ -5,7 +5,7 @@ * * 2007 (c) MontaVista Software, Inc. * 2010 (c) Advanced Micro Devices Inc. - * Borislav Petkov <borislav.petkov@amd.com> + * Borislav Petkov <bp@alien8.de> * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c index 66b5151c1080..2ae78f20cc28 100644 --- a/drivers/edac/mce_amd_inj.c +++ b/drivers/edac/mce_amd_inj.c @@ -6,7 +6,7 @@ * This file may be distributed under the terms of the GNU General Public * License version 2. * - * Copyright (c) 2010: Borislav Petkov <borislav.petkov@amd.com> + * Copyright (c) 2010: Borislav Petkov <bp@alien8.de> * Advanced Micro Devices Inc. */ @@ -168,6 +168,6 @@ module_init(edac_init_mce_inject); module_exit(edac_exit_mce_inject); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Borislav Petkov <borislav.petkov@amd.com>"); +MODULE_AUTHOR("Borislav Petkov <bp@alien8.de>"); MODULE_AUTHOR("AMD Inc."); MODULE_DESCRIPTION("MCE injection facility for testing MCE decoding"); diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index 1162d6b3bf85..bb1b392f5cda 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -1546,6 +1546,8 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev) struct sbp2_logical_unit *lu = sdev->hostdata; sdev->use_10_for_rw = 1; + sdev->no_report_opcodes = 1; + sdev->no_write_same = 1; if (sbp2_param_exclusive_login) sdev->manage_start_stop = 1; diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index f11d8e3b4041..47150f5ded04 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -466,7 +466,7 @@ config GPIO_ADP5588_IRQ config GPIO_ADNP tristate "Avionic Design N-bit GPIO expander" - depends on I2C && OF + depends on I2C && OF_GPIO help This option enables support for N GPIOs found on Avionic Design I2C GPIO expanders. The register space will be extended by powers diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 0f425189de11..ce1c84760076 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -77,7 +77,7 @@ struct mcp23s08_driver_data { /*----------------------------------------------------------------------*/ -#ifdef CONFIG_I2C +#if IS_ENABLED(CONFIG_I2C) static int mcp23008_read(struct mcp23s08 *mcp, unsigned reg) { @@ -399,7 +399,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, break; #endif /* CONFIG_SPI_MASTER */ -#ifdef CONFIG_I2C +#if IS_ENABLED(CONFIG_I2C) case MCP_TYPE_008: mcp->ops = &mcp23008_ops; mcp->chip.ngpio = 8; @@ -473,7 +473,7 @@ fail: /*----------------------------------------------------------------------*/ -#ifdef CONFIG_I2C +#if IS_ENABLED(CONFIG_I2C) static int __devinit mcp230xx_probe(struct i2c_client *client, const struct i2c_device_id *id) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index cf7afb9eb61a..be65c0451ad5 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -92,6 +92,11 @@ static inline void __iomem *mvebu_gpioreg_out(struct mvebu_gpio_chip *mvchip) return mvchip->membase + GPIO_OUT_OFF; } +static inline void __iomem *mvebu_gpioreg_blink(struct mvebu_gpio_chip *mvchip) +{ + return mvchip->membase + GPIO_BLINK_EN_OFF; +} + static inline void __iomem *mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip) { return mvchip->membase + GPIO_IO_CONF_OFF; @@ -206,6 +211,23 @@ static int mvebu_gpio_get(struct gpio_chip *chip, unsigned pin) return (u >> pin) & 1; } +static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned pin, int value) +{ + struct mvebu_gpio_chip *mvchip = + container_of(chip, struct mvebu_gpio_chip, chip); + unsigned long flags; + u32 u; + + spin_lock_irqsave(&mvchip->lock, flags); + u = readl_relaxed(mvebu_gpioreg_blink(mvchip)); + if (value) + u |= 1 << pin; + else + u &= ~(1 << pin); + writel_relaxed(u, mvebu_gpioreg_blink(mvchip)); + spin_unlock_irqrestore(&mvchip->lock, flags); +} + static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned pin) { struct mvebu_gpio_chip *mvchip = @@ -244,6 +266,7 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned pin, if (ret) return ret; + mvebu_gpio_blink(chip, pin, 0); mvebu_gpio_set(chip, pin, value); spin_lock_irqsave(&mvchip->lock, flags); diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index 05a909a17cee..15b182c84ce8 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c @@ -49,13 +49,7 @@ nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc) if (chan->vblank.crtc != crtc) continue; - if (nv_device(priv)->chipset == 0x50) { - nv_wr32(priv, 0x001704, chan->vblank.channel); - nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma); - bar->flush(bar); - nv_wr32(priv, 0x001570, chan->vblank.offset); - nv_wr32(priv, 0x001574, chan->vblank.value); - } else { + if (nv_device(priv)->chipset >= 0xc0) { nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel); bar->flush(bar); nv_wr32(priv, 0x06000c, @@ -63,6 +57,17 @@ nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc) nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset)); nv_wr32(priv, 0x060014, chan->vblank.value); + } else { + nv_wr32(priv, 0x001704, chan->vblank.channel); + nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma); + bar->flush(bar); + if (nv_device(priv)->chipset == 0x50) { + nv_wr32(priv, 0x001570, chan->vblank.offset); + nv_wr32(priv, 0x001574, chan->vblank.value); + } else { + nv_wr32(priv, 0x060010, chan->vblank.offset); + nv_wr32(priv, 0x060014, chan->vblank.value); + } } list_del(&chan->vblank.head); diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c index e45035efb8ca..7bbb1e1b7a8d 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c @@ -669,21 +669,27 @@ nv40_grctx_fill(struct nouveau_device *device, struct nouveau_gpuobj *mem) }); } -void +int nv40_grctx_init(struct nouveau_device *device, u32 *size) { - u32 ctxprog[256], i; + u32 *ctxprog = kmalloc(256 * 4, GFP_KERNEL), i; struct nouveau_grctx ctx = { .device = device, .mode = NOUVEAU_GRCTX_PROG, .data = ctxprog, - .ctxprog_max = ARRAY_SIZE(ctxprog) + .ctxprog_max = 256, }; + if (!ctxprog) + return -ENOMEM; + nv40_grctx_generate(&ctx); nv_wr32(device, 0x400324, 0); for (i = 0; i < ctx.ctxprog_len; i++) nv_wr32(device, 0x400328, ctxprog[i]); *size = ctx.ctxvals_pos * 4; + + kfree(ctxprog); + return 0; } diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c index 425001204a89..cc6574eeb80e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c @@ -346,7 +346,9 @@ nv40_graph_init(struct nouveau_object *object) return ret; /* generate and upload context program */ - nv40_grctx_init(nv_device(priv), &priv->size); + ret = nv40_grctx_init(nv_device(priv), &priv->size); + if (ret) + return ret; /* No context present currently */ nv_wr32(priv, NV40_PGRAPH_CTXCTL_CUR, 0x00000000); diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h index d2ac975afc2e..7da35a4e7970 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h @@ -15,7 +15,7 @@ nv44_graph_class(void *priv) return !(0x0baf & (1 << (device->chipset & 0x0f))); } -void nv40_grctx_init(struct nouveau_device *, u32 *size); +int nv40_grctx_init(struct nouveau_device *, u32 *size); void nv40_grctx_fill(struct nouveau_device *, struct nouveau_gpuobj *); #endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/object.h b/drivers/gpu/drm/nouveau/core/include/core/object.h index 818feabbf4a0..486f1a9217fd 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/object.h +++ b/drivers/gpu/drm/nouveau/core/include/core/object.h @@ -175,14 +175,18 @@ nv_mo32(void *obj, u32 addr, u32 mask, u32 data) return temp; } -static inline bool -nv_strncmp(void *obj, u32 addr, u32 len, const char *str) +static inline int +nv_memcmp(void *obj, u32 addr, const char *str, u32 len) { + unsigned char c1, c2; + while (len--) { - if (nv_ro08(obj, addr++) != *(str++)) - return false; + c1 = nv_ro08(obj, addr++); + c2 = *(str++); + if (c1 != c2) + return c1 - c2; } - return true; + return 0; } #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h index 39e73b91d360..41b7a6a76f19 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h @@ -54,6 +54,7 @@ int nv04_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *, int clk, struct nouveau_pll_vals *); int nv04_clock_pll_prog(struct nouveau_clock *, u32 reg1, struct nouveau_pll_vals *); - +int nva3_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *, + int clk, struct nouveau_pll_vals *); #endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c index 7d750382a833..c51197157749 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c @@ -64,7 +64,7 @@ dcb_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) } } else if (*ver >= 0x15) { - if (!nv_strncmp(bios, dcb - 7, 7, "DEV_REC")) { + if (!nv_memcmp(bios, dcb - 7, "DEV_REC", 7)) { u16 i2c = nv_ro16(bios, dcb + 2); *hdr = 4; *cnt = (i2c - dcb) / 10; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c index cc8d7d162d7c..9068c98b96f6 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c @@ -66,6 +66,24 @@ nva3_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq) return ret; } +int +nva3_clock_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info, + int clk, struct nouveau_pll_vals *pv) +{ + int ret, N, M, P; + + ret = nva3_pll_calc(clock, info, clk, &N, NULL, &M, &P); + + if (ret > 0) { + pv->refclk = info->refclk; + pv->N1 = N; + pv->M1 = M; + pv->log2P = P; + } + return ret; +} + + static int nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -80,6 +98,7 @@ nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return ret; priv->base.pll_set = nva3_clock_pll_set; + priv->base.pll_calc = nva3_clock_pll_calc; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c index 5ccce0b17bf3..f6962c9b6c36 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c @@ -79,6 +79,7 @@ nvc0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return ret; priv->base.pll_set = nvc0_clock_pll_set; + priv->base.pll_calc = nva3_clock_pll_calc; return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index cc79c796afee..cbf1fc60a386 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -241,6 +241,10 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) if (unlikely(!abi16)) return -ENOMEM; + + if (!drm->channel) + return nouveau_abi16_put(abi16, -ENODEV); + client = nv_client(abi16->client); if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 0910125cbbc3..8503b2ea570a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -129,7 +129,8 @@ nouveau_accel_init(struct nouveau_drm *drm) /* initialise synchronisation routines */ if (device->card_type < NV_10) ret = nv04_fence_create(drm); - else if (device->chipset < 0x84) ret = nv10_fence_create(drm); + else if (device->card_type < NV_50) ret = nv10_fence_create(drm); + else if (device->chipset < 0x84) ret = nv50_fence_create(drm); else if (device->card_type < NV_C0) ret = nv84_fence_create(drm); else ret = nvc0_fence_create(drm); if (ret) { diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index af31f829f4a8..219942c660d7 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1330,6 +1330,8 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav break; udelay(1); } + } else { + save->crtc_enabled[i] = false; } } diff --git a/drivers/gpu/drm/radeon/radeon_agp.c b/drivers/gpu/drm/radeon/radeon_agp.c index 10ea17a6b2a6..42433344cb1b 100644 --- a/drivers/gpu/drm/radeon/radeon_agp.c +++ b/drivers/gpu/drm/radeon/radeon_agp.c @@ -69,9 +69,12 @@ static struct radeon_agpmode_quirk radeon_agpmode_quirk_list[] = { /* Intel 82830 830 Chipset Host Bridge / Mobility M6 LY Needs AGPMode 2 (fdo #17360)*/ { PCI_VENDOR_ID_INTEL, 0x3575, PCI_VENDOR_ID_ATI, 0x4c59, PCI_VENDOR_ID_DELL, 0x00e3, 2}, - /* Intel 82852/82855 host bridge / Mobility FireGL 9000 R250 Needs AGPMode 1 (lp #296617) */ + /* Intel 82852/82855 host bridge / Mobility FireGL 9000 RV250 Needs AGPMode 1 (lp #296617) */ { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4c66, PCI_VENDOR_ID_DELL, 0x0149, 1}, + /* Intel 82855PM host bridge / Mobility FireGL 9000 RV250 Needs AGPMode 1 for suspend/resume */ + { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c66, + PCI_VENDOR_ID_IBM, 0x0531, 1}, /* Intel 82852/82855 host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (deb #467460) */ { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4e50, 0x1025, 0x0061, 1}, diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index aa59a254be2c..c02bf208084f 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -39,6 +39,7 @@ #define AT91_TWI_STOP 0x0002 /* Send a Stop Condition */ #define AT91_TWI_MSEN 0x0004 /* Master Transfer Enable */ #define AT91_TWI_SVDIS 0x0020 /* Slave Transfer Disable */ +#define AT91_TWI_QUICK 0x0040 /* SMBus quick command */ #define AT91_TWI_SWRST 0x0080 /* Software Reset */ #define AT91_TWI_MMR 0x0004 /* Master Mode Register */ @@ -212,7 +213,11 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) INIT_COMPLETION(dev->cmd_complete); dev->transfer_status = 0; - if (dev->msg->flags & I2C_M_RD) { + + if (!dev->buf_len) { + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_QUICK); + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); + } else if (dev->msg->flags & I2C_M_RD) { unsigned start_flags = AT91_TWI_START; if (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY) { diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 286ca1917820..0670da79ee5e 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -287,12 +287,14 @@ read_init_dma_fail: select_init_dma_fail: dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE); select_init_pio_fail: + dmaengine_terminate_all(i2c->dmach); return -EINVAL; /* Write failpath. */ write_init_dma_fail: dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE); write_init_pio_fail: + dmaengine_terminate_all(i2c->dmach); return -EINVAL; } diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index db31eaed6ea5..3525c9e62cb0 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -43,7 +43,6 @@ #include <linux/slab.h> #include <linux/i2c-omap.h> #include <linux/pm_runtime.h> -#include <linux/pm_qos.h> /* I2C controller revisions */ #define OMAP_I2C_OMAP1_REV_2 0x20 @@ -187,8 +186,9 @@ struct omap_i2c_dev { int reg_shift; /* bit shift for I2C register addresses */ struct completion cmd_complete; struct resource *ioarea; - u32 latency; /* maximum MPU wkup latency */ - struct pm_qos_request pm_qos_request; + u32 latency; /* maximum mpu wkup latency */ + void (*set_mpu_wkup_lat)(struct device *dev, + long latency); u32 speed; /* Speed of bus in kHz */ u32 dtrev; /* extra revision from DT */ u32 flags; @@ -494,7 +494,9 @@ static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ - dev->latency = (1000000 * dev->threshold) / (1000 * dev->speed / 8); + if (dev->set_mpu_wkup_lat != NULL) + dev->latency = (1000000 * dev->threshold) / + (1000 * dev->speed / 8); } /* @@ -522,6 +524,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, dev->buf = msg->buf; dev->buf_len = msg->len; + /* make sure writes to dev->buf_len are ordered */ + barrier(); + omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len); /* Clear the FIFO Buffers */ @@ -579,7 +584,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, */ timeout = wait_for_completion_timeout(&dev->cmd_complete, OMAP_I2C_TIMEOUT); - dev->buf_len = 0; if (timeout == 0) { dev_err(dev->dev, "controller timed out\n"); omap_i2c_init(dev); @@ -629,16 +633,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) if (r < 0) goto out; - /* - * When waiting for completion of a i2c transfer, we need to - * set a wake up latency constraint for the MPU. This is to - * ensure quick enough wakeup from idle, when transfer - * completes. - */ - if (dev->latency) - pm_qos_add_request(&dev->pm_qos_request, - PM_QOS_CPU_DMA_LATENCY, - dev->latency); + if (dev->set_mpu_wkup_lat != NULL) + dev->set_mpu_wkup_lat(dev->dev, dev->latency); for (i = 0; i < num; i++) { r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); @@ -646,8 +642,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) break; } - if (dev->latency) - pm_qos_remove_request(&dev->pm_qos_request); + if (dev->set_mpu_wkup_lat != NULL) + dev->set_mpu_wkup_lat(dev->dev, -1); if (r == 0) r = num; @@ -1104,6 +1100,7 @@ omap_i2c_probe(struct platform_device *pdev) } else if (pdata != NULL) { dev->speed = pdata->clkrate; dev->flags = pdata->flags; + dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; dev->dtrev = pdata->rev; } @@ -1159,8 +1156,9 @@ omap_i2c_probe(struct platform_device *pdev) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ - dev->latency = (1000000 * dev->fifo_size) / - (1000 * dev->speed / 8); + if (dev->set_mpu_wkup_lat != NULL) + dev->latency = (1000000 * dev->fifo_size) / + (1000 * dev->speed / 8); } /* reset ASAP, clearing any IRQs */ diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 3e0335f1fc60..9d902725bac9 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -806,6 +806,7 @@ static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c) dev_err(i2c->dev, "invalid gpio[%d]: %d\n", idx, gpio); goto free_gpio; } + i2c->gpios[idx] = gpio; ret = gpio_request(gpio, "i2c-bus"); if (ret) { diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index c0ec7d42c3be..1abbc170d8b7 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c @@ -26,10 +26,14 @@ static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src) * input_mt_init_slots() - initialize MT input slots * @dev: input device supporting MT events and finger tracking * @num_slots: number of slots used by the device + * @flags: mt tasks to handle in core * * This function allocates all necessary memory for MT slot handling * in the input device, prepares the ABS_MT_SLOT and * ABS_MT_TRACKING_ID events for use and sets up appropriate buffers. + * Depending on the flags set, it also performs pointer emulation and + * frame synchronization. + * * May be called repeatedly. Returns -EINVAL if attempting to * reinitialize with a different number of slots. */ diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 8f02e3d0e712..4c842c320c2e 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -12,8 +12,8 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define MOUSEDEV_MINOR_BASE 32 -#define MOUSEDEV_MINORS 32 -#define MOUSEDEV_MIX 31 +#define MOUSEDEV_MINORS 31 +#define MOUSEDEV_MIX 63 #include <linux/sched.h> #include <linux/slab.h> diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index f02028ec3db6..78e5d9ab0ba7 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -955,7 +955,8 @@ static int ads7846_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(ads7846_pm, ads7846_suspend, ads7846_resume); -static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads7846 *ts) +static int __devinit ads7846_setup_pendown(struct spi_device *spi, + struct ads7846 *ts) { struct ads7846_platform_data *pdata = spi->dev.platform_data; int err; @@ -981,6 +982,9 @@ static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads784 ts->gpio_pendown = pdata->gpio_pendown; + if (pdata->gpio_pendown_debounce) + gpio_set_debounce(pdata->gpio_pendown, + pdata->gpio_pendown_debounce); } else { dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n"); return -EINVAL; diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index d4a4cd445cab..0badfa48b32b 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -4108,7 +4108,7 @@ static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to) static int intel_iommu_add_device(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); - struct pci_dev *bridge, *dma_pdev; + struct pci_dev *bridge, *dma_pdev = NULL; struct iommu_group *group; int ret; @@ -4122,7 +4122,7 @@ static int intel_iommu_add_device(struct device *dev) dma_pdev = pci_get_domain_bus_and_slot( pci_domain_nr(pdev->bus), bridge->subordinate->number, 0); - else + if (!dma_pdev) dma_pdev = pci_dev_get(bridge); } else dma_pdev = pci_dev_get(pdev); diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index a649f146d17b..c0f7a4266263 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -1054,6 +1054,7 @@ static int smmu_debugfs_stats_show(struct seq_file *s, void *v) stats[i], val, offs); } seq_printf(s, "\n"); + dput(dent); return 0; } diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 02db9183ca01..77e6eff41cae 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -740,8 +740,14 @@ static void rq_completed(struct mapped_device *md, int rw, int run_queue) if (!md_in_flight(md)) wake_up(&md->wait); + /* + * Run this off this callpath, as drivers could invoke end_io while + * inside their request_fn (and holding the queue lock). Calling + * back into ->request_fn() could deadlock attempting to grab the + * queue lock again. + */ if (run_queue) - blk_run_queue(md->queue); + blk_run_queue_async(md->queue); /* * dm_put() must be at the end of this function. See the comment above diff --git a/drivers/md/md.c b/drivers/md/md.c index 9ab768acfb62..61200717687b 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1817,10 +1817,10 @@ retry: memset(bbp, 0xff, PAGE_SIZE); for (i = 0 ; i < bb->count ; i++) { - u64 internal_bb = *p++; + u64 internal_bb = p[i]; u64 store_bb = ((BB_OFFSET(internal_bb) << 10) | BB_LEN(internal_bb)); - *bbp++ = cpu_to_le64(store_bb); + bbp[i] = cpu_to_le64(store_bb); } bb->changed = 0; if (read_seqretry(&bb->lock, seq)) @@ -5294,7 +5294,7 @@ void md_stop_writes(struct mddev *mddev) } EXPORT_SYMBOL_GPL(md_stop_writes); -void md_stop(struct mddev *mddev) +static void __md_stop(struct mddev *mddev) { mddev->ready = 0; mddev->pers->stop(mddev); @@ -5304,6 +5304,18 @@ void md_stop(struct mddev *mddev) mddev->pers = NULL; clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); } + +void md_stop(struct mddev *mddev) +{ + /* stop the array and free an attached data structures. + * This is called from dm-raid + */ + __md_stop(mddev); + bitmap_destroy(mddev); + if (mddev->bio_set) + bioset_free(mddev->bio_set); +} + EXPORT_SYMBOL_GPL(md_stop); static int md_set_readonly(struct mddev *mddev, struct block_device *bdev) @@ -5364,7 +5376,7 @@ static int do_md_stop(struct mddev * mddev, int mode, set_disk_ro(disk, 0); __md_stop_writes(mddev); - md_stop(mddev); + __md_stop(mddev); mddev->queue->merge_bvec_fn = NULL; mddev->queue->backing_dev_info.congested_fn = NULL; @@ -7936,9 +7948,9 @@ int md_is_badblock(struct badblocks *bb, sector_t s, int sectors, sector_t *first_bad, int *bad_sectors) { int hi; - int lo = 0; + int lo; u64 *p = bb->page; - int rv = 0; + int rv; sector_t target = s + sectors; unsigned seq; @@ -7953,7 +7965,8 @@ int md_is_badblock(struct badblocks *bb, sector_t s, int sectors, retry: seq = read_seqbegin(&bb->lock); - + lo = 0; + rv = 0; hi = bb->count; /* Binary search between lo and hi for 'target' diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index d1295aff4173..0d5d0ff2c0f7 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -499,7 +499,7 @@ static void raid10_end_write_request(struct bio *bio, int error) */ one_write_done(r10_bio); if (dec_rdev) - rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev); + rdev_dec_pending(rdev, conf->mddev); } /* @@ -1334,18 +1334,21 @@ retry_write: blocked_rdev = rrdev; break; } + if (rdev && (test_bit(Faulty, &rdev->flags) + || test_bit(Unmerged, &rdev->flags))) + rdev = NULL; if (rrdev && (test_bit(Faulty, &rrdev->flags) || test_bit(Unmerged, &rrdev->flags))) rrdev = NULL; r10_bio->devs[i].bio = NULL; r10_bio->devs[i].repl_bio = NULL; - if (!rdev || test_bit(Faulty, &rdev->flags) || - test_bit(Unmerged, &rdev->flags)) { + + if (!rdev && !rrdev) { set_bit(R10BIO_Degraded, &r10_bio->state); continue; } - if (test_bit(WriteErrorSeen, &rdev->flags)) { + if (rdev && test_bit(WriteErrorSeen, &rdev->flags)) { sector_t first_bad; sector_t dev_sector = r10_bio->devs[i].addr; int bad_sectors; @@ -1387,8 +1390,10 @@ retry_write: max_sectors = good_sectors; } } - r10_bio->devs[i].bio = bio; - atomic_inc(&rdev->nr_pending); + if (rdev) { + r10_bio->devs[i].bio = bio; + atomic_inc(&rdev->nr_pending); + } if (rrdev) { r10_bio->devs[i].repl_bio = bio; atomic_inc(&rrdev->nr_pending); @@ -1444,69 +1449,71 @@ retry_write: for (i = 0; i < conf->copies; i++) { struct bio *mbio; int d = r10_bio->devs[i].devnum; - if (!r10_bio->devs[i].bio) - continue; + if (r10_bio->devs[i].bio) { + struct md_rdev *rdev = conf->mirrors[d].rdev; + mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); + md_trim_bio(mbio, r10_bio->sector - bio->bi_sector, + max_sectors); + r10_bio->devs[i].bio = mbio; + + mbio->bi_sector = (r10_bio->devs[i].addr+ + choose_data_offset(r10_bio, + rdev)); + mbio->bi_bdev = rdev->bdev; + mbio->bi_end_io = raid10_end_write_request; + mbio->bi_rw = WRITE | do_sync | do_fua | do_discard; + mbio->bi_private = r10_bio; - mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - md_trim_bio(mbio, r10_bio->sector - bio->bi_sector, - max_sectors); - r10_bio->devs[i].bio = mbio; + atomic_inc(&r10_bio->remaining); - mbio->bi_sector = (r10_bio->devs[i].addr+ - choose_data_offset(r10_bio, - conf->mirrors[d].rdev)); - mbio->bi_bdev = conf->mirrors[d].rdev->bdev; - mbio->bi_end_io = raid10_end_write_request; - mbio->bi_rw = WRITE | do_sync | do_fua | do_discard; - mbio->bi_private = r10_bio; + cb = blk_check_plugged(raid10_unplug, mddev, + sizeof(*plug)); + if (cb) + plug = container_of(cb, struct raid10_plug_cb, + cb); + else + plug = NULL; + spin_lock_irqsave(&conf->device_lock, flags); + if (plug) { + bio_list_add(&plug->pending, mbio); + plug->pending_cnt++; + } else { + bio_list_add(&conf->pending_bio_list, mbio); + conf->pending_count++; + } + spin_unlock_irqrestore(&conf->device_lock, flags); + if (!plug) + md_wakeup_thread(mddev->thread); + } - atomic_inc(&r10_bio->remaining); + if (r10_bio->devs[i].repl_bio) { + struct md_rdev *rdev = conf->mirrors[d].replacement; + if (rdev == NULL) { + /* Replacement just got moved to main 'rdev' */ + smp_mb(); + rdev = conf->mirrors[d].rdev; + } + mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); + md_trim_bio(mbio, r10_bio->sector - bio->bi_sector, + max_sectors); + r10_bio->devs[i].repl_bio = mbio; + + mbio->bi_sector = (r10_bio->devs[i].addr + + choose_data_offset( + r10_bio, rdev)); + mbio->bi_bdev = rdev->bdev; + mbio->bi_end_io = raid10_end_write_request; + mbio->bi_rw = WRITE | do_sync | do_fua | do_discard; + mbio->bi_private = r10_bio; - cb = blk_check_plugged(raid10_unplug, mddev, sizeof(*plug)); - if (cb) - plug = container_of(cb, struct raid10_plug_cb, cb); - else - plug = NULL; - spin_lock_irqsave(&conf->device_lock, flags); - if (plug) { - bio_list_add(&plug->pending, mbio); - plug->pending_cnt++; - } else { + atomic_inc(&r10_bio->remaining); + spin_lock_irqsave(&conf->device_lock, flags); bio_list_add(&conf->pending_bio_list, mbio); conf->pending_count++; + spin_unlock_irqrestore(&conf->device_lock, flags); + if (!mddev_check_plugged(mddev)) + md_wakeup_thread(mddev->thread); } - spin_unlock_irqrestore(&conf->device_lock, flags); - if (!plug) - md_wakeup_thread(mddev->thread); - - if (!r10_bio->devs[i].repl_bio) - continue; - - mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - md_trim_bio(mbio, r10_bio->sector - bio->bi_sector, - max_sectors); - r10_bio->devs[i].repl_bio = mbio; - - /* We are actively writing to the original device - * so it cannot disappear, so the replacement cannot - * become NULL here - */ - mbio->bi_sector = (r10_bio->devs[i].addr + - choose_data_offset( - r10_bio, - conf->mirrors[d].replacement)); - mbio->bi_bdev = conf->mirrors[d].replacement->bdev; - mbio->bi_end_io = raid10_end_write_request; - mbio->bi_rw = WRITE | do_sync | do_fua | do_discard; - mbio->bi_private = r10_bio; - - atomic_inc(&r10_bio->remaining); - spin_lock_irqsave(&conf->device_lock, flags); - bio_list_add(&conf->pending_bio_list, mbio); - conf->pending_count++; - spin_unlock_irqrestore(&conf->device_lock, flags); - if (!mddev_check_plugged(mddev)) - md_wakeup_thread(mddev->thread); } /* Don't remove the bias on 'remaining' (one_write_done) until diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index c5439dce0295..a4502686e7a8 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2774,10 +2774,12 @@ static void handle_stripe_clean_event(struct r5conf *conf, dev = &sh->dev[i]; if (!test_bit(R5_LOCKED, &dev->flags) && (test_bit(R5_UPTODATE, &dev->flags) || - test_and_clear_bit(R5_Discard, &dev->flags))) { + test_bit(R5_Discard, &dev->flags))) { /* We can return any write requests */ struct bio *wbi, *wbi2; pr_debug("Return write for disc %d\n", i); + if (test_and_clear_bit(R5_Discard, &dev->flags)) + clear_bit(R5_UPTODATE, &dev->flags); wbi = dev->written; dev->written = NULL; while (wbi && wbi->bi_sector < @@ -2795,7 +2797,8 @@ static void handle_stripe_clean_event(struct r5conf *conf, !test_bit(STRIPE_DEGRADED, &sh->state), 0); } - } + } else if (test_bit(R5_Discard, &sh->dev[i].flags)) + clear_bit(R5_Discard, &sh->dev[i].flags); if (test_and_clear_bit(STRIPE_FULL_WRITE, &sh->state)) if (atomic_dec_and_test(&conf->pending_full_writes)) @@ -3490,40 +3493,6 @@ static void handle_stripe(struct stripe_head *sh) handle_failed_sync(conf, sh, &s); } - /* - * might be able to return some write requests if the parity blocks - * are safe, or on a failed drive - */ - pdev = &sh->dev[sh->pd_idx]; - s.p_failed = (s.failed >= 1 && s.failed_num[0] == sh->pd_idx) - || (s.failed >= 2 && s.failed_num[1] == sh->pd_idx); - qdev = &sh->dev[sh->qd_idx]; - s.q_failed = (s.failed >= 1 && s.failed_num[0] == sh->qd_idx) - || (s.failed >= 2 && s.failed_num[1] == sh->qd_idx) - || conf->level < 6; - - if (s.written && - (s.p_failed || ((test_bit(R5_Insync, &pdev->flags) - && !test_bit(R5_LOCKED, &pdev->flags) - && (test_bit(R5_UPTODATE, &pdev->flags) || - test_bit(R5_Discard, &pdev->flags))))) && - (s.q_failed || ((test_bit(R5_Insync, &qdev->flags) - && !test_bit(R5_LOCKED, &qdev->flags) - && (test_bit(R5_UPTODATE, &qdev->flags) || - test_bit(R5_Discard, &qdev->flags)))))) - handle_stripe_clean_event(conf, sh, disks, &s.return_bi); - - /* Now we might consider reading some blocks, either to check/generate - * parity, or to satisfy requests - * or to load a block that is being partially written. - */ - if (s.to_read || s.non_overwrite - || (conf->level == 6 && s.to_write && s.failed) - || (s.syncing && (s.uptodate + s.compute < disks)) - || s.replacing - || s.expanding) - handle_stripe_fill(sh, &s, disks); - /* Now we check to see if any write operations have recently * completed */ @@ -3561,6 +3530,40 @@ static void handle_stripe(struct stripe_head *sh) s.dec_preread_active = 1; } + /* + * might be able to return some write requests if the parity blocks + * are safe, or on a failed drive + */ + pdev = &sh->dev[sh->pd_idx]; + s.p_failed = (s.failed >= 1 && s.failed_num[0] == sh->pd_idx) + || (s.failed >= 2 && s.failed_num[1] == sh->pd_idx); + qdev = &sh->dev[sh->qd_idx]; + s.q_failed = (s.failed >= 1 && s.failed_num[0] == sh->qd_idx) + || (s.failed >= 2 && s.failed_num[1] == sh->qd_idx) + || conf->level < 6; + + if (s.written && + (s.p_failed || ((test_bit(R5_Insync, &pdev->flags) + && !test_bit(R5_LOCKED, &pdev->flags) + && (test_bit(R5_UPTODATE, &pdev->flags) || + test_bit(R5_Discard, &pdev->flags))))) && + (s.q_failed || ((test_bit(R5_Insync, &qdev->flags) + && !test_bit(R5_LOCKED, &qdev->flags) + && (test_bit(R5_UPTODATE, &qdev->flags) || + test_bit(R5_Discard, &qdev->flags)))))) + handle_stripe_clean_event(conf, sh, disks, &s.return_bi); + + /* Now we might consider reading some blocks, either to check/generate + * parity, or to satisfy requests + * or to load a block that is being partially written. + */ + if (s.to_read || s.non_overwrite + || (conf->level == 6 && s.to_write && s.failed) + || (s.syncing && (s.uptodate + s.compute < disks)) + || s.replacing + || s.expanding) + handle_stripe_fill(sh, &s, disks); + /* Now to consider new write requests and what else, if anything * should be read. We do not handle new writes when: * 1/ A 'write' operation (copy+xor) is already in flight. @@ -5529,6 +5532,10 @@ static int run(struct mddev *mddev) * discard data disk but write parity disk */ stripe = stripe * PAGE_SIZE; + /* Round up to power of 2, as discard handling + * currently assumes that */ + while ((stripe-1) & stripe) + stripe = (stripe | (stripe-1)) + 1; mddev->queue->limits.discard_alignment = stripe; mddev->queue->limits.discard_granularity = stripe; /* diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index acab3ef8a310..05acef8c7641 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -201,7 +201,6 @@ config MFD_TPS6586X depends on I2C=y && GENERIC_HARDIRQS select MFD_CORE select REGMAP_I2C - depends on REGULATOR help If you say yes here you get support for the TPS6586X series of Power Management chips. diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 467464368773..9d67bd92edf8 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -24,8 +24,6 @@ #include <linux/err.h> #include <linux/i2c.h> #include <linux/regmap.h> -#include <linux/regulator/of_regulator.h> -#include <linux/regulator/machine.h> #include <linux/mfd/core.h> #include <linux/mfd/tps6586x.h> @@ -99,6 +97,9 @@ static struct mfd_cell tps6586x_cell[] = { .name = "tps6586x-gpio", }, { + .name = "tps6586x-pmic", + }, + { .name = "tps6586x-rtc", }, { @@ -350,80 +351,19 @@ failed: } #ifdef CONFIG_OF -static struct of_regulator_match tps6586x_matches[] = { - { .name = "sys", .driver_data = (void *)TPS6586X_ID_SYS }, - { .name = "sm0", .driver_data = (void *)TPS6586X_ID_SM_0 }, - { .name = "sm1", .driver_data = (void *)TPS6586X_ID_SM_1 }, - { .name = "sm2", .driver_data = (void *)TPS6586X_ID_SM_2 }, - { .name = "ldo0", .driver_data = (void *)TPS6586X_ID_LDO_0 }, - { .name = "ldo1", .driver_data = (void *)TPS6586X_ID_LDO_1 }, - { .name = "ldo2", .driver_data = (void *)TPS6586X_ID_LDO_2 }, - { .name = "ldo3", .driver_data = (void *)TPS6586X_ID_LDO_3 }, - { .name = "ldo4", .driver_data = (void *)TPS6586X_ID_LDO_4 }, - { .name = "ldo5", .driver_data = (void *)TPS6586X_ID_LDO_5 }, - { .name = "ldo6", .driver_data = (void *)TPS6586X_ID_LDO_6 }, - { .name = "ldo7", .driver_data = (void *)TPS6586X_ID_LDO_7 }, - { .name = "ldo8", .driver_data = (void *)TPS6586X_ID_LDO_8 }, - { .name = "ldo9", .driver_data = (void *)TPS6586X_ID_LDO_9 }, - { .name = "ldo_rtc", .driver_data = (void *)TPS6586X_ID_LDO_RTC }, -}; - static struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *client) { - const unsigned int num = ARRAY_SIZE(tps6586x_matches); struct device_node *np = client->dev.of_node; struct tps6586x_platform_data *pdata; - struct tps6586x_subdev_info *devs; - struct device_node *regs; - const char *sys_rail_name = NULL; - unsigned int count; - unsigned int i, j; - int err; - - regs = of_find_node_by_name(np, "regulators"); - if (!regs) - return NULL; - - err = of_regulator_match(&client->dev, regs, tps6586x_matches, num); - if (err < 0) { - of_node_put(regs); - return NULL; - } - - of_node_put(regs); - count = err; - - devs = devm_kzalloc(&client->dev, count * sizeof(*devs), GFP_KERNEL); - if (!devs) - return NULL; - - for (i = 0, j = 0; i < num && j < count; i++) { - struct regulator_init_data *reg_idata; - - if (!tps6586x_matches[i].init_data) - continue; - - reg_idata = tps6586x_matches[i].init_data; - devs[j].name = "tps6586x-regulator"; - devs[j].platform_data = tps6586x_matches[i].init_data; - devs[j].id = (int)tps6586x_matches[i].driver_data; - if (devs[j].id == TPS6586X_ID_SYS) - sys_rail_name = reg_idata->constraints.name; - - if ((devs[j].id == TPS6586X_ID_LDO_5) || - (devs[j].id == TPS6586X_ID_LDO_RTC)) - reg_idata->supply_regulator = sys_rail_name; - - devs[j].of_node = tps6586x_matches[i].of_node; - j++; - } pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) + if (!pdata) { + dev_err(&client->dev, "Memory allocation failed\n"); return NULL; + } - pdata->num_subdevs = count; - pdata->subdevs = devs; + pdata->num_subdevs = 0; + pdata->subdevs = NULL; pdata->gpio_base = -1; pdata->irq_base = -1; pdata->pm_off = of_property_read_bool(np, "ti,system-power-controller"); diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index 01b9255ed631..b829a5710ddc 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c @@ -775,6 +775,7 @@ static const struct reg_default wm5102_reg_default[] = { { 0x00000154, 0x0000 }, /* R340 - Rate Estimator 3 */ { 0x00000155, 0x0000 }, /* R341 - Rate Estimator 4 */ { 0x00000156, 0x0000 }, /* R342 - Rate Estimator 5 */ + { 0x00000161, 0x0000 }, /* R353 - Dynamic Frequency Scaling 1 */ { 0x00000171, 0x0000 }, /* R369 - FLL1 Control 1 */ { 0x00000172, 0x0008 }, /* R370 - FLL1 Control 2 */ { 0x00000173, 0x0018 }, /* R371 - FLL1 Control 3 */ @@ -1564,6 +1565,7 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg) case ARIZONA_RATE_ESTIMATOR_3: case ARIZONA_RATE_ESTIMATOR_4: case ARIZONA_RATE_ESTIMATOR_5: + case ARIZONA_DYNAMIC_FREQUENCY_SCALING_1: case ARIZONA_FLL1_CONTROL_1: case ARIZONA_FLL1_CONTROL_2: case ARIZONA_FLL1_CONTROL_3: @@ -1596,6 +1598,7 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg) case ARIZONA_FLL2_GPIO_CLOCK: case ARIZONA_MIC_CHARGE_PUMP_1: case ARIZONA_LDO1_CONTROL_1: + case ARIZONA_LDO1_CONTROL_2: case ARIZONA_LDO2_CONTROL_1: case ARIZONA_MIC_BIAS_CTRL_1: case ARIZONA_MIC_BIAS_CTRL_2: diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index 8f52fc858e48..5a5cd2ace4a6 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c @@ -240,7 +240,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength) if (*(szlength) != '+') { devlength = simple_strtoul(szlength, &buffer, 0); - devlength = handle_unit(devlength, buffer) - devstart; + devlength = handle_unit(devlength, buffer); if (devlength < devstart) goto err_out; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ec6841d8e956..1a03b7f673ce 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2983,13 +2983,15 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip, /* * Field definitions are in the following datasheets: * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32) - * New style (6 byte ID): Samsung K9GAG08U0F (p.44) + * New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) * Hynix MLC (6 byte ID): Hynix H27UBG8T2B (p.22) * - * Check for ID length, cell type, and Hynix/Samsung ID to decide what - * to do. + * Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung + * ID to decide what to do. */ - if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG) { + if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG && + (chip->cellinfo & NAND_CI_CELLTYPE_MSK) && + id_data[5] != 0x00) { /* Calc pagesize */ mtd->writesize = 2048 << (extid & 0x03); extid >>= 2; diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index 64be8f0848b0..d9127e2ed808 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -121,7 +121,7 @@ static int parse_ofoldpart_partitions(struct mtd_info *master, nr_parts = plen / sizeof(part[0]); *pparts = kzalloc(nr_parts * sizeof(*(*pparts)), GFP_KERNEL); - if (!pparts) + if (!*pparts) return -ENOMEM; names = of_get_property(dp, "partition-names", &plen); diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 7153e0d27101..b3f41f200622 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -3694,7 +3694,7 @@ static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int start, int * flexonenand_set_boundary - Writes the SLC boundary * @param mtd - mtd info structure */ -int flexonenand_set_boundary(struct mtd_info *mtd, int die, +static int flexonenand_set_boundary(struct mtd_info *mtd, int die, int boundary, int lock) { struct onenand_chip *this = mtd->priv; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index b2530b002125..5f5b69f37d2e 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1379,6 +1379,8 @@ static void bond_compute_features(struct bonding *bond) struct net_device *bond_dev = bond->dev; netdev_features_t vlan_features = BOND_VLAN_FEATURES; unsigned short max_hard_header_len = ETH_HLEN; + unsigned int gso_max_size = GSO_MAX_SIZE; + u16 gso_max_segs = GSO_MAX_SEGS; int i; unsigned int flags, dst_release_flag = IFF_XMIT_DST_RELEASE; @@ -1394,11 +1396,16 @@ static void bond_compute_features(struct bonding *bond) dst_release_flag &= slave->dev->priv_flags; if (slave->dev->hard_header_len > max_hard_header_len) max_hard_header_len = slave->dev->hard_header_len; + + gso_max_size = min(gso_max_size, slave->dev->gso_max_size); + gso_max_segs = min(gso_max_segs, slave->dev->gso_max_segs); } done: bond_dev->vlan_features = vlan_features; bond_dev->hard_header_len = max_hard_header_len; + bond_dev->gso_max_segs = gso_max_segs; + netif_set_gso_max_size(bond_dev, gso_max_size); flags = bond_dev->priv_flags & ~IFF_XMIT_DST_RELEASE; bond_dev->priv_flags = flags | dst_release_flag; diff --git a/drivers/net/ethernet/8390/ne.c b/drivers/net/ethernet/8390/ne.c index d04911d33b64..47618e505355 100644 --- a/drivers/net/ethernet/8390/ne.c +++ b/drivers/net/ethernet/8390/ne.c @@ -813,6 +813,7 @@ static int __init ne_drv_probe(struct platform_device *pdev) dev->irq = irq[this_dev]; dev->mem_end = bad[this_dev]; } + SET_NETDEV_DEV(dev, &pdev->dev); err = do_ne_probe(dev); if (err) { free_netdev(dev); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index bd1fd3d87c24..01611b33a93d 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -9545,10 +9545,13 @@ static int __devinit bnx2x_prev_unload_common(struct bnx2x *bp) */ static void __devinit bnx2x_prev_interrupted_dmae(struct bnx2x *bp) { - u32 val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS); - if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN) { - BNX2X_ERR("was error bit was found to be set in pglueb upon startup. Clearing"); - REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR, 1 << BP_FUNC(bp)); + if (!CHIP_IS_E1x(bp)) { + u32 val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS); + if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN) { + BNX2X_ERR("was error bit was found to be set in pglueb upon startup. Clearing"); + REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR, + 1 << BP_FUNC(bp)); + } } } diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index 1c818254b7be..b01f83a044c4 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c @@ -979,17 +979,6 @@ static void cp_init_hw (struct cp_private *cp) cpw32_f (MAC0 + 0, le32_to_cpu (*(__le32 *) (dev->dev_addr + 0))); cpw32_f (MAC0 + 4, le32_to_cpu (*(__le32 *) (dev->dev_addr + 4))); - cpw32_f(HiTxRingAddr, 0); - cpw32_f(HiTxRingAddr + 4, 0); - - ring_dma = cp->ring_dma; - cpw32_f(RxRingAddr, ring_dma & 0xffffffff); - cpw32_f(RxRingAddr + 4, (ring_dma >> 16) >> 16); - - ring_dma += sizeof(struct cp_desc) * CP_RX_RING_SIZE; - cpw32_f(TxRingAddr, ring_dma & 0xffffffff); - cpw32_f(TxRingAddr + 4, (ring_dma >> 16) >> 16); - cp_start_hw(cp); cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */ @@ -1003,6 +992,17 @@ static void cp_init_hw (struct cp_private *cp) cpw8(Config5, cpr8(Config5) & PMEStatus); + cpw32_f(HiTxRingAddr, 0); + cpw32_f(HiTxRingAddr + 4, 0); + + ring_dma = cp->ring_dma; + cpw32_f(RxRingAddr, ring_dma & 0xffffffff); + cpw32_f(RxRingAddr + 4, (ring_dma >> 16) >> 16); + + ring_dma += sizeof(struct cp_desc) * CP_RX_RING_SIZE; + cpw32_f(TxRingAddr, ring_dma & 0xffffffff); + cpw32_f(TxRingAddr + 4, (ring_dma >> 16) >> 16); + cpw16(MultiIntr, 0); cpw8_f(Cfg9346, Cfg9346_Lock); diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c index fb9f6b38511f..edf5edb13140 100644 --- a/drivers/net/ethernet/sis/sis900.c +++ b/drivers/net/ethernet/sis/sis900.c @@ -2479,7 +2479,7 @@ static int sis900_resume(struct pci_dev *pci_dev) netif_start_queue(net_dev); /* Workaround for EDB */ - sis900_set_mode(ioaddr, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED); + sis900_set_mode(sis_priv, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED); /* Enable all known interrupts by setting the interrupt mask. */ sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE); diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 77e6db9dcfed..a788501e978e 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -894,6 +894,8 @@ out: return IRQ_HANDLED; } +static void axienet_dma_err_handler(unsigned long data); + /** * axienet_open - Driver open routine. * @ndev: Pointer to net_device structure diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c index 98934bdf6acf..477d6729b17f 100644 --- a/drivers/net/ethernet/xscale/ixp4xx_eth.c +++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c @@ -1102,10 +1102,12 @@ static int init_queues(struct port *port) { int i; - if (!ports_open) - if (!(dma_pool = dma_pool_create(DRV_NAME, NULL, - POOL_ALLOC_SIZE, 32, 0))) + if (!ports_open) { + dma_pool = dma_pool_create(DRV_NAME, &port->netdev->dev, + POOL_ALLOC_SIZE, 32, 0); + if (!dma_pool) return -ENOMEM; + } if (!(port->desc_tab = dma_pool_alloc(dma_pool, GFP_KERNEL, &port->desc_tab_phys))) diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index 5039f08f5a5b..43e9ab4f4d7e 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -222,7 +222,7 @@ static void sirdev_config_fsm(struct work_struct *work) break; case SIRDEV_STATE_DONGLE_SPEED: - if (dev->dongle_drv->reset) { + if (dev->dongle_drv->set_speed) { ret = dev->dongle_drv->set_speed(dev, fsm->param); if (ret < 0) { fsm->result = ret; diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index 899274f2f9b1..2ed1140df3e9 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -185,17 +185,20 @@ static int __devinit mdio_gpio_probe(struct platform_device *pdev) { struct mdio_gpio_platform_data *pdata; struct mii_bus *new_bus; - int ret; + int ret, bus_id; - if (pdev->dev.of_node) + if (pdev->dev.of_node) { pdata = mdio_gpio_of_get_data(pdev); - else + bus_id = of_alias_get_id(pdev->dev.of_node, "mdio-gpio"); + } else { pdata = pdev->dev.platform_data; + bus_id = pdev->id; + } if (!pdata) return -ENODEV; - new_bus = mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id); + new_bus = mdio_gpio_bus_init(&pdev->dev, pdata, bus_id); if (!new_bus) return -ENODEV; diff --git a/drivers/net/team/team_mode_broadcast.c b/drivers/net/team/team_mode_broadcast.c index 9db0171e9366..c5db428e73fa 100644 --- a/drivers/net/team/team_mode_broadcast.c +++ b/drivers/net/team/team_mode_broadcast.c @@ -29,8 +29,8 @@ static bool bc_transmit(struct team *team, struct sk_buff *skb) if (last) { skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2) { - ret = team_dev_queue_xmit(team, last, - skb2); + ret = !team_dev_queue_xmit(team, last, + skb2); if (!sum_ret) sum_ret = ret; } @@ -39,7 +39,7 @@ static bool bc_transmit(struct team *team, struct sk_buff *skb) } } if (last) { - ret = team_dev_queue_xmit(team, last, skb); + ret = !team_dev_queue_xmit(team, last, skb); if (!sum_ret) sum_ret = ret; } diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c index 3f575afd8cfc..e9a3da588e95 100644 --- a/drivers/net/wan/ixp4xx_hss.c +++ b/drivers/net/wan/ixp4xx_hss.c @@ -969,10 +969,12 @@ static int init_hdlc_queues(struct port *port) { int i; - if (!ports_open) - if (!(dma_pool = dma_pool_create(DRV_NAME, NULL, - POOL_ALLOC_SIZE, 32, 0))) + if (!ports_open) { + dma_pool = dma_pool_create(DRV_NAME, &port->netdev->dev, + POOL_ALLOC_SIZE, 32, 0); + if (!dma_pool) return -ENOMEM; + } if (!(port->desc_tab = dma_pool_alloc(dma_pool, GFP_KERNEL, &port->desc_tab_phys))) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8e1559aba495..1829b445d0b0 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1456,7 +1456,7 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) switch (type) { case ATH9K_RESET_POWER_ON: ret = ath9k_hw_set_reset_power_on(ah); - if (!ret) + if (ret) ah->reset_power_on = true; break; case ATH9K_RESET_WARM: diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index fa4d1b8cd9f6..2d9eee93c743 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -1354,6 +1354,20 @@ static int iwlagn_mac_add_interface(struct ieee80211_hw *hw, vif_priv->ctx = ctx; ctx->vif = vif; + /* + * In SNIFFER device type, the firmware reports the FCS to + * the host, rather than snipping it off. Unfortunately, + * mac80211 doesn't (yet) provide a per-packet flag for + * this, so that we have to set the hardware flag based + * on the interfaces added. As the monitor interface can + * only be present by itself, and will be removed before + * other interfaces are added, this is safe. + */ + if (vif->type == NL80211_IFTYPE_MONITOR) + priv->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS; + else + priv->hw->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS; + err = iwl_setup_interface(priv, ctx); if (!err || reset) goto out; diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 105e3af3c621..79a4ddc002d3 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -480,20 +480,12 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u16 rd_ptr, wr_ptr; - int n_bd = trans_pcie->txq[txq_id].q.n_bd; if (!test_and_clear_bit(txq_id, trans_pcie->queue_used)) { WARN_ONCE(1, "queue %d not used", txq_id); return; } - rd_ptr = iwl_read_prph(trans, SCD_QUEUE_RDPTR(txq_id)) & (n_bd - 1); - wr_ptr = iwl_read_prph(trans, SCD_QUEUE_WRPTR(txq_id)); - - WARN_ONCE(rd_ptr != wr_ptr, "queue %d isn't empty: [%d,%d]", - txq_id, rd_ptr, wr_ptr); - iwl_txq_set_inactive(trans, txq_id); IWL_DEBUG_TX_QUEUES(trans, "Deactivate queue %d\n", txq_id); } diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 8d465107f52b..ae9010ed58de 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -890,9 +890,6 @@ mwifiex_cmd_timeout_func(unsigned long function_context) return; } cmd_node = adapter->curr_cmd; - if (cmd_node->wait_q_enabled) - adapter->cmd_wait_q.status = -ETIMEDOUT; - if (cmd_node) { adapter->dbg.timeout_cmd_id = adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index]; @@ -938,6 +935,14 @@ mwifiex_cmd_timeout_func(unsigned long function_context) dev_err(adapter->dev, "ps_mode=%d ps_state=%d\n", adapter->ps_mode, adapter->ps_state); + + if (cmd_node->wait_q_enabled) { + adapter->cmd_wait_q.status = -ETIMEDOUT; + wake_up_interruptible(&adapter->cmd_wait_q.wait); + mwifiex_cancel_pending_ioctl(adapter); + /* reset cmd_sent flag to unblock new commands */ + adapter->cmd_sent = false; + } } if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) mwifiex_init_fw_complete(adapter); diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index fc8a9bfa1248..82cf0fa2d9f6 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -161,7 +161,6 @@ static int mwifiex_sdio_suspend(struct device *dev) struct sdio_mmc_card *card; struct mwifiex_adapter *adapter; mmc_pm_flag_t pm_flag = 0; - int hs_actived = 0; int i; int ret = 0; @@ -188,12 +187,14 @@ static int mwifiex_sdio_suspend(struct device *dev) adapter = card->adapter; /* Enable the Host Sleep */ - hs_actived = mwifiex_enable_hs(adapter); - if (hs_actived) { - pr_debug("cmd: suspend with MMC_PM_KEEP_POWER\n"); - ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + if (!mwifiex_enable_hs(adapter)) { + dev_err(adapter->dev, "cmd: failed to suspend\n"); + return -EFAULT; } + dev_dbg(adapter->dev, "cmd: suspend with MMC_PM_KEEP_POWER\n"); + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + /* Indicate device suspended */ adapter->is_suspended = true; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 9970c2b1b199..b7e6607e6b6d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -297,6 +297,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = { /*=== Customer ID ===*/ /****** 8188CU ********/ {RTL_USB_DEVICE(0x050d, 0x1102, rtl92cu_hal_cfg)}, /*Belkin - Edimax*/ + {RTL_USB_DEVICE(0x050d, 0x11f2, rtl92cu_hal_cfg)}, /*Belkin - ISY*/ {RTL_USB_DEVICE(0x06f8, 0xe033, rtl92cu_hal_cfg)}, /*Hercules - Edimax*/ {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/ {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/ diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index caa011008cd0..fc24eb9b3948 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -452,29 +452,85 @@ static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev, /* Grant backend access to each skb fragment page. */ for (i = 0; i < frags; i++) { skb_frag_t *frag = skb_shinfo(skb)->frags + i; + struct page *page = skb_frag_page(frag); - tx->flags |= XEN_NETTXF_more_data; + len = skb_frag_size(frag); + offset = frag->page_offset; - id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs); - np->tx_skbs[id].skb = skb_get(skb); - tx = RING_GET_REQUEST(&np->tx, prod++); - tx->id = id; - ref = gnttab_claim_grant_reference(&np->gref_tx_head); - BUG_ON((signed short)ref < 0); + /* Data must not cross a page boundary. */ + BUG_ON(len + offset > PAGE_SIZE<<compound_order(page)); - mfn = pfn_to_mfn(page_to_pfn(skb_frag_page(frag))); - gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id, - mfn, GNTMAP_readonly); + /* Skip unused frames from start of page */ + page += offset >> PAGE_SHIFT; + offset &= ~PAGE_MASK; - tx->gref = np->grant_tx_ref[id] = ref; - tx->offset = frag->page_offset; - tx->size = skb_frag_size(frag); - tx->flags = 0; + while (len > 0) { + unsigned long bytes; + + BUG_ON(offset >= PAGE_SIZE); + + bytes = PAGE_SIZE - offset; + if (bytes > len) + bytes = len; + + tx->flags |= XEN_NETTXF_more_data; + + id = get_id_from_freelist(&np->tx_skb_freelist, + np->tx_skbs); + np->tx_skbs[id].skb = skb_get(skb); + tx = RING_GET_REQUEST(&np->tx, prod++); + tx->id = id; + ref = gnttab_claim_grant_reference(&np->gref_tx_head); + BUG_ON((signed short)ref < 0); + + mfn = pfn_to_mfn(page_to_pfn(page)); + gnttab_grant_foreign_access_ref(ref, + np->xbdev->otherend_id, + mfn, GNTMAP_readonly); + + tx->gref = np->grant_tx_ref[id] = ref; + tx->offset = offset; + tx->size = bytes; + tx->flags = 0; + + offset += bytes; + len -= bytes; + + /* Next frame */ + if (offset == PAGE_SIZE && len) { + BUG_ON(!PageCompound(page)); + page++; + offset = 0; + } + } } np->tx.req_prod_pvt = prod; } +/* + * Count how many ring slots are required to send the frags of this + * skb. Each frag might be a compound page. + */ +static int xennet_count_skb_frag_slots(struct sk_buff *skb) +{ + int i, frags = skb_shinfo(skb)->nr_frags; + int pages = 0; + + for (i = 0; i < frags; i++) { + skb_frag_t *frag = skb_shinfo(skb)->frags + i; + unsigned long size = skb_frag_size(frag); + unsigned long offset = frag->page_offset; + + /* Skip unused frames from start of page */ + offset &= ~PAGE_MASK; + + pages += PFN_UP(offset + size); + } + + return pages; +} + static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned short id; @@ -487,23 +543,23 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) grant_ref_t ref; unsigned long mfn; int notify; - int frags = skb_shinfo(skb)->nr_frags; + int slots; unsigned int offset = offset_in_page(data); unsigned int len = skb_headlen(skb); unsigned long flags; - frags += DIV_ROUND_UP(offset + len, PAGE_SIZE); - if (unlikely(frags > MAX_SKB_FRAGS + 1)) { - printk(KERN_ALERT "xennet: skb rides the rocket: %d frags\n", - frags); - dump_stack(); + slots = DIV_ROUND_UP(offset + len, PAGE_SIZE) + + xennet_count_skb_frag_slots(skb); + if (unlikely(slots > MAX_SKB_FRAGS + 1)) { + net_alert_ratelimited( + "xennet: skb rides the rocket: %d slots\n", slots); goto drop; } spin_lock_irqsave(&np->tx_lock, flags); if (unlikely(!netif_carrier_ok(dev) || - (frags > 1 && !xennet_can_sg(dev)) || + (slots > 1 && !xennet_can_sg(dev)) || netif_needs_gso(skb, netif_skb_features(skb)))) { spin_unlock_irqrestore(&np->tx_lock, flags); goto drop; diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 97c440a8cd61..30ae18a03a9c 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -698,13 +698,14 @@ static void pn533_wq_cmd(struct work_struct *work) cmd = list_first_entry(&dev->cmd_queue, struct pn533_cmd, queue); + list_del(&cmd->queue); + mutex_unlock(&dev->cmd_lock); __pn533_send_cmd_frame_async(dev, cmd->out_frame, cmd->in_frame, cmd->in_frame_len, cmd->cmd_complete, cmd->arg, cmd->flags); - list_del(&cmd->queue); kfree(cmd); } @@ -1678,11 +1679,14 @@ static void pn533_deactivate_target(struct nfc_dev *nfc_dev, static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, u8 *params, int params_len) { - struct pn533_cmd_jump_dep *cmd; struct pn533_cmd_jump_dep_response *resp; struct nfc_target nfc_target; u8 target_gt_len; int rc; + struct pn533_cmd_jump_dep *cmd = (struct pn533_cmd_jump_dep *)arg; + u8 active = cmd->active; + + kfree(arg); if (params_len == -ENOENT) { nfc_dev_dbg(&dev->interface->dev, ""); @@ -1704,7 +1708,6 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, } resp = (struct pn533_cmd_jump_dep_response *) params; - cmd = (struct pn533_cmd_jump_dep *) arg; rc = resp->status & PN533_CMD_RET_MASK; if (rc != PN533_CMD_RET_SUCCESS) { nfc_dev_err(&dev->interface->dev, @@ -1734,7 +1737,7 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, if (rc == 0) rc = nfc_dep_link_is_up(dev->nfc_dev, dev->nfc_dev->targets[0].idx, - !cmd->active, NFC_RF_INITIATOR); + !active, NFC_RF_INITIATOR); return 0; } @@ -1819,12 +1822,8 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame, dev->in_maxlen, pn533_in_dep_link_up_complete, cmd, GFP_KERNEL); - if (rc) - goto out; - - -out: - kfree(cmd); + if (rc < 0) + kfree(cmd); return rc; } @@ -2078,8 +2077,12 @@ error: static int pn533_tm_send_complete(struct pn533 *dev, void *arg, u8 *params, int params_len) { + struct sk_buff *skb_out = arg; + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + dev_kfree_skb(skb_out); + if (params_len < 0) { nfc_dev_err(&dev->interface->dev, "Error %d when sending data", @@ -2117,7 +2120,7 @@ static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb) rc = pn533_send_cmd_frame_async(dev, out_frame, dev->in_frame, dev->in_maxlen, pn533_tm_send_complete, - NULL, GFP_KERNEL); + skb, GFP_KERNEL); if (rc) { nfc_dev_err(&dev->interface->dev, "Error %d when trying to send data", rc); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index d96caefd914a..aeecf0f72cad 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -178,7 +178,7 @@ config PINCTRL_COH901 ports of 8 GPIO pins each. config PINCTRL_SAMSUNG - bool "Samsung pinctrl driver" + bool depends on OF && GPIOLIB select PINMUX select PINCONF diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index 1c5ab0172ea2..2b557119adad 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -394,7 +394,7 @@ static int pm8607_regulator_dt_init(struct platform_device *pdev, #define pm8607_regulator_dt_init(x, y, z) (-1) #endif -static int __devinit pm8607_regulator_probe(struct platform_device *pdev) +static int pm8607_regulator_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); struct pm8607_regulator_info *info = NULL; @@ -454,7 +454,7 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) return 0; } -static int __devexit pm8607_regulator_remove(struct platform_device *pdev) +static int pm8607_regulator_remove(struct platform_device *pdev) { struct pm8607_regulator_info *info = platform_get_drvdata(pdev); @@ -481,7 +481,7 @@ static struct platform_driver pm8607_regulator_driver = { .owner = THIS_MODULE, }, .probe = pm8607_regulator_probe, - .remove = __devexit_p(pm8607_regulator_remove), + .remove = pm8607_regulator_remove, .id_table = pm8607_regulator_driver_ids, }; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 2b8031235125..551a22b07538 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -109,6 +109,16 @@ config REGULATOR_DA9052 This driver supports the voltage regulators of DA9052-BC and DA9053-AA/Bx PMIC. +config REGULATOR_DA9055 + tristate "Dialog Semiconductor DA9055 regulators" + depends on MFD_DA9055 + help + Say y here to support the BUCKs and LDOs regulators found on + Dialog Semiconductor DA9055 PMIC. + + This driver can also be built as a module. If so, the module + will be called da9055-regulator. + config REGULATOR_FAN53555 tristate "Fairchild FAN53555 Regulator" depends on I2C @@ -345,6 +355,17 @@ config REGULATOR_PALMAS on the muxing. This is handled automatically in the driver by reading the mux info from OTP. +config REGULATOR_TPS51632 + tristate "TI TPS51632 Power Regulator" + depends on I2C + select REGMAP_I2C + help + This driver supports TPS51632 voltage regulator chip. + The TPS51632 is 3-2-1 Phase D-Cap+ Step Down Driverless Controller + with Serial VID control and DVFS. + The voltage output can be configure through I2C interface or PWM + interface. + config REGULATOR_TPS6105X tristate "TI TPS6105X Power regulators" depends on TPS6105X @@ -425,6 +446,15 @@ config REGULATOR_TPS65912 help This driver supports TPS65912 voltage regulator chip. +config REGULATOR_TPS80031 + tristate "TI TPS80031/TPS80032 power regualtor driver" + depends on MFD_TPS80031 + help + TPS80031/ TPS80032 Fully Integrated Power Management with Power + Path and Battery Charger. It has 5 configurable step-down + converters, 11 general purpose LDOs, VBUS generator and digital + output to control regulators. + config REGULATOR_TWL4030 bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC" depends on TWL4030_CORE @@ -432,6 +462,13 @@ config REGULATOR_TWL4030 This driver supports the voltage regulators provided by this family of companion chips. +config REGULATOR_VEXPRESS + tristate "Versatile Express regulators" + depends on VEXPRESS_CONFIG + help + This driver provides support for voltage regulators available + on the ARM Ltd's Versatile Express platform. + config REGULATOR_WM831X tristate "Wolfson Microelectronics WM831x PMIC regulators" depends on MFD_WM831X @@ -460,5 +497,12 @@ config REGULATOR_WM8994 This driver provides support for the voltage regulators on the WM8994 CODEC. +config REGULATOR_AS3711 + tristate "AS3711 PMIC" + depends on MFD_AS3711 + help + This driver provides support for the voltage regulators on the + AS3711 PMIC + endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 3b51e0de33da..b802b0c7fb02 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -16,8 +16,10 @@ obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o +obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o +obj-$(CONFIG_REGULATOR_DA9055) += da9055-regulator.o obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o @@ -42,6 +44,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_PALMAS) += palmas-regulator.o +obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o @@ -57,7 +60,9 @@ obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o +obj-$(CONFIG_REGULATOR_TPS80031) += tps80031-regulator.o obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o +obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c index 167c93f21981..8b5876356db9 100644 --- a/drivers/regulator/aat2870-regulator.c +++ b/drivers/regulator/aat2870-regulator.c @@ -187,7 +187,7 @@ static int aat2870_regulator_probe(struct platform_device *pdev) return 0; } -static int __devexit aat2870_regulator_remove(struct platform_device *pdev) +static int aat2870_regulator_remove(struct platform_device *pdev) { struct regulator_dev *rdev = platform_get_drvdata(pdev); @@ -201,7 +201,7 @@ static struct platform_driver aat2870_regulator_driver = { .owner = THIS_MODULE, }, .probe = aat2870_regulator_probe, - .remove = __devexit_p(aat2870_regulator_remove), + .remove = aat2870_regulator_remove, }; static int __init aat2870_regulator_init(void) diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index df4ad8927f0c..111ec69a3e94 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c @@ -494,7 +494,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = { * for all the different regulators. */ -static int __devinit ab3100_regulators_probe(struct platform_device *pdev) +static int ab3100_regulators_probe(struct platform_device *pdev) { struct ab3100_platform_data *plfdata = pdev->dev.platform_data; struct regulator_config config = { }; @@ -571,7 +571,7 @@ static int __devinit ab3100_regulators_probe(struct platform_device *pdev) return 0; } -static int __devexit ab3100_regulators_remove(struct platform_device *pdev) +static int ab3100_regulators_remove(struct platform_device *pdev) { int i; @@ -589,7 +589,7 @@ static struct platform_driver ab3100_regulators_driver = { .owner = THIS_MODULE, }, .probe = ab3100_regulators_probe, - .remove = __devexit_p(ab3100_regulators_remove), + .remove = ab3100_regulators_remove, }; static __init int ab3100_regulators_init(void) diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index e3d1d063025a..09014f38a948 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -641,7 +641,7 @@ static struct ab8500_reg_init ab8500_reg_init[] = { REG_INIT(AB8500_REGUCTRLDISCH2, 0x04, 0x44, 0x16), }; -static __devinit int +static int ab8500_regulator_init_registers(struct platform_device *pdev, int id, int value) { int err; @@ -676,7 +676,7 @@ ab8500_regulator_init_registers(struct platform_device *pdev, int id, int value) return 0; } -static __devinit int ab8500_regulator_register(struct platform_device *pdev, +static int ab8500_regulator_register(struct platform_device *pdev, struct regulator_init_data *init_data, int id, struct device_node *np) @@ -735,7 +735,7 @@ static struct of_regulator_match ab8500_regulator_matches[] = { { .name = "ab8500_ldo_ana", .driver_data = (void *) AB8500_LDO_ANA, }, }; -static __devinit int +static int ab8500_regulator_of_probe(struct platform_device *pdev, struct device_node *np) { int err, i; @@ -751,7 +751,7 @@ ab8500_regulator_of_probe(struct platform_device *pdev, struct device_node *np) return 0; } -static __devinit int ab8500_regulator_probe(struct platform_device *pdev) +static int ab8500_regulator_probe(struct platform_device *pdev) { struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); struct ab8500_platform_data *pdata; @@ -817,7 +817,7 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) return 0; } -static __devexit int ab8500_regulator_remove(struct platform_device *pdev) +static int ab8500_regulator_remove(struct platform_device *pdev) { int i; @@ -836,7 +836,7 @@ static __devexit int ab8500_regulator_remove(struct platform_device *pdev) static struct platform_driver ab8500_regulator_driver = { .probe = ab8500_regulator_probe, - .remove = __devexit_p(ab8500_regulator_remove), + .remove = ab8500_regulator_remove, .driver = { .name = "ab8500-regulator", .owner = THIS_MODULE, diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c index f123f7e3b752..6b981b5faa70 100644 --- a/drivers/regulator/ad5398.c +++ b/drivers/regulator/ad5398.c @@ -211,7 +211,7 @@ static const struct i2c_device_id ad5398_id[] = { }; MODULE_DEVICE_TABLE(i2c, ad5398_id); -static int __devinit ad5398_probe(struct i2c_client *client, +static int ad5398_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct regulator_init_data *init_data = client->dev.platform_data; @@ -256,7 +256,7 @@ err: return ret; } -static int __devexit ad5398_remove(struct i2c_client *client) +static int ad5398_remove(struct i2c_client *client) { struct ad5398_chip_info *chip = i2c_get_clientdata(client); @@ -266,7 +266,7 @@ static int __devexit ad5398_remove(struct i2c_client *client) static struct i2c_driver ad5398_driver = { .probe = ad5398_probe, - .remove = __devexit_p(ad5398_remove), + .remove = ad5398_remove, .driver = { .name = "ad5398", }, diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index 1af97686f444..1aa5246c79d9 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -87,7 +87,7 @@ static struct regulator_ops anatop_rops = { .map_voltage = regulator_map_voltage_linear, }; -static int __devinit anatop_regulator_probe(struct platform_device *pdev) +static int anatop_regulator_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; @@ -186,7 +186,7 @@ anatop_probe_end: return ret; } -static int __devexit anatop_regulator_remove(struct platform_device *pdev) +static int anatop_regulator_remove(struct platform_device *pdev) { struct regulator_dev *rdev = platform_get_drvdata(pdev); struct anatop_regulator *sreg = rdev_get_drvdata(rdev); @@ -210,7 +210,7 @@ static struct platform_driver anatop_regulator_driver = { .of_match_table = of_anatop_regulator_match_tbl, }, .probe = anatop_regulator_probe, - .remove = __devexit_p(anatop_regulator_remove), + .remove = anatop_regulator_remove, }; static int __init anatop_regulator_init(void) diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index d184aa35abcb..ed7beec53af8 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -34,6 +34,108 @@ struct arizona_ldo1 { struct regulator_init_data init_data; }; +static int arizona_ldo1_hc_list_voltage(struct regulator_dev *rdev, + unsigned int selector) +{ + if (selector >= rdev->desc->n_voltages) + return -EINVAL; + + if (selector == rdev->desc->n_voltages - 1) + return 1800000; + else + return rdev->desc->min_uV + (rdev->desc->uV_step * selector); +} + +static int arizona_ldo1_hc_map_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + int sel; + + sel = DIV_ROUND_UP(min_uV - rdev->desc->min_uV, rdev->desc->uV_step); + if (sel >= rdev->desc->n_voltages) + sel = rdev->desc->n_voltages - 1; + + return sel; +} + +static int arizona_ldo1_hc_set_voltage_sel(struct regulator_dev *rdev, + unsigned sel) +{ + struct arizona_ldo1 *ldo = rdev_get_drvdata(rdev); + struct regmap *regmap = ldo->arizona->regmap; + unsigned int val; + int ret; + + if (sel == rdev->desc->n_voltages - 1) + val = ARIZONA_LDO1_HI_PWR; + else + val = 0; + + ret = regmap_update_bits(regmap, ARIZONA_LDO1_CONTROL_2, + ARIZONA_LDO1_HI_PWR, val); + if (ret != 0) + return ret; + + ret = regmap_update_bits(regmap, ARIZONA_DYNAMIC_FREQUENCY_SCALING_1, + ARIZONA_SUBSYS_MAX_FREQ, val); + if (ret != 0) + return ret; + + if (val) + return 0; + + val = sel << ARIZONA_LDO1_VSEL_SHIFT; + + return regmap_update_bits(regmap, ARIZONA_LDO1_CONTROL_1, + ARIZONA_LDO1_VSEL_MASK, val); +} + +static int arizona_ldo1_hc_get_voltage_sel(struct regulator_dev *rdev) +{ + struct arizona_ldo1 *ldo = rdev_get_drvdata(rdev); + struct regmap *regmap = ldo->arizona->regmap; + unsigned int val; + int ret; + + ret = regmap_read(regmap, ARIZONA_LDO1_CONTROL_2, &val); + if (ret != 0) + return ret; + + if (val & ARIZONA_LDO1_HI_PWR) + return rdev->desc->n_voltages - 1; + + ret = regmap_read(regmap, ARIZONA_LDO1_CONTROL_1, &val); + if (ret != 0) + return ret; + + return (val & ARIZONA_LDO1_VSEL_MASK) >> ARIZONA_LDO1_VSEL_SHIFT; +} + +static struct regulator_ops arizona_ldo1_hc_ops = { + .list_voltage = arizona_ldo1_hc_list_voltage, + .map_voltage = arizona_ldo1_hc_map_voltage, + .get_voltage_sel = arizona_ldo1_hc_get_voltage_sel, + .set_voltage_sel = arizona_ldo1_hc_set_voltage_sel, + .get_bypass = regulator_get_bypass_regmap, + .set_bypass = regulator_set_bypass_regmap, +}; + +static const struct regulator_desc arizona_ldo1_hc = { + .name = "LDO1", + .supply_name = "LDOVDD", + .type = REGULATOR_VOLTAGE, + .ops = &arizona_ldo1_hc_ops, + + .bypass_reg = ARIZONA_LDO1_CONTROL_1, + .bypass_mask = ARIZONA_LDO1_BYPASS, + .min_uV = 900000, + .uV_step = 50000, + .n_voltages = 8, + .enable_time = 500, + + .owner = THIS_MODULE, +}; + static struct regulator_ops arizona_ldo1_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, @@ -55,11 +157,22 @@ static const struct regulator_desc arizona_ldo1 = { .bypass_mask = ARIZONA_LDO1_BYPASS, .min_uV = 900000, .uV_step = 50000, - .n_voltages = 6, + .n_voltages = 7, + .enable_time = 500, .owner = THIS_MODULE, }; +static const struct regulator_init_data arizona_ldo1_dvfs = { + .constraints = { + .min_uV = 1200000, + .max_uV = 1800000, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | + REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = 1, +}; + static const struct regulator_init_data arizona_ldo1_default = { .constraints = { .valid_ops_mask = REGULATOR_CHANGE_STATUS, @@ -67,9 +180,10 @@ static const struct regulator_init_data arizona_ldo1_default = { .num_consumer_supplies = 1, }; -static __devinit int arizona_ldo1_probe(struct platform_device *pdev) +static int arizona_ldo1_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); + const struct regulator_desc *desc; struct regulator_config config = { }; struct arizona_ldo1 *ldo1; int ret; @@ -87,7 +201,17 @@ static __devinit int arizona_ldo1_probe(struct platform_device *pdev) * default init_data for it. This will be overridden with * platform data if provided. */ - ldo1->init_data = arizona_ldo1_default; + switch (arizona->type) { + case WM5102: + desc = &arizona_ldo1_hc; + ldo1->init_data = arizona_ldo1_dvfs; + break; + default: + desc = &arizona_ldo1; + ldo1->init_data = arizona_ldo1_default; + break; + } + ldo1->init_data.consumer_supplies = &ldo1->supply; ldo1->supply.supply = "DCVDD"; ldo1->supply.dev_name = dev_name(arizona->dev); @@ -102,7 +226,7 @@ static __devinit int arizona_ldo1_probe(struct platform_device *pdev) else config.init_data = &ldo1->init_data; - ldo1->regulator = regulator_register(&arizona_ldo1, &config); + ldo1->regulator = regulator_register(desc, &config); if (IS_ERR(ldo1->regulator)) { ret = PTR_ERR(ldo1->regulator); dev_err(arizona->dev, "Failed to register LDO1 supply: %d\n", @@ -115,7 +239,7 @@ static __devinit int arizona_ldo1_probe(struct platform_device *pdev) return 0; } -static __devexit int arizona_ldo1_remove(struct platform_device *pdev) +static int arizona_ldo1_remove(struct platform_device *pdev) { struct arizona_ldo1 *ldo1 = platform_get_drvdata(pdev); @@ -126,7 +250,7 @@ static __devexit int arizona_ldo1_remove(struct platform_device *pdev) static struct platform_driver arizona_ldo1_driver = { .probe = arizona_ldo1_probe, - .remove = __devexit_p(arizona_ldo1_remove), + .remove = arizona_ldo1_remove, .driver = { .name = "arizona-ldo1", .owner = THIS_MODULE, diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c index d9b1f82cc5bd..a6d040cbf8ac 100644 --- a/drivers/regulator/arizona-micsupp.c +++ b/drivers/regulator/arizona-micsupp.c @@ -101,6 +101,8 @@ static const struct regulator_desc arizona_micsupp = { .bypass_reg = ARIZONA_MIC_CHARGE_PUMP_1, .bypass_mask = ARIZONA_CPMIC_BYPASS, + .enable_time = 3000, + .owner = THIS_MODULE, }; @@ -115,7 +117,7 @@ static const struct regulator_init_data arizona_micsupp_default = { .num_consumer_supplies = 1, }; -static __devinit int arizona_micsupp_probe(struct platform_device *pdev) +static int arizona_micsupp_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = { }; @@ -166,7 +168,7 @@ static __devinit int arizona_micsupp_probe(struct platform_device *pdev) return 0; } -static __devexit int arizona_micsupp_remove(struct platform_device *pdev) +static int arizona_micsupp_remove(struct platform_device *pdev) { struct arizona_micsupp *micsupp = platform_get_drvdata(pdev); @@ -177,7 +179,7 @@ static __devexit int arizona_micsupp_remove(struct platform_device *pdev) static struct platform_driver arizona_micsupp_driver = { .probe = arizona_micsupp_probe, - .remove = __devexit_p(arizona_micsupp_remove), + .remove = arizona_micsupp_remove, .driver = { .name = "arizona-micsupp", .owner = THIS_MODULE, diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c new file mode 100644 index 000000000000..2f1341db38a0 --- /dev/null +++ b/drivers/regulator/as3711-regulator.c @@ -0,0 +1,369 @@ +/* + * AS3711 PMIC regulator driver, using DCDC Step Down and LDO supplies + * + * Copyright (C) 2012 Renesas Electronics Corporation + * Author: Guennadi Liakhovetski, <g.liakhovetski@gmx.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License as + * published by the Free Software Foundation + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/mfd/as3711.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/slab.h> + +struct as3711_regulator_info { + struct regulator_desc desc; + unsigned int max_uV; +}; + +struct as3711_regulator { + struct as3711_regulator_info *reg_info; + struct regulator_dev *rdev; +}; + +static int as3711_list_voltage_sd(struct regulator_dev *rdev, + unsigned int selector) +{ + if (selector >= rdev->desc->n_voltages) + return -EINVAL; + + if (!selector) + return 0; + if (selector < 0x41) + return 600000 + selector * 12500; + if (selector < 0x71) + return 1400000 + (selector - 0x40) * 25000; + return 2600000 + (selector - 0x70) * 50000; +} + +static int as3711_list_voltage_aldo(struct regulator_dev *rdev, + unsigned int selector) +{ + if (selector >= rdev->desc->n_voltages) + return -EINVAL; + + if (selector < 0x10) + return 1200000 + selector * 50000; + return 1800000 + (selector - 0x10) * 100000; +} + +static int as3711_list_voltage_dldo(struct regulator_dev *rdev, + unsigned int selector) +{ + if (selector >= rdev->desc->n_voltages || + (selector > 0x10 && selector < 0x20)) + return -EINVAL; + + if (selector < 0x11) + return 900000 + selector * 50000; + return 1750000 + (selector - 0x20) * 50000; +} + +static int as3711_bound_check(struct regulator_dev *rdev, + int *min_uV, int *max_uV) +{ + struct as3711_regulator *reg = rdev_get_drvdata(rdev); + struct as3711_regulator_info *info = reg->reg_info; + + dev_dbg(&rdev->dev, "%s(), %d, %d, %d\n", __func__, + *min_uV, rdev->desc->min_uV, info->max_uV); + + if (*max_uV < *min_uV || + *min_uV > info->max_uV || rdev->desc->min_uV > *max_uV) + return -EINVAL; + + if (rdev->desc->n_voltages == 1) + return 0; + + if (*max_uV > info->max_uV) + *max_uV = info->max_uV; + + if (*min_uV < rdev->desc->min_uV) + *min_uV = rdev->desc->min_uV; + + return *min_uV; +} + +static int as3711_sel_check(int min, int max, int bottom, int step) +{ + int sel, voltage; + + /* Round up min, when dividing: keeps us within the range */ + sel = DIV_ROUND_UP(min - bottom, step); + voltage = sel * step + bottom; + pr_debug("%s(): select %d..%d in %d+N*%d: %d\n", __func__, + min, max, bottom, step, sel); + if (voltage > max) + return -EINVAL; + + return sel; +} + +static int as3711_map_voltage_sd(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + int ret; + + ret = as3711_bound_check(rdev, &min_uV, &max_uV); + if (ret <= 0) + return ret; + + if (min_uV <= 1400000) + return as3711_sel_check(min_uV, max_uV, 600000, 12500); + + if (min_uV <= 2600000) + return as3711_sel_check(min_uV, max_uV, 1400000, 25000) + 0x40; + + return as3711_sel_check(min_uV, max_uV, 2600000, 50000) + 0x70; +} + +/* + * The regulator API supports 4 modes of operataion: FAST, NORMAL, IDLE and + * STANDBY. We map them in the following way to AS3711 SD1-4 DCDC modes: + * FAST: sdX_fast=1 + * NORMAL: low_noise=1 + * IDLE: low_noise=0 + */ + +static int as3711_set_mode_sd(struct regulator_dev *rdev, unsigned int mode) +{ + unsigned int fast_bit = rdev->desc->enable_mask, + low_noise_bit = fast_bit << 4; + u8 val; + + switch (mode) { + case REGULATOR_MODE_FAST: + val = fast_bit | low_noise_bit; + break; + case REGULATOR_MODE_NORMAL: + val = low_noise_bit; + break; + case REGULATOR_MODE_IDLE: + val = 0; + break; + default: + return -EINVAL; + } + + return regmap_update_bits(rdev->regmap, AS3711_SD_CONTROL_1, + low_noise_bit | fast_bit, val); +} + +static unsigned int as3711_get_mode_sd(struct regulator_dev *rdev) +{ + unsigned int fast_bit = rdev->desc->enable_mask, + low_noise_bit = fast_bit << 4, mask = fast_bit | low_noise_bit; + unsigned int val; + int ret = regmap_read(rdev->regmap, AS3711_SD_CONTROL_1, &val); + + if (ret < 0) + return ret; + + if ((val & mask) == mask) + return REGULATOR_MODE_FAST; + + if ((val & mask) == low_noise_bit) + return REGULATOR_MODE_NORMAL; + + if (!(val & mask)) + return REGULATOR_MODE_IDLE; + + return -EINVAL; +} + +static int as3711_map_voltage_aldo(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + int ret; + + ret = as3711_bound_check(rdev, &min_uV, &max_uV); + if (ret <= 0) + return ret; + + if (min_uV <= 1800000) + return as3711_sel_check(min_uV, max_uV, 1200000, 50000); + + return as3711_sel_check(min_uV, max_uV, 1800000, 100000) + 0x10; +} + +static int as3711_map_voltage_dldo(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + int ret; + + ret = as3711_bound_check(rdev, &min_uV, &max_uV); + if (ret <= 0) + return ret; + + if (min_uV <= 1700000) + return as3711_sel_check(min_uV, max_uV, 900000, 50000); + + return as3711_sel_check(min_uV, max_uV, 1750000, 50000) + 0x20; +} + +static struct regulator_ops as3711_sd_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = as3711_list_voltage_sd, + .map_voltage = as3711_map_voltage_sd, + .get_mode = as3711_get_mode_sd, + .set_mode = as3711_set_mode_sd, +}; + +static struct regulator_ops as3711_aldo_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = as3711_list_voltage_aldo, + .map_voltage = as3711_map_voltage_aldo, +}; + +static struct regulator_ops as3711_dldo_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = as3711_list_voltage_dldo, + .map_voltage = as3711_map_voltage_dldo, +}; + +#define AS3711_REG(_id, _en_reg, _en_bit, _vmask, _vshift, _min_uV, _max_uV, _sfx) \ + [AS3711_REGULATOR_ ## _id] = { \ + .desc = { \ + .name = "as3711-regulator-" # _id, \ + .id = AS3711_REGULATOR_ ## _id, \ + .n_voltages = (_vmask + 1), \ + .ops = &as3711_ ## _sfx ## _ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .vsel_reg = AS3711_ ## _id ## _VOLTAGE, \ + .vsel_mask = _vmask << _vshift, \ + .enable_reg = AS3711_ ## _en_reg, \ + .enable_mask = BIT(_en_bit), \ + .min_uV = _min_uV, \ + }, \ + .max_uV = _max_uV, \ +} + +static struct as3711_regulator_info as3711_reg_info[] = { + AS3711_REG(SD_1, SD_CONTROL, 0, 0x7f, 0, 612500, 3350000, sd), + AS3711_REG(SD_2, SD_CONTROL, 1, 0x7f, 0, 612500, 3350000, sd), + AS3711_REG(SD_3, SD_CONTROL, 2, 0x7f, 0, 612500, 3350000, sd), + AS3711_REG(SD_4, SD_CONTROL, 3, 0x7f, 0, 612500, 3350000, sd), + AS3711_REG(LDO_1, LDO_1_VOLTAGE, 7, 0x1f, 0, 1200000, 3300000, aldo), + AS3711_REG(LDO_2, LDO_2_VOLTAGE, 7, 0x1f, 0, 1200000, 3300000, aldo), + AS3711_REG(LDO_3, LDO_3_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), + AS3711_REG(LDO_4, LDO_4_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), + AS3711_REG(LDO_5, LDO_5_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), + AS3711_REG(LDO_6, LDO_6_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), + AS3711_REG(LDO_7, LDO_7_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), + AS3711_REG(LDO_8, LDO_8_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), + /* StepUp output voltage depends on supplying regulator */ +}; + +#define AS3711_REGULATOR_NUM ARRAY_SIZE(as3711_reg_info) + +static int as3711_regulator_probe(struct platform_device *pdev) +{ + struct as3711_regulator_pdata *pdata = dev_get_platdata(&pdev->dev); + struct as3711 *as3711 = dev_get_drvdata(pdev->dev.parent); + struct regulator_init_data *reg_data; + struct regulator_config config = {.dev = &pdev->dev,}; + struct as3711_regulator *reg = NULL; + struct as3711_regulator *regs; + struct regulator_dev *rdev; + struct as3711_regulator_info *ri; + int ret; + int id; + + if (!pdata) + dev_dbg(&pdev->dev, "No platform data...\n"); + + regs = devm_kzalloc(&pdev->dev, AS3711_REGULATOR_NUM * + sizeof(struct as3711_regulator), GFP_KERNEL); + if (!regs) { + dev_err(&pdev->dev, "Memory allocation failed exiting..\n"); + return -ENOMEM; + } + + for (id = 0, ri = as3711_reg_info; id < AS3711_REGULATOR_NUM; ++id, ri++) { + reg_data = pdata ? pdata->init_data[id] : NULL; + + /* No need to register if there is no regulator data */ + if (!ri->desc.name) + continue; + + reg = ®s[id]; + reg->reg_info = ri; + + config.init_data = reg_data; + config.driver_data = reg; + config.regmap = as3711->regmap; + + rdev = regulator_register(&ri->desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "Failed to register regulator %s\n", + ri->desc.name); + ret = PTR_ERR(rdev); + goto eregreg; + } + reg->rdev = rdev; + } + platform_set_drvdata(pdev, regs); + return 0; + +eregreg: + while (--id >= 0) + regulator_unregister(regs[id].rdev); + + return ret; +} + +static int as3711_regulator_remove(struct platform_device *pdev) +{ + struct as3711_regulator *regs = platform_get_drvdata(pdev); + int id; + + for (id = 0; id < AS3711_REGULATOR_NUM; ++id) + regulator_unregister(regs[id].rdev); + return 0; +} + +static struct platform_driver as3711_regulator_driver = { + .driver = { + .name = "as3711-regulator", + .owner = THIS_MODULE, + }, + .probe = as3711_regulator_probe, + .remove = as3711_regulator_remove, +}; + +static int __init as3711_regulator_init(void) +{ + return platform_driver_register(&as3711_regulator_driver); +} +subsys_initcall(as3711_regulator_init); + +static void __exit as3711_regulator_exit(void) +{ + platform_driver_unregister(&as3711_regulator_driver); +} +module_exit(as3711_regulator_exit); + +MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); +MODULE_DESCRIPTION("AS3711 regulator driver"); +MODULE_ALIAS("platform:as3711-regulator"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e872c8be080e..35c149bb2ad3 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -199,8 +199,11 @@ static int regulator_check_consumers(struct regulator_dev *rdev, *min_uV = regulator->min_uV; } - if (*min_uV > *max_uV) + if (*min_uV > *max_uV) { + dev_err(regulator->dev, "Restricting voltage, %u-%uuV\n", + regulator->min_uV, regulator->max_uV); return -EINVAL; + } return 0; } @@ -880,7 +883,9 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, /* final: [min_uV..max_uV] valid iff constraints valid */ if (max_uV < min_uV) { - rdev_err(rdev, "unsupportable voltage constraints\n"); + rdev_err(rdev, + "unsupportable voltage constraints %u-%uuV\n", + min_uV, max_uV); return -EINVAL; } @@ -1867,6 +1872,28 @@ int regulator_is_enabled(struct regulator *regulator) EXPORT_SYMBOL_GPL(regulator_is_enabled); /** + * regulator_can_change_voltage - check if regulator can change voltage + * @regulator: regulator source + * + * Returns positive if the regulator driver backing the source/client + * can change its voltage, false otherwise. Usefull for detecting fixed + * or dummy regulators and disabling voltage change logic in the client + * driver. + */ +int regulator_can_change_voltage(struct regulator *regulator) +{ + struct regulator_dev *rdev = regulator->rdev; + + if (rdev->constraints && + rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE && + rdev->desc->n_voltages > 1) + return 1; + + return 0; +} +EXPORT_SYMBOL_GPL(regulator_can_change_voltage); + +/** * regulator_count_voltages - count regulator_list_voltage() selectors * @regulator: regulator source * @@ -1985,6 +2012,11 @@ int regulator_is_supported_voltage(struct regulator *regulator, return ret; } + /* Any voltage within constrains range is fine? */ + if (rdev->desc->continuous_voltage_range) + return min_uV >= rdev->constraints->min_uV && + max_uV <= rdev->constraints->max_uV; + ret = regulator_count_voltages(regulator); if (ret < 0) return ret; diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index 36c5b92fe0af..2afa5730f324 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -460,7 +460,7 @@ static inline struct da903x_regulator_info *find_regulator_info(int id) return NULL; } -static int __devinit da903x_regulator_probe(struct platform_device *pdev) +static int da903x_regulator_probe(struct platform_device *pdev) { struct da903x_regulator_info *ri = NULL; struct regulator_dev *rdev; @@ -499,7 +499,7 @@ static int __devinit da903x_regulator_probe(struct platform_device *pdev) return 0; } -static int __devexit da903x_regulator_remove(struct platform_device *pdev) +static int da903x_regulator_remove(struct platform_device *pdev) { struct regulator_dev *rdev = platform_get_drvdata(pdev); @@ -513,7 +513,7 @@ static struct platform_driver da903x_regulator_driver = { .owner = THIS_MODULE, }, .probe = da903x_regulator_probe, - .remove = __devexit_p(da903x_regulator_remove), + .remove = da903x_regulator_remove, }; static int __init da903x_regulator_init(void) diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index 27355b1199e5..d0963090442d 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c @@ -129,17 +129,17 @@ static int da9052_dcdc_set_current_limit(struct regulator_dev *rdev, int min_uA, else if (offset == 0) row = 1; - if (min_uA > da9052_current_limits[row][DA9052_MAX_UA] || - max_uA < da9052_current_limits[row][DA9052_MIN_UA]) - return -EINVAL; - for (i = DA9052_CURRENT_RANGE - 1; i >= 0; i--) { - if (da9052_current_limits[row][i] <= max_uA) { + if ((min_uA <= da9052_current_limits[row][i]) && + (da9052_current_limits[row][i] <= max_uA)) { reg_val = i; break; } } + if (i < 0) + return -EINVAL; + /* Determine the even or odd position of the buck current limit * register field */ @@ -365,7 +365,7 @@ static inline struct da9052_regulator_info *find_regulator_info(u8 chip_id, return NULL; } -static int __devinit da9052_regulator_probe(struct platform_device *pdev) +static int da9052_regulator_probe(struct platform_device *pdev) { struct regulator_config config = { }; struct da9052_regulator *regulator; @@ -430,7 +430,7 @@ static int __devinit da9052_regulator_probe(struct platform_device *pdev) return 0; } -static int __devexit da9052_regulator_remove(struct platform_device *pdev) +static int da9052_regulator_remove(struct platform_device *pdev) { struct da9052_regulator *regulator = platform_get_drvdata(pdev); @@ -440,7 +440,7 @@ static int __devexit da9052_regulator_remove(struct platform_device *pdev) static struct platform_driver da9052_regulator_driver = { .probe = da9052_regulator_probe, - .remove = __devexit_p(da9052_regulator_remove), + .remove = da9052_regulator_remove, .driver = { .name = "da9052-regulator", .owner = THIS_MODULE, diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c new file mode 100644 index 000000000000..db59ce7534cd --- /dev/null +++ b/drivers/regulator/da9055-regulator.c @@ -0,0 +1,680 @@ +/* +* Regulator driver for DA9055 PMIC +* +* Copyright(c) 2012 Dialog Semiconductor Ltd. +* +* Author: David Dajun Chen <dchen@diasemi.com> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +*/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> + +#include <linux/mfd/da9055/core.h> +#include <linux/mfd/da9055/reg.h> +#include <linux/mfd/da9055/pdata.h> + +#define DA9055_MIN_UA 0 +#define DA9055_MAX_UA 3 + +#define DA9055_LDO_MODE_SYNC 0 +#define DA9055_LDO_MODE_SLEEP 1 + +#define DA9055_BUCK_MODE_SLEEP 1 +#define DA9055_BUCK_MODE_SYNC 2 +#define DA9055_BUCK_MODE_AUTO 3 + +/* DA9055 REGULATOR IDs */ +#define DA9055_ID_BUCK1 0 +#define DA9055_ID_BUCK2 1 +#define DA9055_ID_LDO1 2 +#define DA9055_ID_LDO2 3 +#define DA9055_ID_LDO3 4 +#define DA9055_ID_LDO4 5 +#define DA9055_ID_LDO5 6 +#define DA9055_ID_LDO6 7 + +/* DA9055 BUCK current limit */ +static const int da9055_current_limits[] = { 500000, 600000, 700000, 800000 }; + +struct da9055_conf_reg { + int reg; + int sel_mask; + int en_mask; +}; + +struct da9055_volt_reg { + int reg_a; + int reg_b; + int sl_shift; + int v_offset; + int v_mask; + int v_shift; +}; + +struct da9055_mode_reg { + int reg; + int mask; + int shift; +}; + +struct da9055_regulator_info { + struct regulator_desc reg_desc; + struct da9055_conf_reg conf; + struct da9055_volt_reg volt; + struct da9055_mode_reg mode; +}; + +struct da9055_regulator { + struct da9055 *da9055; + struct da9055_regulator_info *info; + struct regulator_dev *rdev; + enum gpio_select reg_rselect; +}; + +static unsigned int da9055_buck_get_mode(struct regulator_dev *rdev) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + int ret, mode = 0; + + ret = da9055_reg_read(regulator->da9055, info->mode.reg); + if (ret < 0) + return ret; + + switch ((ret & info->mode.mask) >> info->mode.shift) { + case DA9055_BUCK_MODE_SYNC: + mode = REGULATOR_MODE_FAST; + break; + case DA9055_BUCK_MODE_AUTO: + mode = REGULATOR_MODE_NORMAL; + break; + case DA9055_BUCK_MODE_SLEEP: + mode = REGULATOR_MODE_STANDBY; + break; + } + + return mode; +} + +static int da9055_buck_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + int val = 0; + + switch (mode) { + case REGULATOR_MODE_FAST: + val = DA9055_BUCK_MODE_SYNC << info->mode.shift; + break; + case REGULATOR_MODE_NORMAL: + val = DA9055_BUCK_MODE_AUTO << info->mode.shift; + break; + case REGULATOR_MODE_STANDBY: + val = DA9055_BUCK_MODE_SLEEP << info->mode.shift; + break; + } + + return da9055_reg_update(regulator->da9055, info->mode.reg, + info->mode.mask, val); +} + +static unsigned int da9055_ldo_get_mode(struct regulator_dev *rdev) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + int ret; + + ret = da9055_reg_read(regulator->da9055, info->volt.reg_b); + if (ret < 0) + return ret; + + if (ret >> info->volt.sl_shift) + return REGULATOR_MODE_STANDBY; + else + return REGULATOR_MODE_NORMAL; +} + +static int da9055_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + struct da9055_volt_reg volt = info->volt; + int val = 0; + + switch (mode) { + case REGULATOR_MODE_NORMAL: + case REGULATOR_MODE_FAST: + val = DA9055_LDO_MODE_SYNC; + break; + case REGULATOR_MODE_STANDBY: + val = DA9055_LDO_MODE_SLEEP; + break; + } + + return da9055_reg_update(regulator->da9055, volt.reg_b, + 1 << volt.sl_shift, + val << volt.sl_shift); +} + +static int da9055_buck_get_current_limit(struct regulator_dev *rdev) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + int ret; + + ret = da9055_reg_read(regulator->da9055, DA9055_REG_BUCK_LIM); + if (ret < 0) + return ret; + + ret &= info->mode.mask; + return da9055_current_limits[ret >> info->mode.shift]; +} + +static int da9055_buck_set_current_limit(struct regulator_dev *rdev, int min_uA, + int max_uA) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + int i; + + for (i = ARRAY_SIZE(da9055_current_limits) - 1; i >= 0; i--) { + if ((min_uA <= da9055_current_limits[i]) && + (da9055_current_limits[i] <= max_uA)) + return da9055_reg_update(regulator->da9055, + DA9055_REG_BUCK_LIM, + info->mode.mask, + i << info->mode.shift); + } + + return -EINVAL; +} + +static int da9055_list_voltage(struct regulator_dev *rdev, unsigned selector) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + + if (selector >= rdev->desc->n_voltages) + return -EINVAL; + + if (selector < info->volt.v_offset) + return 0; + + selector -= info->volt.v_offset; + return rdev->desc->min_uV + (rdev->desc->uV_step * selector); +} + +static int da9055_map_voltage(struct regulator_dev *rdev, int min_uV, + int max_uV) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + int sel, voltage; + + if (min_uV < rdev->desc->min_uV) + min_uV = rdev->desc->min_uV; + + sel = DIV_ROUND_UP(min_uV - rdev->desc->min_uV, rdev->desc->uV_step); + sel += info->volt.v_offset; + + voltage = da9055_list_voltage(rdev, sel); + if (voltage < min_uV || voltage > max_uV) + return -EINVAL; + + return sel; +} + +static int da9055_regulator_get_voltage_sel(struct regulator_dev *rdev) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + struct da9055_volt_reg volt = info->volt; + int ret, sel; + + /* + * There are two voltage register set A & B for voltage ramping but + * either one of then can be active therefore we first determine + * the active register set. + */ + ret = da9055_reg_read(regulator->da9055, info->conf.reg); + if (ret < 0) + return ret; + + ret &= info->conf.sel_mask; + + /* Get the voltage for the active register set A/B */ + if (ret == DA9055_REGUALTOR_SET_A) + ret = da9055_reg_read(regulator->da9055, volt.reg_a); + else + ret = da9055_reg_read(regulator->da9055, volt.reg_b); + + if (ret < 0) + return ret; + + sel = (ret & volt.v_mask); + if (sel <= volt.v_offset) + return 0; + else + return sel; +} + +static int da9055_regulator_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + int ret; + + /* + * Regulator register set A/B is not selected through GPIO therefore + * we use default register set A for voltage ramping. + */ + if (regulator->reg_rselect == NO_GPIO) { + /* Select register set A */ + ret = da9055_reg_update(regulator->da9055, info->conf.reg, + info->conf.sel_mask, DA9055_SEL_REG_A); + if (ret < 0) + return ret; + + /* Set the voltage */ + return da9055_reg_update(regulator->da9055, info->volt.reg_a, + info->volt.v_mask, selector); + } + + /* + * Here regulator register set A/B is selected through GPIO. + * Therefore we first determine the selected register set A/B and + * then set the desired voltage for that register set A/B. + */ + ret = da9055_reg_read(regulator->da9055, info->conf.reg); + if (ret < 0) + return ret; + + ret &= info->conf.sel_mask; + + /* Set the voltage */ + if (ret == DA9055_REGUALTOR_SET_A) + return da9055_reg_update(regulator->da9055, info->volt.reg_a, + info->volt.v_mask, selector); + else + return da9055_reg_update(regulator->da9055, info->volt.reg_b, + info->volt.v_mask, selector); +} + +static int da9055_regulator_set_suspend_voltage(struct regulator_dev *rdev, + int uV) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + int ret; + + /* Select register set B for suspend voltage ramping. */ + if (regulator->reg_rselect == NO_GPIO) { + ret = da9055_reg_update(regulator->da9055, info->conf.reg, + info->conf.sel_mask, DA9055_SEL_REG_B); + if (ret < 0) + return ret; + } + + ret = da9055_map_voltage(rdev, uV, uV); + if (ret < 0) + return ret; + + return da9055_reg_update(regulator->da9055, info->volt.reg_b, + info->volt.v_mask, ret); +} + +static int da9055_suspend_enable(struct regulator_dev *rdev) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + + /* Select register set B for voltage ramping. */ + if (regulator->reg_rselect == NO_GPIO) + return da9055_reg_update(regulator->da9055, info->conf.reg, + info->conf.sel_mask, DA9055_SEL_REG_B); + else + return 0; +} + +static int da9055_suspend_disable(struct regulator_dev *rdev) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + + /* Diselect register set B. */ + if (regulator->reg_rselect == NO_GPIO) + return da9055_reg_update(regulator->da9055, info->conf.reg, + info->conf.sel_mask, DA9055_SEL_REG_A); + else + return 0; +} + +static struct regulator_ops da9055_buck_ops = { + .get_mode = da9055_buck_get_mode, + .set_mode = da9055_buck_set_mode, + + .get_current_limit = da9055_buck_get_current_limit, + .set_current_limit = da9055_buck_set_current_limit, + + .get_voltage_sel = da9055_regulator_get_voltage_sel, + .set_voltage_sel = da9055_regulator_set_voltage_sel, + .list_voltage = da9055_list_voltage, + .map_voltage = da9055_map_voltage, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + + .set_suspend_voltage = da9055_regulator_set_suspend_voltage, + .set_suspend_enable = da9055_suspend_enable, + .set_suspend_disable = da9055_suspend_disable, + .set_suspend_mode = da9055_buck_set_mode, +}; + +static struct regulator_ops da9055_ldo_ops = { + .get_mode = da9055_ldo_get_mode, + .set_mode = da9055_ldo_set_mode, + + .get_voltage_sel = da9055_regulator_get_voltage_sel, + .set_voltage_sel = da9055_regulator_set_voltage_sel, + .list_voltage = da9055_list_voltage, + .map_voltage = da9055_map_voltage, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + + .set_suspend_voltage = da9055_regulator_set_suspend_voltage, + .set_suspend_enable = da9055_suspend_enable, + .set_suspend_disable = da9055_suspend_disable, + .set_suspend_mode = da9055_ldo_set_mode, + +}; + +#define DA9055_LDO(_id, step, min, max, vbits, voffset) \ +{\ + .reg_desc = {\ + .name = #_id,\ + .ops = &da9055_ldo_ops,\ + .type = REGULATOR_VOLTAGE,\ + .id = DA9055_ID_##_id,\ + .n_voltages = (max - min) / step + 1 + (voffset), \ + .enable_reg = DA9055_REG_BCORE_CONT + DA9055_ID_##_id, \ + .enable_mask = 1, \ + .min_uV = (min) * 1000,\ + .uV_step = (step) * 1000,\ + .owner = THIS_MODULE,\ + },\ + .conf = {\ + .reg = DA9055_REG_BCORE_CONT + DA9055_ID_##_id, \ + .sel_mask = (1 << 4),\ + .en_mask = 1,\ + },\ + .volt = {\ + .reg_a = DA9055_REG_VBCORE_A + DA9055_ID_##_id, \ + .reg_b = DA9055_REG_VBCORE_B + DA9055_ID_##_id, \ + .sl_shift = 7,\ + .v_offset = (voffset),\ + .v_mask = (1 << (vbits)) - 1,\ + .v_shift = (vbits),\ + },\ +} + +#define DA9055_BUCK(_id, step, min, max, vbits, voffset, mbits, sbits) \ +{\ + .reg_desc = {\ + .name = #_id,\ + .ops = &da9055_buck_ops,\ + .type = REGULATOR_VOLTAGE,\ + .id = DA9055_ID_##_id,\ + .n_voltages = (max - min) / step + 1 + (voffset), \ + .enable_reg = DA9055_REG_BCORE_CONT + DA9055_ID_##_id, \ + .enable_mask = 1,\ + .min_uV = (min) * 1000,\ + .uV_step = (step) * 1000,\ + .owner = THIS_MODULE,\ + },\ + .conf = {\ + .reg = DA9055_REG_BCORE_CONT + DA9055_ID_##_id, \ + .sel_mask = (1 << 4),\ + .en_mask = 1,\ + },\ + .volt = {\ + .reg_a = DA9055_REG_VBCORE_A + DA9055_ID_##_id, \ + .reg_b = DA9055_REG_VBCORE_B + DA9055_ID_##_id, \ + .sl_shift = 7,\ + .v_offset = (voffset),\ + .v_mask = (1 << (vbits)) - 1,\ + .v_shift = (vbits),\ + },\ + .mode = {\ + .reg = DA9055_REG_BCORE_MODE,\ + .mask = (mbits),\ + .shift = (sbits),\ + },\ +} + +static struct da9055_regulator_info da9055_regulator_info[] = { + DA9055_BUCK(BUCK1, 25, 725, 2075, 6, 9, 0xc, 2), + DA9055_BUCK(BUCK2, 25, 925, 2500, 6, 0, 3, 0), + DA9055_LDO(LDO1, 50, 900, 3300, 6, 2), + DA9055_LDO(LDO2, 50, 900, 3300, 6, 3), + DA9055_LDO(LDO3, 50, 900, 3300, 6, 2), + DA9055_LDO(LDO4, 50, 900, 3300, 6, 2), + DA9055_LDO(LDO5, 50, 900, 2750, 6, 2), + DA9055_LDO(LDO6, 20, 900, 3300, 7, 0), +}; + +/* + * Configures regulator to be controlled either through GPIO 1 or 2. + * GPIO can control regulator state and/or select the regulator register + * set A/B for voltage ramping. + */ +static __devinit int da9055_gpio_init(struct da9055_regulator *regulator, + struct regulator_config *config, + struct da9055_pdata *pdata, int id) +{ + struct da9055_regulator_info *info = regulator->info; + int ret = 0; + + if (pdata->gpio_ren && pdata->gpio_ren[id]) { + char name[18]; + int gpio_mux = pdata->gpio_ren[id]; + + config->ena_gpio = pdata->ena_gpio[id]; + config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH; + config->ena_gpio_invert = 1; + + /* + * GPI pin is muxed with regulator to control the + * regulator state. + */ + sprintf(name, "DA9055 GPI %d", gpio_mux); + ret = devm_gpio_request_one(config->dev, gpio_mux, GPIOF_DIR_IN, + name); + if (ret < 0) + goto err; + + /* + * Let the regulator know that its state is controlled + * through GPI. + */ + ret = da9055_reg_update(regulator->da9055, info->conf.reg, + DA9055_E_GPI_MASK, + pdata->reg_ren[id] + << DA9055_E_GPI_SHIFT); + if (ret < 0) + goto err; + } + + if (pdata->gpio_rsel && pdata->gpio_rsel[id]) { + char name[18]; + int gpio_mux = pdata->gpio_rsel[id]; + + regulator->reg_rselect = pdata->reg_rsel[id]; + + /* + * GPI pin is muxed with regulator to select the + * regulator register set A/B for voltage ramping. + */ + sprintf(name, "DA9055 GPI %d", gpio_mux); + ret = devm_gpio_request_one(config->dev, gpio_mux, GPIOF_DIR_IN, + name); + if (ret < 0) + goto err; + + /* + * Let the regulator know that its register set A/B + * will be selected through GPI for voltage ramping. + */ + ret = da9055_reg_update(regulator->da9055, info->conf.reg, + DA9055_V_GPI_MASK, + pdata->reg_rsel[id] + << DA9055_V_GPI_SHIFT); + } + +err: + return ret; +} + +static irqreturn_t da9055_ldo5_6_oc_irq(int irq, void *data) +{ + struct da9055_regulator *regulator = data; + + regulator_notifier_call_chain(regulator->rdev, + REGULATOR_EVENT_OVER_CURRENT, NULL); + + return IRQ_HANDLED; +} + +static inline struct da9055_regulator_info *find_regulator_info(int id) +{ + struct da9055_regulator_info *info; + int i; + + for (i = 0; i < ARRAY_SIZE(da9055_regulator_info); i++) { + info = &da9055_regulator_info[i]; + if (info->reg_desc.id == id) + return info; + } + + return NULL; +} + +static int __devinit da9055_regulator_probe(struct platform_device *pdev) +{ + struct regulator_config config = { }; + struct da9055_regulator *regulator; + struct da9055 *da9055 = dev_get_drvdata(pdev->dev.parent); + struct da9055_pdata *pdata = da9055->dev->platform_data; + int ret, irq; + + if (pdata == NULL || pdata->regulators[pdev->id] == NULL) + return -ENODEV; + + regulator = devm_kzalloc(&pdev->dev, sizeof(struct da9055_regulator), + GFP_KERNEL); + if (!regulator) + return -ENOMEM; + + regulator->info = find_regulator_info(pdev->id); + if (regulator->info == NULL) { + dev_err(&pdev->dev, "invalid regulator ID specified\n"); + return -EINVAL; + } + + regulator->da9055 = da9055; + config.dev = &pdev->dev; + config.driver_data = regulator; + config.regmap = da9055->regmap; + + if (pdata && pdata->regulators) + config.init_data = pdata->regulators[pdev->id]; + + ret = da9055_gpio_init(regulator, &config, pdata, pdev->id); + if (ret < 0) + return ret; + + regulator->rdev = regulator_register(®ulator->info->reg_desc, + &config); + if (IS_ERR(regulator->rdev)) { + dev_err(&pdev->dev, "Failed to register regulator %s\n", + regulator->info->reg_desc.name); + ret = PTR_ERR(regulator->rdev); + return ret; + } + + /* Only LDO 5 and 6 has got the over current interrupt */ + if (pdev->id == DA9055_ID_LDO5 || pdev->id == DA9055_ID_LDO6) { + irq = platform_get_irq_byname(pdev, "REGULATOR"); + irq = regmap_irq_get_virq(da9055->irq_data, irq); + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + da9055_ldo5_6_oc_irq, + IRQF_TRIGGER_HIGH | + IRQF_ONESHOT | + IRQF_PROBE_SHARED, + pdev->name, regulator); + if (ret != 0) { + if (ret != -EBUSY) { + dev_err(&pdev->dev, + "Failed to request Regulator IRQ %d: %d\n", + irq, ret); + goto err_regulator; + } + } + } + + platform_set_drvdata(pdev, regulator); + + return 0; + +err_regulator: + regulator_unregister(regulator->rdev); + return ret; +} + +static int __devexit da9055_regulator_remove(struct platform_device *pdev) +{ + struct da9055_regulator *regulator = platform_get_drvdata(pdev); + + regulator_unregister(regulator->rdev); + + return 0; +} + +static struct platform_driver da9055_regulator_driver = { + .probe = da9055_regulator_probe, + .remove = __devexit_p(da9055_regulator_remove), + .driver = { + .name = "da9055-regulator", + .owner = THIS_MODULE, + }, +}; + +static int __init da9055_regulator_init(void) +{ + return platform_driver_register(&da9055_regulator_driver); +} +subsys_initcall(da9055_regulator_init); + +static void __exit da9055_regulator_exit(void) +{ + platform_driver_unregister(&da9055_regulator_driver); +} +module_exit(da9055_regulator_exit); + +MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); +MODULE_DESCRIPTION("Power Regulator driver for Dialog DA9055 PMIC"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:da9055-regulator"); diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c index 359f8d18fc3f..219d162b651e 100644 --- a/drivers/regulator/db8500-prcmu.c +++ b/drivers/regulator/db8500-prcmu.c @@ -412,7 +412,7 @@ dbx500_regulator_info[DB8500_NUM_REGULATORS] = { }, }; -static __devinit int db8500_regulator_register(struct platform_device *pdev, +static int db8500_regulator_register(struct platform_device *pdev, struct regulator_init_data *init_data, int id, struct device_node *np) @@ -474,7 +474,7 @@ static struct of_regulator_match db8500_regulator_matches[] = { { .name = "db8500_esram34_ret", .driver_data = (void *) DB8500_REGULATOR_SWITCH_ESRAM34RET, }, }; -static __devinit int +static int db8500_regulator_of_probe(struct platform_device *pdev, struct device_node *np) { @@ -491,7 +491,7 @@ db8500_regulator_of_probe(struct platform_device *pdev, return 0; } -static int __devinit db8500_regulator_probe(struct platform_device *pdev) +static int db8500_regulator_probe(struct platform_device *pdev) { struct regulator_init_data *db8500_init_data = dev_get_platdata(&pdev->dev); diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c index f2e5ecdc5864..261f3d2299bc 100644 --- a/drivers/regulator/dbx500-prcmu.c +++ b/drivers/regulator/dbx500-prcmu.c @@ -173,7 +173,7 @@ int __attribute__((weak)) dbx500_regulator_testcase( return 0; } -int __devinit +int ux500_regulator_debug_init(struct platform_device *pdev, struct dbx500_regulator_info *regulator_info, int num_regulators) @@ -230,7 +230,7 @@ exit_no_debugfs: return -ENOMEM; } -int __devexit ux500_regulator_debug_exit(void) +int ux500_regulator_debug_exit(void) { debugfs_remove_recursive(rdebug.dir); kfree(rdebug.state_after_suspend); diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c index 03a1d7c11ef2..df9f42524abb 100644 --- a/drivers/regulator/dummy.c +++ b/drivers/regulator/dummy.c @@ -37,7 +37,7 @@ static struct regulator_desc dummy_desc = { .ops = &dummy_ops, }; -static int __devinit dummy_regulator_probe(struct platform_device *pdev) +static int dummy_regulator_probe(struct platform_device *pdev) { struct regulator_config config = { }; int ret; diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index 339f4d732e97..9165b0c40ed3 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -230,7 +230,7 @@ static struct regmap_config fan53555_regmap_config = { .val_bits = 8, }; -static int __devinit fan53555_regulator_probe(struct i2c_client *client, +static int fan53555_regulator_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct fan53555_device_info *di; @@ -293,7 +293,7 @@ static int __devinit fan53555_regulator_probe(struct i2c_client *client, } -static int __devexit fan53555_regulator_remove(struct i2c_client *client) +static int fan53555_regulator_remove(struct i2c_client *client) { struct fan53555_device_info *di = i2c_get_clientdata(client); @@ -311,7 +311,7 @@ static struct i2c_driver fan53555_regulator_driver = { .name = "fan53555-regulator", }, .probe = fan53555_regulator_probe, - .remove = __devexit_p(fan53555_regulator_remove), + .remove = fan53555_regulator_remove, .id_table = fan53555_id, }; diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 185468c4d38f..48d5b7608b00 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -134,7 +134,7 @@ static struct regulator_ops fixed_voltage_ops = { .list_voltage = fixed_voltage_list_voltage, }; -static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev) +static int reg_fixed_voltage_probe(struct platform_device *pdev) { struct fixed_voltage_config *config; struct fixed_voltage_data *drvdata; @@ -234,7 +234,7 @@ err: return ret; } -static int __devexit reg_fixed_voltage_remove(struct platform_device *pdev) +static int reg_fixed_voltage_remove(struct platform_device *pdev) { struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev); @@ -255,7 +255,7 @@ MODULE_DEVICE_TABLE(of, fixed_of_match); static struct platform_driver regulator_fixed_voltage_driver = { .probe = reg_fixed_voltage_probe, - .remove = __devexit_p(reg_fixed_voltage_remove), + .remove = reg_fixed_voltage_remove, .driver = { .name = "reg-fixed-voltage", .owner = THIS_MODULE, diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c index 8b5944f2d7d1..2cfd9d3079e8 100644 --- a/drivers/regulator/gpio-regulator.c +++ b/drivers/regulator/gpio-regulator.c @@ -28,9 +28,12 @@ #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> #include <linux/regulator/gpio-regulator.h> #include <linux/gpio.h> #include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_gpio.h> struct gpio_regulator_data { struct regulator_desc desc; @@ -129,18 +132,108 @@ static struct regulator_ops gpio_regulator_voltage_ops = { .list_voltage = gpio_regulator_list_voltage, }; +struct gpio_regulator_config * +of_get_gpio_regulator_config(struct device *dev, struct device_node *np) +{ + struct gpio_regulator_config *config; + struct property *prop; + const char *regtype; + int proplen, gpio, i; + + config = devm_kzalloc(dev, + sizeof(struct gpio_regulator_config), + GFP_KERNEL); + if (!config) + return ERR_PTR(-ENOMEM); + + config->init_data = of_get_regulator_init_data(dev, np); + if (!config->init_data) + return ERR_PTR(-EINVAL); + + config->supply_name = config->init_data->constraints.name; + + if (of_property_read_bool(np, "enable-active-high")) + config->enable_high = true; + + if (of_property_read_bool(np, "enable-at-boot")) + config->enabled_at_boot = true; + + of_property_read_u32(np, "startup-delay-us", &config->startup_delay); + + config->enable_gpio = of_get_named_gpio(np, "enable-gpio", 0); + + /* Fetch GPIOs. */ + for (i = 0; ; i++) + if (of_get_named_gpio(np, "gpios", i) < 0) + break; + config->nr_gpios = i; + + config->gpios = devm_kzalloc(dev, + sizeof(struct gpio) * config->nr_gpios, + GFP_KERNEL); + if (!config->gpios) + return ERR_PTR(-ENOMEM); + + for (i = 0; config->nr_gpios; i++) { + gpio = of_get_named_gpio(np, "gpios", i); + if (gpio < 0) + break; + config->gpios[i].gpio = gpio; + } + + /* Fetch states. */ + prop = of_find_property(np, "states", NULL); + if (!prop) { + dev_err(dev, "No 'states' property found\n"); + return ERR_PTR(-EINVAL); + } + + proplen = prop->length / sizeof(int); + + config->states = devm_kzalloc(dev, + sizeof(struct gpio_regulator_state) + * (proplen / 2), + GFP_KERNEL); + if (!config->states) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < proplen / 2; i++) { + config->states[i].value = + be32_to_cpup((int *)prop->value + (i * 2)); + config->states[i].gpios = + be32_to_cpup((int *)prop->value + (i * 2 + 1)); + } + config->nr_states = i; + + of_property_read_string(np, "regulator-type", ®type); + + if (!strncmp("voltage", regtype, 7)) + config->type = REGULATOR_VOLTAGE; + else if (!strncmp("current", regtype, 7)) + config->type = REGULATOR_CURRENT; + + return config; +} + static struct regulator_ops gpio_regulator_current_ops = { .get_current_limit = gpio_regulator_get_value, .set_current_limit = gpio_regulator_set_current_limit, }; -static int __devinit gpio_regulator_probe(struct platform_device *pdev) +static int gpio_regulator_probe(struct platform_device *pdev) { struct gpio_regulator_config *config = pdev->dev.platform_data; + struct device_node *np = pdev->dev.of_node; struct gpio_regulator_data *drvdata; struct regulator_config cfg = { }; int ptr, ret, state; + if (np) { + config = of_get_gpio_regulator_config(&pdev->dev, np); + if (IS_ERR(config)) + return PTR_ERR(config); + } + drvdata = devm_kzalloc(&pdev->dev, sizeof(struct gpio_regulator_data), GFP_KERNEL); if (drvdata == NULL) { @@ -215,6 +308,7 @@ static int __devinit gpio_regulator_probe(struct platform_device *pdev) cfg.dev = &pdev->dev; cfg.init_data = config->init_data; cfg.driver_data = drvdata; + cfg.of_node = np; if (config->enable_gpio >= 0) cfg.ena_gpio = config->enable_gpio; @@ -254,7 +348,7 @@ err: return ret; } -static int __devexit gpio_regulator_remove(struct platform_device *pdev) +static int gpio_regulator_remove(struct platform_device *pdev) { struct gpio_regulator_data *drvdata = platform_get_drvdata(pdev); @@ -270,12 +364,20 @@ static int __devexit gpio_regulator_remove(struct platform_device *pdev) return 0; } +#if defined(CONFIG_OF) +static const struct of_device_id regulator_gpio_of_match[] __devinitconst = { + { .compatible = "regulator-gpio", }, + {}, +}; +#endif + static struct platform_driver gpio_regulator_driver = { .probe = gpio_regulator_probe, - .remove = __devexit_p(gpio_regulator_remove), + .remove = gpio_regulator_remove, .driver = { .name = "gpio-regulator", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(regulator_gpio_of_match), }, }; diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index d8ecf49a5777..d1e5bee2a26b 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -106,7 +106,7 @@ static const struct regulator_desc isl_rd[] = { }, }; -static int __devinit isl6271a_probe(struct i2c_client *i2c, +static int isl6271a_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct regulator_config config = { }; @@ -151,7 +151,7 @@ error: return err; } -static int __devexit isl6271a_remove(struct i2c_client *i2c) +static int isl6271a_remove(struct i2c_client *i2c) { struct isl_pmic *pmic = i2c_get_clientdata(i2c); int i; @@ -174,7 +174,7 @@ static struct i2c_driver isl6271a_i2c_driver = { .owner = THIS_MODULE, }, .probe = isl6271a_probe, - .remove = __devexit_p(isl6271a_remove), + .remove = isl6271a_remove, .id_table = isl6271a_id, }; diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 7c6e3b8ff484..5f68ff11a298 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -386,7 +386,7 @@ static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val) return ret; } -static int __devinit setup_regulators(struct lp3971 *lp3971, +static int setup_regulators(struct lp3971 *lp3971, struct lp3971_platform_data *pdata) { int i, err; @@ -429,7 +429,7 @@ err_nomem: return err; } -static int __devinit lp3971_i2c_probe(struct i2c_client *i2c, +static int lp3971_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct lp3971 *lp3971; @@ -472,7 +472,7 @@ err_detect: return ret; } -static int __devexit lp3971_i2c_remove(struct i2c_client *i2c) +static int lp3971_i2c_remove(struct i2c_client *i2c) { struct lp3971 *lp3971 = i2c_get_clientdata(i2c); int i; @@ -498,7 +498,7 @@ static struct i2c_driver lp3971_i2c_driver = { .owner = THIS_MODULE, }, .probe = lp3971_i2c_probe, - .remove = __devexit_p(lp3971_i2c_remove), + .remove = lp3971_i2c_remove, .id_table = lp3971_i2c_id, }; diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c index 3cdc755d9b22..69c42c318b87 100644 --- a/drivers/regulator/lp3972.c +++ b/drivers/regulator/lp3972.c @@ -481,7 +481,7 @@ static const struct regulator_desc regulators[] = { }, }; -static int __devinit setup_regulators(struct lp3972 *lp3972, +static int setup_regulators(struct lp3972 *lp3972, struct lp3972_platform_data *pdata) { int i, err; @@ -523,7 +523,7 @@ err_nomem: return err; } -static int __devinit lp3972_i2c_probe(struct i2c_client *i2c, +static int lp3972_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct lp3972 *lp3972; @@ -569,7 +569,7 @@ err_detect: return ret; } -static int __devexit lp3972_i2c_remove(struct i2c_client *i2c) +static int lp3972_i2c_remove(struct i2c_client *i2c) { struct lp3972 *lp3972 = i2c_get_clientdata(i2c); int i; @@ -594,7 +594,7 @@ static struct i2c_driver lp3972_i2c_driver = { .owner = THIS_MODULE, }, .probe = lp3972_i2c_probe, - .remove = __devexit_p(lp3972_i2c_remove), + .remove = lp3972_i2c_remove, .id_table = lp3972_i2c_id, }; diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c index 708f4b6a17dc..9289ead715ca 100644 --- a/drivers/regulator/lp872x.c +++ b/drivers/regulator/lp872x.c @@ -893,7 +893,7 @@ err_dev: return ret; } -static int __devexit lp872x_remove(struct i2c_client *cl) +static int lp872x_remove(struct i2c_client *cl) { struct lp872x *lp = i2c_get_clientdata(cl); @@ -914,7 +914,7 @@ static struct i2c_driver lp872x_driver = { .owner = THIS_MODULE, }, .probe = lp872x_probe, - .remove = __devexit_p(lp872x_remove), + .remove = lp872x_remove, .id_table = lp872x_ids, }; diff --git a/drivers/regulator/lp8788-buck.c b/drivers/regulator/lp8788-buck.c index ba3e0aa402de..aef3f2b0c5ea 100644 --- a/drivers/regulator/lp8788-buck.c +++ b/drivers/regulator/lp8788-buck.c @@ -429,18 +429,6 @@ static struct regulator_desc lp8788_buck_desc[] = { }, }; -static int _gpio_request(struct lp8788_buck *buck, int gpio, char *name) -{ - struct device *dev = buck->lp->dev; - - if (!gpio_is_valid(gpio)) { - dev_err(dev, "invalid gpio: %d\n", gpio); - return -EINVAL; - } - - return devm_gpio_request_one(dev, gpio, DVS_LOW, name); -} - static int lp8788_dvs_gpio_request(struct lp8788_buck *buck, enum lp8788_buck_id id) { @@ -452,7 +440,8 @@ static int lp8788_dvs_gpio_request(struct lp8788_buck *buck, switch (id) { case BUCK1: gpio = pdata->buck1_dvs->gpio; - ret = _gpio_request(buck, gpio, b1_name); + ret = devm_gpio_request_one(buck->lp->dev, gpio, DVS_LOW, + b1_name); if (ret) return ret; @@ -461,7 +450,8 @@ static int lp8788_dvs_gpio_request(struct lp8788_buck *buck, case BUCK2: for (i = 0 ; i < LP8788_NUM_BUCK2_DVS ; i++) { gpio = pdata->buck2_dvs->gpio[i]; - ret = _gpio_request(buck, gpio, b2_name[i]); + ret = devm_gpio_request_one(buck->lp->dev, gpio, + DVS_LOW, b2_name[i]); if (ret) return ret; } @@ -504,7 +494,7 @@ set_default_dvs_mode: default_dvs_mode[id]); } -static __devinit int lp8788_buck_probe(struct platform_device *pdev) +static int lp8788_buck_probe(struct platform_device *pdev) { struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); int id = pdev->id; @@ -542,7 +532,7 @@ static __devinit int lp8788_buck_probe(struct platform_device *pdev) return 0; } -static int __devexit lp8788_buck_remove(struct platform_device *pdev) +static int lp8788_buck_remove(struct platform_device *pdev) { struct lp8788_buck *buck = platform_get_drvdata(pdev); @@ -554,7 +544,7 @@ static int __devexit lp8788_buck_remove(struct platform_device *pdev) static struct platform_driver lp8788_buck_driver = { .probe = lp8788_buck_probe, - .remove = __devexit_p(lp8788_buck_remove), + .remove = lp8788_buck_remove, .driver = { .name = LP8788_DEV_BUCK, .owner = THIS_MODULE, diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c index 6796eeb47dc6..3792741708ce 100644 --- a/drivers/regulator/lp8788-ldo.c +++ b/drivers/regulator/lp8788-ldo.c @@ -126,7 +126,7 @@ struct lp8788_ldo { }; /* DLDO 1, 2, 3, 9 voltage table */ -const int lp8788_dldo1239_vtbl[] = { +static const int lp8788_dldo1239_vtbl[] = { 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000, 2600000, 2700000, 2800000, 2900000, 3000000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, @@ -662,14 +662,6 @@ static int lp8788_config_ldo_enable_mode(struct lp8788_ldo *ldo, [EN_DLDO7] = LP8788_EN_SEL_DLDO7_M, [EN_DLDO911] = LP8788_EN_SEL_DLDO911_M, }; - u8 val[] = { - [EN_ALDO1] = 0 << 5, - [EN_ALDO234] = 0 << 4, - [EN_ALDO5] = 0 << 3, - [EN_ALDO7] = 0 << 2, - [EN_DLDO7] = 0 << 1, - [EN_DLDO911] = 0 << 0, - }; switch (id) { case DLDO7: @@ -708,11 +700,10 @@ static int lp8788_config_ldo_enable_mode(struct lp8788_ldo *ldo, return ret; set_default_ldo_enable_mode: - return lp8788_update_bits(lp, LP8788_EN_SEL, en_mask[enable_id], - val[enable_id]); + return lp8788_update_bits(lp, LP8788_EN_SEL, en_mask[enable_id], 0); } -static __devinit int lp8788_dldo_probe(struct platform_device *pdev) +static int lp8788_dldo_probe(struct platform_device *pdev) { struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); int id = pdev->id; @@ -749,7 +740,7 @@ static __devinit int lp8788_dldo_probe(struct platform_device *pdev) return 0; } -static int __devexit lp8788_dldo_remove(struct platform_device *pdev) +static int lp8788_dldo_remove(struct platform_device *pdev) { struct lp8788_ldo *ldo = platform_get_drvdata(pdev); @@ -761,14 +752,14 @@ static int __devexit lp8788_dldo_remove(struct platform_device *pdev) static struct platform_driver lp8788_dldo_driver = { .probe = lp8788_dldo_probe, - .remove = __devexit_p(lp8788_dldo_remove), + .remove = lp8788_dldo_remove, .driver = { .name = LP8788_DEV_DLDO, .owner = THIS_MODULE, }, }; -static __devinit int lp8788_aldo_probe(struct platform_device *pdev) +static int lp8788_aldo_probe(struct platform_device *pdev) { struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); int id = pdev->id; @@ -805,7 +796,7 @@ static __devinit int lp8788_aldo_probe(struct platform_device *pdev) return 0; } -static int __devexit lp8788_aldo_remove(struct platform_device *pdev) +static int lp8788_aldo_remove(struct platform_device *pdev) { struct lp8788_ldo *ldo = platform_get_drvdata(pdev); @@ -817,7 +808,7 @@ static int __devexit lp8788_aldo_remove(struct platform_device *pdev) static struct platform_driver lp8788_aldo_driver = { .probe = lp8788_aldo_probe, - .remove = __devexit_p(lp8788_aldo_remove), + .remove = lp8788_aldo_remove, .driver = { .name = LP8788_DEV_ALDO, .owner = THIS_MODULE, diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index f67af3c1b963..8c5a54f541b5 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -44,6 +44,9 @@ struct max1586_data { unsigned int min_uV; unsigned int max_uV; + unsigned int v3_curr_sel; + unsigned int v6_curr_sel; + struct regulator_dev *rdev[0]; }; @@ -63,31 +66,60 @@ static int v6_voltages_uv[] = { 1, 1800000, 2500000, 3000000 }; * R24 and R25=100kOhm as described in the data sheet. * The gain is approximately: 1 + R24/R25 + R24/185.5kOhm */ +static int max1586_v3_get_voltage_sel(struct regulator_dev *rdev) +{ + struct max1586_data *max1586 = rdev_get_drvdata(rdev); + + return max1586->v3_curr_sel; +} + static int max1586_v3_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { struct max1586_data *max1586 = rdev_get_drvdata(rdev); struct i2c_client *client = max1586->client; + int ret; u8 v3_prog; dev_dbg(&client->dev, "changing voltage v3 to %dmv\n", regulator_list_voltage_linear(rdev, selector) / 1000); v3_prog = I2C_V3_SELECT | (u8) selector; - return i2c_smbus_write_byte(client, v3_prog); + ret = i2c_smbus_write_byte(client, v3_prog); + if (ret) + return ret; + + max1586->v3_curr_sel = selector; + + return 0; +} + +static int max1586_v6_get_voltage_sel(struct regulator_dev *rdev) +{ + struct max1586_data *max1586 = rdev_get_drvdata(rdev); + + return max1586->v6_curr_sel; } static int max1586_v6_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector) { - struct i2c_client *client = rdev_get_drvdata(rdev); + struct max1586_data *max1586 = rdev_get_drvdata(rdev); + struct i2c_client *client = max1586->client; u8 v6_prog; + int ret; dev_dbg(&client->dev, "changing voltage v6 to %dmv\n", rdev->desc->volt_table[selector] / 1000); v6_prog = I2C_V6_SELECT | (u8) selector; - return i2c_smbus_write_byte(client, v6_prog); + ret = i2c_smbus_write_byte(client, v6_prog); + if (ret) + return ret; + + max1586->v6_curr_sel = selector; + + return 0; } /* @@ -95,12 +127,14 @@ static int max1586_v6_set_voltage_sel(struct regulator_dev *rdev, * the set up value. */ static struct regulator_ops max1586_v3_ops = { + .get_voltage_sel = max1586_v3_get_voltage_sel, .set_voltage_sel = max1586_v3_set_voltage_sel, .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, }; static struct regulator_ops max1586_v6_ops = { + .get_voltage_sel = max1586_v6_get_voltage_sel, .set_voltage_sel = max1586_v6_set_voltage_sel, .list_voltage = regulator_list_voltage_table, }; @@ -125,7 +159,7 @@ static struct regulator_desc max1586_reg[] = { }, }; -static int __devinit max1586_pmic_probe(struct i2c_client *client, +static int max1586_pmic_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { struct regulator_dev **rdev; @@ -148,6 +182,10 @@ static int __devinit max1586_pmic_probe(struct i2c_client *client, max1586->min_uV = MAX1586_V3_MIN_UV / 1000 * pdata->v3_gain / 1000; max1586->max_uV = MAX1586_V3_MAX_UV / 1000 * pdata->v3_gain / 1000; + /* Set curr_sel to default voltage on power-up */ + max1586->v3_curr_sel = 24; /* 1.3V */ + max1586->v6_curr_sel = 0; + rdev = max1586->rdev; for (i = 0; i < pdata->num_subdevs && i <= MAX1586_V6; i++) { id = pdata->subdevs[i].id; @@ -188,7 +226,7 @@ err: return ret; } -static int __devexit max1586_pmic_remove(struct i2c_client *client) +static int max1586_pmic_remove(struct i2c_client *client) { struct max1586_data *max1586 = i2c_get_clientdata(client); int i; @@ -207,7 +245,7 @@ MODULE_DEVICE_TABLE(i2c, max1586_id); static struct i2c_driver max1586_pmic_driver = { .probe = max1586_pmic_probe, - .remove = __devexit_p(max1586_pmic_remove), + .remove = max1586_pmic_remove, .driver = { .name = "max1586", .owner = THIS_MODULE, diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c index 2a67d08658ad..b85040caaea3 100644 --- a/drivers/regulator/max77686.c +++ b/drivers/regulator/max77686.c @@ -67,8 +67,94 @@ enum max77686_ramp_rate { struct max77686_data { struct regulator_dev *rdev[MAX77686_REGULATORS]; + unsigned int opmode[MAX77686_REGULATORS]; }; +/* Some BUCKS supports Normal[ON/OFF] mode during suspend */ +static int max77686_buck_set_suspend_disable(struct regulator_dev *rdev) +{ + unsigned int val; + struct max77686_data *max77686 = rdev_get_drvdata(rdev); + + if (rdev->desc->id == MAX77686_BUCK1) + val = 0x1; + else + val = 0x1 << MAX77686_OPMODE_BUCK234_SHIFT; + + max77686->opmode[rdev->desc->id] = val; + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, + val); +} + +/* Some LDOs supports [LPM/Normal]ON mode during suspend state */ +static int max77686_set_suspend_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct max77686_data *max77686 = rdev_get_drvdata(rdev); + unsigned int val; + + /* BUCK[5-9] doesn't support this feature */ + if (rdev->desc->id >= MAX77686_BUCK5) + return 0; + + switch (mode) { + case REGULATOR_MODE_IDLE: /* ON in LP Mode */ + val = 0x2 << MAX77686_OPMODE_SHIFT; + break; + case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */ + val = 0x3 << MAX77686_OPMODE_SHIFT; + break; + default: + pr_warn("%s: regulator_suspend_mode : 0x%x not supported\n", + rdev->desc->name, mode); + return -EINVAL; + } + + max77686->opmode[rdev->desc->id] = val; + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, + val); +} + +/* Some LDOs supports LPM-ON/OFF/Normal-ON mode during suspend state */ +static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + unsigned int val; + struct max77686_data *max77686 = rdev_get_drvdata(rdev); + + switch (mode) { + case REGULATOR_MODE_STANDBY: /* switch off */ + val = 0x1 << MAX77686_OPMODE_SHIFT; + break; + case REGULATOR_MODE_IDLE: /* ON in LP Mode */ + val = 0x2 << MAX77686_OPMODE_SHIFT; + break; + case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */ + val = 0x3 << MAX77686_OPMODE_SHIFT; + break; + default: + pr_warn("%s: regulator_suspend_mode : 0x%x not supported\n", + rdev->desc->name, mode); + return -EINVAL; + } + + max77686->opmode[rdev->desc->id] = val; + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, + val); +} + +static int max77686_enable(struct regulator_dev *rdev) +{ + struct max77686_data *max77686 = rdev_get_drvdata(rdev); + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, + max77686->opmode[rdev->desc->id]); +} + static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) { unsigned int ramp_value = RAMP_RATE_NO_CTRL; @@ -98,23 +184,49 @@ static struct regulator_ops max77686_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, - .enable = regulator_enable_regmap, + .enable = max77686_enable, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_suspend_mode = max77686_set_suspend_mode, +}; + +static struct regulator_ops max77686_ldo_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = max77686_enable, .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_suspend_mode = max77686_ldo_set_suspend_mode, +}; + +static struct regulator_ops max77686_buck1_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = max77686_enable, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_suspend_disable = max77686_buck_set_suspend_disable, }; static struct regulator_ops max77686_buck_dvs_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, - .enable = regulator_enable_regmap, + .enable = max77686_enable, .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, .set_ramp_delay = max77686_set_ramp_delay, + .set_suspend_disable = max77686_buck_set_suspend_disable, }; #define regulator_desc_ldo(num) { \ @@ -133,9 +245,41 @@ static struct regulator_ops max77686_buck_dvs_ops = { .enable_mask = MAX77686_OPMODE_MASK \ << MAX77686_OPMODE_SHIFT, \ } +#define regulator_desc_lpm_ldo(num) { \ + .name = "LDO"#num, \ + .id = MAX77686_LDO##num, \ + .ops = &max77686_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = MAX77686_LDO_MINUV, \ + .uV_step = MAX77686_LDO_UVSTEP, \ + .ramp_delay = MAX77686_RAMP_DELAY, \ + .n_voltages = MAX77686_VSEL_MASK + 1, \ + .vsel_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ + .vsel_mask = MAX77686_VSEL_MASK, \ + .enable_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ + .enable_mask = MAX77686_OPMODE_MASK \ + << MAX77686_OPMODE_SHIFT, \ +} #define regulator_desc_ldo_low(num) { \ .name = "LDO"#num, \ .id = MAX77686_LDO##num, \ + .ops = &max77686_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = MAX77686_LDO_LOW_MINUV, \ + .uV_step = MAX77686_LDO_LOW_UVSTEP, \ + .ramp_delay = MAX77686_RAMP_DELAY, \ + .n_voltages = MAX77686_VSEL_MASK + 1, \ + .vsel_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ + .vsel_mask = MAX77686_VSEL_MASK, \ + .enable_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ + .enable_mask = MAX77686_OPMODE_MASK \ + << MAX77686_OPMODE_SHIFT, \ +} +#define regulator_desc_ldo1_low(num) { \ + .name = "LDO"#num, \ + .id = MAX77686_LDO##num, \ .ops = &max77686_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -167,7 +311,7 @@ static struct regulator_ops max77686_buck_dvs_ops = { #define regulator_desc_buck1(num) { \ .name = "BUCK"#num, \ .id = MAX77686_BUCK##num, \ - .ops = &max77686_ops, \ + .ops = &max77686_buck1_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ .min_uV = MAX77686_BUCK_MINUV, \ @@ -197,7 +341,7 @@ static struct regulator_ops max77686_buck_dvs_ops = { } static struct regulator_desc regulators[] = { - regulator_desc_ldo_low(1), + regulator_desc_ldo1_low(1), regulator_desc_ldo_low(2), regulator_desc_ldo(3), regulator_desc_ldo(4), @@ -206,13 +350,13 @@ static struct regulator_desc regulators[] = { regulator_desc_ldo_low(7), regulator_desc_ldo_low(8), regulator_desc_ldo(9), - regulator_desc_ldo(10), - regulator_desc_ldo(11), - regulator_desc_ldo(12), + regulator_desc_lpm_ldo(10), + regulator_desc_lpm_ldo(11), + regulator_desc_lpm_ldo(12), regulator_desc_ldo(13), - regulator_desc_ldo(14), + regulator_desc_lpm_ldo(14), regulator_desc_ldo_low(15), - regulator_desc_ldo(16), + regulator_desc_lpm_ldo(16), regulator_desc_ldo(17), regulator_desc_ldo(18), regulator_desc_ldo(19), @@ -280,7 +424,7 @@ static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev, } #endif /* CONFIG_OF */ -static __devinit int max77686_pmic_probe(struct platform_device *pdev) +static int max77686_pmic_probe(struct platform_device *pdev) { struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max77686_platform_data *pdata = dev_get_platdata(iodev->dev); @@ -314,12 +458,14 @@ static __devinit int max77686_pmic_probe(struct platform_device *pdev) config.dev = &pdev->dev; config.regmap = iodev->regmap; + config.driver_data = max77686; platform_set_drvdata(pdev, max77686); for (i = 0; i < MAX77686_REGULATORS; i++) { config.init_data = pdata->regulators[i].initdata; config.of_node = pdata->regulators[i].of_node; + max77686->opmode[i] = regulators[i].enable_mask; max77686->rdev[i] = regulator_register(®ulators[i], &config); if (IS_ERR(max77686->rdev[i])) { ret = PTR_ERR(max77686->rdev[i]); @@ -337,7 +483,7 @@ err: return ret; } -static int __devexit max77686_pmic_remove(struct platform_device *pdev) +static int max77686_pmic_remove(struct platform_device *pdev) { struct max77686_data *max77686 = platform_get_drvdata(pdev); int i; @@ -360,7 +506,7 @@ static struct platform_driver max77686_pmic_driver = { .owner = THIS_MODULE, }, .probe = max77686_pmic_probe, - .remove = __devexit_p(max77686_pmic_remove), + .remove = max77686_pmic_remove, .id_table = max77686_pmic_id, }; diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index 9d540cd02dab..3ca14380f22d 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -176,7 +176,7 @@ static struct regmap_config max8649_regmap_config = { .val_bits = 8, }; -static int __devinit max8649_regulator_probe(struct i2c_client *client, +static int max8649_regulator_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct max8649_platform_data *pdata = client->dev.platform_data; @@ -271,7 +271,7 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client, return 0; } -static int __devexit max8649_regulator_remove(struct i2c_client *client) +static int max8649_regulator_remove(struct i2c_client *client) { struct max8649_regulator_info *info = i2c_get_clientdata(client); @@ -291,7 +291,7 @@ MODULE_DEVICE_TABLE(i2c, max8649_id); static struct i2c_driver max8649_driver = { .probe = max8649_regulator_probe, - .remove = __devexit_p(max8649_regulator_remove), + .remove = max8649_regulator_remove, .driver = { .name = "max8649", }, diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index 8d531742f593..4d7c635c36c2 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -305,7 +305,7 @@ static const struct regulator_desc max8660_reg[] = { }, }; -static int __devinit max8660_probe(struct i2c_client *client, +static int max8660_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { struct regulator_dev **rdev; @@ -420,7 +420,7 @@ err_out: return ret; } -static int __devexit max8660_remove(struct i2c_client *client) +static int max8660_remove(struct i2c_client *client) { struct max8660 *max8660 = i2c_get_clientdata(client); int i; @@ -440,7 +440,7 @@ MODULE_DEVICE_TABLE(i2c, max8660_id); static struct i2c_driver max8660_driver = { .probe = max8660_probe, - .remove = __devexit_p(max8660_remove), + .remove = max8660_remove, .driver = { .name = "max8660", .owner = THIS_MODULE, diff --git a/drivers/regulator/max8907-regulator.c b/drivers/regulator/max8907-regulator.c index af7607515ab9..d1a77512d83e 100644 --- a/drivers/regulator/max8907-regulator.c +++ b/drivers/regulator/max8907-regulator.c @@ -275,7 +275,7 @@ static inline struct device_node *match_of_node(int index) } #endif -static __devinit int max8907_regulator_probe(struct platform_device *pdev) +static int max8907_regulator_probe(struct platform_device *pdev) { struct max8907 *max8907 = dev_get_drvdata(pdev->dev.parent); struct max8907_platform_data *pdata = dev_get_platdata(max8907->dev); @@ -368,7 +368,7 @@ err_unregister_regulator: return ret; } -static __devexit int max8907_regulator_remove(struct platform_device *pdev) +static int max8907_regulator_remove(struct platform_device *pdev) { struct max8907_regulator *pmic = platform_get_drvdata(pdev); int i; @@ -385,7 +385,7 @@ static struct platform_driver max8907_regulator_driver = { .owner = THIS_MODULE, }, .probe = max8907_regulator_probe, - .remove = __devexit_p(max8907_regulator_remove), + .remove = max8907_regulator_remove, }; static int __init max8907_regulator_init(void) diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index 9bb0be37495f..446a85445553 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -17,6 +17,8 @@ #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/mfd/max8925.h> +#include <linux/of.h> +#include <linux/regulator/of_regulator.h> #define SD1_DVM_VMIN 850000 #define SD1_DVM_VMAX 1000000 @@ -187,6 +189,34 @@ static struct regulator_ops max8925_regulator_ldo_ops = { .enable_reg = MAX8925_LDOCTL##_id, \ } +#ifdef CONFIG_OF +static struct of_regulator_match max8925_regulator_matches[] = { + { .name = "SDV1",}, + { .name = "SDV2",}, + { .name = "SDV3",}, + { .name = "LDO1",}, + { .name = "LDO2",}, + { .name = "LDO3",}, + { .name = "LDO4",}, + { .name = "LDO5",}, + { .name = "LDO6",}, + { .name = "LDO7",}, + { .name = "LDO8",}, + { .name = "LDO9",}, + { .name = "LDO10",}, + { .name = "LDO11",}, + { .name = "LDO12",}, + { .name = "LDO13",}, + { .name = "LDO14",}, + { .name = "LDO15",}, + { .name = "LDO16",}, + { .name = "LDO17",}, + { .name = "LDO18",}, + { .name = "LDO19",}, + { .name = "LDO20",}, +}; +#endif + static struct max8925_regulator_info max8925_regulator_info[] = { MAX8925_SDV(1, 637.5, 1425, 12.5), MAX8925_SDV(2, 650, 2225, 25), @@ -214,7 +244,37 @@ static struct max8925_regulator_info max8925_regulator_info[] = { MAX8925_LDO(20, 750, 3900, 50), }; -static int __devinit max8925_regulator_probe(struct platform_device *pdev) +#ifdef CONFIG_OF +static int max8925_regulator_dt_init(struct platform_device *pdev, + struct max8925_regulator_info *info, + struct regulator_config *config, + int ridx) +{ + struct device_node *nproot, *np; + int rcount; + nproot = pdev->dev.parent->of_node; + if (!nproot) + return -ENODEV; + np = of_find_node_by_name(nproot, "regulators"); + if (!np) { + dev_err(&pdev->dev, "failed to find regulators node\n"); + return -ENODEV; + } + + rcount = of_regulator_match(&pdev->dev, np, + &max8925_regulator_matches[ridx], 1); + if (rcount < 0) + return -ENODEV; + config->init_data = max8925_regulator_matches[ridx].init_data; + config->of_node = max8925_regulator_matches[ridx].of_node; + + return 0; +} +#else +#define max8925_regulator_dt_init(w, x, y, z) (-1) +#endif + +static int max8925_regulator_probe(struct platform_device *pdev) { struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); struct regulator_init_data *pdata = pdev->dev.platform_data; @@ -222,7 +282,7 @@ static int __devinit max8925_regulator_probe(struct platform_device *pdev) struct max8925_regulator_info *ri; struct resource *res; struct regulator_dev *rdev; - int i; + int i, regulator_idx; res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (!res) { @@ -231,9 +291,12 @@ static int __devinit max8925_regulator_probe(struct platform_device *pdev) } for (i = 0; i < ARRAY_SIZE(max8925_regulator_info); i++) { ri = &max8925_regulator_info[i]; - if (ri->vol_reg == res->start) + if (ri->vol_reg == res->start) { + regulator_idx = i; break; + } } + if (i == ARRAY_SIZE(max8925_regulator_info)) { dev_err(&pdev->dev, "Failed to find regulator %llu\n", (unsigned long long)res->start); @@ -243,9 +306,12 @@ static int __devinit max8925_regulator_probe(struct platform_device *pdev) ri->chip = chip; config.dev = &pdev->dev; - config.init_data = pdata; config.driver_data = ri; + if (max8925_regulator_dt_init(pdev, ri, &config, regulator_idx)) + if (pdata) + config.init_data = pdata; + rdev = regulator_register(&ri->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", @@ -257,7 +323,7 @@ static int __devinit max8925_regulator_probe(struct platform_device *pdev) return 0; } -static int __devexit max8925_regulator_remove(struct platform_device *pdev) +static int max8925_regulator_remove(struct platform_device *pdev) { struct regulator_dev *rdev = platform_get_drvdata(pdev); @@ -273,7 +339,7 @@ static struct platform_driver max8925_regulator_driver = { .owner = THIS_MODULE, }, .probe = max8925_regulator_probe, - .remove = __devexit_p(max8925_regulator_remove), + .remove = max8925_regulator_remove, }; static int __init max8925_regulator_init(void) diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index 355ca7bad9d5..fc7935a19e3a 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -126,7 +126,7 @@ static const struct regulator_desc regulator = { .owner = THIS_MODULE, }; -static int __devinit max8952_pmic_probe(struct i2c_client *client, +static int max8952_pmic_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); @@ -247,7 +247,7 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client, return 0; } -static int __devexit max8952_pmic_remove(struct i2c_client *client) +static int max8952_pmic_remove(struct i2c_client *client) { struct max8952_data *max8952 = i2c_get_clientdata(client); struct max8952_platform_data *pdata = max8952->pdata; @@ -268,7 +268,7 @@ MODULE_DEVICE_TABLE(i2c, max8952_ids); static struct i2c_driver max8952_pmic_driver = { .probe = max8952_pmic_probe, - .remove = __devexit_p(max8952_pmic_remove), + .remove = max8952_pmic_remove, .driver = { .name = "max8952", }, diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index e39a0c7260dc..cea9ec9093eb 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c @@ -933,7 +933,7 @@ static struct regulator_desc regulators[] = { max8997_charger_fixedstate_ops), }; -static __devinit int max8997_pmic_probe(struct platform_device *pdev) +static int max8997_pmic_probe(struct platform_device *pdev) { struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev); @@ -1120,7 +1120,7 @@ err_out: return ret; } -static int __devexit max8997_pmic_remove(struct platform_device *pdev) +static int max8997_pmic_remove(struct platform_device *pdev) { struct max8997_data *max8997 = platform_get_drvdata(pdev); struct regulator_dev **rdev = max8997->rdev; @@ -1143,7 +1143,7 @@ static struct platform_driver max8997_pmic_driver = { .owner = THIS_MODULE, }, .probe = max8997_pmic_probe, - .remove = __devexit_p(max8997_pmic_remove), + .remove = max8997_pmic_remove, .id_table = max8997_pmic_id, }; diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index 5dfa920ff0c8..b821d08eb64a 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -633,7 +633,7 @@ static struct regulator_desc regulators[] = { } }; -static __devinit int max8998_pmic_probe(struct platform_device *pdev) +static int max8998_pmic_probe(struct platform_device *pdev) { struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev); @@ -818,7 +818,7 @@ err_out: return ret; } -static int __devexit max8998_pmic_remove(struct platform_device *pdev) +static int max8998_pmic_remove(struct platform_device *pdev) { struct max8998_data *max8998 = platform_get_drvdata(pdev); struct regulator_dev **rdev = max8998->rdev; @@ -842,7 +842,7 @@ static struct platform_driver max8998_pmic_driver = { .owner = THIS_MODULE, }, .probe = max8998_pmic_probe, - .remove = __devexit_p(max8998_pmic_remove), + .remove = max8998_pmic_remove, .id_table = max8998_pmic_id, }; diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index 0801a6d0c122..c46c6705cd74 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -392,7 +392,7 @@ static struct regulator_ops mc13783_gpo_regulator_ops = { .set_voltage = mc13xxx_fixed_regulator_set_voltage, }; -static int __devinit mc13783_regulator_probe(struct platform_device *pdev) +static int mc13783_regulator_probe(struct platform_device *pdev) { struct mc13xxx_regulator_priv *priv; struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent); @@ -445,7 +445,7 @@ err: return ret; } -static int __devexit mc13783_regulator_remove(struct platform_device *pdev) +static int mc13783_regulator_remove(struct platform_device *pdev) { struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); struct mc13xxx_regulator_platform_data *pdata = @@ -465,7 +465,7 @@ static struct platform_driver mc13783_regulator_driver = { .name = "mc13783-regulator", .owner = THIS_MODULE, }, - .remove = __devexit_p(mc13783_regulator_remove), + .remove = mc13783_regulator_remove, .probe = mc13783_regulator_probe, }; diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index 1fa63812f7ac..0d84b1f33199 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -486,7 +486,7 @@ static unsigned int mc13892_vcam_get_mode(struct regulator_dev *rdev) } -static int __devinit mc13892_regulator_probe(struct platform_device *pdev) +static int mc13892_regulator_probe(struct platform_device *pdev) { struct mc13xxx_regulator_priv *priv; struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent); @@ -588,7 +588,7 @@ err_unlock: return ret; } -static int __devexit mc13892_regulator_remove(struct platform_device *pdev) +static int mc13892_regulator_remove(struct platform_device *pdev) { struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); int i; @@ -606,7 +606,7 @@ static struct platform_driver mc13892_regulator_driver = { .name = "mc13892-regulator", .owner = THIS_MODULE, }, - .remove = __devexit_p(mc13892_regulator_remove), + .remove = mc13892_regulator_remove, .probe = mc13892_regulator_probe, }; diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index 88cbb832d555..4ed89c654110 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -162,7 +162,7 @@ struct regulator_ops mc13xxx_fixed_regulator_ops = { EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_ops); #ifdef CONFIG_OF -int __devinit mc13xxx_get_num_regulators_dt(struct platform_device *pdev) +int mc13xxx_get_num_regulators_dt(struct platform_device *pdev) { struct device_node *parent, *child; int num = 0; @@ -179,7 +179,7 @@ int __devinit mc13xxx_get_num_regulators_dt(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(mc13xxx_get_num_regulators_dt); -struct mc13xxx_regulator_init_data * __devinit mc13xxx_parse_regulators_dt( +struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( struct platform_device *pdev, struct mc13xxx_regulator *regulators, int num_regulators) { diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 07aee694ba92..3d445929cc80 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -595,7 +595,7 @@ static struct of_regulator_match palmas_matches[] = { { .name = "ldousb", }, }; -static void __devinit palmas_dt_to_pdata(struct device *dev, +static void palmas_dt_to_pdata(struct device *dev, struct device_node *node, struct palmas_pmic_platform_data *pdata) { @@ -663,7 +663,7 @@ static void __devinit palmas_dt_to_pdata(struct device *dev, } -static __devinit int palmas_probe(struct platform_device *pdev) +static int palmas_probe(struct platform_device *pdev) { struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); struct palmas_pmic_platform_data *pdata = pdev->dev.platform_data; @@ -868,7 +868,7 @@ err_unregister_regulator: return ret; } -static int __devexit palmas_remove(struct platform_device *pdev) +static int palmas_remove(struct platform_device *pdev) { struct palmas_pmic *pmic = platform_get_drvdata(pdev); int id; @@ -890,7 +890,7 @@ static struct platform_driver palmas_driver = { .owner = THIS_MODULE, }, .probe = palmas_probe, - .remove = __devexit_p(palmas_remove), + .remove = palmas_remove, }; static int __init palmas_init(void) diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c index 68777acc099f..4899342f1fc1 100644 --- a/drivers/regulator/pcap-regulator.c +++ b/drivers/regulator/pcap-regulator.c @@ -236,7 +236,7 @@ static const struct regulator_desc pcap_regulators[] = { VREG(VAUX4), VREG(VSIM), VREG(VSIM2), VREG(VVIB), VREG(SW1), VREG(SW2), }; -static int __devinit pcap_regulator_probe(struct platform_device *pdev) +static int pcap_regulator_probe(struct platform_device *pdev) { struct regulator_dev *rdev; void *pcap = dev_get_drvdata(pdev->dev.parent); @@ -255,7 +255,7 @@ static int __devinit pcap_regulator_probe(struct platform_device *pdev) return 0; } -static int __devexit pcap_regulator_remove(struct platform_device *pdev) +static int pcap_regulator_remove(struct platform_device *pdev) { struct regulator_dev *rdev = platform_get_drvdata(pdev); @@ -271,7 +271,7 @@ static struct platform_driver pcap_regulator_driver = { .owner = THIS_MODULE, }, .probe = pcap_regulator_probe, - .remove = __devexit_p(pcap_regulator_remove), + .remove = pcap_regulator_remove, }; static int __init pcap_regulator_init(void) diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c index 092e5cb848a1..d776f518aa0d 100644 --- a/drivers/regulator/pcf50633-regulator.c +++ b/drivers/regulator/pcf50633-regulator.c @@ -196,7 +196,7 @@ static const struct regulator_desc regulators[] = { [PCF50633_REGULATOR_MEMLDO] = PCF50633_REGULATOR("memldo", MEMLDO, 28), }; -static int __devinit pcf50633_regulator_probe(struct platform_device *pdev) +static int pcf50633_regulator_probe(struct platform_device *pdev) { struct regulator_dev *rdev; struct pcf50633 *pcf; @@ -222,7 +222,7 @@ static int __devinit pcf50633_regulator_probe(struct platform_device *pdev) return 0; } -static int __devexit pcf50633_regulator_remove(struct platform_device *pdev) +static int pcf50633_regulator_remove(struct platform_device *pdev) { struct regulator_dev *rdev = platform_get_drvdata(pdev); @@ -237,7 +237,7 @@ static struct platform_driver pcf50633_regulator_driver = { .name = "pcf50633-regltr", }, .probe = pcf50633_regulator_probe, - .remove = __devexit_p(pcf50633_regulator_remove), + .remove = pcf50633_regulator_remove, }; static int __init pcf50633_regulator_init(void) diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c index 8bf4e8c9de9a..9e6f78694bf1 100644 --- a/drivers/regulator/rc5t583-regulator.c +++ b/drivers/regulator/rc5t583-regulator.c @@ -119,7 +119,7 @@ static struct rc5t583_regulator_info rc5t583_reg_info[RC5T583_REGULATOR_MAX] = { RC5T583_REG(LDO9, LDOEN1, 1, LDODIS1, 1, 0x7F, 900, 3400, 25000, 133), }; -static int __devinit rc5t583_regulator_probe(struct platform_device *pdev) +static int 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); @@ -198,7 +198,7 @@ clean_exit: return ret; } -static int __devexit rc5t583_regulator_remove(struct platform_device *pdev) +static int rc5t583_regulator_remove(struct platform_device *pdev) { struct rc5t583_regulator *regs = platform_get_drvdata(pdev); int id; @@ -214,7 +214,7 @@ static struct platform_driver rc5t583_regulator_driver = { .owner = THIS_MODULE, }, .probe = rc5t583_regulator_probe, - .remove = __devexit_p(rc5t583_regulator_remove), + .remove = rc5t583_regulator_remove, }; static int __init rc5t583_regulator_init(void) diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 926f9c8f2fac..85fc086c1319 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -231,7 +231,7 @@ static struct regulator_desc regulators[] = { regulator_desc_buck10, }; -static __devinit int s2mps11_pmic_probe(struct platform_device *pdev) +static int s2mps11_pmic_probe(struct platform_device *pdev) { struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct sec_platform_data *pdata = dev_get_platdata(iodev->dev); @@ -307,7 +307,7 @@ err: return ret; } -static int __devexit s2mps11_pmic_remove(struct platform_device *pdev) +static int s2mps11_pmic_remove(struct platform_device *pdev) { struct s2mps11_info *s2mps11 = platform_get_drvdata(pdev); int i; @@ -330,7 +330,7 @@ static struct platform_driver s2mps11_pmic_driver = { .owner = THIS_MODULE, }, .probe = s2mps11_pmic_probe, - .remove = __devexit_p(s2mps11_pmic_remove), + .remove = s2mps11_pmic_remove, .id_table = s2mps11_pmic_id, }; diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index abe64a32aedf..2b822bec3c2d 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -499,7 +499,7 @@ static struct regulator_desc regulators[] = { s5m8767_regulator_desc(BUCK9), }; -static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) +static int s5m8767_pmic_probe(struct platform_device *pdev) { struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct sec_platform_data *pdata = dev_get_platdata(iodev->dev); @@ -773,7 +773,7 @@ err: return ret; } -static int __devexit s5m8767_pmic_remove(struct platform_device *pdev) +static int s5m8767_pmic_remove(struct platform_device *pdev) { struct s5m8767_info *s5m8767 = platform_get_drvdata(pdev); struct regulator_dev **rdev = s5m8767->rdev; @@ -798,7 +798,7 @@ static struct platform_driver s5m8767_pmic_driver = { .owner = THIS_MODULE, }, .probe = s5m8767_pmic_probe, - .remove = __devexit_p(s5m8767_pmic_remove), + .remove = s5m8767_pmic_remove, .id_table = s5m8767_pmic_id, }; diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c new file mode 100644 index 000000000000..a9c3a4a6cca0 --- /dev/null +++ b/drivers/regulator/tps51632-regulator.c @@ -0,0 +1,332 @@ +/* + * tps51632-regulator.c -- TI TPS51632 + * + * Regulator driver for TPS51632 3-2-1 Phase D-Cap Step Down Driverless + * Controller with serial VID control and DVFS. + * + * Copyright (c) 2012, NVIDIA Corporation. + * + * Author: Laxman Dewangan <ldewangan@nvidia.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/tps51632-regulator.h> +#include <linux/slab.h> + +/* Register definitions */ +#define TPS51632_VOLTAGE_SELECT_REG 0x0 +#define TPS51632_VOLTAGE_BASE_REG 0x1 +#define TPS51632_OFFSET_REG 0x2 +#define TPS51632_IMON_REG 0x3 +#define TPS51632_VMAX_REG 0x4 +#define TPS51632_DVFS_CONTROL_REG 0x5 +#define TPS51632_POWER_STATE_REG 0x6 +#define TPS51632_SLEW_REGS 0x7 +#define TPS51632_FAULT_REG 0x14 + +#define TPS51632_MAX_REG 0x15 + +#define TPS51632_VOUT_MASK 0x7F +#define TPS51632_VOUT_OFFSET_MASK 0x1F +#define TPS51632_VMAX_MASK 0x7F +#define TPS51632_VMAX_LOCK 0x80 + +/* TPS51632_DVFS_CONTROL_REG */ +#define TPS51632_DVFS_PWMEN 0x1 +#define TPS51632_DVFS_STEP_20 0x2 +#define TPS51632_DVFS_VMAX_PG 0x4 +#define TPS51632_DVFS_PWMRST 0x8 +#define TPS51632_DVFS_OCA_EN 0x10 +#define TPS51632_DVFS_FCCM 0x20 + +/* TPS51632_POWER_STATE_REG */ +#define TPS51632_POWER_STATE_MASK 0x03 +#define TPS51632_POWER_STATE_MULTI_PHASE_CCM 0x0 +#define TPS51632_POWER_STATE_SINGLE_PHASE_CCM 0x1 +#define TPS51632_POWER_STATE_SINGLE_PHASE_DCM 0x2 + +#define TPS51632_MIN_VOLATGE 500000 +#define TPS51632_MAX_VOLATGE 1520000 +#define TPS51632_VOLATGE_STEP_10mV 10000 +#define TPS51632_VOLATGE_STEP_20mV 20000 +#define TPS51632_MAX_VSEL 0x7F +#define TPS51632_MIN_VSEL 0x19 +#define TPS51632_DEFAULT_RAMP_DELAY 6000 +#define TPS51632_VOLT_VSEL(uV) \ + (DIV_ROUND_UP(uV - TPS51632_MIN_VOLATGE, \ + TPS51632_VOLATGE_STEP_10mV) + \ + TPS51632_MIN_VSEL) + +/* TPS51632 chip information */ +struct tps51632_chip { + struct device *dev; + struct regulator_desc desc; + struct regulator_dev *rdev; + struct regmap *regmap; + bool enable_pwm_dvfs; +}; + +static int tps51632_dcdc_get_voltage_sel(struct regulator_dev *rdev) +{ + struct tps51632_chip *tps = rdev_get_drvdata(rdev); + unsigned int data; + int ret; + unsigned int reg = TPS51632_VOLTAGE_SELECT_REG; + int vsel; + + if (tps->enable_pwm_dvfs) + reg = TPS51632_VOLTAGE_BASE_REG; + + ret = regmap_read(tps->regmap, reg, &data); + if (ret < 0) { + dev_err(tps->dev, "reg read failed, err %d\n", ret); + return ret; + } + + vsel = data & TPS51632_VOUT_MASK; + + if (vsel < TPS51632_MIN_VSEL) + return 0; + else + return vsel - TPS51632_MIN_VSEL; +} + +static int tps51632_dcdc_set_voltage_sel(struct regulator_dev *rdev, + unsigned selector) +{ + struct tps51632_chip *tps = rdev_get_drvdata(rdev); + int vsel; + int ret; + unsigned int reg = TPS51632_VOLTAGE_SELECT_REG; + + if (tps->enable_pwm_dvfs) + reg = TPS51632_VOLTAGE_BASE_REG; + + vsel = selector + TPS51632_MIN_VSEL; + if (vsel > TPS51632_MAX_VSEL) + return -EINVAL; + + ret = regmap_write(tps->regmap, TPS51632_VOLTAGE_SELECT_REG, vsel); + if (ret < 0) + dev_err(tps->dev, "reg write failed, err %d\n", ret); + return ret; +} + +static int tps51632_dcdc_set_ramp_delay(struct regulator_dev *rdev, + int ramp_delay) +{ + struct tps51632_chip *tps = rdev_get_drvdata(rdev); + int bit = ramp_delay/6000; + int ret; + + if (bit) + bit--; + ret = regmap_write(tps->regmap, TPS51632_SLEW_REGS, BIT(bit)); + if (ret < 0) + dev_err(tps->dev, "SLEW reg write failed, err %d\n", ret); + return ret; +} + +static struct regulator_ops tps51632_dcdc_ops = { + .get_voltage_sel = tps51632_dcdc_get_voltage_sel, + .set_voltage_sel = tps51632_dcdc_set_voltage_sel, + .list_voltage = regulator_list_voltage_linear, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = tps51632_dcdc_set_ramp_delay, +}; + +static int tps51632_init_dcdc(struct tps51632_chip *tps, + struct tps51632_regulator_platform_data *pdata) +{ + int ret; + uint8_t control = 0; + int vsel; + + if (!pdata->enable_pwm_dvfs) + goto skip_pwm_config; + + control |= TPS51632_DVFS_PWMEN; + tps->enable_pwm_dvfs = pdata->enable_pwm_dvfs; + vsel = TPS51632_VOLT_VSEL(pdata->base_voltage_uV); + ret = regmap_write(tps->regmap, TPS51632_VOLTAGE_BASE_REG, vsel); + if (ret < 0) { + dev_err(tps->dev, "BASE reg write failed, err %d\n", ret); + return ret; + } + + if (pdata->dvfs_step_20mV) + control |= TPS51632_DVFS_STEP_20; + + if (pdata->max_voltage_uV) { + unsigned int vmax; + /** + * TPS51632 hw behavior: VMAX register can be write only + * once as it get locked after first write. The lock get + * reset only when device is power-reset. + * Write register only when lock bit is not enabled. + */ + ret = regmap_read(tps->regmap, TPS51632_VMAX_REG, &vmax); + if (ret < 0) { + dev_err(tps->dev, "VMAX read failed, err %d\n", ret); + return ret; + } + if (!(vmax & TPS51632_VMAX_LOCK)) { + vsel = TPS51632_VOLT_VSEL(pdata->max_voltage_uV); + ret = regmap_write(tps->regmap, TPS51632_VMAX_REG, + vsel); + if (ret < 0) { + dev_err(tps->dev, + "VMAX write failed, err %d\n", ret); + return ret; + } + } + } + +skip_pwm_config: + ret = regmap_write(tps->regmap, TPS51632_DVFS_CONTROL_REG, control); + if (ret < 0) + dev_err(tps->dev, "DVFS reg write failed, err %d\n", ret); + return ret; +} + +static bool rd_wr_reg(struct device *dev, unsigned int reg) +{ + if ((reg >= 0x8) && (reg <= 0x10)) + return false; + return true; +} + +static const struct regmap_config tps51632_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .writeable_reg = rd_wr_reg, + .readable_reg = rd_wr_reg, + .max_register = TPS51632_MAX_REG - 1, + .cache_type = REGCACHE_RBTREE, +}; + +static int tps51632_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tps51632_regulator_platform_data *pdata; + struct regulator_dev *rdev; + struct tps51632_chip *tps; + int ret; + struct regulator_config config = { }; + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->dev, "No Platform data\n"); + return -EINVAL; + } + + tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); + if (!tps) { + dev_err(&client->dev, "Memory allocation failed\n"); + return -ENOMEM; + } + + tps->dev = &client->dev; + tps->desc.name = id->name; + tps->desc.id = 0; + tps->desc.ramp_delay = TPS51632_DEFAULT_RAMP_DELAY; + tps->desc.min_uV = TPS51632_MIN_VOLATGE; + tps->desc.uV_step = TPS51632_VOLATGE_STEP_10mV; + tps->desc.n_voltages = (TPS51632_MAX_VSEL - TPS51632_MIN_VSEL) + 1; + tps->desc.ops = &tps51632_dcdc_ops; + tps->desc.type = REGULATOR_VOLTAGE; + tps->desc.owner = THIS_MODULE; + + tps->regmap = devm_regmap_init_i2c(client, &tps51632_regmap_config); + if (IS_ERR(tps->regmap)) { + ret = PTR_ERR(tps->regmap); + dev_err(&client->dev, "regmap init failed, err %d\n", ret); + return ret; + } + i2c_set_clientdata(client, tps); + + ret = tps51632_init_dcdc(tps, pdata); + if (ret < 0) { + dev_err(tps->dev, "Init failed, err = %d\n", ret); + return ret; + } + + /* Register the regulators */ + config.dev = &client->dev; + config.init_data = pdata->reg_init_data; + config.driver_data = tps; + config.regmap = tps->regmap; + config.of_node = client->dev.of_node; + + rdev = regulator_register(&tps->desc, &config); + if (IS_ERR(rdev)) { + dev_err(tps->dev, "regulator register failed\n"); + return PTR_ERR(rdev); + } + + tps->rdev = rdev; + return 0; +} + +static int tps51632_remove(struct i2c_client *client) +{ + struct tps51632_chip *tps = i2c_get_clientdata(client); + + regulator_unregister(tps->rdev); + return 0; +} + +static const struct i2c_device_id tps51632_id[] = { + {.name = "tps51632",}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, tps51632_id); + +static struct i2c_driver tps51632_i2c_driver = { + .driver = { + .name = "tps51632", + .owner = THIS_MODULE, + }, + .probe = tps51632_probe, + .remove = tps51632_remove, + .id_table = tps51632_id, +}; + +static int __init tps51632_init(void) +{ + return i2c_add_driver(&tps51632_i2c_driver); +} +subsys_initcall(tps51632_init); + +static void __exit tps51632_cleanup(void) +{ + i2c_del_driver(&tps51632_i2c_driver); +} +module_exit(tps51632_cleanup); + +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_DESCRIPTION("TPS51632 voltage regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/tps6105x-regulator.c b/drivers/regulator/tps6105x-regulator.c index 1378409efaec..ec9453ffb77f 100644 --- a/drivers/regulator/tps6105x-regulator.c +++ b/drivers/regulator/tps6105x-regulator.c @@ -127,7 +127,7 @@ static const struct regulator_desc tps6105x_regulator_desc = { /* * Registers the chip as a voltage regulator */ -static int __devinit tps6105x_regulator_probe(struct platform_device *pdev) +static int tps6105x_regulator_probe(struct platform_device *pdev) { struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev); struct tps6105x_platform_data *pdata = tps6105x->pdata; @@ -159,7 +159,7 @@ static int __devinit tps6105x_regulator_probe(struct platform_device *pdev) return 0; } -static int __devexit tps6105x_regulator_remove(struct platform_device *pdev) +static int tps6105x_regulator_remove(struct platform_device *pdev) { struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev); regulator_unregister(tps6105x->regulator); @@ -172,7 +172,7 @@ static struct platform_driver tps6105x_regulator_driver = { .owner = THIS_MODULE, }, .probe = tps6105x_regulator_probe, - .remove = __devexit_p(tps6105x_regulator_remove), + .remove = tps6105x_regulator_remove, }; static __init int tps6105x_regulator_init(void) diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index 68729a7c8709..acbd63fde415 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -243,7 +243,7 @@ static struct regulator_ops tps62360_dcdc_ops = { .get_mode = tps62360_get_mode, }; -static int __devinit tps62360_init_dcdc(struct tps62360_chip *tps, +static int tps62360_init_dcdc(struct tps62360_chip *tps, struct tps62360_regulator_platform_data *pdata) { int ret; @@ -339,7 +339,7 @@ static const struct of_device_id tps62360_of_match[] = { MODULE_DEVICE_TABLE(of, tps62360_of_match); #endif -static int __devinit tps62360_probe(struct i2c_client *client, +static int tps62360_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct regulator_config config = { }; @@ -490,7 +490,7 @@ static int __devinit tps62360_probe(struct i2c_client *client, * * Unregister TPS driver as an i2c client device driver */ -static int __devexit tps62360_remove(struct i2c_client *client) +static int tps62360_remove(struct i2c_client *client) { struct tps62360_chip *tps = i2c_get_clientdata(client); @@ -531,7 +531,7 @@ static struct i2c_driver tps62360_i2c_driver = { .of_match_table = of_match_ptr(tps62360_of_match), }, .probe = tps62360_probe, - .remove = __devexit_p(tps62360_remove), + .remove = tps62360_remove, .shutdown = tps62360_shutdown, .id_table = tps62360_id, }; diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index 6998d579d07b..9b9af6d889c8 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -219,7 +219,7 @@ static struct regmap_config tps65023_regmap_config = { .val_bits = 8, }; -static int __devinit tps_65023_probe(struct i2c_client *client, +static int tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct tps_driver_data *drv_data = (void *)id->driver_data; @@ -319,7 +319,7 @@ static int __devinit tps_65023_probe(struct i2c_client *client, return error; } -static int __devexit tps_65023_remove(struct i2c_client *client) +static int tps_65023_remove(struct i2c_client *client) { struct tps_pmic *tps = i2c_get_clientdata(client); int i; @@ -446,7 +446,7 @@ static struct i2c_driver tps_65023_i2c_driver = { .owner = THIS_MODULE, }, .probe = tps_65023_probe, - .remove = __devexit_p(tps_65023_remove), + .remove = tps_65023_remove, .id_table = tps_65023_id, }; diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c index 07d01ccdf308..0233cfb56560 100644 --- a/drivers/regulator/tps6507x-regulator.c +++ b/drivers/regulator/tps6507x-regulator.c @@ -356,7 +356,7 @@ static struct regulator_ops tps6507x_pmic_ops = { .list_voltage = regulator_list_voltage_table, }; -static __devinit int tps6507x_pmic_probe(struct platform_device *pdev) +static int tps6507x_pmic_probe(struct platform_device *pdev) { struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent); struct tps_info *info = &tps6507x_pmic_regs[0]; @@ -439,7 +439,7 @@ fail: return error; } -static int __devexit tps6507x_pmic_remove(struct platform_device *pdev) +static int tps6507x_pmic_remove(struct platform_device *pdev) { struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev); struct tps6507x_pmic *tps = tps6507x_dev->pmic; @@ -456,7 +456,7 @@ static struct platform_driver tps6507x_pmic_driver = { .owner = THIS_MODULE, }, .probe = tps6507x_pmic_probe, - .remove = __devexit_p(tps6507x_pmic_remove), + .remove = tps6507x_pmic_remove, }; static int __init tps6507x_pmic_init(void) diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c index 001ad554ac62..3974a992220f 100644 --- a/drivers/regulator/tps65090-regulator.c +++ b/drivers/regulator/tps65090-regulator.c @@ -18,119 +18,240 @@ #include <linux/module.h> #include <linux/init.h> +#include <linux/gpio.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/mfd/tps65090.h> -#include <linux/regulator/tps65090-regulator.h> struct tps65090_regulator { - int id; - /* used by regulator core */ - struct regulator_desc desc; - - /* Device */ struct device *dev; + struct regulator_desc *desc; + struct regulator_dev *rdev; +}; + +static struct regulator_ops tps65090_ext_control_ops = { +}; + +static struct regulator_ops tps65090_reg_contol_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, }; -static struct regulator_ops tps65090_ops = { - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, +static struct regulator_ops tps65090_ldo_ops = { }; -#define tps65090_REG(_id) \ +#define tps65090_REG_DESC(_id, _sname, _en_reg, _ops) \ { \ - .id = TPS65090_ID_##_id, \ - .desc = { \ - .name = tps65090_rails(_id), \ - .id = TPS65090_ID_##_id, \ - .ops = &tps65090_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .enable_reg = (TPS65090_ID_##_id) + 12, \ - .enable_mask = BIT(0), \ - }, \ + .name = "TPS65090_RAILS"#_id, \ + .supply_name = _sname, \ + .id = TPS65090_REGULATOR_##_id, \ + .ops = &_ops, \ + .enable_reg = _en_reg, \ + .enable_mask = BIT(0), \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ } -static struct tps65090_regulator TPS65090_regulator[] = { - tps65090_REG(DCDC1), - tps65090_REG(DCDC2), - tps65090_REG(DCDC3), - tps65090_REG(FET1), - tps65090_REG(FET2), - tps65090_REG(FET3), - tps65090_REG(FET4), - tps65090_REG(FET5), - tps65090_REG(FET6), - tps65090_REG(FET7), +static struct regulator_desc tps65090_regulator_desc[] = { + tps65090_REG_DESC(DCDC1, "vsys1", 0x0C, tps65090_reg_contol_ops), + tps65090_REG_DESC(DCDC2, "vsys2", 0x0D, tps65090_reg_contol_ops), + tps65090_REG_DESC(DCDC3, "vsys3", 0x0E, tps65090_reg_contol_ops), + tps65090_REG_DESC(FET1, "infet1", 0x0F, tps65090_reg_contol_ops), + tps65090_REG_DESC(FET2, "infet2", 0x10, tps65090_reg_contol_ops), + tps65090_REG_DESC(FET3, "infet3", 0x11, tps65090_reg_contol_ops), + tps65090_REG_DESC(FET4, "infet4", 0x12, tps65090_reg_contol_ops), + tps65090_REG_DESC(FET5, "infet5", 0x13, tps65090_reg_contol_ops), + tps65090_REG_DESC(FET6, "infet6", 0x14, tps65090_reg_contol_ops), + tps65090_REG_DESC(FET7, "infet7", 0x15, tps65090_reg_contol_ops), + tps65090_REG_DESC(LDO1, "vsys_l1", 0, tps65090_ldo_ops), + tps65090_REG_DESC(LDO2, "vsys_l2", 0, tps65090_ldo_ops), }; -static inline struct tps65090_regulator *find_regulator_info(int id) +static inline bool is_dcdc(int id) { - struct tps65090_regulator *ri; - int i; + switch (id) { + case TPS65090_REGULATOR_DCDC1: + case TPS65090_REGULATOR_DCDC2: + case TPS65090_REGULATOR_DCDC3: + return true; + default: + return false; + } +} + +static int tps65090_config_ext_control( + struct tps65090_regulator *ri, bool enable) +{ + int ret; + struct device *parent = ri->dev->parent; + unsigned int reg_en_reg = ri->desc->enable_reg; + + if (enable) + ret = tps65090_set_bits(parent, reg_en_reg, 1); + else + ret = tps65090_clr_bits(parent, reg_en_reg, 1); + if (ret < 0) + dev_err(ri->dev, "Error in updating reg 0x%x\n", reg_en_reg); + return ret; +} + +static int tps65090_regulator_disable_ext_control( + struct tps65090_regulator *ri, + struct tps65090_regulator_plat_data *tps_pdata) +{ + int ret = 0; + struct device *parent = ri->dev->parent; + unsigned int reg_en_reg = ri->desc->enable_reg; + + /* + * First enable output for internal control if require. + * And then disable external control. + */ + if (tps_pdata->reg_init_data->constraints.always_on || + tps_pdata->reg_init_data->constraints.boot_on) { + ret = tps65090_set_bits(parent, reg_en_reg, 0); + if (ret < 0) { + dev_err(ri->dev, "Error in set reg 0x%x\n", reg_en_reg); + return ret; + } + } + return tps65090_config_ext_control(ri, false); +} + +static void tps65090_configure_regulator_config( + struct tps65090_regulator_plat_data *tps_pdata, + struct regulator_config *config) +{ + if (gpio_is_valid(tps_pdata->gpio)) { + int gpio_flag = GPIOF_OUT_INIT_LOW; + + if (tps_pdata->reg_init_data->constraints.always_on || + tps_pdata->reg_init_data->constraints.boot_on) + gpio_flag = GPIOF_OUT_INIT_HIGH; - for (i = 0; i < ARRAY_SIZE(TPS65090_regulator); i++) { - ri = &TPS65090_regulator[i]; - if (ri->desc.id == id) - return ri; + config->ena_gpio = tps_pdata->gpio; + config->ena_gpio_flags = gpio_flag; } - return NULL; } -static int __devinit tps65090_regulator_probe(struct platform_device *pdev) +static int tps65090_regulator_probe(struct platform_device *pdev) { struct tps65090 *tps65090_mfd = dev_get_drvdata(pdev->dev.parent); struct tps65090_regulator *ri = NULL; struct regulator_config config = { }; struct regulator_dev *rdev; - struct tps65090_regulator_platform_data *tps_pdata; - int id = pdev->id; + struct tps65090_regulator_plat_data *tps_pdata; + struct tps65090_regulator *pmic; + struct tps65090_platform_data *tps65090_pdata; + int num; + int ret; - dev_dbg(&pdev->dev, "Probing regulator %d\n", id); + dev_dbg(&pdev->dev, "Probing regulator\n"); - ri = find_regulator_info(id); - if (ri == NULL) { - dev_err(&pdev->dev, "invalid regulator ID specified\n"); + tps65090_pdata = dev_get_platdata(pdev->dev.parent); + if (!tps65090_pdata) { + dev_err(&pdev->dev, "Platform data missing\n"); return -EINVAL; } - tps_pdata = pdev->dev.platform_data; - ri->dev = &pdev->dev; - - config.dev = &pdev->dev; - config.init_data = &tps_pdata->regulator; - config.driver_data = ri; - config.regmap = tps65090_mfd->rmap; - - rdev = regulator_register(&ri->desc, &config); - if (IS_ERR(rdev)) { - dev_err(&pdev->dev, "failed to register regulator %s\n", - ri->desc.name); - return PTR_ERR(rdev); + + pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic), + GFP_KERNEL); + if (!pmic) { + dev_err(&pdev->dev, "mem alloc for pmic failed\n"); + return -ENOMEM; + } + + for (num = 0; num < TPS65090_REGULATOR_MAX; num++) { + tps_pdata = tps65090_pdata->reg_pdata[num]; + + ri = &pmic[num]; + ri->dev = &pdev->dev; + ri->desc = &tps65090_regulator_desc[num]; + + /* + * TPS5090 DCDC support the control from external digital input. + * Configure it as per platform data. + */ + if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data) { + if (tps_pdata->enable_ext_control) { + tps65090_configure_regulator_config( + tps_pdata, &config); + ri->desc->ops = &tps65090_ext_control_ops; + } else { + ret = tps65090_regulator_disable_ext_control( + ri, tps_pdata); + if (ret < 0) { + dev_err(&pdev->dev, + "failed disable ext control\n"); + goto scrub; + } + } + } + + config.dev = &pdev->dev; + config.driver_data = ri; + config.regmap = tps65090_mfd->rmap; + if (tps_pdata) + config.init_data = tps_pdata->reg_init_data; + else + config.init_data = NULL; + + rdev = regulator_register(ri->desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register regulator %s\n", + ri->desc->name); + ret = PTR_ERR(rdev); + goto scrub; + } + ri->rdev = rdev; + + /* Enable external control if it is require */ + if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data && + tps_pdata->enable_ext_control) { + ret = tps65090_config_ext_control(ri, true); + if (ret < 0) { + /* Increment num to get unregister rdev */ + num++; + goto scrub; + } + } } - platform_set_drvdata(pdev, rdev); + platform_set_drvdata(pdev, pmic); return 0; + +scrub: + while (--num >= 0) { + ri = &pmic[num]; + regulator_unregister(ri->rdev); + } + return ret; } -static int __devexit tps65090_regulator_remove(struct platform_device *pdev) +static int tps65090_regulator_remove(struct platform_device *pdev) { - struct regulator_dev *rdev = platform_get_drvdata(pdev); + struct tps65090_regulator *pmic = platform_get_drvdata(pdev); + struct tps65090_regulator *ri; + int num; - regulator_unregister(rdev); + for (num = 0; num < TPS65090_REGULATOR_MAX; ++num) { + ri = &pmic[num]; + regulator_unregister(ri->rdev); + } return 0; } static struct platform_driver tps65090_regulator_driver = { .driver = { - .name = "tps65090-regulator", + .name = "tps65090-pmic", .owner = THIS_MODULE, }, .probe = tps65090_regulator_probe, - .remove = __devexit_p(tps65090_regulator_remove), + .remove = tps65090_regulator_remove, }; static int __init tps65090_regulator_init(void) diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index ab00cab905b7..73dce7664126 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -332,7 +332,7 @@ static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev) } #endif -static int __devinit tps65217_regulator_probe(struct platform_device *pdev) +static int tps65217_regulator_probe(struct platform_device *pdev) { struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); struct tps65217_board *pdata = dev_get_platdata(tps->dev); @@ -397,7 +397,7 @@ err_unregister_regulator: return ret; } -static int __devexit tps65217_regulator_remove(struct platform_device *pdev) +static int tps65217_regulator_remove(struct platform_device *pdev) { struct tps65217 *tps = platform_get_drvdata(pdev); unsigned int i; @@ -415,7 +415,7 @@ static struct platform_driver tps65217_regulator_driver = { .name = "tps65217-pmic", }, .probe = tps65217_regulator_probe, - .remove = __devexit_p(tps65217_regulator_remove), + .remove = tps65217_regulator_remove, }; static int __init tps65217_regulator_init(void) diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c index 058d2f2675e9..843ee0a9bb92 100644 --- a/drivers/regulator/tps6524x-regulator.c +++ b/drivers/regulator/tps6524x-regulator.c @@ -592,7 +592,7 @@ static int pmic_remove(struct spi_device *spi) return 0; } -static int __devinit pmic_probe(struct spi_device *spi) +static int pmic_probe(struct spi_device *spi) { struct tps6524x *hw; struct device *dev = &spi->dev; @@ -649,7 +649,7 @@ fail: static struct spi_driver pmic_driver = { .probe = pmic_probe, - .remove = __devexit_p(pmic_remove), + .remove = pmic_remove, .driver = { .name = "tps6524x", .owner = THIS_MODULE, diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index ce1e7cb8d513..9ce44109f2aa 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -17,10 +17,12 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/err.h> +#include <linux/of.h> #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> #include <linux/mfd/tps6586x.h> /* supply control and voltage setting */ @@ -255,10 +257,10 @@ static inline int tps6586x_regulator_preinit(struct device *parent, 1 << ri->enable_bit[1]); } -static int tps6586x_regulator_set_slew_rate(struct platform_device *pdev) +static int tps6586x_regulator_set_slew_rate(struct platform_device *pdev, + int id, struct regulator_init_data *p) { struct device *parent = pdev->dev.parent; - struct regulator_init_data *p = pdev->dev.platform_data; struct tps6586x_settings *setting = p->driver_data; uint8_t reg; @@ -269,7 +271,7 @@ static int tps6586x_regulator_set_slew_rate(struct platform_device *pdev) return 0; /* only SM0 and SM1 can have the slew rate settings */ - switch (pdev->id) { + switch (id) { case TPS6586X_ID_SM_0: reg = TPS6586X_SM0SL; break; @@ -298,58 +300,185 @@ static inline struct tps6586x_regulator *find_regulator_info(int id) return NULL; } -static int __devinit tps6586x_regulator_probe(struct platform_device *pdev) +#ifdef CONFIG_OF +static struct of_regulator_match tps6586x_matches[] = { + { .name = "sys", .driver_data = (void *)TPS6586X_ID_SYS }, + { .name = "sm0", .driver_data = (void *)TPS6586X_ID_SM_0 }, + { .name = "sm1", .driver_data = (void *)TPS6586X_ID_SM_1 }, + { .name = "sm2", .driver_data = (void *)TPS6586X_ID_SM_2 }, + { .name = "ldo0", .driver_data = (void *)TPS6586X_ID_LDO_0 }, + { .name = "ldo1", .driver_data = (void *)TPS6586X_ID_LDO_1 }, + { .name = "ldo2", .driver_data = (void *)TPS6586X_ID_LDO_2 }, + { .name = "ldo3", .driver_data = (void *)TPS6586X_ID_LDO_3 }, + { .name = "ldo4", .driver_data = (void *)TPS6586X_ID_LDO_4 }, + { .name = "ldo5", .driver_data = (void *)TPS6586X_ID_LDO_5 }, + { .name = "ldo6", .driver_data = (void *)TPS6586X_ID_LDO_6 }, + { .name = "ldo7", .driver_data = (void *)TPS6586X_ID_LDO_7 }, + { .name = "ldo8", .driver_data = (void *)TPS6586X_ID_LDO_8 }, + { .name = "ldo9", .driver_data = (void *)TPS6586X_ID_LDO_9 }, + { .name = "ldo_rtc", .driver_data = (void *)TPS6586X_ID_LDO_RTC }, +}; + +static struct tps6586x_platform_data *tps6586x_parse_regulator_dt( + struct platform_device *pdev, + struct of_regulator_match **tps6586x_reg_matches) +{ + const unsigned int num = ARRAY_SIZE(tps6586x_matches); + struct device_node *np = pdev->dev.parent->of_node; + struct device_node *regs; + const char *sys_rail = NULL; + unsigned int i; + struct tps6586x_platform_data *pdata; + int err; + + regs = of_find_node_by_name(np, "regulators"); + if (!regs) { + dev_err(&pdev->dev, "regulator node not found\n"); + return NULL; + } + + err = of_regulator_match(&pdev->dev, regs, tps6586x_matches, num); + if (err < 0) { + dev_err(&pdev->dev, "Regulator match failed, e %d\n", err); + of_node_put(regs); + return NULL; + } + + of_node_put(regs); + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, "Memory alloction failed\n"); + return NULL; + } + + for (i = 0; i < num; i++) { + int id; + if (!tps6586x_matches[i].init_data) + continue; + + pdata->reg_init_data[i] = tps6586x_matches[i].init_data; + id = (int)tps6586x_matches[i].driver_data; + if (id == TPS6586X_ID_SYS) + sys_rail = pdata->reg_init_data[i]->constraints.name; + + if ((id == TPS6586X_ID_LDO_5) || (id == TPS6586X_ID_LDO_RTC)) + pdata->reg_init_data[i]->supply_regulator = sys_rail; + } + *tps6586x_reg_matches = tps6586x_matches; + return pdata; +} +#else +static struct tps6586x_platform_data *tps6586x_parse_regulator_dt( + struct platform_device *pdev, + struct of_regulator_match **tps6586x_reg_matches) +{ + *tps6586x_reg_matches = NULL; + return NULL; +} +#endif + +static int tps6586x_regulator_probe(struct platform_device *pdev) { struct tps6586x_regulator *ri = NULL; struct regulator_config config = { }; - struct regulator_dev *rdev; - int id = pdev->id; + struct regulator_dev **rdev; + struct regulator_init_data *reg_data; + struct tps6586x_platform_data *pdata; + struct of_regulator_match *tps6586x_reg_matches = NULL; + int id; int err; dev_dbg(&pdev->dev, "Probing regulator %d\n", id); - ri = find_regulator_info(id); - if (ri == NULL) { - dev_err(&pdev->dev, "invalid regulator ID specified\n"); - return -EINVAL; - } + pdata = dev_get_platdata(pdev->dev.parent); + if ((!pdata) && (pdev->dev.parent->of_node)) + pdata = tps6586x_parse_regulator_dt(pdev, + &tps6586x_reg_matches); - err = tps6586x_regulator_preinit(pdev->dev.parent, ri); - if (err) - return err; + if (!pdata) { + dev_err(&pdev->dev, "Platform data not available, exiting\n"); + return -ENODEV; + } - config.dev = pdev->dev.parent; - config.of_node = pdev->dev.of_node; - config.init_data = pdev->dev.platform_data; - config.driver_data = ri; + rdev = devm_kzalloc(&pdev->dev, TPS6586X_ID_MAX_REGULATOR * + sizeof(*rdev), GFP_KERNEL); + if (!rdev) { + dev_err(&pdev->dev, "Mmemory alloc failed\n"); + return -ENOMEM; + } - rdev = regulator_register(&ri->desc, &config); - if (IS_ERR(rdev)) { - dev_err(&pdev->dev, "failed to register regulator %s\n", - ri->desc.name); - return PTR_ERR(rdev); + for (id = 0; id < TPS6586X_ID_MAX_REGULATOR; ++id) { + reg_data = pdata->reg_init_data[id]; + + ri = find_regulator_info(id); + if (!ri) { + dev_err(&pdev->dev, "invalid regulator ID specified\n"); + err = -EINVAL; + goto fail; + } + + err = tps6586x_regulator_preinit(pdev->dev.parent, ri); + if (err) { + dev_err(&pdev->dev, + "regulator %d preinit failed, e %d\n", id, err); + goto fail; + } + + config.dev = pdev->dev.parent; + config.init_data = reg_data; + config.driver_data = ri; + + if (tps6586x_reg_matches) + config.of_node = tps6586x_reg_matches[id].of_node; + + rdev[id] = regulator_register(&ri->desc, &config); + if (IS_ERR(rdev[id])) { + dev_err(&pdev->dev, "failed to register regulator %s\n", + ri->desc.name); + err = PTR_ERR(rdev[id]); + goto fail; + } + + if (reg_data) { + err = tps6586x_regulator_set_slew_rate(pdev, id, + reg_data); + if (err < 0) { + dev_err(&pdev->dev, + "Slew rate config failed, e %d\n", err); + regulator_unregister(rdev[id]); + goto fail; + } + } } platform_set_drvdata(pdev, rdev); + return 0; - return tps6586x_regulator_set_slew_rate(pdev); +fail: + while (--id >= 0) + regulator_unregister(rdev[id]); + return err; } -static int __devexit tps6586x_regulator_remove(struct platform_device *pdev) +static int tps6586x_regulator_remove(struct platform_device *pdev) { - struct regulator_dev *rdev = platform_get_drvdata(pdev); + struct regulator_dev **rdev = platform_get_drvdata(pdev); + int id = TPS6586X_ID_MAX_REGULATOR; + + while (--id >= 0) + regulator_unregister(rdev[id]); - regulator_unregister(rdev); return 0; } static struct platform_driver tps6586x_regulator_driver = { .driver = { - .name = "tps6586x-regulator", + .name = "tps6586x-pmic", .owner = THIS_MODULE, }, .probe = tps6586x_regulator_probe, - .remove = __devexit_p(tps6586x_regulator_remove), + .remove = tps6586x_regulator_remove, }; static int __init tps6586x_regulator_init(void) diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index 793adda560c3..6b77bbf32ebc 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -1026,7 +1026,7 @@ static inline struct tps65910_board *tps65910_parse_dt_reg_data( } #endif -static __devinit int tps65910_probe(struct platform_device *pdev) +static int tps65910_probe(struct platform_device *pdev) { struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = { }; @@ -1184,7 +1184,7 @@ err_unregister_regulator: return err; } -static int __devexit tps65910_remove(struct platform_device *pdev) +static int tps65910_remove(struct platform_device *pdev) { struct tps65910_reg *pmic = platform_get_drvdata(pdev); int i; @@ -1231,7 +1231,7 @@ static struct platform_driver tps65910_driver = { .owner = THIS_MODULE, }, .probe = tps65910_probe, - .remove = __devexit_p(tps65910_remove), + .remove = tps65910_remove, .shutdown = tps65910_shutdown, }; diff --git a/drivers/regulator/tps65912-regulator.c b/drivers/regulator/tps65912-regulator.c index 18b2a1dcb4b5..17e994e47dc1 100644 --- a/drivers/regulator/tps65912-regulator.c +++ b/drivers/regulator/tps65912-regulator.c @@ -459,7 +459,7 @@ static struct regulator_ops tps65912_ops_ldo = { .list_voltage = tps65912_list_voltage, }; -static __devinit int tps65912_probe(struct platform_device *pdev) +static int tps65912_probe(struct platform_device *pdev) { struct tps65912 *tps65912 = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = { }; @@ -525,7 +525,7 @@ err: return err; } -static int __devexit tps65912_remove(struct platform_device *pdev) +static int tps65912_remove(struct platform_device *pdev) { struct tps65912_reg *tps65912_reg = platform_get_drvdata(pdev); int i; @@ -541,7 +541,7 @@ static struct platform_driver tps65912_driver = { .owner = THIS_MODULE, }, .probe = tps65912_probe, - .remove = __devexit_p(tps65912_remove), + .remove = tps65912_remove, }; static int __init tps65912_init(void) diff --git a/drivers/regulator/tps80031-regulator.c b/drivers/regulator/tps80031-regulator.c new file mode 100644 index 000000000000..127d1754fcd3 --- /dev/null +++ b/drivers/regulator/tps80031-regulator.c @@ -0,0 +1,793 @@ +/* + * tps80031-regulator.c -- TI TPS80031 regulator driver. + * + * Regulator driver for TITPS80031/TPS80032 Fully Integrated Power + * Management with Power Path and Battery Charger. + * + * Copyright (c) 2012, NVIDIA Corporation. + * + * Author: Laxman Dewangan <ldewangan@nvidia.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/mfd/tps80031.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/slab.h> + +/* Flags for DCDC Voltage reading */ +#define DCDC_OFFSET_EN BIT(0) +#define DCDC_EXTENDED_EN BIT(1) +#define TRACK_MODE_ENABLE BIT(2) + +#define SMPS_MULTOFFSET_VIO BIT(1) +#define SMPS_MULTOFFSET_SMPS1 BIT(3) +#define SMPS_MULTOFFSET_SMPS2 BIT(4) +#define SMPS_MULTOFFSET_SMPS3 BIT(6) +#define SMPS_MULTOFFSET_SMPS4 BIT(0) + +#define SMPS_CMD_MASK 0xC0 +#define SMPS_VSEL_MASK 0x3F +#define LDO_VSEL_MASK 0x1F +#define LDO_TRACK_VSEL_MASK 0x3F + +#define MISC2_LDOUSB_IN_VSYS BIT(4) +#define MISC2_LDOUSB_IN_PMID BIT(3) +#define MISC2_LDOUSB_IN_MASK 0x18 + +#define MISC2_LDO3_SEL_VIB_VAL BIT(0) +#define MISC2_LDO3_SEL_VIB_MASK 0x1 + +#define BOOST_HW_PWR_EN BIT(5) +#define BOOST_HW_PWR_EN_MASK BIT(5) + +#define OPA_MODE_EN BIT(6) +#define OPA_MODE_EN_MASK BIT(6) + +#define USB_VBUS_CTRL_SET 0x04 +#define USB_VBUS_CTRL_CLR 0x05 +#define VBUS_DISCHRG 0x20 + +struct tps80031_regulator_info { + /* Regulator register address.*/ + u8 trans_reg; + u8 state_reg; + u8 force_reg; + u8 volt_reg; + u8 volt_id; + + /*Power request bits */ + int preq_bit; + + /* used by regulator core */ + struct regulator_desc desc; + +}; + +struct tps80031_regulator { + struct device *dev; + struct regulator_dev *rdev; + struct tps80031_regulator_info *rinfo; + + u8 device_flags; + unsigned int config_flags; + unsigned int ext_ctrl_flag; +}; + +static inline struct device *to_tps80031_dev(struct regulator_dev *rdev) +{ + return rdev_get_dev(rdev)->parent->parent; +} + +static int tps80031_reg_is_enabled(struct regulator_dev *rdev) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps80031_dev(rdev); + u8 reg_val; + int ret; + + if (ri->ext_ctrl_flag & TPS80031_EXT_PWR_REQ) + return true; + + ret = tps80031_read(parent, TPS80031_SLAVE_ID1, ri->rinfo->state_reg, + ®_val); + if (ret < 0) { + dev_err(&rdev->dev, "Reg 0x%02x read failed, err = %d\n", + ri->rinfo->state_reg, ret); + return ret; + } + return ((reg_val & TPS80031_STATE_MASK) == TPS80031_STATE_ON); +} + +static int tps80031_reg_enable(struct regulator_dev *rdev) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps80031_dev(rdev); + int ret; + + if (ri->ext_ctrl_flag & TPS80031_EXT_PWR_REQ) + return 0; + + ret = tps80031_update(parent, TPS80031_SLAVE_ID1, ri->rinfo->state_reg, + TPS80031_STATE_ON, TPS80031_STATE_MASK); + if (ret < 0) { + dev_err(&rdev->dev, "Reg 0x%02x update failed, err = %d\n", + ri->rinfo->state_reg, ret); + return ret; + } + return ret; +} + +static int tps80031_reg_disable(struct regulator_dev *rdev) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps80031_dev(rdev); + int ret; + + if (ri->ext_ctrl_flag & TPS80031_EXT_PWR_REQ) + return 0; + + ret = tps80031_update(parent, TPS80031_SLAVE_ID1, ri->rinfo->state_reg, + TPS80031_STATE_OFF, TPS80031_STATE_MASK); + if (ret < 0) + dev_err(&rdev->dev, "Reg 0x%02x update failed, err = %d\n", + ri->rinfo->state_reg, ret); + return ret; +} + +/* DCDC voltages for the selector of 58 to 63 */ +static int tps80031_dcdc_voltages[4][5] = { + { 1350, 1500, 1800, 1900, 2100}, + { 1350, 1500, 1800, 1900, 2100}, + { 2084, 2315, 2778, 2932, 3241}, + { 4167, 2315, 2778, 2932, 3241}, +}; + +static int tps80031_dcdc_list_voltage(struct regulator_dev *rdev, unsigned sel) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + int volt_index = ri->device_flags & 0x3; + + if (sel == 0) + return 0; + else if (sel < 58) + return regulator_list_voltage_linear(rdev, sel - 1); + else + return tps80031_dcdc_voltages[volt_index][sel - 58] * 1000; +} + +static int tps80031_dcdc_set_voltage_sel(struct regulator_dev *rdev, + unsigned vsel) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps80031_dev(rdev); + int ret; + u8 reg_val; + + if (ri->rinfo->force_reg) { + ret = tps80031_read(parent, ri->rinfo->volt_id, + ri->rinfo->force_reg, ®_val); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", + ri->rinfo->force_reg, ret); + return ret; + } + if (!(reg_val & SMPS_CMD_MASK)) { + ret = tps80031_update(parent, ri->rinfo->volt_id, + ri->rinfo->force_reg, vsel, SMPS_VSEL_MASK); + if (ret < 0) + dev_err(ri->dev, + "reg 0x%02x update failed, e = %d\n", + ri->rinfo->force_reg, ret); + return ret; + } + } + ret = tps80031_update(parent, ri->rinfo->volt_id, + ri->rinfo->volt_reg, vsel, SMPS_VSEL_MASK); + if (ret < 0) + dev_err(ri->dev, "reg 0x%02x update failed, e = %d\n", + ri->rinfo->volt_reg, ret); + return ret; +} + +static int tps80031_dcdc_get_voltage_sel(struct regulator_dev *rdev) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps80031_dev(rdev); + uint8_t vsel = 0; + int ret; + + if (ri->rinfo->force_reg) { + ret = tps80031_read(parent, ri->rinfo->volt_id, + ri->rinfo->force_reg, &vsel); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", + ri->rinfo->force_reg, ret); + return ret; + } + + if (!(vsel & SMPS_CMD_MASK)) + return vsel & SMPS_VSEL_MASK; + } + ret = tps80031_read(parent, ri->rinfo->volt_id, + ri->rinfo->volt_reg, &vsel); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", + ri->rinfo->volt_reg, ret); + return ret; + } + return vsel & SMPS_VSEL_MASK; +} + +static int tps80031_ldo_set_voltage_sel(struct regulator_dev *rdev, + unsigned sel) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps80031_dev(rdev); + int ret; + + /* Check for valid setting for TPS80031 or TPS80032-ES1.0 */ + if ((ri->rinfo->desc.id == TPS80031_REGULATOR_LDO2) && + (ri->device_flags & TRACK_MODE_ENABLE)) { + unsigned nvsel = (sel) & 0x1F; + if (((tps80031_get_chip_info(parent) == TPS80031) || + ((tps80031_get_chip_info(parent) == TPS80032) && + (tps80031_get_pmu_version(parent) == 0x0))) && + ((nvsel == 0x0) || (nvsel >= 0x19 && nvsel <= 0x1F))) { + dev_err(ri->dev, + "Invalid sel %d in track mode LDO2\n", + nvsel); + return -EINVAL; + } + } + + ret = tps80031_write(parent, ri->rinfo->volt_id, + ri->rinfo->volt_reg, sel); + if (ret < 0) + dev_err(ri->dev, "Error in writing reg 0x%02x, e = %d\n", + ri->rinfo->volt_reg, ret); + return ret; +} + +static int tps80031_ldo_get_voltage_sel(struct regulator_dev *rdev) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps80031_dev(rdev); + uint8_t vsel; + int ret; + + ret = tps80031_read(parent, ri->rinfo->volt_id, + ri->rinfo->volt_reg, &vsel); + if (ret < 0) { + dev_err(ri->dev, "Error in writing the Voltage register\n"); + return ret; + } + return vsel & rdev->desc->vsel_mask; +} + +static int tps80031_ldo_list_voltage(struct regulator_dev *rdev, unsigned sel) +{ + if (sel == 0) + return 0; + else + return regulator_list_voltage_linear(rdev, sel - 1); +} + +static int tps80031_vbus_is_enabled(struct regulator_dev *rdev) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps80031_dev(rdev); + int ret = -EIO; + uint8_t ctrl1 = 0; + uint8_t ctrl3 = 0; + + ret = tps80031_read(parent, TPS80031_SLAVE_ID2, + TPS80031_CHARGERUSB_CTRL1, &ctrl1); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", + TPS80031_CHARGERUSB_CTRL1, ret); + return ret; + } + ret = tps80031_read(parent, TPS80031_SLAVE_ID2, + TPS80031_CHARGERUSB_CTRL3, &ctrl3); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", + TPS80031_CHARGERUSB_CTRL1, ret); + return ret; + } + if ((ctrl1 & OPA_MODE_EN) && (ctrl3 & BOOST_HW_PWR_EN)) + return 1; + return ret; +} + +static int tps80031_vbus_enable(struct regulator_dev *rdev) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps80031_dev(rdev); + int ret; + + ret = tps80031_set_bits(parent, TPS80031_SLAVE_ID2, + TPS80031_CHARGERUSB_CTRL1, OPA_MODE_EN); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", + TPS80031_CHARGERUSB_CTRL1, ret); + return ret; + } + + ret = tps80031_set_bits(parent, TPS80031_SLAVE_ID2, + TPS80031_CHARGERUSB_CTRL3, BOOST_HW_PWR_EN); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", + TPS80031_CHARGERUSB_CTRL3, ret); + return ret; + } + return ret; +} + +static int tps80031_vbus_disable(struct regulator_dev *rdev) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps80031_dev(rdev); + int ret = 0; + + if (ri->config_flags & TPS80031_VBUS_DISCHRG_EN_PDN) { + ret = tps80031_write(parent, TPS80031_SLAVE_ID2, + USB_VBUS_CTRL_SET, VBUS_DISCHRG); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x write failed, e = %d\n", + USB_VBUS_CTRL_SET, ret); + return ret; + } + } + + ret = tps80031_clr_bits(parent, TPS80031_SLAVE_ID2, + TPS80031_CHARGERUSB_CTRL1, OPA_MODE_EN); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x clearbit failed, e = %d\n", + TPS80031_CHARGERUSB_CTRL1, ret); + return ret; + } + + ret = tps80031_clr_bits(parent, TPS80031_SLAVE_ID2, + TPS80031_CHARGERUSB_CTRL3, BOOST_HW_PWR_EN); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x clearbit failed, e = %d\n", + TPS80031_CHARGERUSB_CTRL3, ret); + return ret; + } + + mdelay(DIV_ROUND_UP(ri->rinfo->desc.enable_time, 1000)); + if (ri->config_flags & TPS80031_VBUS_DISCHRG_EN_PDN) { + ret = tps80031_write(parent, TPS80031_SLAVE_ID2, + USB_VBUS_CTRL_CLR, VBUS_DISCHRG); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x write failed, e = %d\n", + USB_VBUS_CTRL_CLR, ret); + return ret; + } + } + return ret; +} + +static struct regulator_ops tps80031_dcdc_ops = { + .list_voltage = tps80031_dcdc_list_voltage, + .set_voltage_sel = tps80031_dcdc_set_voltage_sel, + .get_voltage_sel = tps80031_dcdc_get_voltage_sel, + .enable = tps80031_reg_enable, + .disable = tps80031_reg_disable, + .is_enabled = tps80031_reg_is_enabled, +}; + +static struct regulator_ops tps80031_ldo_ops = { + .list_voltage = tps80031_ldo_list_voltage, + .set_voltage_sel = tps80031_ldo_set_voltage_sel, + .get_voltage_sel = tps80031_ldo_get_voltage_sel, + .enable = tps80031_reg_enable, + .disable = tps80031_reg_disable, + .is_enabled = tps80031_reg_is_enabled, +}; + +static struct regulator_ops tps80031_vbus_sw_ops = { + .enable = tps80031_vbus_enable, + .disable = tps80031_vbus_disable, + .is_enabled = tps80031_vbus_is_enabled, +}; + +static struct regulator_ops tps80031_vbus_hw_ops = { +}; + +static struct regulator_ops tps80031_ext_reg_ops = { + .enable = tps80031_reg_enable, + .disable = tps80031_reg_disable, + .is_enabled = tps80031_reg_is_enabled, +}; + +/* Non-exiting default definition for some register */ +#define TPS80031_SMPS3_CFG_FORCE 0 +#define TPS80031_SMPS4_CFG_FORCE 0 + +#define TPS80031_VBUS_CFG_TRANS 0 +#define TPS80031_VBUS_CFG_STATE 0 + +#define TPS80031_REG_SMPS(_id, _volt_id, _pbit) \ +{ \ + .trans_reg = TPS80031_##_id##_CFG_TRANS, \ + .state_reg = TPS80031_##_id##_CFG_STATE, \ + .force_reg = TPS80031_##_id##_CFG_FORCE, \ + .volt_reg = TPS80031_##_id##_CFG_VOLTAGE, \ + .volt_id = TPS80031_SLAVE_##_volt_id, \ + .preq_bit = _pbit, \ + .desc = { \ + .name = "tps80031_"#_id, \ + .id = TPS80031_REGULATOR_##_id, \ + .n_voltages = 63, \ + .ops = &tps80031_dcdc_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .enable_time = 500, \ + }, \ +} + +#define TPS80031_REG_LDO(_id, _preq_bit) \ +{ \ + .trans_reg = TPS80031_##_id##_CFG_TRANS, \ + .state_reg = TPS80031_##_id##_CFG_STATE, \ + .volt_reg = TPS80031_##_id##_CFG_VOLTAGE, \ + .volt_id = TPS80031_SLAVE_ID1, \ + .preq_bit = _preq_bit, \ + .desc = { \ + .owner = THIS_MODULE, \ + .name = "tps80031_"#_id, \ + .id = TPS80031_REGULATOR_##_id, \ + .ops = &tps80031_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .min_uV = 1000000, \ + .uV_step = 100000, \ + .n_voltages = 25, \ + .vsel_mask = LDO_VSEL_MASK, \ + .enable_time = 500, \ + }, \ +} + +#define TPS80031_REG_FIXED(_id, max_mV, _ops, _delay, _pbit) \ +{ \ + .trans_reg = TPS80031_##_id##_CFG_TRANS, \ + .state_reg = TPS80031_##_id##_CFG_STATE, \ + .volt_id = TPS80031_SLAVE_ID1, \ + .preq_bit = _pbit, \ + .desc = { \ + .name = "tps80031_"#_id, \ + .id = TPS80031_REGULATOR_##_id, \ + .n_voltages = 2, \ + .ops = &_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .enable_time = _delay, \ + }, \ +} + +static struct tps80031_regulator_info tps80031_rinfo[TPS80031_REGULATOR_MAX] = { + TPS80031_REG_SMPS(VIO, ID0, 4), + TPS80031_REG_SMPS(SMPS1, ID0, 0), + TPS80031_REG_SMPS(SMPS2, ID0, 1), + TPS80031_REG_SMPS(SMPS3, ID1, 2), + TPS80031_REG_SMPS(SMPS4, ID1, 3), + TPS80031_REG_LDO(VANA, -1), + TPS80031_REG_LDO(LDO1, 8), + TPS80031_REG_LDO(LDO2, 9), + TPS80031_REG_LDO(LDO3, 10), + TPS80031_REG_LDO(LDO4, 11), + TPS80031_REG_LDO(LDO5, 12), + TPS80031_REG_LDO(LDO6, 13), + TPS80031_REG_LDO(LDO7, 14), + TPS80031_REG_LDO(LDOLN, 15), + TPS80031_REG_LDO(LDOUSB, 5), + TPS80031_REG_FIXED(VBUS, 5000, tps80031_vbus_hw_ops, 100000, -1), + TPS80031_REG_FIXED(REGEN1, 3300, tps80031_ext_reg_ops, 0, 16), + TPS80031_REG_FIXED(REGEN2, 3300, tps80031_ext_reg_ops, 0, 17), + TPS80031_REG_FIXED(SYSEN, 3300, tps80031_ext_reg_ops, 0, 18), +}; + +static int tps80031_power_req_config(struct device *parent, + struct tps80031_regulator *ri, + struct tps80031_regulator_platform_data *tps80031_pdata) +{ + int ret = 0; + + if (ri->rinfo->preq_bit < 0) + goto skip_pwr_req_config; + + ret = tps80031_ext_power_req_config(parent, ri->ext_ctrl_flag, + ri->rinfo->preq_bit, ri->rinfo->state_reg, + ri->rinfo->trans_reg); + if (ret < 0) { + dev_err(ri->dev, "ext powerreq config failed, err = %d\n", ret); + return ret; + } + +skip_pwr_req_config: + if (tps80031_pdata->ext_ctrl_flag & TPS80031_PWR_ON_ON_SLEEP) { + ret = tps80031_update(parent, TPS80031_SLAVE_ID1, + ri->rinfo->trans_reg, TPS80031_TRANS_SLEEP_ON, + TPS80031_TRANS_SLEEP_MASK); + if (ret < 0) { + dev_err(ri->dev, "Reg 0x%02x update failed, e %d\n", + ri->rinfo->trans_reg, ret); + return ret; + } + } + return ret; +} + +static int tps80031_regulator_config(struct device *parent, + struct tps80031_regulator *ri, + struct tps80031_regulator_platform_data *tps80031_pdata) +{ + int ret = 0; + + switch (ri->rinfo->desc.id) { + case TPS80031_REGULATOR_LDOUSB: + if (ri->config_flags & (TPS80031_USBLDO_INPUT_VSYS | + TPS80031_USBLDO_INPUT_PMID)) { + unsigned val = 0; + if (ri->config_flags & TPS80031_USBLDO_INPUT_VSYS) + val = MISC2_LDOUSB_IN_VSYS; + else + val = MISC2_LDOUSB_IN_PMID; + + ret = tps80031_update(parent, TPS80031_SLAVE_ID1, + TPS80031_MISC2, val, + MISC2_LDOUSB_IN_MASK); + if (ret < 0) { + dev_err(ri->dev, + "LDOUSB config failed, e= %d\n", ret); + return ret; + } + } + break; + + case TPS80031_REGULATOR_LDO3: + if (ri->config_flags & TPS80031_LDO3_OUTPUT_VIB) { + ret = tps80031_update(parent, TPS80031_SLAVE_ID1, + TPS80031_MISC2, MISC2_LDO3_SEL_VIB_VAL, + MISC2_LDO3_SEL_VIB_MASK); + if (ret < 0) { + dev_err(ri->dev, + "LDO3 config failed, e = %d\n", ret); + return ret; + } + } + break; + + case TPS80031_REGULATOR_VBUS: + /* Provide SW control Ops if VBUS is SW control */ + if (!(ri->config_flags & TPS80031_VBUS_SW_ONLY)) + ri->rinfo->desc.ops = &tps80031_vbus_sw_ops; + break; + default: + break; + } + + /* Configure Active state to ON, SLEEP to OFF and OFF_state to OFF */ + ret = tps80031_update(parent, TPS80031_SLAVE_ID1, ri->rinfo->trans_reg, + TPS80031_TRANS_ACTIVE_ON | TPS80031_TRANS_SLEEP_OFF | + TPS80031_TRANS_OFF_OFF, TPS80031_TRANS_ACTIVE_MASK | + TPS80031_TRANS_SLEEP_MASK | TPS80031_TRANS_OFF_MASK); + if (ret < 0) { + dev_err(ri->dev, "trans reg update failed, e %d\n", ret); + return ret; + } + + return ret; +} + +static int check_smps_mode_mult(struct device *parent, + struct tps80031_regulator *ri) +{ + int mult_offset; + int ret; + u8 smps_offset; + u8 smps_mult; + + ret = tps80031_read(parent, TPS80031_SLAVE_ID1, + TPS80031_SMPS_OFFSET, &smps_offset); + if (ret < 0) { + dev_err(parent, "Error in reading smps offset register\n"); + return ret; + } + + ret = tps80031_read(parent, TPS80031_SLAVE_ID1, + TPS80031_SMPS_MULT, &smps_mult); + if (ret < 0) { + dev_err(parent, "Error in reading smps mult register\n"); + return ret; + } + + switch (ri->rinfo->desc.id) { + case TPS80031_REGULATOR_VIO: + mult_offset = SMPS_MULTOFFSET_VIO; + break; + case TPS80031_REGULATOR_SMPS1: + mult_offset = SMPS_MULTOFFSET_SMPS1; + break; + case TPS80031_REGULATOR_SMPS2: + mult_offset = SMPS_MULTOFFSET_SMPS2; + break; + case TPS80031_REGULATOR_SMPS3: + mult_offset = SMPS_MULTOFFSET_SMPS3; + break; + case TPS80031_REGULATOR_SMPS4: + mult_offset = SMPS_MULTOFFSET_SMPS4; + break; + case TPS80031_REGULATOR_LDO2: + ri->device_flags = smps_mult & BIT(5) ? TRACK_MODE_ENABLE : 0; + /* TRACK mode the ldo2 varies from 600mV to 1300mV */ + if (ri->device_flags & TRACK_MODE_ENABLE) { + ri->rinfo->desc.min_uV = 600000; + ri->rinfo->desc.uV_step = 12500; + ri->rinfo->desc.n_voltages = 57; + ri->rinfo->desc.vsel_mask = LDO_TRACK_VSEL_MASK; + } + return 0; + default: + return 0; + } + + ri->device_flags = (smps_offset & mult_offset) ? DCDC_OFFSET_EN : 0; + ri->device_flags |= (smps_mult & mult_offset) ? DCDC_EXTENDED_EN : 0; + switch (ri->device_flags) { + case 0: + ri->rinfo->desc.min_uV = 607700; + ri->rinfo->desc.uV_step = 12660; + break; + case DCDC_OFFSET_EN: + ri->rinfo->desc.min_uV = 700000; + ri->rinfo->desc.uV_step = 12500; + break; + case DCDC_EXTENDED_EN: + ri->rinfo->desc.min_uV = 1852000; + ri->rinfo->desc.uV_step = 38600; + break; + case DCDC_OFFSET_EN | DCDC_EXTENDED_EN: + ri->rinfo->desc.min_uV = 2161000; + ri->rinfo->desc.uV_step = 38600; + break; + } + return 0; +} + +static int tps80031_regulator_probe(struct platform_device *pdev) +{ + struct tps80031_platform_data *pdata; + struct tps80031_regulator_platform_data *tps_pdata; + struct tps80031_regulator_info *rinfo; + struct tps80031_regulator *ri; + struct tps80031_regulator *pmic; + struct regulator_dev *rdev; + struct regulator_config config = { }; + int ret; + int num; + + pdata = dev_get_platdata(pdev->dev.parent); + + if (!pdata) { + dev_err(&pdev->dev, "No platform data\n"); + return -EINVAL; + } + + pmic = devm_kzalloc(&pdev->dev, + TPS80031_REGULATOR_MAX * sizeof(*pmic), GFP_KERNEL); + if (!pmic) { + dev_err(&pdev->dev, "mem alloc for pmic failed\n"); + return -ENOMEM; + } + + for (num = 0; num < TPS80031_REGULATOR_MAX; ++num) { + tps_pdata = pdata->regulator_pdata[num]; + rinfo = &tps80031_rinfo[num]; + ri = &pmic[num]; + ri->rinfo = rinfo; + ri->dev = &pdev->dev; + + check_smps_mode_mult(pdev->dev.parent, ri); + config.dev = &pdev->dev; + config.init_data = NULL; + config.driver_data = ri; + if (tps_pdata) { + config.init_data = tps_pdata->reg_init_data; + ri->config_flags = tps_pdata->config_flags; + ri->ext_ctrl_flag = tps_pdata->ext_ctrl_flag; + ret = tps80031_regulator_config(pdev->dev.parent, + ri, tps_pdata); + if (ret < 0) { + dev_err(&pdev->dev, + "regulator config failed, e %d\n", ret); + goto fail; + } + + ret = tps80031_power_req_config(pdev->dev.parent, + ri, tps_pdata); + if (ret < 0) { + dev_err(&pdev->dev, + "pwr_req config failed, err %d\n", ret); + goto fail; + } + } + rdev = regulator_register(&ri->rinfo->desc, &config); + if (IS_ERR_OR_NULL(rdev)) { + dev_err(&pdev->dev, + "register regulator failed %s\n", + ri->rinfo->desc.name); + ret = PTR_ERR(rdev); + goto fail; + } + ri->rdev = rdev; + } + + platform_set_drvdata(pdev, pmic); + return 0; +fail: + while (--num >= 0) { + ri = &pmic[num]; + regulator_unregister(ri->rdev); + } + return ret; +} + +static int tps80031_regulator_remove(struct platform_device *pdev) +{ + struct tps80031_regulator *pmic = platform_get_drvdata(pdev); + struct tps80031_regulator *ri = NULL; + int num; + + for (num = 0; num < TPS80031_REGULATOR_MAX; ++num) { + ri = &pmic[num]; + regulator_unregister(ri->rdev); + } + return 0; +} + +static struct platform_driver tps80031_regulator_driver = { + .driver = { + .name = "tps80031-pmic", + .owner = THIS_MODULE, + }, + .probe = tps80031_regulator_probe, + .remove = tps80031_regulator_remove, +}; + +static int __init tps80031_regulator_init(void) +{ + return platform_driver_register(&tps80031_regulator_driver); +} +subsys_initcall(tps80031_regulator_init); + +static void __exit tps80031_regulator_exit(void) +{ + platform_driver_unregister(&tps80031_regulator_driver); +} +module_exit(tps80031_regulator_exit); + +MODULE_ALIAS("platform:tps80031-regulator"); +MODULE_DESCRIPTION("Regulator Driver for TI TPS80031 PMIC"); +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 7eb986a40746..493c8c6a241f 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -1116,7 +1116,7 @@ static const struct of_device_id twl_of_match[] __devinitconst = { }; MODULE_DEVICE_TABLE(of, twl_of_match); -static int __devinit twlreg_probe(struct platform_device *pdev) +static int twlreg_probe(struct platform_device *pdev) { int i, id; struct twlreg_info *info; @@ -1241,7 +1241,7 @@ static int __devinit twlreg_probe(struct platform_device *pdev) return 0; } -static int __devexit twlreg_remove(struct platform_device *pdev) +static int twlreg_remove(struct platform_device *pdev) { struct regulator_dev *rdev = platform_get_drvdata(pdev); struct twlreg_info *info = rdev->reg_data; @@ -1255,7 +1255,7 @@ MODULE_ALIAS("platform:twl_reg"); static struct platform_driver twlreg_driver = { .probe = twlreg_probe, - .remove = __devexit_p(twlreg_remove), + .remove = twlreg_remove, /* NOTE: short name, to work around driver model truncation of * "twl_regulator.12" (and friends) to "twl_regulator.1". */ diff --git a/drivers/regulator/vexpress.c b/drivers/regulator/vexpress.c new file mode 100644 index 000000000000..4668c7f8133d --- /dev/null +++ b/drivers/regulator/vexpress.c @@ -0,0 +1,147 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright (C) 2012 ARM Limited + */ + +#define DRVNAME "vexpress-regulator" +#define pr_fmt(fmt) DRVNAME ": " fmt + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/vexpress.h> + +struct vexpress_regulator { + struct regulator_desc desc; + struct regulator_dev *regdev; + struct vexpress_config_func *func; +}; + +static int vexpress_regulator_get_voltage(struct regulator_dev *regdev) +{ + struct vexpress_regulator *reg = rdev_get_drvdata(regdev); + u32 uV; + int err = vexpress_config_read(reg->func, 0, &uV); + + return err ? err : uV; +} + +static int vexpress_regulator_set_voltage(struct regulator_dev *regdev, + int min_uV, int max_uV, unsigned *selector) +{ + struct vexpress_regulator *reg = rdev_get_drvdata(regdev); + + return vexpress_config_write(reg->func, 0, min_uV); +} + +static struct regulator_ops vexpress_regulator_ops_ro = { + .get_voltage = vexpress_regulator_get_voltage, +}; + +static struct regulator_ops vexpress_regulator_ops = { + .get_voltage = vexpress_regulator_get_voltage, + .set_voltage = vexpress_regulator_set_voltage, +}; + +static int vexpress_regulator_probe(struct platform_device *pdev) +{ + int err; + struct vexpress_regulator *reg; + struct regulator_init_data *init_data; + struct regulator_config config = { }; + + reg = devm_kzalloc(&pdev->dev, sizeof(*reg), GFP_KERNEL); + if (!reg) { + err = -ENOMEM; + goto error_kzalloc; + } + + reg->func = vexpress_config_func_get_by_dev(&pdev->dev); + if (!reg->func) { + err = -ENXIO; + goto error_get_func; + } + + reg->desc.name = dev_name(&pdev->dev); + reg->desc.type = REGULATOR_VOLTAGE; + reg->desc.owner = THIS_MODULE; + reg->desc.continuous_voltage_range = true; + + init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node); + if (!init_data) { + err = -EINVAL; + goto error_get_regulator_init_data; + } + + init_data->constraints.apply_uV = 0; + if (init_data->constraints.min_uV && init_data->constraints.max_uV) + reg->desc.ops = &vexpress_regulator_ops; + else + reg->desc.ops = &vexpress_regulator_ops_ro; + + config.dev = &pdev->dev; + config.init_data = init_data; + config.driver_data = reg; + config.of_node = pdev->dev.of_node; + + reg->regdev = regulator_register(®->desc, &config); + if (IS_ERR(reg->regdev)) { + err = PTR_ERR(reg->regdev); + goto error_regulator_register; + } + + platform_set_drvdata(pdev, reg); + + return 0; + +error_regulator_register: +error_get_regulator_init_data: + vexpress_config_func_put(reg->func); +error_get_func: +error_kzalloc: + return err; +} + +static int vexpress_regulator_remove(struct platform_device *pdev) +{ + struct vexpress_regulator *reg = platform_get_drvdata(pdev); + + vexpress_config_func_put(reg->func); + regulator_unregister(reg->regdev); + + return 0; +} + +static struct of_device_id vexpress_regulator_of_match[] = { + { .compatible = "arm,vexpress-volt", }, + { } +}; + +static struct platform_driver vexpress_regulator_driver = { + .probe = vexpress_regulator_probe, + .remove = vexpress_regulator_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + .of_match_table = vexpress_regulator_of_match, + }, +}; + +module_platform_driver(vexpress_regulator_driver); + +MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>"); +MODULE_DESCRIPTION("Versatile Express regulator"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:vexpress-regulator"); diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c index c038e7422538..01c66e9712a4 100644 --- a/drivers/regulator/virtual.c +++ b/drivers/regulator/virtual.c @@ -285,7 +285,7 @@ static const struct attribute_group regulator_virtual_attr_group = { .attrs = regulator_virtual_attributes, }; -static int __devinit regulator_virtual_probe(struct platform_device *pdev) +static int regulator_virtual_probe(struct platform_device *pdev) { char *reg_id = pdev->dev.platform_data; struct virtual_consumer_data *drvdata; @@ -321,7 +321,7 @@ static int __devinit regulator_virtual_probe(struct platform_device *pdev) return 0; } -static int __devexit regulator_virtual_remove(struct platform_device *pdev) +static int regulator_virtual_remove(struct platform_device *pdev) { struct virtual_consumer_data *drvdata = platform_get_drvdata(pdev); @@ -337,7 +337,7 @@ static int __devexit regulator_virtual_remove(struct platform_device *pdev) static struct platform_driver regulator_virtual_consumer_driver = { .probe = regulator_virtual_probe, - .remove = __devexit_p(regulator_virtual_remove), + .remove = regulator_virtual_remove, .driver = { .name = "reg-virt-consumer", .owner = THIS_MODULE, diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 782c228a19bd..bce25658e12e 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -290,7 +290,7 @@ static int wm831x_buckv_set_voltage_sel(struct regulator_dev *rdev, if (vsel > dcdc->dvs_vsel) { ret = wm831x_set_bits(wm831x, dvs_reg, WM831X_DC1_DVS_VSEL_MASK, - dcdc->dvs_vsel); + vsel); if (ret == 0) dcdc->dvs_vsel = vsel; else @@ -387,7 +387,7 @@ static struct regulator_ops wm831x_buckv_ops = { * Set up DVS control. We just log errors since we can still run * (with reduced performance) if we fail. */ -static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc, +static void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc, struct wm831x_buckv_pdata *pdata) { struct wm831x *wm831x = dcdc->wm831x; @@ -448,7 +448,7 @@ static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc, } } -static __devinit int wm831x_buckv_probe(struct platform_device *pdev) +static int wm831x_buckv_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; @@ -562,7 +562,7 @@ err: return ret; } -static __devexit int wm831x_buckv_remove(struct platform_device *pdev) +static int wm831x_buckv_remove(struct platform_device *pdev) { struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); struct wm831x *wm831x = dcdc->wm831x; @@ -582,7 +582,7 @@ static __devexit int wm831x_buckv_remove(struct platform_device *pdev) static struct platform_driver wm831x_buckv_driver = { .probe = wm831x_buckv_probe, - .remove = __devexit_p(wm831x_buckv_remove), + .remove = wm831x_buckv_remove, .driver = { .name = "wm831x-buckv", .owner = THIS_MODULE, @@ -623,7 +623,7 @@ static struct regulator_ops wm831x_buckp_ops = { .set_suspend_mode = wm831x_dcdc_set_suspend_mode, }; -static __devinit int wm831x_buckp_probe(struct platform_device *pdev) +static int wm831x_buckp_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; @@ -710,7 +710,7 @@ err: return ret; } -static __devexit int wm831x_buckp_remove(struct platform_device *pdev) +static int wm831x_buckp_remove(struct platform_device *pdev) { struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); @@ -725,7 +725,7 @@ static __devexit int wm831x_buckp_remove(struct platform_device *pdev) static struct platform_driver wm831x_buckp_driver = { .probe = wm831x_buckp_probe, - .remove = __devexit_p(wm831x_buckp_remove), + .remove = wm831x_buckp_remove, .driver = { .name = "wm831x-buckp", .owner = THIS_MODULE, @@ -771,7 +771,7 @@ static struct regulator_ops wm831x_boostp_ops = { .disable = regulator_disable_regmap, }; -static __devinit int wm831x_boostp_probe(struct platform_device *pdev) +static int wm831x_boostp_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; @@ -845,7 +845,7 @@ err: return ret; } -static __devexit int wm831x_boostp_remove(struct platform_device *pdev) +static int wm831x_boostp_remove(struct platform_device *pdev) { struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); @@ -860,7 +860,7 @@ static __devexit int wm831x_boostp_remove(struct platform_device *pdev) static struct platform_driver wm831x_boostp_driver = { .probe = wm831x_boostp_probe, - .remove = __devexit_p(wm831x_boostp_remove), + .remove = wm831x_boostp_remove, .driver = { .name = "wm831x-boostp", .owner = THIS_MODULE, @@ -883,7 +883,7 @@ static struct regulator_ops wm831x_epe_ops = { .get_status = wm831x_dcdc_get_status, }; -static __devinit int wm831x_epe_probe(struct platform_device *pdev) +static int wm831x_epe_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; @@ -936,7 +936,7 @@ err: return ret; } -static __devexit int wm831x_epe_remove(struct platform_device *pdev) +static int wm831x_epe_remove(struct platform_device *pdev) { struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); @@ -948,7 +948,7 @@ static __devexit int wm831x_epe_remove(struct platform_device *pdev) static struct platform_driver wm831x_epe_driver = { .probe = wm831x_epe_probe, - .remove = __devexit_p(wm831x_epe_remove), + .remove = wm831x_epe_remove, .driver = { .name = "wm831x-epe", .owner = THIS_MODULE, diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c index 2646a1902b33..68586ee3e1cb 100644 --- a/drivers/regulator/wm831x-isink.c +++ b/drivers/regulator/wm831x-isink.c @@ -148,7 +148,7 @@ static irqreturn_t wm831x_isink_irq(int irq, void *data) } -static __devinit int wm831x_isink_probe(struct platform_device *pdev) +static int wm831x_isink_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; @@ -221,7 +221,7 @@ err: return ret; } -static __devexit int wm831x_isink_remove(struct platform_device *pdev) +static int wm831x_isink_remove(struct platform_device *pdev) { struct wm831x_isink *isink = platform_get_drvdata(pdev); @@ -236,7 +236,7 @@ static __devexit int wm831x_isink_remove(struct platform_device *pdev) static struct platform_driver wm831x_isink_driver = { .probe = wm831x_isink_probe, - .remove = __devexit_p(wm831x_isink_remove), + .remove = wm831x_isink_remove, .driver = { .name = "wm831x-isink", .owner = THIS_MODULE, diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index c2dc03993dc7..1ec379a9a95c 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -247,7 +247,7 @@ static struct regulator_ops wm831x_gp_ldo_ops = { .disable = regulator_disable_regmap, }; -static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev) +static int wm831x_gp_ldo_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; @@ -334,7 +334,7 @@ err: return ret; } -static __devexit int wm831x_gp_ldo_remove(struct platform_device *pdev) +static int wm831x_gp_ldo_remove(struct platform_device *pdev) { struct wm831x_ldo *ldo = platform_get_drvdata(pdev); @@ -349,7 +349,7 @@ static __devexit int wm831x_gp_ldo_remove(struct platform_device *pdev) static struct platform_driver wm831x_gp_ldo_driver = { .probe = wm831x_gp_ldo_probe, - .remove = __devexit_p(wm831x_gp_ldo_remove), + .remove = wm831x_gp_ldo_remove, .driver = { .name = "wm831x-ldo", .owner = THIS_MODULE, @@ -504,7 +504,7 @@ static struct regulator_ops wm831x_aldo_ops = { .disable = regulator_disable_regmap, }; -static __devinit int wm831x_aldo_probe(struct platform_device *pdev) +static int wm831x_aldo_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; @@ -590,7 +590,7 @@ err: return ret; } -static __devexit int wm831x_aldo_remove(struct platform_device *pdev) +static int wm831x_aldo_remove(struct platform_device *pdev) { struct wm831x_ldo *ldo = platform_get_drvdata(pdev); @@ -603,7 +603,7 @@ static __devexit int wm831x_aldo_remove(struct platform_device *pdev) static struct platform_driver wm831x_aldo_driver = { .probe = wm831x_aldo_probe, - .remove = __devexit_p(wm831x_aldo_remove), + .remove = wm831x_aldo_remove, .driver = { .name = "wm831x-aldo", .owner = THIS_MODULE, @@ -660,7 +660,7 @@ static struct regulator_ops wm831x_alive_ldo_ops = { .disable = regulator_disable_regmap, }; -static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev) +static int wm831x_alive_ldo_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; @@ -737,7 +737,7 @@ err: return ret; } -static __devexit int wm831x_alive_ldo_remove(struct platform_device *pdev) +static int wm831x_alive_ldo_remove(struct platform_device *pdev) { struct wm831x_ldo *ldo = platform_get_drvdata(pdev); @@ -748,7 +748,7 @@ static __devexit int wm831x_alive_ldo_remove(struct platform_device *pdev) static struct platform_driver wm831x_alive_ldo_driver = { .probe = wm831x_alive_ldo_probe, - .remove = __devexit_p(wm831x_alive_ldo_remove), + .remove = wm831x_alive_ldo_remove, .driver = { .name = "wm831x-alive-ldo", .owner = THIS_MODULE, diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index 27c746ef0636..c6a32ea80b9d 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -226,7 +226,7 @@ static struct regulator_desc regulators[] = { }, }; -static int __devinit wm8400_regulator_probe(struct platform_device *pdev) +static int wm8400_regulator_probe(struct platform_device *pdev) { struct wm8400 *wm8400 = container_of(pdev, struct wm8400, regulators[pdev->id]); struct regulator_config config = { }; @@ -246,7 +246,7 @@ static int __devinit wm8400_regulator_probe(struct platform_device *pdev) return 0; } -static int __devexit wm8400_regulator_remove(struct platform_device *pdev) +static int wm8400_regulator_remove(struct platform_device *pdev) { struct regulator_dev *rdev = platform_get_drvdata(pdev); @@ -261,7 +261,7 @@ static struct platform_driver wm8400_regulator_driver = { .name = "wm8400-regulator", }, .probe = wm8400_regulator_probe, - .remove = __devexit_p(wm8400_regulator_remove), + .remove = wm8400_regulator_remove, }; /** diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 86bb48db149e..6ff872342648 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -99,7 +99,7 @@ static const struct regulator_desc wm8994_ldo_desc[] = { }, }; -static __devinit int wm8994_ldo_probe(struct platform_device *pdev) +static int wm8994_ldo_probe(struct platform_device *pdev) { struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent); struct wm8994_pdata *pdata = wm8994->dev->platform_data; @@ -142,7 +142,7 @@ err: return ret; } -static __devexit int wm8994_ldo_remove(struct platform_device *pdev) +static int wm8994_ldo_remove(struct platform_device *pdev) { struct wm8994_ldo *ldo = platform_get_drvdata(pdev); @@ -155,7 +155,7 @@ static __devexit int wm8994_ldo_remove(struct platform_device *pdev) static struct platform_driver wm8994_ldo_driver = { .probe = wm8994_ldo_probe, - .remove = __devexit_p(wm8994_ldo_remove), + .remove = wm8994_ldo_remove, .driver = { .name = "wm8994-ldo", .owner = THIS_MODULE, diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index c1bafc3f3fb1..9594ab62702b 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -1972,7 +1972,7 @@ sci_io_request_frame_handler(struct isci_request *ireq, frame_index, (void **)&frame_buffer); - sci_controller_copy_sata_response(&ireq->stp.req, + sci_controller_copy_sata_response(&ireq->stp.rsp, frame_header, frame_buffer); diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 2936b447cae9..2c0d0ec8150b 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -55,6 +55,7 @@ #include <linux/cpu.h> #include <linux/mutex.h> #include <linux/async.h> +#include <asm/unaligned.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -1062,6 +1063,50 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf, EXPORT_SYMBOL_GPL(scsi_get_vpd_page); /** + * scsi_report_opcode - Find out if a given command opcode is supported + * @sdev: scsi device to query + * @buffer: scratch buffer (must be at least 20 bytes long) + * @len: length of buffer + * @opcode: opcode for command to look up + * + * Uses the REPORT SUPPORTED OPERATION CODES to look up the given + * opcode. Returns 0 if RSOC fails or if the command opcode is + * unsupported. Returns 1 if the device claims to support the command. + */ +int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer, + unsigned int len, unsigned char opcode) +{ + unsigned char cmd[16]; + struct scsi_sense_hdr sshdr; + int result; + + if (sdev->no_report_opcodes || sdev->scsi_level < SCSI_SPC_3) + return 0; + + memset(cmd, 0, 16); + cmd[0] = MAINTENANCE_IN; + cmd[1] = MI_REPORT_SUPPORTED_OPERATION_CODES; + cmd[2] = 1; /* One command format */ + cmd[3] = opcode; + put_unaligned_be32(len, &cmd[6]); + memset(buffer, 0, len); + + result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len, + &sshdr, 30 * HZ, 3, NULL); + + if (result && scsi_sense_valid(&sshdr) && + sshdr.sense_key == ILLEGAL_REQUEST && + (sshdr.asc == 0x20 || sshdr.asc == 0x24) && sshdr.ascq == 0x00) + return 0; + + if ((buffer[1] & 3) == 3) /* Command supported */ + return 1; + + return 0; +} +EXPORT_SYMBOL(scsi_report_opcode); + +/** * scsi_device_get - get an additional reference to a scsi_device * @sdev: device to get a reference to * diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index da36a3a81a9e..9032e910bca3 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -900,11 +900,23 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) action = ACTION_FAIL; error = -EILSEQ; /* INVALID COMMAND OPCODE or INVALID FIELD IN CDB */ - } else if ((sshdr.asc == 0x20 || sshdr.asc == 0x24) && - (cmd->cmnd[0] == UNMAP || - cmd->cmnd[0] == WRITE_SAME_16 || - cmd->cmnd[0] == WRITE_SAME)) { - description = "Discard failure"; + } else if (sshdr.asc == 0x20 || sshdr.asc == 0x24) { + switch (cmd->cmnd[0]) { + case UNMAP: + description = "Discard failure"; + break; + case WRITE_SAME: + case WRITE_SAME_16: + if (cmd->cmnd[1] & 0x8) + description = "Discard failure"; + else + description = + "Write same failure"; + break; + default: + description = "Invalid command failure"; + break; + } action = ACTION_FAIL; error = -EREMOTEIO; } else diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 12f6fdfc1147..352bc77b7c88 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -99,6 +99,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC); #endif static void sd_config_discard(struct scsi_disk *, unsigned int); +static void sd_config_write_same(struct scsi_disk *); static int sd_revalidate_disk(struct gendisk *); static void sd_unlock_native_capacity(struct gendisk *disk); static int sd_probe(struct device *); @@ -395,6 +396,45 @@ sd_store_max_medium_access_timeouts(struct device *dev, return err ? err : count; } +static ssize_t +sd_show_write_same_blocks(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + + return snprintf(buf, 20, "%u\n", sdkp->max_ws_blocks); +} + +static ssize_t +sd_store_write_same_blocks(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + struct scsi_device *sdp = sdkp->device; + unsigned long max; + int err; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (sdp->type != TYPE_DISK) + return -EINVAL; + + err = kstrtoul(buf, 10, &max); + + if (err) + return err; + + if (max == 0) + sdp->no_write_same = 1; + else if (max <= SD_MAX_WS16_BLOCKS) + sdkp->max_ws_blocks = max; + + sd_config_write_same(sdkp); + + return count; +} + static struct device_attribute sd_disk_attrs[] = { __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type, sd_store_cache_type), @@ -410,6 +450,8 @@ static struct device_attribute sd_disk_attrs[] = { __ATTR(thin_provisioning, S_IRUGO, sd_show_thin_provisioning, NULL), __ATTR(provisioning_mode, S_IRUGO|S_IWUSR, sd_show_provisioning_mode, sd_store_provisioning_mode), + __ATTR(max_write_same_blocks, S_IRUGO|S_IWUSR, + sd_show_write_same_blocks, sd_store_write_same_blocks), __ATTR(max_medium_access_timeouts, S_IRUGO|S_IWUSR, sd_show_max_medium_access_timeouts, sd_store_max_medium_access_timeouts), @@ -561,19 +603,23 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) return; case SD_LBP_UNMAP: - max_blocks = min_not_zero(sdkp->max_unmap_blocks, 0xffffffff); + max_blocks = min_not_zero(sdkp->max_unmap_blocks, + (u32)SD_MAX_WS16_BLOCKS); break; case SD_LBP_WS16: - max_blocks = min_not_zero(sdkp->max_ws_blocks, 0xffffffff); + max_blocks = min_not_zero(sdkp->max_ws_blocks, + (u32)SD_MAX_WS16_BLOCKS); break; case SD_LBP_WS10: - max_blocks = min_not_zero(sdkp->max_ws_blocks, (u32)0xffff); + max_blocks = min_not_zero(sdkp->max_ws_blocks, + (u32)SD_MAX_WS10_BLOCKS); break; case SD_LBP_ZERO: - max_blocks = min_not_zero(sdkp->max_ws_blocks, (u32)0xffff); + max_blocks = min_not_zero(sdkp->max_ws_blocks, + (u32)SD_MAX_WS10_BLOCKS); q->limits.discard_zeroes_data = 1; break; } @@ -583,29 +629,26 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) } /** - * scsi_setup_discard_cmnd - unmap blocks on thinly provisioned device + * sd_setup_discard_cmnd - unmap blocks on thinly provisioned device * @sdp: scsi device to operate one * @rq: Request to prepare * * Will issue either UNMAP or WRITE SAME(16) depending on preference * indicated by target device. **/ -static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) +static int sd_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) { struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); - struct bio *bio = rq->bio; - sector_t sector = bio->bi_sector; - unsigned int nr_sectors = bio_sectors(bio); + sector_t sector = blk_rq_pos(rq); + unsigned int nr_sectors = blk_rq_sectors(rq); + unsigned int nr_bytes = blk_rq_bytes(rq); unsigned int len; int ret; char *buf; struct page *page; - if (sdkp->device->sector_size == 4096) { - sector >>= 3; - nr_sectors >>= 3; - } - + sector >>= ilog2(sdp->sector_size) - 9; + nr_sectors >>= ilog2(sdp->sector_size) - 9; rq->timeout = SD_TIMEOUT; memset(rq->cmd, 0, rq->cmd_len); @@ -660,6 +703,7 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) blk_add_request_payload(rq, page, len); ret = scsi_setup_blk_pc_cmnd(sdp, rq); rq->buffer = page_address(page); + rq->__data_len = nr_bytes; out: if (ret != BLKPREP_OK) { @@ -669,6 +713,83 @@ out: return ret; } +static void sd_config_write_same(struct scsi_disk *sdkp) +{ + struct request_queue *q = sdkp->disk->queue; + unsigned int logical_block_size = sdkp->device->sector_size; + unsigned int blocks = 0; + + if (sdkp->device->no_write_same) { + sdkp->max_ws_blocks = 0; + goto out; + } + + /* Some devices can not handle block counts above 0xffff despite + * supporting WRITE SAME(16). Consequently we default to 64k + * blocks per I/O unless the device explicitly advertises a + * bigger limit. + */ + if (sdkp->max_ws_blocks == 0) + sdkp->max_ws_blocks = SD_MAX_WS10_BLOCKS; + + if (sdkp->ws16 || sdkp->max_ws_blocks > SD_MAX_WS10_BLOCKS) + blocks = min_not_zero(sdkp->max_ws_blocks, + (u32)SD_MAX_WS16_BLOCKS); + else + blocks = min_not_zero(sdkp->max_ws_blocks, + (u32)SD_MAX_WS10_BLOCKS); + +out: + blk_queue_max_write_same_sectors(q, blocks * (logical_block_size >> 9)); +} + +/** + * sd_setup_write_same_cmnd - write the same data to multiple blocks + * @sdp: scsi device to operate one + * @rq: Request to prepare + * + * Will issue either WRITE SAME(10) or WRITE SAME(16) depending on + * preference indicated by target device. + **/ +static int sd_setup_write_same_cmnd(struct scsi_device *sdp, struct request *rq) +{ + struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); + struct bio *bio = rq->bio; + sector_t sector = blk_rq_pos(rq); + unsigned int nr_sectors = blk_rq_sectors(rq); + unsigned int nr_bytes = blk_rq_bytes(rq); + int ret; + + if (sdkp->device->no_write_same) + return BLKPREP_KILL; + + BUG_ON(bio_offset(bio) || bio_iovec(bio)->bv_len != sdp->sector_size); + + sector >>= ilog2(sdp->sector_size) - 9; + nr_sectors >>= ilog2(sdp->sector_size) - 9; + + rq->__data_len = sdp->sector_size; + rq->timeout = SD_WRITE_SAME_TIMEOUT; + memset(rq->cmd, 0, rq->cmd_len); + + if (sdkp->ws16 || sector > 0xffffffff || nr_sectors > 0xffff) { + rq->cmd_len = 16; + rq->cmd[0] = WRITE_SAME_16; + put_unaligned_be64(sector, &rq->cmd[2]); + put_unaligned_be32(nr_sectors, &rq->cmd[10]); + } else { + rq->cmd_len = 10; + rq->cmd[0] = WRITE_SAME; + put_unaligned_be32(sector, &rq->cmd[2]); + put_unaligned_be16(nr_sectors, &rq->cmd[7]); + } + + ret = scsi_setup_blk_pc_cmnd(sdp, rq); + rq->__data_len = nr_bytes; + + return ret; +} + static int scsi_setup_flush_cmnd(struct scsi_device *sdp, struct request *rq) { rq->timeout = SD_FLUSH_TIMEOUT; @@ -712,7 +833,10 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) * block PC requests to make life easier. */ if (rq->cmd_flags & REQ_DISCARD) { - ret = scsi_setup_discard_cmnd(sdp, rq); + ret = sd_setup_discard_cmnd(sdp, rq); + goto out; + } else if (rq->cmd_flags & REQ_WRITE_SAME) { + ret = sd_setup_write_same_cmnd(sdp, rq); goto out; } else if (rq->cmd_flags & REQ_FLUSH) { ret = scsi_setup_flush_cmnd(sdp, rq); @@ -1482,12 +1606,21 @@ static int sd_done(struct scsi_cmnd *SCpnt) unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt); struct scsi_sense_hdr sshdr; struct scsi_disk *sdkp = scsi_disk(SCpnt->request->rq_disk); + struct request *req = SCpnt->request; int sense_valid = 0; int sense_deferred = 0; unsigned char op = SCpnt->cmnd[0]; + unsigned char unmap = SCpnt->cmnd[1] & 8; - if ((SCpnt->request->cmd_flags & REQ_DISCARD) && !result) - scsi_set_resid(SCpnt, 0); + if (req->cmd_flags & REQ_DISCARD || req->cmd_flags & REQ_WRITE_SAME) { + if (!result) { + good_bytes = blk_rq_bytes(req); + scsi_set_resid(SCpnt, 0); + } else { + good_bytes = 0; + scsi_set_resid(SCpnt, blk_rq_bytes(req)); + } + } if (result) { sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr); @@ -1536,9 +1669,25 @@ static int sd_done(struct scsi_cmnd *SCpnt) if (sshdr.asc == 0x10) /* DIX: Host detected corruption */ good_bytes = sd_completed_bytes(SCpnt); /* INVALID COMMAND OPCODE or INVALID FIELD IN CDB */ - if ((sshdr.asc == 0x20 || sshdr.asc == 0x24) && - (op == UNMAP || op == WRITE_SAME_16 || op == WRITE_SAME)) - sd_config_discard(sdkp, SD_LBP_DISABLE); + if (sshdr.asc == 0x20 || sshdr.asc == 0x24) { + switch (op) { + case UNMAP: + sd_config_discard(sdkp, SD_LBP_DISABLE); + break; + case WRITE_SAME_16: + case WRITE_SAME: + if (unmap) + sd_config_discard(sdkp, SD_LBP_DISABLE); + else { + sdkp->device->no_write_same = 1; + sd_config_write_same(sdkp); + + good_bytes = 0; + req->__data_len = blk_rq_bytes(req); + req->cmd_flags |= REQ_QUIET; + } + } + } break; default: break; @@ -2374,9 +2523,7 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) if (buffer[3] == 0x3c) { unsigned int lba_count, desc_count; - sdkp->max_ws_blocks = - (u32) min_not_zero(get_unaligned_be64(&buffer[36]), - (u64)0xffffffff); + sdkp->max_ws_blocks = (u32)get_unaligned_be64(&buffer[36]); if (!sdkp->lbpme) goto out; @@ -2469,6 +2616,13 @@ static void sd_read_block_provisioning(struct scsi_disk *sdkp) kfree(buffer); } +static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer) +{ + if (scsi_report_opcode(sdkp->device, buffer, SD_BUF_SIZE, + WRITE_SAME_16)) + sdkp->ws16 = 1; +} + static int sd_try_extended_inquiry(struct scsi_device *sdp) { /* @@ -2528,6 +2682,7 @@ static int sd_revalidate_disk(struct gendisk *disk) sd_read_write_protect_flag(sdkp, buffer); sd_read_cache_type(sdkp, buffer); sd_read_app_tag_own(sdkp, buffer); + sd_read_write_same(sdkp, buffer); } sdkp->first_scan = 0; @@ -2545,6 +2700,7 @@ static int sd_revalidate_disk(struct gendisk *disk) blk_queue_flush(sdkp->disk->queue, flush); set_capacity(disk, sdkp->capacity); + sd_config_write_same(sdkp); kfree(buffer); out: diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 47c52a6d733c..74a1e4ca5401 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -14,6 +14,7 @@ #define SD_TIMEOUT (30 * HZ) #define SD_MOD_TIMEOUT (75 * HZ) #define SD_FLUSH_TIMEOUT (60 * HZ) +#define SD_WRITE_SAME_TIMEOUT (120 * HZ) /* * Number of allowed retries @@ -39,6 +40,11 @@ enum { }; enum { + SD_MAX_WS10_BLOCKS = 0xffff, + SD_MAX_WS16_BLOCKS = 0x7fffff, +}; + +enum { SD_LBP_FULL = 0, /* Full logical block provisioning */ SD_LBP_UNMAP, /* Use UNMAP command */ SD_LBP_WS16, /* Use WRITE SAME(16) with UNMAP bit */ @@ -77,6 +83,7 @@ struct scsi_disk { unsigned lbpws : 1; unsigned lbpws10 : 1; unsigned lbpvpd : 1; + unsigned ws16 : 1; }; #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev) diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index a3d54366afcc..92f35abee92d 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -186,6 +186,12 @@ static int slave_configure(struct scsi_device *sdev) /* Some devices don't handle VPD pages correctly */ sdev->skip_vpd_pages = 1; + /* Do not attempt to use REPORT SUPPORTED OPERATION CODES */ + sdev->no_report_opcodes = 1; + + /* Do not attempt to use WRITE SAME */ + sdev->no_write_same = 1; + /* Some disks return the total number of blocks in response * to READ CAPACITY rather than the highest block number. * If this device makes that mistake, tell the sd driver. */ diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index d64ac3842884..bee92846cfab 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -365,11 +365,20 @@ struct platform_device *dsi_get_dsidev_from_id(int module) struct omap_dss_output *out; enum omap_dss_output_id id; - id = module == 0 ? OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; + switch (module) { + case 0: + id = OMAP_DSS_OUTPUT_DSI1; + break; + case 1: + id = OMAP_DSS_OUTPUT_DSI2; + break; + default: + return NULL; + } out = omap_dss_get_output(id); - return out->pdev; + return out ? out->pdev : NULL; } static inline void dsi_write_reg(struct platform_device *dsidev, diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 2ab1c3e96553..5f6eea801b06 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -697,11 +697,15 @@ static int dss_get_clocks(void) dss.dss_clk = clk; - clk = clk_get(NULL, dss.feat->clk_name); - if (IS_ERR(clk)) { - DSSERR("Failed to get %s\n", dss.feat->clk_name); - r = PTR_ERR(clk); - goto err; + if (dss.feat->clk_name) { + clk = clk_get(NULL, dss.feat->clk_name); + if (IS_ERR(clk)) { + DSSERR("Failed to get %s\n", dss.feat->clk_name); + r = PTR_ERR(clk); + goto err; + } + } else { + clk = NULL; } dss.dpll4_m4_ck = clk; @@ -805,10 +809,10 @@ static int __init dss_init_features(struct device *dev) if (cpu_is_omap24xx()) src = &omap24xx_dss_feats; - else if (cpu_is_omap34xx()) - src = &omap34xx_dss_feats; else if (cpu_is_omap3630()) src = &omap3630_dss_feats; + else if (cpu_is_omap34xx()) + src = &omap34xx_dss_feats; else if (cpu_is_omap44xx()) src = &omap44xx_dss_feats; else if (soc_is_omap54xx()) diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index a48a7dd75b33..8c9b8b3b7f77 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -644,8 +644,10 @@ static void hdmi_dump_regs(struct seq_file *s) { mutex_lock(&hdmi.lock); - if (hdmi_runtime_get()) + if (hdmi_runtime_get()) { + mutex_unlock(&hdmi.lock); return; + } hdmi.ip_data.ops->dump_wrapper(&hdmi.ip_data, s); hdmi.ip_data.ops->dump_pll(&hdmi.ip_data, s); diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 606b89f12351..d630b26a005c 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -787,7 +787,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) case OMAPFB_WAITFORVSYNC: DBG("ioctl WAITFORVSYNC\n"); - if (!display && !display->output && !display->output->manager) { + if (!display || !display->output || !display->output->manager) { r = -EINVAL; break; } diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index 8adb9cc267f9..71f5c459b088 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c @@ -361,13 +361,13 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) down_write(&mm->mmap_sem); vma = find_vma(mm, m.addr); - ret = -EINVAL; if (!vma || vma->vm_ops != &privcmd_vm_ops || (m.addr != vma->vm_start) || ((m.addr + (nr_pages << PAGE_SHIFT)) != vma->vm_end) || !privcmd_enforce_singleshot_mapping(vma)) { up_write(&mm->mmap_sem); + ret = -EINVAL; goto out; } @@ -383,12 +383,16 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) up_write(&mm->mmap_sem); - if (state.global_error && (version == 1)) { - /* Write back errors in second pass. */ - state.user_mfn = (xen_pfn_t *)m.arr; - state.err = err_array; - ret = traverse_pages(m.num, sizeof(xen_pfn_t), - &pagelist, mmap_return_errors_v1, &state); + if (version == 1) { + if (state.global_error) { + /* Write back errors in second pass. */ + state.user_mfn = (xen_pfn_t *)m.arr; + state.err = err_array; + ret = traverse_pages(m.num, sizeof(xen_pfn_t), + &pagelist, mmap_return_errors_v1, &state); + } else + ret = 0; + } else if (version == 2) { ret = __copy_to_user(m.err, err_array, m.num * sizeof(int)); if (ret) diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index 7320a66e958f..22548f56197b 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c @@ -2101,8 +2101,9 @@ int ext3_trim_fs(struct super_block *sb, struct fstrim_range *range) end = start + (range->len >> sb->s_blocksize_bits) - 1; minlen = range->minlen >> sb->s_blocksize_bits; - if (unlikely(minlen > EXT3_BLOCKS_PER_GROUP(sb)) || - unlikely(start >= max_blks)) + if (minlen > EXT3_BLOCKS_PER_GROUP(sb) || + start >= max_blks || + range->len < sb->s_blocksize) return -EINVAL; if (end >= max_blks) end = max_blks - 1; diff --git a/fs/file.c b/fs/file.c index 708d997a7748..7cb71b992603 100644 --- a/fs/file.c +++ b/fs/file.c @@ -685,7 +685,6 @@ void do_close_on_exec(struct files_struct *files) struct fdtable *fdt; /* exec unshares first */ - BUG_ON(atomic_read(&files->count) != 1); spin_lock(&files->file_lock); for (i = 0; ; i++) { unsigned long set; diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 60ef3fb707ff..1506673c087e 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -138,33 +138,39 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, struct page *pg; struct inode *inode = mapping->host; struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); + struct jffs2_raw_inode ri; + uint32_t alloc_len = 0; pgoff_t index = pos >> PAGE_CACHE_SHIFT; uint32_t pageofs = index << PAGE_CACHE_SHIFT; int ret = 0; + jffs2_dbg(1, "%s()\n", __func__); + + if (pageofs > inode->i_size) { + ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len, + ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); + if (ret) + return ret; + } + + mutex_lock(&f->sem); pg = grab_cache_page_write_begin(mapping, index, flags); - if (!pg) + if (!pg) { + if (alloc_len) + jffs2_complete_reservation(c); + mutex_unlock(&f->sem); return -ENOMEM; + } *pagep = pg; - jffs2_dbg(1, "%s()\n", __func__); - - if (pageofs > inode->i_size) { + if (alloc_len) { /* Make new hole frag from old EOF to new page */ - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - struct jffs2_raw_inode ri; struct jffs2_full_dnode *fn; - uint32_t alloc_len; jffs2_dbg(1, "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", (unsigned int)inode->i_size, pageofs); - ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len, - ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); - if (ret) - goto out_page; - - mutex_lock(&f->sem); memset(&ri, 0, sizeof(ri)); ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); @@ -191,7 +197,6 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, if (IS_ERR(fn)) { ret = PTR_ERR(fn); jffs2_complete_reservation(c); - mutex_unlock(&f->sem); goto out_page; } ret = jffs2_add_full_dnode_to_inode(c, f, fn); @@ -206,12 +211,10 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, jffs2_mark_node_obsolete(c, fn->raw); jffs2_free_full_dnode(fn); jffs2_complete_reservation(c); - mutex_unlock(&f->sem); goto out_page; } jffs2_complete_reservation(c); inode->i_size = pageofs; - mutex_unlock(&f->sem); } /* @@ -220,18 +223,18 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, * case of a short-copy. */ if (!PageUptodate(pg)) { - mutex_lock(&f->sem); ret = jffs2_do_readpage_nolock(inode, pg); - mutex_unlock(&f->sem); if (ret) goto out_page; } + mutex_unlock(&f->sem); jffs2_dbg(1, "end write_begin(). pg->flags %lx\n", pg->flags); return ret; out_page: unlock_page(pg); page_cache_release(pg); + mutex_unlock(&f->sem); return ret; } diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 721d692fa8d4..6fcaeb8c902e 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -258,7 +258,8 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, if (ret) goto out_close_fd; - fd_install(fd, f); + if (fd != FAN_NOFD) + fd_install(fd, f); return fanotify_event_metadata.event_len; out_close_fd: diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index f27f01a98aa2..d83736fbc26c 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -1782,8 +1782,9 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, BUG_ON(!th->t_trans_id); - dquot_initialize(inode); + reiserfs_write_unlock(inode->i_sb); err = dquot_alloc_inode(inode); + reiserfs_write_lock(inode->i_sb); if (err) goto out_end_trans; if (!dir->i_nlink) { @@ -1979,8 +1980,10 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, out_end_trans: journal_end(th, th->t_super, th->t_blocks_allocated); + reiserfs_write_unlock(inode->i_sb); /* Drop can be outside and it needs more credits so it's better to have it outside */ dquot_drop(inode); + reiserfs_write_lock(inode->i_sb); inode->i_flags |= S_NOQUOTA; make_bad_inode(inode); @@ -3103,10 +3106,9 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) /* must be turned off for recursive notify_change calls */ ia_valid = attr->ia_valid &= ~(ATTR_KILL_SUID|ATTR_KILL_SGID); - depth = reiserfs_write_lock_once(inode->i_sb); if (is_quota_modification(inode, attr)) dquot_initialize(inode); - + depth = reiserfs_write_lock_once(inode->i_sb); if (attr->ia_valid & ATTR_SIZE) { /* version 2 items will be caught by the s_maxbytes check ** done for us in vmtruncate @@ -3170,7 +3172,9 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) error = journal_begin(&th, inode->i_sb, jbegin_count); if (error) goto out; + reiserfs_write_unlock_once(inode->i_sb, depth); error = dquot_transfer(inode, attr); + depth = reiserfs_write_lock_once(inode->i_sb); if (error) { journal_end(&th, inode->i_sb, jbegin_count); goto out; diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index f8afa4b162b8..2f40a4c70a4d 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c @@ -1968,7 +1968,9 @@ int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct tree key2type(&(key->on_disk_key))); #endif + reiserfs_write_unlock(inode->i_sb); retval = dquot_alloc_space_nodirty(inode, pasted_size); + reiserfs_write_lock(inode->i_sb); if (retval) { pathrelse(search_path); return retval; @@ -2061,9 +2063,11 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th, "reiserquota insert_item(): allocating %u id=%u type=%c", quota_bytes, inode->i_uid, head2type(ih)); #endif + reiserfs_write_unlock(inode->i_sb); /* We can't dirty inode here. It would be immediately written but * appropriate stat item isn't inserted yet... */ retval = dquot_alloc_space_nodirty(inode, quota_bytes); + reiserfs_write_lock(inode->i_sb); if (retval) { pathrelse(path); return retval; diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 1078ae179993..418bdc3a57da 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -298,7 +298,9 @@ static int finish_unfinished(struct super_block *s) retval = remove_save_link_only(s, &save_link_key, 0); continue; } + reiserfs_write_unlock(s); dquot_initialize(inode); + reiserfs_write_lock(s); if (truncate && S_ISDIR(inode->i_mode)) { /* We got a truncate request for a dir which is impossible. @@ -1335,7 +1337,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) kfree(qf_names[i]); #endif err = -EINVAL; - goto out_err; + goto out_unlock; } #ifdef CONFIG_QUOTA handle_quota_files(s, qf_names, &qfmt); @@ -1379,7 +1381,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) if (blocks) { err = reiserfs_resize(s, blocks); if (err != 0) - goto out_err; + goto out_unlock; } if (*mount_flags & MS_RDONLY) { @@ -1389,9 +1391,15 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) /* it is read-only already */ goto out_ok; + /* + * Drop write lock. Quota will retake it when needed and lock + * ordering requires calling dquot_suspend() without it. + */ + reiserfs_write_unlock(s); err = dquot_suspend(s, -1); if (err < 0) goto out_err; + reiserfs_write_lock(s); /* try to remount file system with read-only permissions */ if (sb_umount_state(rs) == REISERFS_VALID_FS @@ -1401,7 +1409,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) err = journal_begin(&th, s, 10); if (err) - goto out_err; + goto out_unlock; /* Mounting a rw partition read-only. */ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1); @@ -1416,7 +1424,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) if (reiserfs_is_journal_aborted(journal)) { err = journal->j_errno; - goto out_err; + goto out_unlock; } handle_data_mode(s, mount_options); @@ -1425,7 +1433,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) s->s_flags &= ~MS_RDONLY; /* now it is safe to call journal_begin */ err = journal_begin(&th, s, 10); if (err) - goto out_err; + goto out_unlock; /* Mount a partition which is read-only, read-write */ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1); @@ -1442,10 +1450,16 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) SB_JOURNAL(s)->j_must_wait = 1; err = journal_end(&th, s, 10); if (err) - goto out_err; + goto out_unlock; if (!(*mount_flags & MS_RDONLY)) { + /* + * Drop write lock. Quota will retake it when needed and lock + * ordering requires calling dquot_resume() without it. + */ + reiserfs_write_unlock(s); dquot_resume(s, -1); + reiserfs_write_lock(s); finish_unfinished(s); reiserfs_xattr_init(s, *mount_flags); } @@ -1455,9 +1469,10 @@ out_ok: reiserfs_write_unlock(s); return 0; +out_unlock: + reiserfs_write_unlock(s); out_err: kfree(new_opts); - reiserfs_write_unlock(s); return err; } @@ -2095,13 +2110,15 @@ static int reiserfs_write_dquot(struct dquot *dquot) REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); if (ret) goto out; + reiserfs_write_unlock(dquot->dq_sb); ret = dquot_commit(dquot); + reiserfs_write_lock(dquot->dq_sb); err = journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); if (!ret && err) ret = err; - out: +out: reiserfs_write_unlock(dquot->dq_sb); return ret; } @@ -2117,13 +2134,15 @@ static int reiserfs_acquire_dquot(struct dquot *dquot) REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb)); if (ret) goto out; + reiserfs_write_unlock(dquot->dq_sb); ret = dquot_acquire(dquot); + reiserfs_write_lock(dquot->dq_sb); err = journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb)); if (!ret && err) ret = err; - out: +out: reiserfs_write_unlock(dquot->dq_sb); return ret; } @@ -2137,19 +2156,21 @@ static int reiserfs_release_dquot(struct dquot *dquot) ret = journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb)); + reiserfs_write_unlock(dquot->dq_sb); if (ret) { /* Release dquot anyway to avoid endless cycle in dqput() */ dquot_release(dquot); goto out; } ret = dquot_release(dquot); + reiserfs_write_lock(dquot->dq_sb); err = journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb)); if (!ret && err) ret = err; - out: reiserfs_write_unlock(dquot->dq_sb); +out: return ret; } @@ -2174,11 +2195,13 @@ static int reiserfs_write_info(struct super_block *sb, int type) ret = journal_begin(&th, sb, 2); if (ret) goto out; + reiserfs_write_unlock(sb); ret = dquot_commit_info(sb, type); + reiserfs_write_lock(sb); err = journal_end(&th, sb, 2); if (!ret && err) ret = err; - out: +out: reiserfs_write_unlock(sb); return ret; } @@ -2203,8 +2226,11 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, struct reiserfs_transaction_handle th; int opt = type == USRQUOTA ? REISERFS_USRQUOTA : REISERFS_GRPQUOTA; - if (!(REISERFS_SB(sb)->s_mount_opt & (1 << opt))) - return -EINVAL; + reiserfs_write_lock(sb); + if (!(REISERFS_SB(sb)->s_mount_opt & (1 << opt))) { + err = -EINVAL; + goto out; + } /* Quotafile not on the same filesystem? */ if (path->dentry->d_sb != sb) { @@ -2246,8 +2272,10 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, if (err) goto out; } - err = dquot_quota_on(sb, type, format_id, path); + reiserfs_write_unlock(sb); + return dquot_quota_on(sb, type, format_id, path); out: + reiserfs_write_unlock(sb); return err; } @@ -2320,7 +2348,9 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type, tocopy = sb->s_blocksize - offset < towrite ? sb->s_blocksize - offset : towrite; tmp_bh.b_state = 0; + reiserfs_write_lock(sb); err = reiserfs_get_block(inode, blk, &tmp_bh, GET_BLOCK_CREATE); + reiserfs_write_unlock(sb); if (err) goto out; if (offset || tocopy != sb->s_blocksize) @@ -2336,10 +2366,12 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type, flush_dcache_page(bh->b_page); set_buffer_uptodate(bh); unlock_buffer(bh); + reiserfs_write_lock(sb); reiserfs_prepare_for_journal(sb, bh, 1); journal_mark_dirty(current->journal_info, sb, bh); if (!journal_quota) reiserfs_add_ordered_list(inode, bh); + reiserfs_write_unlock(sb); brelse(bh); offset = 0; towrite -= tocopy; diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index e562dd43f41f..e57e2daa357c 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -481,11 +481,17 @@ static inline int bio_add_buffer(struct bio *bio, struct buffer_head *bh) * * The fix is two passes across the ioend list - one to start writeback on the * buffer_heads, and then submit them for I/O on the second pass. + * + * If @fail is non-zero, it means that we have a situation where some part of + * the submission process has failed after we have marked paged for writeback + * and unlocked them. In this situation, we need to fail the ioend chain rather + * than submit it to IO. This typically only happens on a filesystem shutdown. */ STATIC void xfs_submit_ioend( struct writeback_control *wbc, - xfs_ioend_t *ioend) + xfs_ioend_t *ioend, + int fail) { xfs_ioend_t *head = ioend; xfs_ioend_t *next; @@ -506,6 +512,18 @@ xfs_submit_ioend( next = ioend->io_list; bio = NULL; + /* + * If we are failing the IO now, just mark the ioend with an + * error and finish it. This will run IO completion immediately + * as there is only one reference to the ioend at this point in + * time. + */ + if (fail) { + ioend->io_error = -fail; + xfs_finish_ioend(ioend); + continue; + } + for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) { if (!bio) { @@ -1060,7 +1078,18 @@ xfs_vm_writepage( xfs_start_page_writeback(page, 1, count); - if (ioend && imap_valid) { + /* if there is no IO to be submitted for this page, we are done */ + if (!ioend) + return 0; + + ASSERT(iohead); + + /* + * Any errors from this point onwards need tobe reported through the IO + * completion path as we have marked the initial page as under writeback + * and unlocked it. + */ + if (imap_valid) { xfs_off_t end_index; end_index = imap.br_startoff + imap.br_blockcount; @@ -1079,20 +1108,15 @@ xfs_vm_writepage( wbc, end_index); } - if (iohead) { - /* - * Reserve log space if we might write beyond the on-disk - * inode size. - */ - if (ioend->io_type != XFS_IO_UNWRITTEN && - xfs_ioend_is_append(ioend)) { - err = xfs_setfilesize_trans_alloc(ioend); - if (err) - goto error; - } - xfs_submit_ioend(wbc, iohead); - } + /* + * Reserve log space if we might write beyond the on-disk inode size. + */ + err = 0; + if (ioend->io_type != XFS_IO_UNWRITTEN && xfs_ioend_is_append(ioend)) + err = xfs_setfilesize_trans_alloc(ioend); + + xfs_submit_ioend(wbc, iohead, err); return 0; diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c index d330111ca738..70eec1829776 100644 --- a/fs/xfs/xfs_attr_leaf.c +++ b/fs/xfs/xfs_attr_leaf.c @@ -1291,6 +1291,7 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, leaf2 = blk2->bp->b_addr; ASSERT(leaf1->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC)); ASSERT(leaf2->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC)); + ASSERT(leaf2->hdr.count == 0); args = state->args; trace_xfs_attr_leaf_rebalance(args); @@ -1361,6 +1362,7 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, * I assert that since all callers pass in an empty * second buffer, this code should never execute. */ + ASSERT(0); /* * Figure the total bytes to be added to the destination leaf. @@ -1422,10 +1424,24 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, args->index2 = 0; args->blkno2 = blk2->blkno; } else { + /* + * On a double leaf split, the original attr location + * is already stored in blkno2/index2, so don't + * overwrite it overwise we corrupt the tree. + */ blk2->index = blk1->index - be16_to_cpu(leaf1->hdr.count); - args->index = args->index2 = blk2->index; - args->blkno = args->blkno2 = blk2->blkno; + args->index = blk2->index; + args->blkno = blk2->blkno; + if (!state->extravalid) { + /* + * set the new attr location to match the old + * one and let the higher level split code + * decide where in the leaf to place it. + */ + args->index2 = blk2->index; + args->blkno2 = blk2->blkno; + } } } else { ASSERT(state->inleaf == 1); diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index 933b7930b863..4b0b8dd1b7b0 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -1197,9 +1197,14 @@ xfs_buf_bio_end_io( { xfs_buf_t *bp = (xfs_buf_t *)bio->bi_private; - xfs_buf_ioerror(bp, -error); + /* + * don't overwrite existing errors - otherwise we can lose errors on + * buffers that require multiple bios to complete. + */ + if (!bp->b_error) + xfs_buf_ioerror(bp, -error); - if (!error && xfs_buf_is_vmapped(bp) && (bp->b_flags & XBF_READ)) + if (!bp->b_error && xfs_buf_is_vmapped(bp) && (bp->b_flags & XBF_READ)) invalidate_kernel_vmap_range(bp->b_addr, xfs_buf_vmap_len(bp)); _xfs_buf_ioend(bp, 1); @@ -1279,6 +1284,11 @@ next_chunk: if (size) goto next_chunk; } else { + /* + * This is guaranteed not to be the last io reference count + * because the caller (xfs_buf_iorequest) holds a count itself. + */ + atomic_dec(&bp->b_io_remaining); xfs_buf_ioerror(bp, EIO); bio_put(bio); } diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index af1cbaf535ed..c5c35e629426 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -210,6 +210,7 @@ {0x1002, 0x6798, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6799, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ {0x1002, 0x679A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x679B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ {0x1002, 0x679E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ {0x1002, 0x679F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h index df804ba73e0b..92a0dc75bc74 100644 --- a/include/linux/i2c-omap.h +++ b/include/linux/i2c-omap.h @@ -34,6 +34,7 @@ struct omap_i2c_bus_platform_data { u32 clkrate; u32 rev; u32 flags; + void (*set_mpu_wkup_lat)(struct device *dev, long set); }; #endif diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h index 7671a287dfee..ba26e99c388d 100644 --- a/include/linux/mfd/arizona/registers.h +++ b/include/linux/mfd/arizona/registers.h @@ -76,6 +76,7 @@ #define ARIZONA_RATE_ESTIMATOR_3 0x154 #define ARIZONA_RATE_ESTIMATOR_4 0x155 #define ARIZONA_RATE_ESTIMATOR_5 0x156 +#define ARIZONA_DYNAMIC_FREQUENCY_SCALING_1 0x161 #define ARIZONA_FLL1_CONTROL_1 0x171 #define ARIZONA_FLL1_CONTROL_2 0x172 #define ARIZONA_FLL1_CONTROL_3 0x173 @@ -110,6 +111,7 @@ #define ARIZONA_FLL2_GPIO_CLOCK 0x1AA #define ARIZONA_MIC_CHARGE_PUMP_1 0x200 #define ARIZONA_LDO1_CONTROL_1 0x210 +#define ARIZONA_LDO1_CONTROL_2 0x212 #define ARIZONA_LDO2_CONTROL_1 0x213 #define ARIZONA_MIC_BIAS_CTRL_1 0x218 #define ARIZONA_MIC_BIAS_CTRL_2 0x219 @@ -1574,6 +1576,13 @@ #define ARIZONA_SAMPLE_RATE_DETECT_D_WIDTH 5 /* SAMPLE_RATE_DETECT_D - [4:0] */ /* + * R353 (0x161) - Dynamic Frequency Scaling 1 + */ +#define ARIZONA_SUBSYS_MAX_FREQ 0x0001 /* SUBSYS_MAX_FREQ */ +#define ARIZONA_SUBSYS_MAX_FREQ_SHIFT 0 /* SUBSYS_MAX_FREQ */ +#define ARIZONA_SUBSYS_MAX_FREQ_WIDTH 1 /* SUBSYS_MAX_FREQ */ + +/* * R369 (0x171) - FLL1 Control 1 */ #define ARIZONA_FLL1_FREERUN 0x0002 /* FLL1_FREERUN */ @@ -1889,6 +1898,13 @@ #define ARIZONA_LDO1_ENA_WIDTH 1 /* LDO1_ENA */ /* + * R530 (0x212) - LDO1 Control 2 + */ +#define ARIZONA_LDO1_HI_PWR 0x0001 /* LDO1_HI_PWR */ +#define ARIZONA_LDO1_HI_PWR_SHIFT 0 /* LDO1_HI_PWR */ +#define ARIZONA_LDO1_HI_PWR_WIDTH 1 /* LDO1_HI_PWR */ + +/* * R531 (0x213) - LDO2 Control 1 */ #define ARIZONA_LDO2_VSEL_MASK 0x07E0 /* LDO2_VSEL - [10:5] */ diff --git a/include/linux/mfd/da9055/pdata.h b/include/linux/mfd/da9055/pdata.h index 147293b4471d..f87a6c172a91 100644 --- a/include/linux/mfd/da9055/pdata.h +++ b/include/linux/mfd/da9055/pdata.h @@ -25,8 +25,29 @@ struct da9055_pdata { int gpio_base; struct regulator_init_data *regulators[DA9055_MAX_REGULATORS]; - bool reset_enable; /* Enable RTC in RESET Mode */ - enum gpio_select *gpio_rsel; /* Select regulator set thru GPIO 1/2 */ - enum gpio_select *gpio_ren; /* Enable regulator thru GPIO 1/2 */ + /* Enable RTC in RESET Mode */ + bool reset_enable; + /* + * GPI muxed pin to control + * regulator state A/B, 0 if not available. + */ + int *gpio_ren; + /* + * GPI muxed pin to control + * regulator set, 0 if not available. + */ + int *gpio_rsel; + /* + * Regulator mode control bits value (GPI offset) that + * that controls the regulator state, 0 if not available. + */ + enum gpio_select *reg_ren; + /* + * Regulator mode control bits value (GPI offset) that + * controls the regulator set A/B, 0 if not available. + */ + enum gpio_select *reg_rsel; + /* GPIOs to enable regulator, 0 if not available */ + int *ena_gpio; }; #endif /* __DA9055_PDATA_H */ diff --git a/include/linux/mfd/tps65090.h b/include/linux/mfd/tps65090.h index 6bc31d854626..804e280c1e1d 100644 --- a/include/linux/mfd/tps65090.h +++ b/include/linux/mfd/tps65090.h @@ -24,6 +24,25 @@ #include <linux/irq.h> +/* TPS65090 Regulator ID */ +enum { + TPS65090_REGULATOR_DCDC1, + TPS65090_REGULATOR_DCDC2, + TPS65090_REGULATOR_DCDC3, + TPS65090_REGULATOR_FET1, + TPS65090_REGULATOR_FET2, + TPS65090_REGULATOR_FET3, + TPS65090_REGULATOR_FET4, + TPS65090_REGULATOR_FET5, + TPS65090_REGULATOR_FET6, + TPS65090_REGULATOR_FET7, + TPS65090_REGULATOR_LDO1, + TPS65090_REGULATOR_LDO2, + + /* Last entry for maximum ID */ + TPS65090_REGULATOR_MAX, +}; + struct tps65090 { struct mutex lock; struct device *dev; @@ -41,10 +60,26 @@ struct tps65090_subdev_info { void *platform_data; }; +/* + * struct tps65090_regulator_plat_data + * + * @reg_init_data: The regulator init data. + * @enable_ext_control: Enable extrenal control or not. Only available for + * DCDC1, DCDC2 and DCDC3. + * @gpio: Gpio number if external control is enabled and controlled through + * gpio. + */ +struct tps65090_regulator_plat_data { + struct regulator_init_data *reg_init_data; + bool enable_ext_control; + int gpio; +}; + struct tps65090_platform_data { int irq_base; int num_subdevs; struct tps65090_subdev_info *subdevs; + struct tps65090_regulator_plat_data *reg_pdata[TPS65090_REGULATOR_MAX]; }; /* diff --git a/include/linux/mfd/tps6586x.h b/include/linux/mfd/tps6586x.h index 2dd123194958..f8da0e152567 100644 --- a/include/linux/mfd/tps6586x.h +++ b/include/linux/mfd/tps6586x.h @@ -29,6 +29,7 @@ enum { TPS6586X_ID_LDO_8, TPS6586X_ID_LDO_9, TPS6586X_ID_LDO_RTC, + TPS6586X_ID_MAX_REGULATOR, }; enum { @@ -79,6 +80,8 @@ struct tps6586x_platform_data { int gpio_base; int irq_base; bool pm_off; + + struct regulator_init_data *reg_init_data[TPS6586X_ID_MAX_REGULATOR]; }; /* diff --git a/include/linux/of_address.h b/include/linux/of_address.h index e20e3af68fb6..0506eb53519b 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -42,10 +42,12 @@ static inline struct device_node *of_find_matching_node_by_address( { return NULL; } +#ifndef of_iomap static inline void __iomem *of_iomap(struct device_node *device, int index) { return NULL; } +#endif static inline const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, unsigned int *flags) { diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index c43cd3556b1f..5d0f7c10bef1 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -160,6 +160,7 @@ int regulator_bulk_force_disable(int num_consumers, void regulator_bulk_free(int num_consumers, struct regulator_bulk_data *consumers); +int regulator_can_change_voltage(struct regulator *regulator); int regulator_count_voltages(struct regulator *regulator); int regulator_list_voltage(struct regulator *regulator, unsigned selector); int regulator_is_supported_voltage(struct regulator *regulator, diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 7932a3bf21bd..f2b72b230b9b 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -181,6 +181,8 @@ enum regulator_type { * @type: Indicates if the regulator is a voltage or current regulator. * @owner: Module providing the regulator, used for refcounting. * + * @continuous_voltage_range: Indicates if the regulator can set any + * voltage within constrains range. * @n_voltages: Number of selectors available for ops.list_voltage(). * * @min_uV: Voltage given by the lowest selector (if linear mapping) @@ -199,6 +201,7 @@ struct regulator_desc { const char *name; const char *supply_name; int id; + bool continuous_voltage_range; unsigned n_voltages; struct regulator_ops *ops; int irq; diff --git a/include/linux/regulator/tps51632-regulator.h b/include/linux/regulator/tps51632-regulator.h new file mode 100644 index 000000000000..d00841e1a75a --- /dev/null +++ b/include/linux/regulator/tps51632-regulator.h @@ -0,0 +1,47 @@ +/* + * tps51632-regulator.h -- TPS51632 regulator + * + * Interface for regulator driver for TPS51632 3-2-1 Phase D-Cap Step Down + * Driverless Controller with serial VID control and DVFS. + * + * Copyright (C) 2012 NVIDIA Corporation + + * Author: Laxman Dewangan <ldewangan@nvidia.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef __LINUX_REGULATOR_TPS51632_H +#define __LINUX_REGULATOR_TPS51632_H + +/* + * struct tps51632_regulator_platform_data - tps51632 regulator platform data. + * + * @reg_init_data: The regulator init data. + * @enable_pwm_dvfs: Enable PWM DVFS or not. + * @dvfs_step_20mV: Step for DVFS is 20mV or 10mV. + * @max_voltage_uV: Maximum possible voltage in PWM-DVFS mode. + * @base_voltage_uV: Base voltage when PWM-DVFS enabled. + */ +struct tps51632_regulator_platform_data { + struct regulator_init_data *reg_init_data; + bool enable_pwm_dvfs; + bool dvfs_step_20mV; + int max_voltage_uV; + int base_voltage_uV; +}; + +#endif /* __LINUX_REGULATOR_TPS51632_H */ diff --git a/include/linux/regulator/tps65090-regulator.h b/include/linux/regulator/tps65090-regulator.h deleted file mode 100644 index 0fa04b64db3e..000000000000 --- a/include/linux/regulator/tps65090-regulator.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Regulator driver interface for TI TPS65090 PMIC family - * - * 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 __REGULATOR_TPS65090_H -#define __REGULATOR_TPS65090_H - -#include <linux/regulator/machine.h> - -#define tps65090_rails(_name) "tps65090_"#_name - -enum { - TPS65090_ID_DCDC1, - TPS65090_ID_DCDC2, - TPS65090_ID_DCDC3, - TPS65090_ID_FET1, - TPS65090_ID_FET2, - TPS65090_ID_FET3, - TPS65090_ID_FET4, - TPS65090_ID_FET5, - TPS65090_ID_FET6, - TPS65090_ID_FET7, -}; - -/* - * struct tps65090_regulator_platform_data - * - * @regulator: The regulator init data. - * @slew_rate_uV_per_us: Slew rate microvolt per microsec. - */ - -struct tps65090_regulator_platform_data { - struct regulator_init_data regulator; -}; - -#endif /* __REGULATOR_TPS65090_H */ diff --git a/include/linux/spi/ads7846.h b/include/linux/spi/ads7846.h index c64de9dd7631..2f694f3846a9 100644 --- a/include/linux/spi/ads7846.h +++ b/include/linux/spi/ads7846.h @@ -46,8 +46,9 @@ struct ads7846_platform_data { u16 debounce_rep; /* additional consecutive good readings * required after the first two */ int gpio_pendown; /* the GPIO used to decide the pendown - * state if get_pendown_state == NULL - */ + * state if get_pendown_state == NULL */ + int gpio_pendown_debounce; /* platform specific debounce time for + * the gpio_pendown */ int (*get_pendown_state)(void); int (*filter_init) (const struct ads7846_platform_data *pdata, void **filter_data); diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 6f0ba01afe73..63445ede48bb 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1351,7 +1351,7 @@ struct xfrm6_tunnel { }; extern void xfrm_init(void); -extern void xfrm4_init(int rt_hash_size); +extern void xfrm4_init(void); extern int xfrm_state_init(struct net *net); extern void xfrm_state_fini(struct net *net); extern void xfrm4_state_init(void); diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 88fae8d20154..55367b04dc94 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -135,6 +135,8 @@ struct scsi_device { * because we did a bus reset. */ unsigned use_10_for_rw:1; /* first try 10-byte read / write */ unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */ + unsigned no_report_opcodes:1; /* no REPORT SUPPORTED OPERATION CODES */ + unsigned no_write_same:1; /* no WRITE SAME command */ unsigned skip_ms_page_8:1; /* do not use MODE SENSE page 0x08 */ unsigned skip_ms_page_3f:1; /* do not use MODE SENSE page 0x3f */ unsigned skip_vpd_pages:1; /* do not read VPD pages */ @@ -362,6 +364,8 @@ extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries, struct scsi_sense_hdr *sshdr); extern int scsi_get_vpd_page(struct scsi_device *, u8 page, unsigned char *buf, int buf_len); +extern int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer, + unsigned int len, unsigned char opcode); extern int scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state); extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type, diff --git a/lib/mpi/longlong.h b/lib/mpi/longlong.h index 678ce4f1e124..095ab157a521 100644 --- a/lib/mpi/longlong.h +++ b/lib/mpi/longlong.h @@ -641,7 +641,14 @@ do { \ ************** MIPS ***************** ***************************************/ #if defined(__mips__) && W_TYPE_SIZE == 32 -#if __GNUC__ > 2 || __GNUC_MINOR__ >= 7 +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4 +#define umul_ppmm(w1, w0, u, v) \ +do { \ + UDItype __ll = (UDItype)(u) * (v); \ + w1 = __ll >> 32; \ + w0 = __ll; \ +} while (0) +#elif __GNUC__ > 2 || __GNUC_MINOR__ >= 7 #define umul_ppmm(w1, w0, u, v) \ __asm__ ("multu %2,%3" \ : "=l" ((USItype)(w0)), \ @@ -666,7 +673,15 @@ do { \ ************** MIPS/64 ************** ***************************************/ #if (defined(__mips) && __mips >= 3) && W_TYPE_SIZE == 64 -#if __GNUC__ > 2 || __GNUC_MINOR__ >= 7 +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4 +#define umul_ppmm(w1, w0, u, v) \ +do { \ + typedef unsigned int __ll_UTItype __attribute__((mode(TI))); \ + __ll_UTItype __ll = (__ll_UTItype)(u) * (v); \ + w1 = __ll >> 64; \ + w0 = __ll; \ +} while (0) +#elif __GNUC__ > 2 || __GNUC_MINOR__ >= 7 #define umul_ppmm(w1, w0, u, v) \ __asm__ ("dmultu %2,%3" \ : "=l" ((UDItype)(w0)), \ diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 7bb35ac0964a..bcb72c6e2b2d 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1405,7 +1405,7 @@ int capture_free_page(struct page *page, int alloc_order, int migratetype) mt = get_pageblock_migratetype(page); if (unlikely(mt != MIGRATE_ISOLATE)) - __mod_zone_freepage_state(zone, -(1UL << order), mt); + __mod_zone_freepage_state(zone, -(1UL << alloc_order), mt); if (alloc_order != order) expand(zone, page, alloc_order, order, diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index bcf02f608cbf..017a8bacfb27 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -429,6 +429,17 @@ static struct attribute_group netstat_group = { .name = "statistics", .attrs = netstat_attrs, }; + +#if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) +static struct attribute *wireless_attrs[] = { + NULL +}; + +static struct attribute_group wireless_group = { + .name = "wireless", + .attrs = wireless_attrs, +}; +#endif #endif /* CONFIG_SYSFS */ #ifdef CONFIG_RPS @@ -1409,6 +1420,15 @@ int netdev_register_kobject(struct net_device *net) groups++; *groups++ = &netstat_group; + +#if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) + if (net->ieee80211_ptr) + *groups++ = &wireless_group; +#if IS_ENABLED(CONFIG_WIRELESS_EXT) + else if (net->wireless_handlers) + *groups++ = &wireless_group; +#endif +#endif #endif /* CONFIG_SYSFS */ error = device_add(dev); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index a8c651216fa6..df251424d816 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1785,6 +1785,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res, if (dev_out->flags & IFF_LOOPBACK) flags |= RTCF_LOCAL; + do_cache = true; if (type == RTN_BROADCAST) { flags |= RTCF_BROADCAST | RTCF_LOCAL; fi = NULL; @@ -1793,6 +1794,8 @@ static struct rtable *__mkroute_output(const struct fib_result *res, if (!ip_check_mc_rcu(in_dev, fl4->daddr, fl4->saddr, fl4->flowi4_proto)) flags &= ~RTCF_LOCAL; + else + do_cache = false; /* If multicast route do not exist use * default one, but do not gateway in this case. * Yes, it is hack. @@ -1802,8 +1805,8 @@ static struct rtable *__mkroute_output(const struct fib_result *res, } fnhe = NULL; - do_cache = fi != NULL; - if (fi) { + do_cache &= fi != NULL; + if (do_cache) { struct rtable __rcu **prth; struct fib_nh *nh = &FIB_RES_NH(*res); @@ -2597,7 +2600,7 @@ int __init ip_rt_init(void) pr_err("Unable to create route proc files\n"); #ifdef CONFIG_XFRM xfrm_init(); - xfrm4_init(ip_rt_max_size); + xfrm4_init(); #endif rtnl_register(PF_INET, RTM_GETROUTE, inet_rtm_getroute, NULL, NULL); diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 05c5ab8d983c..3be0ac2c1920 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -279,19 +279,8 @@ static void __exit xfrm4_policy_fini(void) xfrm_policy_unregister_afinfo(&xfrm4_policy_afinfo); } -void __init xfrm4_init(int rt_max_size) +void __init xfrm4_init(void) { - /* - * Select a default value for the gc_thresh based on the main route - * table hash size. It seems to me the worst case scenario is when - * we have ipsec operating in transport mode, in which we create a - * dst_entry per socket. The xfrm gc algorithm starts trying to remove - * entries at gc_thresh, and prevents new allocations as 2*gc_thresh - * so lets set an initial xfrm gc_thresh value at the rt_max_size/2. - * That will let us store an ipsec connection per route table entry, - * and start cleaning when were 1/2 full - */ - xfrm4_dst_ops.gc_thresh = rt_max_size/2; dst_entries_init(&xfrm4_dst_ops); xfrm4_state_init(); diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index c4f934176cab..30647857a375 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -252,6 +252,7 @@ struct dst_entry *inet6_csk_update_pmtu(struct sock *sk, u32 mtu) return NULL; dst->ops->update_pmtu(dst, sk, NULL, mtu); - return inet6_csk_route_socket(sk, &fl6); + dst = inet6_csk_route_socket(sk, &fl6); + return IS_ERR(dst) ? NULL : dst; } EXPORT_SYMBOL_GPL(inet6_csk_update_pmtu); diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index bf87c70ac6c5..c21e33d1abd0 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1151,10 +1151,6 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) mutex_lock(&sdata->u.ibss.mtx); - sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH; - memset(sdata->u.ibss.bssid, 0, ETH_ALEN); - sdata->u.ibss.ssid_len = 0; - active_ibss = ieee80211_sta_active_ibss(sdata); if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) { @@ -1175,6 +1171,10 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) } } + ifibss->state = IEEE80211_IBSS_MLME_SEARCH; + memset(ifibss->bssid, 0, ETH_ALEN); + ifibss->ssid_len = 0; + sta_info_flush(sdata->local, sdata); spin_lock_bh(&ifibss->incomplete_lock); diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c index ec3dba5dcd62..5c0b78528e55 100644 --- a/net/netfilter/ipset/ip_set_hash_ip.c +++ b/net/netfilter/ipset/ip_set_hash_ip.c @@ -173,6 +173,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], return adtfn(set, &nip, timeout, flags); } + ip_to = ip; if (tb[IPSET_ATTR_IP_TO]) { ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); if (ret) @@ -185,8 +186,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], if (!cidr || cidr > 32) return -IPSET_ERR_INVALID_CIDR; ip_set_mask_from_to(ip, ip_to, cidr); - } else - ip_to = ip; + } hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1); diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c index 0171f7502fa5..6283351f4eeb 100644 --- a/net/netfilter/ipset/ip_set_hash_ipport.c +++ b/net/netfilter/ipset/ip_set_hash_ipport.c @@ -162,7 +162,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], const struct ip_set_hash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipport4_elem data = { }; - u32 ip, ip_to = 0, p = 0, port, port_to; + u32 ip, ip_to, p = 0, port, port_to; u32 timeout = h->timeout; bool with_ports = false; int ret; @@ -210,7 +210,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], return ip_set_eexist(ret, flags) ? 0 : ret; } - ip = ntohl(data.ip); + ip_to = ip = ntohl(data.ip); if (tb[IPSET_ATTR_IP_TO]) { ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); if (ret) @@ -223,8 +223,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], if (!cidr || cidr > 32) return -IPSET_ERR_INVALID_CIDR; ip_set_mask_from_to(ip, ip_to, cidr); - } else - ip_to = ip; + } port_to = port = ntohs(data.port); if (with_ports && tb[IPSET_ATTR_PORT_TO]) { diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c index 6344ef551ec8..6a21271c8d5a 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportip.c +++ b/net/netfilter/ipset/ip_set_hash_ipportip.c @@ -166,7 +166,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], const struct ip_set_hash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipportip4_elem data = { }; - u32 ip, ip_to = 0, p = 0, port, port_to; + u32 ip, ip_to, p = 0, port, port_to; u32 timeout = h->timeout; bool with_ports = false; int ret; @@ -218,7 +218,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], return ip_set_eexist(ret, flags) ? 0 : ret; } - ip = ntohl(data.ip); + ip_to = ip = ntohl(data.ip); if (tb[IPSET_ATTR_IP_TO]) { ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); if (ret) @@ -231,8 +231,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], if (!cidr || cidr > 32) return -IPSET_ERR_INVALID_CIDR; ip_set_mask_from_to(ip, ip_to, cidr); - } else - ip_to = ip; + } port_to = port = ntohs(data.port); if (with_ports && tb[IPSET_ATTR_PORT_TO]) { diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c index cb71f9a774e7..2d5cd4ee30eb 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportnet.c +++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c @@ -215,8 +215,8 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], const struct ip_set_hash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipportnet4_elem data = { .cidr = HOST_MASK - 1 }; - u32 ip, ip_to = 0, p = 0, port, port_to; - u32 ip2_from = 0, ip2_to, ip2_last, ip2; + u32 ip, ip_to, p = 0, port, port_to; + u32 ip2_from, ip2_to, ip2_last, ip2; u32 timeout = h->timeout; bool with_ports = false; u8 cidr; @@ -286,6 +286,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], return ip_set_eexist(ret, flags) ? 0 : ret; } + ip_to = ip; if (tb[IPSET_ATTR_IP_TO]) { ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); if (ret) @@ -306,6 +307,8 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], if (port > port_to) swap(port, port_to); } + + ip2_to = ip2_from; if (tb[IPSET_ATTR_IP2_TO]) { ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to); if (ret) diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c index 8847b4d8be06..701c88a20fea 100644 --- a/net/netfilter/nfnetlink_cttimeout.c +++ b/net/netfilter/nfnetlink_cttimeout.c @@ -41,7 +41,8 @@ MODULE_DESCRIPTION("cttimeout: Extended Netfilter Connection Tracking timeout tu static LIST_HEAD(cttimeout_list); static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = { - [CTA_TIMEOUT_NAME] = { .type = NLA_NUL_STRING }, + [CTA_TIMEOUT_NAME] = { .type = NLA_NUL_STRING, + .len = CTNL_TIMEOUT_NAME_MAX - 1}, [CTA_TIMEOUT_L3PROTO] = { .type = NLA_U16 }, [CTA_TIMEOUT_L4PROTO] = { .type = NLA_U8 }, [CTA_TIMEOUT_DATA] = { .type = NLA_NESTED }, diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index cc10d073c338..9e8f4b2801f6 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -1210,7 +1210,7 @@ int nfc_llcp_register_device(struct nfc_dev *ndev) local->remote_miu = LLCP_DEFAULT_MIU; local->remote_lto = LLCP_DEFAULT_LTO; - list_add(&llcp_devices, &local->list); + list_add(&local->list, &llcp_devices); return 0; } diff --git a/scripts/sign-file b/scripts/sign-file index 87ca59d36e7e..974a20b661b7 100755 --- a/scripts/sign-file +++ b/scripts/sign-file @@ -156,12 +156,12 @@ sub asn1_extract($$@) if ($l == 0x1) { $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)); - } elsif ($l = 0x2) { + } elsif ($l == 0x2) { $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0], 2)); - } elsif ($l = 0x3) { + } elsif ($l == 0x3) { $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)) << 16; $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0] + 1, 2)); - } elsif ($l = 0x4) { + } elsif ($l == 0x4) { $len = unpack("N", substr(${$cursor->[2]}, $cursor->[0], 4)); } else { die $x509, ": ", $cursor->[0], ": ASN.1 element too long (", $l, ")\n"; diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c index 28f911cdd7c7..c5454c0477c3 100644 --- a/security/selinux/netnode.c +++ b/security/selinux/netnode.c @@ -174,7 +174,8 @@ static void sel_netnode_insert(struct sel_netnode *node) if (sel_netnode_hash[idx].size == SEL_NETNODE_HASH_BKT_LIMIT) { struct sel_netnode *tail; tail = list_entry( - rcu_dereference(sel_netnode_hash[idx].list.prev), + rcu_dereference_protected(sel_netnode_hash[idx].list.prev, + lockdep_is_held(&sel_netnode_lock)), struct sel_netnode, list); list_del_rcu(&tail->list); kfree_rcu(tail, rcu); diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 70d4848b5cd0..d010de12335e 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -95,6 +95,7 @@ int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset) EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset); #ifdef CONFIG_PM +#define codec_in_pm(codec) ((codec)->in_pm) static void hda_power_work(struct work_struct *work); static void hda_keep_power_on(struct hda_codec *codec); #define hda_codec_is_power_on(codec) ((codec)->power_on) @@ -104,6 +105,7 @@ static inline void hda_call_pm_notify(struct hda_bus *bus, bool power_up) bus->ops.pm_notify(bus, power_up); } #else +#define codec_in_pm(codec) 0 static inline void hda_keep_power_on(struct hda_codec *codec) {} #define hda_codec_is_power_on(codec) 1 #define hda_call_pm_notify(bus, state) {} @@ -228,7 +230,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, } mutex_unlock(&bus->cmd_mutex); snd_hda_power_down(codec); - if (res && *res == -1 && bus->rirb_error) { + if (!codec_in_pm(codec) && res && *res == -1 && bus->rirb_error) { if (bus->response_reset) { snd_printd("hda_codec: resetting BUS due to " "fatal communication error\n"); @@ -238,7 +240,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, goto again; } /* clear reset-flag when the communication gets recovered */ - if (!err) + if (!err || codec_in_pm(codec)) bus->response_reset = 0; return err; } @@ -3616,6 +3618,8 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq) { unsigned int state; + codec->in_pm = 1; + if (codec->patch_ops.suspend) codec->patch_ops.suspend(codec); hda_cleanup_all_streams(codec); @@ -3630,6 +3634,7 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq) codec->power_transition = 0; codec->power_jiffies = jiffies; spin_unlock(&codec->power_lock); + codec->in_pm = 0; return state; } @@ -3638,6 +3643,8 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq) */ static void hda_call_codec_resume(struct hda_codec *codec) { + codec->in_pm = 1; + /* set as if powered on for avoiding re-entering the resume * in the resume / power-save sequence */ @@ -3656,6 +3663,8 @@ static void hda_call_codec_resume(struct hda_codec *codec) snd_hda_codec_resume_cache(codec); } snd_hda_jack_report_sync(codec); + + codec->in_pm = 0; snd_hda_power_down(codec); /* flag down before returning */ } #endif /* CONFIG_PM */ diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 507fe8a917b6..4f4e545c0f4b 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -869,6 +869,7 @@ struct hda_codec { unsigned int power_on :1; /* current (global) power-state */ unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */ unsigned int pm_down_notified:1; /* PM notified to controller */ + unsigned int in_pm:1; /* suspend/resume being performed */ int power_transition; /* power-state in transition */ int power_count; /* current (global) power refcount */ struct delayed_work power_work; /* delayed task for powerdown */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index cd2dbaf1be78..f9d870e554d9 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -556,6 +556,12 @@ enum { #define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */ #define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */ #define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ +#define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ + +/* quirks for Intel PCH */ +#define AZX_DCAPS_INTEL_PCH \ + (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_BUFSIZE | \ + AZX_DCAPS_COUNT_LPIB_DELAY | AZX_DCAPS_PM_RUNTIME) /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ @@ -2433,6 +2439,9 @@ static void azx_power_notify(struct hda_bus *bus, bool power_up) { struct azx *chip = bus->private_data; + if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) + return; + if (power_up) pm_runtime_get_sync(&chip->pci->dev); else @@ -2548,7 +2557,8 @@ static int azx_runtime_suspend(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; - if (!power_save_controller) + if (!power_save_controller || + !(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) return -EAGAIN; azx_stop_chip(chip); @@ -3429,39 +3439,30 @@ static void __devexit azx_remove(struct pci_dev *pci) static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { /* CPT */ { PCI_DEVICE(0x8086, 0x1c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* PBG */ { PCI_DEVICE(0x8086, 0x1d20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE}, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Panther Point */ { PCI_DEVICE(0x8086, 0x1e20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Lynx Point */ { PCI_DEVICE(0x8086, 0x8c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Lynx Point-LP */ { PCI_DEVICE(0x8086, 0x9c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Lynx Point-LP */ { PCI_DEVICE(0x8086, 0x9c21), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Haswell */ { PCI_DEVICE(0x8086, 0x0c0c), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH }, { PCI_DEVICE(0x8086, 0x0d0c), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH }, /* 5 Series/3400 */ { PCI_DEVICE(0x8086, 0x3b56), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH }, /* SCH */ { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index d5f3a26d608d..3bcb67172358 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -466,6 +466,7 @@ static int parse_output(struct hda_codec *codec) memcpy(cfg->speaker_pins, cfg->line_out_pins, sizeof(cfg->speaker_pins)); cfg->line_outs = 0; + memset(cfg->line_out_pins, 0, sizeof(cfg->line_out_pins)); } return 0; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 68fd49294b26..ad68d223f8af 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7065,6 +7065,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 }, { .id = 0x10ec0283, .name = "ALC283", .patch = patch_alc269 }, { .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 }, + { .id = 0x10ec0292, .name = "ALC292", .patch = patch_alc269 }, { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", .patch = patch_alc861 }, { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index c03b65af3059..054967d8bac2 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -268,7 +268,7 @@ EXPORT_SYMBOL_GPL(arizona_out_ev); static unsigned int arizona_sysclk_48k_rates[] = { 6144000, 12288000, - 22579200, + 24576000, 49152000, 73728000, 98304000, @@ -278,7 +278,7 @@ static unsigned int arizona_sysclk_48k_rates[] = { static unsigned int arizona_sysclk_44k1_rates[] = { 5644800, 11289600, - 24576000, + 22579200, 45158400, 67737600, 90316800, diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index f994af34f552..e3f0a7f3131e 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -485,7 +485,7 @@ static int cs4271_probe(struct snd_soc_codec *codec) gpio_nreset = cs4271plat->gpio_nreset; if (gpio_nreset >= 0) - if (gpio_request(gpio_nreset, "CS4271 Reset")) + if (devm_gpio_request(codec->dev, gpio_nreset, "CS4271 Reset")) gpio_nreset = -EINVAL; if (gpio_nreset >= 0) { /* Reset codec */ @@ -535,15 +535,10 @@ static int cs4271_probe(struct snd_soc_codec *codec) static int cs4271_remove(struct snd_soc_codec *codec) { struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); - int gpio_nreset; - gpio_nreset = cs4271->gpio_nreset; - - if (gpio_is_valid(gpio_nreset)) { + if (gpio_is_valid(cs4271->gpio_nreset)) /* Set codec to the reset state */ - gpio_set_value(gpio_nreset, 0); - gpio_free(gpio_nreset); - } + gpio_set_value(cs4271->gpio_nreset, 0); return 0; }; diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c index b9f16598324c..2ba08148655f 100644 --- a/sound/soc/kirkwood/kirkwood-dma.c +++ b/sound/soc/kirkwood/kirkwood-dma.c @@ -71,7 +71,6 @@ static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id) printk(KERN_WARNING "%s: got err interrupt 0x%lx\n", __func__, cause); writel(cause, priv->io + KIRKWOOD_ERR_CAUSE); - return IRQ_HANDLED; } /* we've enabled only bytes interrupts ... */ @@ -178,7 +177,7 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream) } dram = mv_mbus_dram_info(); - addr = virt_to_phys(substream->dma_buffer.area); + addr = substream->dma_buffer.addr; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { prdata->play_stream = substream; kirkwood_dma_conf_mbus_windows(priv->io, diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index 542538d10ab7..1d5db484d2df 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -95,7 +95,7 @@ static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate) do { cpu_relax(); value = readl(io + KIRKWOOD_DCO_SPCR_STATUS); - value &= KIRKWOOD_DCO_SPCR_STATUS; + value &= KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK; } while (value == 0); } @@ -180,67 +180,72 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); - unsigned long value; - - /* - * specs says KIRKWOOD_PLAYCTL must be read 2 times before - * changing it. So read 1 time here and 1 later. - */ - value = readl(priv->io + KIRKWOOD_PLAYCTL); + uint32_t ctl, value; + + ctl = readl(priv->io + KIRKWOOD_PLAYCTL); + if (ctl & KIRKWOOD_PLAYCTL_PAUSE) { + unsigned timeout = 5000; + /* + * The Armada510 spec says that if we enter pause mode, the + * busy bit must be read back as clear _twice_. Make sure + * we respect that otherwise we get DMA underruns. + */ + do { + value = ctl; + ctl = readl(priv->io + KIRKWOOD_PLAYCTL); + if (!((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY)) + break; + udelay(1); + } while (timeout--); + + if ((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY) + dev_notice(dai->dev, "timed out waiting for busy to deassert: %08x\n", + ctl); + } switch (cmd) { case SNDRV_PCM_TRIGGER_START: - /* stop audio, enable interrupts */ - value = readl(priv->io + KIRKWOOD_PLAYCTL); - value |= KIRKWOOD_PLAYCTL_PAUSE; - writel(value, priv->io + KIRKWOOD_PLAYCTL); - value = readl(priv->io + KIRKWOOD_INT_MASK); value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES; writel(value, priv->io + KIRKWOOD_INT_MASK); /* configure audio & enable i2s playback */ - value = readl(priv->io + KIRKWOOD_PLAYCTL); - value &= ~KIRKWOOD_PLAYCTL_BURST_MASK; - value &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE + ctl &= ~KIRKWOOD_PLAYCTL_BURST_MASK; + ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE | KIRKWOOD_PLAYCTL_SPDIF_EN); if (priv->burst == 32) - value |= KIRKWOOD_PLAYCTL_BURST_32; + ctl |= KIRKWOOD_PLAYCTL_BURST_32; else - value |= KIRKWOOD_PLAYCTL_BURST_128; - value |= KIRKWOOD_PLAYCTL_I2S_EN; - writel(value, priv->io + KIRKWOOD_PLAYCTL); + ctl |= KIRKWOOD_PLAYCTL_BURST_128; + ctl |= KIRKWOOD_PLAYCTL_I2S_EN; + writel(ctl, priv->io + KIRKWOOD_PLAYCTL); break; case SNDRV_PCM_TRIGGER_STOP: /* stop audio, disable interrupts */ - value = readl(priv->io + KIRKWOOD_PLAYCTL); - value |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; - writel(value, priv->io + KIRKWOOD_PLAYCTL); + ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; + writel(ctl, priv->io + KIRKWOOD_PLAYCTL); value = readl(priv->io + KIRKWOOD_INT_MASK); value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES; writel(value, priv->io + KIRKWOOD_INT_MASK); /* disable all playbacks */ - value = readl(priv->io + KIRKWOOD_PLAYCTL); - value &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN); - writel(value, priv->io + KIRKWOOD_PLAYCTL); + ctl &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN); + writel(ctl, priv->io + KIRKWOOD_PLAYCTL); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: - value = readl(priv->io + KIRKWOOD_PLAYCTL); - value |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; - writel(value, priv->io + KIRKWOOD_PLAYCTL); + ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; + writel(ctl, priv->io + KIRKWOOD_PLAYCTL); break; case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - value = readl(priv->io + KIRKWOOD_PLAYCTL); - value &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE); - writel(value, priv->io + KIRKWOOD_PLAYCTL); + ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE); + writel(ctl, priv->io + KIRKWOOD_PLAYCTL); break; default: @@ -260,11 +265,6 @@ static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: - /* stop audio, enable interrupts */ - value = readl(priv->io + KIRKWOOD_RECCTL); - value |= KIRKWOOD_RECCTL_PAUSE; - writel(value, priv->io + KIRKWOOD_RECCTL); - value = readl(priv->io + KIRKWOOD_INT_MASK); value |= KIRKWOOD_INT_CAUSE_REC_BYTES; writel(value, priv->io + KIRKWOOD_INT_MASK); diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c index b56b9a3c6169..a2ca1567b9e4 100644 --- a/sound/soc/samsung/bells.c +++ b/sound/soc/samsung/bells.c @@ -212,7 +212,7 @@ static struct snd_soc_dai_link bells_dai_wm5102[] = { { .name = "Sub", .stream_name = "Sub", - .cpu_dai_name = "wm5110-aif3", + .cpu_dai_name = "wm5102-aif3", .codec_dai_name = "wm9081-hifi", .codec_name = "wm9081.1-006c", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF @@ -247,7 +247,7 @@ static struct snd_soc_dai_link bells_dai_wm5110[] = { { .name = "Sub", .stream_name = "Sub", - .cpu_dai_name = "wm5102-aif3", + .cpu_dai_name = "wm5110-aif3", .codec_dai_name = "wm9081-hifi", .codec_name = "wm9081.1-006c", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF diff --git a/sound/usb/midi.c b/sound/usb/midi.c index c83f6143c0eb..eeefbce3873c 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -148,6 +148,7 @@ struct snd_usb_midi_out_endpoint { struct snd_usb_midi_out_endpoint* ep; struct snd_rawmidi_substream *substream; int active; + bool autopm_reference; uint8_t cable; /* cable number << 4 */ uint8_t state; #define STATE_UNKNOWN 0 @@ -1076,7 +1077,8 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) return -ENXIO; } err = usb_autopm_get_interface(umidi->iface); - if (err < 0) + port->autopm_reference = err >= 0; + if (err < 0 && err != -EACCES) return -EIO; substream->runtime->private_data = port; port->state = STATE_UNKNOWN; @@ -1087,9 +1089,11 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream) { struct snd_usb_midi* umidi = substream->rmidi->private_data; + struct usbmidi_out_port *port = substream->runtime->private_data; substream_open(substream, 0); - usb_autopm_put_interface(umidi->iface); + if (port->autopm_reference) + usb_autopm_put_interface(umidi->iface); return 0; } diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 5c12a3fe8c3e..ef6fa24fc473 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -459,7 +459,7 @@ static int configure_endpoint(struct snd_usb_substream *subs) return ret; if (subs->sync_endpoint) - ret = snd_usb_endpoint_set_params(subs->data_endpoint, + ret = snd_usb_endpoint_set_params(subs->sync_endpoint, subs->pcm_format, subs->channels, subs->period_bytes, |