aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/cgroups/memory.txt74
-rw-r--r--MAINTAINERS3
-rw-r--r--arch/s390/defconfig16
-rw-r--r--arch/s390/include/asm/compat.h2
-rw-r--r--arch/s390/include/asm/elf.h9
-rw-r--r--arch/s390/include/asm/system.h2
-rw-r--r--arch/s390/include/asm/thread_info.h6
-rw-r--r--arch/s390/kernel/process.c38
-rw-r--r--arch/s390/kernel/vdso.c4
-rw-r--r--arch/s390/mm/mmap.c49
-rw-r--r--arch/x86/Kconfig12
-rw-r--r--arch/x86/pci/broadcom_bus.c11
-rw-r--r--arch/x86/pci/common.c41
-rw-r--r--arch/x86/pci/irq.c3
-rw-r--r--arch/x86/platform/olpc/olpc-xo1.c101
-rw-r--r--drivers/acpi/apei/hest.c22
-rw-r--r--drivers/acpi/pci_root.c35
-rw-r--r--drivers/char/agp/intel-agp.c4
-rw-r--r--drivers/char/agp/intel-gtt.c2
-rw-r--r--drivers/gpio/cs5535-gpio.c93
-rw-r--r--drivers/gpio/timbgpio.c6
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c2
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c3
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h1
-rw-r--r--drivers/gpu/drm/i915/i915_gem_execbuffer.c25
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c2
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c17
-rw-r--r--drivers/gpu/drm/i915/intel_display.c17
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c8
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c2
-rw-r--r--drivers/i2c/busses/scx200_acb.c200
-rw-r--r--drivers/media/video/cafe_ccic.c4
-rw-r--r--drivers/mfd/88pm860x-core.c36
-rw-r--r--drivers/mfd/Kconfig16
-rw-r--r--drivers/mfd/Makefile3
-rw-r--r--drivers/mfd/ab3550-core.c28
-rw-r--r--drivers/mfd/ab8500-core.c306
-rw-r--r--drivers/mfd/ab8500-debugfs.c1016
-rw-r--r--drivers/mfd/ab8500-spi.c143
-rw-r--r--drivers/mfd/asic3.c62
-rw-r--r--drivers/mfd/cs5535-mfd.c151
-rw-r--r--drivers/mfd/ezx-pcap.c25
-rw-r--r--drivers/mfd/htc-egpio.c27
-rw-r--r--drivers/mfd/htc-i2cpld.c40
-rw-r--r--drivers/mfd/jz4740-adc.c25
-rw-r--r--drivers/mfd/max8925-core.c30
-rw-r--r--drivers/mfd/max8998-irq.c37
-rw-r--r--drivers/mfd/max8998.c134
-rw-r--r--drivers/mfd/mc13xxx-core.c2
-rw-r--r--drivers/mfd/mfd-core.c4
-rw-r--r--drivers/mfd/sm501.c9
-rw-r--r--drivers/mfd/stmpe.c28
-rw-r--r--drivers/mfd/t7l66xb.c20
-rw-r--r--drivers/mfd/tc6393xb.c22
-rw-r--r--drivers/mfd/tps65010.c2
-rw-r--r--drivers/mfd/tps6586x.c36
-rw-r--r--drivers/mfd/twl-core.c2
-rw-r--r--drivers/mfd/twl4030-irq.c28
-rw-r--r--drivers/mfd/twl6030-irq.c2
-rw-r--r--drivers/mfd/vx855.c2
-rw-r--r--drivers/mfd/wm831x-core.c17
-rw-r--r--drivers/mfd/wm831x-i2c.c14
-rw-r--r--drivers/mfd/wm831x-irq.c53
-rw-r--r--drivers/mfd/wm831x-spi.c18
-rw-r--r--drivers/mfd/wm8350-irq.c32
-rw-r--r--drivers/mfd/wm8994-core.c46
-rw-r--r--drivers/mfd/wm8994-irq.c32
-rw-r--r--drivers/misc/Kconfig2
-rw-r--r--drivers/misc/cs5535-mfgpt.c73
-rw-r--r--drivers/net/myri10ge/myri10ge.c4
-rw-r--r--drivers/net/sfc/falcon.c25
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c4
-rw-r--r--drivers/pci/msi.c5
-rw-r--r--drivers/pci/msi.h6
-rw-r--r--drivers/pci/pci-acpi.c3
-rw-r--r--drivers/pci/pci-driver.c5
-rw-r--r--drivers/pci/pci-stub.c7
-rw-r--r--drivers/pci/pci-sysfs.c2
-rw-r--r--drivers/pci/pci.c25
-rw-r--r--drivers/pci/pci.h14
-rw-r--r--drivers/pci/pcie/aer/aerdrv.c1
-rw-r--r--drivers/pci/pcie/aer/aerdrv.h3
-rw-r--r--drivers/pci/pcie/aspm.c21
-rw-r--r--drivers/pci/pcie/pme.c31
-rw-r--r--drivers/pci/pcie/portdrv.h5
-rw-r--r--drivers/pci/pcie/portdrv_acpi.c23
-rw-r--r--drivers/pci/pcie/portdrv_core.c25
-rw-r--r--drivers/pci/pcie/portdrv_pci.c37
-rw-r--r--drivers/power/Kconfig20
-rw-r--r--drivers/power/Makefile2
-rw-r--r--drivers/power/collie_battery.c13
-rw-r--r--drivers/power/ds2760_battery.c2
-rw-r--r--drivers/power/gpio-charger.c188
-rw-r--r--drivers/power/intel_mid_battery.c2
-rw-r--r--drivers/power/isp1704_charger.c201
-rw-r--r--drivers/power/jz4740-battery.c13
-rw-r--r--drivers/power/max17042_battery.c239
-rw-r--r--drivers/power/olpc_battery.c114
-rw-r--r--drivers/power/power_supply_core.c6
-rw-r--r--drivers/power/s3c_adc_battery.c12
-rw-r--r--drivers/power/tosa_battery.c13
-rw-r--r--drivers/power/wm97xx_battery.c4
-rw-r--r--drivers/power/z2_battery.c6
-rw-r--r--drivers/regulator/max8998.c94
-rw-r--r--drivers/rtc/rtc-max8998.c54
-rw-r--r--drivers/s390/cio/device.c1
-rw-r--r--drivers/scsi/ipr.c8
-rw-r--r--drivers/scsi/pmcraid.c7
-rw-r--r--drivers/staging/sm7xx/smtcfb.c2
-rw-r--r--fs/afs/cmservice.c12
-rw-r--r--fs/afs/internal.h1
-rw-r--r--fs/afs/main.c13
-rw-r--r--fs/afs/mntpt.c11
-rw-r--r--fs/afs/rxrpc.c2
-rw-r--r--fs/afs/server.c13
-rw-r--r--fs/afs/vlocation.c14
-rw-r--r--fs/fscache/operation.c2
-rw-r--r--fs/namei.c37
-rw-r--r--include/acpi/apei.h6
-rw-r--r--include/linux/gpio.h4
-rw-r--r--include/linux/list_bl.h2
-rw-r--r--include/linux/mfd/ab8500.h53
-rw-r--r--include/linux/mfd/core.h6
-rw-r--r--include/linux/mfd/max8998-private.h2
-rw-r--r--include/linux/mfd/max8998.h31
-rw-r--r--include/linux/mfd/wm831x/core.h1
-rw-r--r--include/linux/page_cgroup.h23
-rw-r--r--include/linux/pci-acpi.h6
-rw-r--r--include/linux/pci-aspm.h5
-rw-r--r--include/linux/pci.h20
-rw-r--r--include/linux/pci_ids.h3
-rw-r--r--include/linux/pci_regs.h10
-rw-r--r--include/linux/power/gpio-charger.h41
-rw-r--r--include/linux/power/max17042_battery.h30
-rw-r--r--include/linux/s3c_adc_battery.h1
-rw-r--r--kernel/cgroup.c19
-rw-r--r--net/rxrpc/af_rxrpc.c2
-rw-r--r--sound/pci/cs5535audio/cs5535audio_pm.c7
138 files changed, 3137 insertions, 1824 deletions
diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt
index bac328c232f5..7781857dc940 100644
--- a/Documentation/cgroups/memory.txt
+++ b/Documentation/cgroups/memory.txt
@@ -385,10 +385,6 @@ mapped_file - # of bytes of mapped file (includes tmpfs/shmem)
pgpgin - # of pages paged in (equivalent to # of charging events).
pgpgout - # of pages paged out (equivalent to # of uncharging events).
swap - # of bytes of swap usage
-dirty - # of bytes that are waiting to get written back to the disk.
-writeback - # of bytes that are actively being written back to the disk.
-nfs_unstable - # of bytes sent to the NFS server, but not yet committed to
- the actual storage.
inactive_anon - # of bytes of anonymous memory and swap cache memory on
LRU list.
active_anon - # of bytes of anonymous and swap cache memory on active
@@ -410,9 +406,6 @@ total_mapped_file - sum of all children's "cache"
total_pgpgin - sum of all children's "pgpgin"
total_pgpgout - sum of all children's "pgpgout"
total_swap - sum of all children's "swap"
-total_dirty - sum of all children's "dirty"
-total_writeback - sum of all children's "writeback"
-total_nfs_unstable - sum of all children's "nfs_unstable"
total_inactive_anon - sum of all children's "inactive_anon"
total_active_anon - sum of all children's "active_anon"
total_inactive_file - sum of all children's "inactive_file"
@@ -460,73 +453,6 @@ memory under it will be reclaimed.
You can reset failcnt by writing 0 to failcnt file.
# echo 0 > .../memory.failcnt
-5.5 dirty memory
-
-Control the maximum amount of dirty pages a cgroup can have at any given time.
-
-Limiting dirty memory is like fixing the max amount of dirty (hard to reclaim)
-page cache used by a cgroup. So, in case of multiple cgroup writers, they will
-not be able to consume more than their designated share of dirty pages and will
-be forced to perform write-out if they cross that limit.
-
-The interface is equivalent to the procfs interface: /proc/sys/vm/dirty_*. It
-is possible to configure a limit to trigger both a direct writeback or a
-background writeback performed by per-bdi flusher threads. The root cgroup
-memory.dirty_* control files are read-only and match the contents of
-the /proc/sys/vm/dirty_* files.
-
-Per-cgroup dirty limits can be set using the following files in the cgroupfs:
-
-- memory.dirty_ratio: the amount of dirty memory (expressed as a percentage of
- cgroup memory) at which a process generating dirty pages will itself start
- writing out dirty data.
-
-- memory.dirty_limit_in_bytes: the amount of dirty memory (expressed in bytes)
- in the cgroup at which a process generating dirty pages will start itself
- writing out dirty data. Suffix (k, K, m, M, g, or G) can be used to indicate
- that value is kilo, mega or gigabytes.
-
- Note: memory.dirty_limit_in_bytes is the counterpart of memory.dirty_ratio.
- Only one of them may be specified at a time. When one is written it is
- immediately taken into account to evaluate the dirty memory limits and the
- other appears as 0 when read.
-
-- memory.dirty_background_ratio: the amount of dirty memory of the cgroup
- (expressed as a percentage of cgroup memory) at which background writeback
- kernel threads will start writing out dirty data.
-
-- memory.dirty_background_limit_in_bytes: the amount of dirty memory (expressed
- in bytes) in the cgroup at which background writeback kernel threads will
- start writing out dirty data. Suffix (k, K, m, M, g, or G) can be used to
- indicate that value is kilo, mega or gigabytes.
-
- Note: memory.dirty_background_limit_in_bytes is the counterpart of
- memory.dirty_background_ratio. Only one of them may be specified at a time.
- When one is written it is immediately taken into account to evaluate the dirty
- memory limits and the other appears as 0 when read.
-
-A cgroup may contain more dirty memory than its dirty limit. This is possible
-because of the principle that the first cgroup to touch a page is charged for
-it. Subsequent page counting events (dirty, writeback, nfs_unstable) are also
-counted to the originally charged cgroup.
-
-Example: If page is allocated by a cgroup A task, then the page is charged to
-cgroup A. If the page is later dirtied by a task in cgroup B, then the cgroup A
-dirty count will be incremented. If cgroup A is over its dirty limit but cgroup
-B is not, then dirtying a cgroup A page from a cgroup B task may push cgroup A
-over its dirty limit without throttling the dirtying cgroup B task.
-
-When use_hierarchy=0, each cgroup has dirty memory usage and limits.
-System-wide dirty limits are also consulted. Dirty memory consumption is
-checked against both system-wide and per-cgroup dirty limits.
-
-The current implementation does not enforce per-cgroup dirty limits when
-use_hierarchy=1. System-wide dirty limits are used for processes in such
-cgroups. Attempts to read memory.dirty_* files return the system-wide
-values. Writes to the memory.dirty_* files return error. An enhanced
-implementation is needed to check the chain of parents to ensure that no
-dirty limit is exceeded.
-
6. Hierarchy support
The memory controller supports a deep hierarchy and hierarchical accounting.
diff --git a/MAINTAINERS b/MAINTAINERS
index af656ded404e..89e4d4b145bb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5272,8 +5272,7 @@ S: Supported
F: drivers/s390/net/
S390 ZCRYPT DRIVER
-M: Felix Beck <[email protected]>
-M: Ralph Wuerthner <[email protected]>
+M: Holger Dengler <[email protected]>
W: http://www.ibm.com/developerworks/linux/linux390/
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index d79697157ac0..29c82c640a88 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -5,10 +5,21 @@ CONFIG_AUDIT=y
CONFIG_RCU_TRACE=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_MEM_RES_CTLR=y
+CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_CGROUP=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_PERF_EVENTS=y
+# CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
@@ -19,7 +30,9 @@ CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT=y
CONFIG_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTREMOVE=y
+CONFIG_KSM=y
CONFIG_BINFMT_MISC=m
+CONFIG_CMM=m
CONFIG_HZ_100=y
CONFIG_KEXEC=y
CONFIG_PM=y
@@ -105,6 +118,7 @@ CONFIG_DEBUG_LIST=y
CONFIG_DEBUG_NOTIFIERS=y
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_KPROBES_SANITY_TEST=y
+CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
CONFIG_CPU_NOTIFIER_ERROR_INJECT=m
CONFIG_LATENCYTOP=y
CONFIG_SYSCTL_SYSCALL_CHECK=y
diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h
index a875c2f542e1..da359ca6fe55 100644
--- a/arch/s390/include/asm/compat.h
+++ b/arch/s390/include/asm/compat.h
@@ -169,7 +169,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr)
static inline int is_compat_task(void)
{
- return test_thread_flag(TIF_31BIT);
+ return is_32bit_task();
}
#else
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h
index 354d42616c7e..10c029cfcc7d 100644
--- a/arch/s390/include/asm/elf.h
+++ b/arch/s390/include/asm/elf.h
@@ -161,7 +161,9 @@ extern unsigned int vdso_enabled;
use of this is to invoke "./ld.so someprog" to test out a new version of
the loader. We need to make sure that it is out of the way of the program
that it will "exec", and that there is sufficient room for the brk. */
-#define ELF_ET_DYN_BASE (STACK_TOP / 3 * 2)
+
+extern unsigned long randomize_et_dyn(unsigned long base);
+#define ELF_ET_DYN_BASE (randomize_et_dyn(STACK_TOP / 3 * 2))
/* This yields a mask that user programs can use to figure out what
instruction set this CPU supports. */
@@ -206,6 +208,8 @@ do { \
current->mm->context.noexec == 0; \
})
+#define STACK_RND_MASK 0x7ffUL
+
#define ARCH_DLINFO \
do { \
if (vdso_enabled) \
@@ -218,4 +222,7 @@ struct linux_binprm;
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
int arch_setup_additional_pages(struct linux_binprm *, int);
+extern unsigned long arch_randomize_brk(struct mm_struct *mm);
+#define arch_randomize_brk arch_randomize_brk
+
#endif
diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h
index 6710b0eac165..8f8d759f6a7b 100644
--- a/arch/s390/include/asm/system.h
+++ b/arch/s390/include/asm/system.h
@@ -449,7 +449,7 @@ extern void (*_machine_restart)(char *command);
extern void (*_machine_halt)(void);
extern void (*_machine_power_off)(void);
-#define arch_align_stack(x) (x)
+extern unsigned long arch_align_stack(unsigned long sp);
static inline int tprot(unsigned long addr)
{
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h
index ebc77091466f..ad1382f7932e 100644
--- a/arch/s390/include/asm/thread_info.h
+++ b/arch/s390/include/asm/thread_info.h
@@ -118,6 +118,12 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_SINGLE_STEP (1<<TIF_FREEZE)
#define _TIF_FREEZE (1<<TIF_FREEZE)
+#ifdef CONFIG_64BIT
+#define is_32bit_task() (test_thread_flag(TIF_31BIT))
+#else
+#define is_32bit_task() (1)
+#endif
+
#endif /* __KERNEL__ */
#define PREEMPT_ACTIVE 0x4000000
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 6ba42222b542..a895e69379f7 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -30,9 +30,11 @@
#include <linux/tick.h>
#include <linux/elfcore.h>
#include <linux/kernel_stat.h>
+#include <linux/personality.h>
#include <linux/syscalls.h>
#include <linux/compat.h>
#include <linux/kprobes.h>
+#include <linux/random.h>
#include <asm/compat.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -332,3 +334,39 @@ unsigned long get_wchan(struct task_struct *p)
}
return 0;
}
+
+unsigned long arch_align_stack(unsigned long sp)
+{
+ if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
+ sp -= get_random_int() & ~PAGE_MASK;
+ return sp & ~0xf;
+}
+
+static inline unsigned long brk_rnd(void)
+{
+ /* 8MB for 32bit, 1GB for 64bit */
+ if (is_32bit_task())
+ return (get_random_int() & 0x7ffUL) << PAGE_SHIFT;
+ else
+ return (get_random_int() & 0x3ffffUL) << PAGE_SHIFT;
+}
+
+unsigned long arch_randomize_brk(struct mm_struct *mm)
+{
+ unsigned long ret = PAGE_ALIGN(mm->brk + brk_rnd());
+
+ if (ret < mm->brk)
+ return mm->brk;
+ return ret;
+}
+
+unsigned long randomize_et_dyn(unsigned long base)
+{
+ unsigned long ret = PAGE_ALIGN(base + brk_rnd());
+
+ if (!(current->flags & PF_RANDOMIZE))
+ return base;
+ if (ret < base)
+ return base;
+ return ret;
+}
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c
index e3150dd2fe74..f438d74dedbd 100644
--- a/arch/s390/kernel/vdso.c
+++ b/arch/s390/kernel/vdso.c
@@ -203,7 +203,6 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
if (!uses_interp)
return 0;
- vdso_base = mm->mmap_base;
#ifdef CONFIG_64BIT
vdso_pagelist = vdso64_pagelist;
vdso_pages = vdso64_pages;
@@ -233,8 +232,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
* fail and end up putting it elsewhere.
*/
down_write(&mm->mmap_sem);
- vdso_base = get_unmapped_area(NULL, vdso_base,
- vdso_pages << PAGE_SHIFT, 0, 0);
+ vdso_base = get_unmapped_area(NULL, 0, vdso_pages << PAGE_SHIFT, 0, 0);
if (IS_ERR_VALUE(vdso_base)) {
rc = vdso_base;
goto out_up;
diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c
index 869efbaed3ea..c9a9f7f18188 100644
--- a/arch/s390/mm/mmap.c
+++ b/arch/s390/mm/mmap.c
@@ -27,17 +27,44 @@
#include <linux/personality.h>
#include <linux/mm.h>
#include <linux/module.h>
+#include <linux/random.h>
#include <asm/pgalloc.h>
#include <asm/compat.h>
+static unsigned long stack_maxrandom_size(void)
+{
+ if (!(current->flags & PF_RANDOMIZE))
+ return 0;
+ if (current->personality & ADDR_NO_RANDOMIZE)
+ return 0;
+ return STACK_RND_MASK << PAGE_SHIFT;
+}
+
/*
* Top of mmap area (just below the process stack).
*
- * Leave an at least ~128 MB hole.
+ * Leave at least a ~32 MB hole.
*/
-#define MIN_GAP (128*1024*1024)
+#define MIN_GAP (32*1024*1024)
#define MAX_GAP (STACK_TOP/6*5)
+static inline int mmap_is_legacy(void)
+{
+ if (current->personality & ADDR_COMPAT_LAYOUT)
+ return 1;
+ if (rlimit(RLIMIT_STACK) == RLIM_INFINITY)
+ return 1;
+ return sysctl_legacy_va_layout;
+}
+
+static unsigned long mmap_rnd(void)
+{
+ if (!(current->flags & PF_RANDOMIZE))
+ return 0;
+ /* 8MB randomization for mmap_base */
+ return (get_random_int() & 0x7ffUL) << PAGE_SHIFT;
+}
+
static inline unsigned long mmap_base(void)
{
unsigned long gap = rlimit(RLIMIT_STACK);
@@ -46,22 +73,8 @@ static inline unsigned long mmap_base(void)
gap = MIN_GAP;
else if (gap > MAX_GAP)
gap = MAX_GAP;
-
- return STACK_TOP - (gap & PAGE_MASK);
-}
-
-static inline int mmap_is_legacy(void)
-{
-#ifdef CONFIG_64BIT
- /*
- * Force standard allocation for 64 bit programs.
- */
- if (!is_compat_task())
- return 1;
-#endif
- return sysctl_legacy_va_layout ||
- (current->personality & ADDR_COMPAT_LAYOUT) ||
- rlimit(RLIMIT_STACK) == RLIM_INFINITY;
+ gap &= PAGE_MASK;
+ return STACK_TOP - stack_maxrandom_size() - mmap_rnd() - gap;
}
#ifndef CONFIG_64BIT
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 36ed2e2c896b..47ae4a751a59 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1934,13 +1934,19 @@ config PCI_MMCONFIG
depends on X86_64 && PCI && ACPI
config PCI_CNB20LE_QUIRK
- bool "Read CNB20LE Host Bridge Windows"
- depends on PCI
+ bool "Read CNB20LE Host Bridge Windows" if EMBEDDED
+ default n
+ depends on PCI && EXPERIMENTAL
help
Read the PCI windows out of the CNB20LE host bridge. This allows
PCI hotplug to work on systems with the CNB20LE chipset which do
not have ACPI.
+ There's no public spec for this chipset, and this functionality
+ is known to be incomplete.
+
+ You should say N unless you know you need this.
+
config DMAR
bool "Support for DMA Remapping Devices (EXPERIMENTAL)"
depends on PCI_MSI && ACPI && EXPERIMENTAL
@@ -2068,7 +2074,7 @@ config OLPC
config OLPC_XO1
tristate "OLPC XO-1 support"
- depends on OLPC && PCI
+ depends on OLPC && MFD_CS5535
---help---
Add support for non-essential features of the OLPC XO-1 laptop.
diff --git a/arch/x86/pci/broadcom_bus.c b/arch/x86/pci/broadcom_bus.c
index 0846a5bbbfbd..ab8269b0da29 100644
--- a/arch/x86/pci/broadcom_bus.c
+++ b/arch/x86/pci/broadcom_bus.c
@@ -9,6 +9,7 @@
* option) any later version.
*/
+#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/pci.h>
@@ -25,12 +26,14 @@ static void __devinit cnb20le_res(struct pci_dev *dev)
u8 fbus, lbus;
int i;
+#ifdef CONFIG_ACPI
/*
- * The x86_pci_root_bus_res_quirks() function already refuses to use
- * this information if ACPI _CRS was used. Therefore, we don't bother
- * checking if ACPI is enabled, and just generate the information
- * for both the ACPI _CRS and no ACPI cases.
+ * We should get host bridge information from ACPI unless the BIOS
+ * doesn't support it.
*/
+ if (acpi_os_get_root_pointer())
+ return;
+#endif
info = &pci_root_info[pci_root_num];
pci_root_num++;
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index f7c8a399978c..5fe75026ecc2 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -22,6 +22,7 @@ unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
unsigned int pci_early_dump_regs;
static int pci_bf_sort;
+static int smbios_type_b1_flag;
int pci_routeirq;
int noioapicquirk;
#ifdef CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS
@@ -185,6 +186,39 @@ static int __devinit set_bf_sort(const struct dmi_system_id *d)
return 0;
}
+static void __devinit read_dmi_type_b1(const struct dmi_header *dm,
+ void *private_data)
+{
+ u8 *d = (u8 *)dm + 4;
+
+ if (dm->type != 0xB1)
+ return;
+ switch (((*(u32 *)d) >> 9) & 0x03) {
+ case 0x00:
+ printk(KERN_INFO "dmi type 0xB1 record - unknown flag\n");
+ break;
+ case 0x01: /* set pci=bfsort */
+ smbios_type_b1_flag = 1;
+ break;
+ case 0x02: /* do not set pci=bfsort */
+ smbios_type_b1_flag = 2;
+ break;
+ default:
+ break;
+ }
+}
+
+static int __devinit find_sort_method(const struct dmi_system_id *d)
+{
+ dmi_walk(read_dmi_type_b1, NULL);
+
+ if (smbios_type_b1_flag == 1) {
+ set_bf_sort(d);
+ return 0;
+ }
+ return -1;
+}
+
/*
* Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus)
*/
@@ -213,6 +247,13 @@ static const struct dmi_system_id __devinitconst pciprobe_dmi_table[] = {
},
#endif /* __i386__ */
{
+ .callback = find_sort_method,
+ .ident = "Dell System",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ },
+ },
+ {
.callback = set_bf_sort,
.ident = "Dell PowerEdge 1950",
.matches = {
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index 9f9bfb705cf9..87e6c8323117 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -589,7 +589,8 @@ static __init int intel_router_probe(struct irq_router *r, struct pci_dev *route
case PCI_DEVICE_ID_INTEL_ICH10_1:
case PCI_DEVICE_ID_INTEL_ICH10_2:
case PCI_DEVICE_ID_INTEL_ICH10_3:
- case PCI_DEVICE_ID_INTEL_PATSBURG_LPC:
+ case PCI_DEVICE_ID_INTEL_PATSBURG_LPC_0:
+ case PCI_DEVICE_ID_INTEL_PATSBURG_LPC_1:
r->name = "PIIX/ICH";
r->get = pirq_piix_get;
r->set = pirq_piix_set;
diff --git a/arch/x86/platform/olpc/olpc-xo1.c b/arch/x86/platform/olpc/olpc-xo1.c
index f5442c03abc3..127775696d6c 100644
--- a/arch/x86/platform/olpc/olpc-xo1.c
+++ b/arch/x86/platform/olpc/olpc-xo1.c
@@ -1,6 +1,7 @@
/*
* Support for features of the OLPC XO-1 laptop
*
+ * Copyright (C) 2010 Andres Salomon <[email protected]>
* Copyright (C) 2010 One Laptop per Child
* Copyright (C) 2006 Red Hat, Inc.
* Copyright (C) 2006 Advanced Micro Devices, Inc.
@@ -12,8 +13,6 @@
*/
#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/pci_ids.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
@@ -22,9 +21,6 @@
#define DRV_NAME "olpc-xo1"
-#define PMS_BAR 4
-#define ACPI_BAR 5
-
/* PMC registers (PMS block) */
#define PM_SCLK 0x10
#define PM_IN_SLPCTL 0x20
@@ -57,65 +53,67 @@ static void xo1_power_off(void)
outl(0x00002000, acpi_base + PM1_CNT);
}
-/* Read the base addresses from the PCI BAR info */
-static int __devinit setup_bases(struct pci_dev *pdev)
+static int __devinit olpc_xo1_probe(struct platform_device *pdev)
{
- int r;
+ struct resource *res;
- r = pci_enable_device_io(pdev);
- if (r) {
- dev_err(&pdev->dev, "can't enable device IO\n");
- return r;
- }
+ /* don't run on non-XOs */
+ if (!machine_is_olpc())
+ return -ENODEV;
- r = pci_request_region(pdev, ACPI_BAR, DRV_NAME);
- if (r) {
- dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", ACPI_BAR);
- return r;
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't fetch device resource info\n");
+ return -EIO;
}
- r = pci_request_region(pdev, PMS_BAR, DRV_NAME);
- if (r) {
- dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", PMS_BAR);
- pci_release_region(pdev, ACPI_BAR);
- return r;
+ if (!request_region(res->start, resource_size(res), DRV_NAME)) {
+ dev_err(&pdev->dev, "can't request region\n");
+ return -EIO;
}
- acpi_base = pci_resource_start(pdev, ACPI_BAR);
- pms_base = pci_resource_start(pdev, PMS_BAR);
+ if (strcmp(pdev->name, "cs5535-pms") == 0)
+ pms_base = res->start;
+ else if (strcmp(pdev->name, "cs5535-acpi") == 0)
+ acpi_base = res->start;
+
+ /* If we have both addresses, we can override the poweroff hook */
+ if (pms_base && acpi_base) {
+ pm_power_off = xo1_power_off;
+ printk(KERN_INFO "OLPC XO-1 support registered\n");
+ }
return 0;
}
-static int __devinit olpc_xo1_probe(struct platform_device *pdev)
+static int __devexit olpc_xo1_remove(struct platform_device *pdev)
{
- struct pci_dev *pcidev;
- int r;
-
- pcidev = pci_get_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA,
- NULL);
- if (!pdev)
- return -ENODEV;
-
- r = setup_bases(pcidev);
- if (r)
- return r;
+ struct resource *r;
- pm_power_off = xo1_power_off;
+ r = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ release_region(r->start, resource_size(r));
- printk(KERN_INFO "OLPC XO-1 support registered\n");
- return 0;
-}
+ if (strcmp(pdev->name, "cs5535-pms") == 0)
+ pms_base = 0;
+ else if (strcmp(pdev->name, "cs5535-acpi") == 0)
+ acpi_base = 0;
-static int __devexit olpc_xo1_remove(struct platform_device *pdev)
-{
pm_power_off = NULL;
return 0;
}
-static struct platform_driver olpc_xo1_driver = {
+static struct platform_driver cs5535_pms_drv = {
+ .driver = {
+ .name = "cs5535-pms",
+ .owner = THIS_MODULE,
+ },
+ .probe = olpc_xo1_probe,
+ .remove = __devexit_p(olpc_xo1_remove),
+};
+
+static struct platform_driver cs5535_acpi_drv = {
.driver = {
- .name = DRV_NAME,
+ .name = "cs5535-acpi",
.owner = THIS_MODULE,
},
.probe = olpc_xo1_probe,
@@ -124,12 +122,23 @@ static struct platform_driver olpc_xo1_driver = {
static int __init olpc_xo1_init(void)
{
- return platform_driver_register(&olpc_xo1_driver);
+ int r;
+
+ r = platform_driver_register(&cs5535_pms_drv);
+ if (r)
+ return r;
+
+ r = platform_driver_register(&cs5535_acpi_drv);
+ if (r)
+ platform_driver_unregister(&cs5535_pms_drv);
+
+ return r;
}
static void __exit olpc_xo1_exit(void)
{
- platform_driver_unregister(&olpc_xo1_driver);
+ platform_driver_unregister(&cs5535_acpi_drv);
+ platform_driver_unregister(&cs5535_pms_drv);
}
MODULE_AUTHOR("Daniel Drake <[email protected]>");
diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c
index daa7bc63f1d4..4ee58e72b730 100644
--- a/drivers/acpi/apei/hest.c
+++ b/drivers/acpi/apei/hest.c
@@ -195,24 +195,24 @@ static int __init setup_hest_disable(char *str)
__setup("hest_disable", setup_hest_disable);
-static int __init hest_init(void)
+void __init acpi_hest_init(void)
{
acpi_status status;
int rc = -ENODEV;
unsigned int ghes_count = 0;
if (acpi_disabled)
- goto err;
+ return;
if (hest_disable) {
- pr_info(HEST_PFX "HEST tabling parsing is disabled.\n");
- goto err;
+ pr_info(HEST_PFX "Table parsing disabled.\n");
+ return;
}
status = acpi_get_table(ACPI_SIG_HEST, 0,
(struct acpi_table_header **)&hest_tab);
if (status == AE_NOT_FOUND) {
- pr_info(HEST_PFX "Table is not found!\n");
+ pr_info(HEST_PFX "Table not found.\n");
goto err;
} else if (ACPI_FAILURE(status)) {
const char *msg = acpi_format_exception(status);
@@ -226,15 +226,11 @@ static int __init hest_init(void)
goto err;
rc = hest_ghes_dev_register(ghes_count);
- if (rc)
- goto err;
-
- pr_info(HEST_PFX "HEST table parsing is initialized.\n");
+ if (!rc) {
+ pr_info(HEST_PFX "Table parsing has been initialized.\n");
+ return;
+ }
- return 0;
err:
hest_disable = 1;
- return rc;
}
-
-subsys_initcall(hest_init);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 96668ad09622..d9766797cd98 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -36,6 +36,7 @@
#include <linux/slab.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#include <acpi/apei.h>
#define PREFIX "ACPI: "
@@ -47,6 +48,11 @@ static int acpi_pci_root_add(struct acpi_device *device);
static int acpi_pci_root_remove(struct acpi_device *device, int type);
static int acpi_pci_root_start(struct acpi_device *device);
+#define ACPI_PCIE_REQ_SUPPORT (OSC_EXT_PCI_CONFIG_SUPPORT \
+ | OSC_ACTIVE_STATE_PWR_SUPPORT \
+ | OSC_CLOCK_PWR_CAPABILITY_SUPPORT \
+ | OSC_MSI_SUPPORT)
+
static const struct acpi_device_id root_device_ids[] = {
{"PNP0A03", 0},
{"", 0},
@@ -566,6 +572,33 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
if (flags != base_flags)
acpi_pci_osc_support(root, flags);
+ if (!pcie_ports_disabled
+ && (flags & ACPI_PCIE_REQ_SUPPORT) == ACPI_PCIE_REQ_SUPPORT) {
+ flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL
+ | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL
+ | OSC_PCI_EXPRESS_PME_CONTROL;
+
+ if (pci_aer_available()) {
+ if (aer_acpi_firmware_first())
+ dev_dbg(root->bus->bridge,
+ "PCIe errors handled by BIOS.\n");
+ else
+ flags |= OSC_PCI_EXPRESS_AER_CONTROL;
+ }
+
+ dev_info(root->bus->bridge,
+ "Requesting ACPI _OSC control (0x%02x)\n", flags);
+
+ status = acpi_pci_osc_control_set(device->handle, &flags,
+ OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
+ if (ACPI_SUCCESS(status))
+ dev_info(root->bus->bridge,
+ "ACPI _OSC control (0x%02x) granted\n", flags);
+ else
+ dev_dbg(root->bus->bridge,
+ "ACPI _OSC request failed (code %d)\n", status);
+ }
+
pci_acpi_add_bus_pm_notifier(device, root->bus);
if (device->wakeup.flags.run_wake)
device_set_run_wake(root->bus->bridge, true);
@@ -603,6 +636,8 @@ static int __init acpi_pci_root_init(void)
if (acpi_pci_disabled)
return 0;
+ acpi_hest_init();
+
pci_acpi_crs_quirks();
if (acpi_bus_register_driver(&acpi_pci_root_driver) < 0)
return -ENODEV;
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 07e9796fead7..857df10c0428 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -717,8 +717,8 @@ static const struct intel_agp_driver_description {
{ PCI_DEVICE_ID_INTEL_82820_UP_HB, "i820", &intel_820_driver },
{ PCI_DEVICE_ID_INTEL_82830_HB, "830M", &intel_830mp_driver },
{ PCI_DEVICE_ID_INTEL_82840_HB, "i840", &intel_840_driver },
- { PCI_DEVICE_ID_INTEL_82845_HB, "845G", &intel_845_driver },
- { PCI_DEVICE_ID_INTEL_82845G_HB, "830M", &intel_845_driver },
+ { PCI_DEVICE_ID_INTEL_82845_HB, "i845", &intel_845_driver },
+ { PCI_DEVICE_ID_INTEL_82845G_HB, "845G", &intel_845_driver },
{ PCI_DEVICE_ID_INTEL_82850_HB, "i850", &intel_850_driver },
{ PCI_DEVICE_ID_INTEL_82854_HB, "854", &intel_845_driver },
{ PCI_DEVICE_ID_INTEL_82855PM_HB, "855PM", &intel_845_driver },
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index e921b693412b..826ab0939a12 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -1361,7 +1361,7 @@ static const struct intel_gtt_driver_description {
&i81x_gtt_driver},
{ PCI_DEVICE_ID_INTEL_82830_CGC, "830M",
&i8xx_gtt_driver},
- { PCI_DEVICE_ID_INTEL_82845G_IG, "830M",
+ { PCI_DEVICE_ID_INTEL_82845G_IG, "845G",
&i8xx_gtt_driver},
{ PCI_DEVICE_ID_INTEL_82854_IG, "854",
&i8xx_gtt_driver},
diff --git a/drivers/gpio/cs5535-gpio.c b/drivers/gpio/cs5535-gpio.c
index 815d98b2c1ba..0d05ea7d499b 100644
--- a/drivers/gpio/cs5535-gpio.c
+++ b/drivers/gpio/cs5535-gpio.c
@@ -11,14 +11,13 @@
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/module.h>
-#include <linux/pci.h>
+#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/cs5535.h>
#include <asm/msr.h>
#define DRV_NAME "cs5535-gpio"
-#define GPIO_BAR 1
/*
* Some GPIO pins
@@ -47,7 +46,7 @@ static struct cs5535_gpio_chip {
struct gpio_chip chip;
resource_size_t base;
- struct pci_dev *pdev;
+ struct platform_device *pdev;
spinlock_t lock;
} cs5535_gpio_chip;
@@ -301,10 +300,10 @@ static struct cs5535_gpio_chip cs5535_gpio_chip = {
},
};
-static int __init cs5535_gpio_probe(struct pci_dev *pdev,
- const struct pci_device_id *pci_id)
+static int __devinit cs5535_gpio_probe(struct platform_device *pdev)
{
- int err;
+ struct resource *res;
+ int err = -EIO;
ulong mask_orig = mask;
/* There are two ways to get the GPIO base address; one is by
@@ -314,25 +313,23 @@ static int __init cs5535_gpio_probe(struct pci_dev *pdev,
* it turns out to be unreliable in the face of crappy BIOSes, we
* can always go back to using MSRs.. */
- err = pci_enable_device_io(pdev);
- if (err) {
- dev_err(&pdev->dev, "can't enable device IO\n");
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't fetch device resource info\n");
goto done;
}
- err = pci_request_region(pdev, GPIO_BAR, DRV_NAME);
- if (err) {
- dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", GPIO_BAR);
+ if (!request_region(res->start, resource_size(res), pdev->name)) {
+ dev_err(&pdev->dev, "can't request region\n");
goto done;
}
/* set up the driver-specific struct */
- cs5535_gpio_chip.base = pci_resource_start(pdev, GPIO_BAR);
+ cs5535_gpio_chip.base = res->start;
cs5535_gpio_chip.pdev = pdev;
spin_lock_init(&cs5535_gpio_chip.lock);
- dev_info(&pdev->dev, "allocated PCI BAR #%d: base 0x%llx\n", GPIO_BAR,
- (unsigned long long) cs5535_gpio_chip.base);
+ dev_info(&pdev->dev, "reserved resource region %pR\n", res);
/* mask out reserved pins */
mask &= 0x1F7FFFFF;
@@ -350,78 +347,49 @@ static int __init cs5535_gpio_probe(struct pci_dev *pdev,
if (err)
goto release_region;
- dev_info(&pdev->dev, DRV_NAME ": GPIO support successfully loaded.\n");
+ dev_info(&pdev->dev, "GPIO support successfully loaded.\n");
return 0;
release_region:
- pci_release_region(pdev, GPIO_BAR);
+ release_region(res->start, resource_size(res));
done:
return err;
}
-static void __exit cs5535_gpio_remove(struct pci_dev *pdev)
+static int __devexit cs5535_gpio_remove(struct platform_device *pdev)
{
+ struct resource *r;
int err;
err = gpiochip_remove(&cs5535_gpio_chip.chip);
if (err) {
/* uhh? */
dev_err(&pdev->dev, "unable to remove gpio_chip?\n");
+ return err;
}
- pci_release_region(pdev, GPIO_BAR);
-}
-
-static struct pci_device_id cs5535_gpio_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
- { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, cs5535_gpio_pci_tbl);
-/*
- * We can't use the standard PCI driver registration stuff here, since
- * that allows only one driver to bind to each PCI device (and we want
- * multiple drivers to be able to bind to the device). Instead, manually
- * scan for the PCI device, request a single region, and keep track of the
- * devices that we're using.
- */
-
-static int __init cs5535_gpio_scan_pci(void)
-{
- struct pci_dev *pdev;
- int err = -ENODEV;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(cs5535_gpio_pci_tbl); i++) {
- pdev = pci_get_device(cs5535_gpio_pci_tbl[i].vendor,
- cs5535_gpio_pci_tbl[i].device, NULL);
- if (pdev) {
- err = cs5535_gpio_probe(pdev, &cs5535_gpio_pci_tbl[i]);
- if (err)
- pci_dev_put(pdev);
-
- /* we only support a single CS5535/6 southbridge */
- break;
- }
- }
-
- return err;
+ r = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ release_region(r->start, resource_size(r));
+ return 0;
}
-static void __exit cs5535_gpio_free_pci(void)
-{
- cs5535_gpio_remove(cs5535_gpio_chip.pdev);
- pci_dev_put(cs5535_gpio_chip.pdev);
-}
+static struct platform_driver cs5535_gpio_drv = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = cs5535_gpio_probe,
+ .remove = __devexit_p(cs5535_gpio_remove),
+};
static int __init cs5535_gpio_init(void)
{
- return cs5535_gpio_scan_pci();
+ return platform_driver_register(&cs5535_gpio_drv);
}
static void __exit cs5535_gpio_exit(void)
{
- cs5535_gpio_free_pci();
+ platform_driver_unregister(&cs5535_gpio_drv);
}
module_init(cs5535_gpio_init);
@@ -430,3 +398,4 @@ module_exit(cs5535_gpio_exit);
MODULE_AUTHOR("Andres Salomon <[email protected]>");
MODULE_DESCRIPTION("AMD CS5535/CS5536 GPIO driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/gpio/timbgpio.c b/drivers/gpio/timbgpio.c
index 349131eb1ce0..58c8f30352dd 100644
--- a/drivers/gpio/timbgpio.c
+++ b/drivers/gpio/timbgpio.c
@@ -193,13 +193,13 @@ out:
return ret;
}
-static void timbgpio_irq(struct irq_data *d, struct irq_desc *desc)
+static void timbgpio_irq(unsigned int irq, struct irq_desc *desc)
{
- struct timbgpio *tgpio = irq_data_get_irq_data(d);
+ struct timbgpio *tgpio = get_irq_data(irq);
unsigned long ipr;
int offset;
- desc->irq_data.chip->ack(irq_get_irq_data(d));
+ desc->irq_data.chip->irq_ack(irq_get_irq_data(irq));
ipr = ioread32(tgpio->membase + TGPIO_IPR);
iowrite32(ipr, tgpio->membase + TGPIO_ICR);
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 19a3d58044dd..3601466c5502 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -703,7 +703,7 @@ static void print_error_buffers(struct seq_file *m,
seq_printf(m, "%s [%d]:\n", name, count);
while (count--) {
- seq_printf(m, " %08x %8zd %04x %04x %08x%s%s%s%s%s%s",
+ seq_printf(m, " %08x %8u %04x %04x %08x%s%s%s%s%s%s",
err->gtt_offset,
err->size,
err->read_domains,
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 0de75a23f8e7..72fea2bcfc4f 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -49,6 +49,9 @@ module_param_named(powersave, i915_powersave, int, 0600);
unsigned int i915_lvds_downclock = 0;
module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
+unsigned int i915_panel_use_ssc = 1;
+module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600);
+
bool i915_try_reset = true;
module_param_named(reset, i915_try_reset, bool, 0600);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 385fc7ec39d3..5969f46ac2d6 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -954,6 +954,7 @@ extern int i915_max_ioctl;
extern unsigned int i915_fbpercrtc;
extern unsigned int i915_powersave;
extern unsigned int i915_lvds_downclock;
+extern unsigned int i915_panel_use_ssc;
extern int i915_suspend(struct drm_device *dev, pm_message_t state);
extern int i915_resume(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index e69834341ef0..dcfdf4151b6d 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -464,8 +464,6 @@ i915_gem_execbuffer_relocate(struct drm_device *dev,
int ret;
list_for_each_entry(obj, objects, exec_list) {
- obj->base.pending_read_domains = 0;
- obj->base.pending_write_domain = 0;
ret = i915_gem_execbuffer_relocate_object(obj, eb);
if (ret)
return ret;
@@ -505,6 +503,9 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
list_move(&obj->exec_list, &ordered_objects);
else
list_move_tail(&obj->exec_list, &ordered_objects);
+
+ obj->base.pending_read_domains = 0;
+ obj->base.pending_write_domain = 0;
}
list_splice(&ordered_objects, objects);
@@ -636,6 +637,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
{
struct drm_i915_gem_relocation_entry *reloc;
struct drm_i915_gem_object *obj;
+ int *reloc_offset;
int i, total, ret;
/* We may process another execbuffer during the unlock... */
@@ -653,8 +655,11 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
for (i = 0; i < count; i++)
total += exec[i].relocation_count;
+ reloc_offset = drm_malloc_ab(count, sizeof(*reloc_offset));
reloc = drm_malloc_ab(total, sizeof(*reloc));
- if (reloc == NULL) {
+ if (reloc == NULL || reloc_offset == NULL) {
+ drm_free_large(reloc);
+ drm_free_large(reloc_offset);
mutex_lock(&dev->struct_mutex);
return -ENOMEM;
}
@@ -672,6 +677,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
goto err;
}
+ reloc_offset[i] = total;
total += exec[i].relocation_count;
}
@@ -705,17 +711,12 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
if (ret)
goto err;
- total = 0;
list_for_each_entry(obj, objects, exec_list) {
- obj->base.pending_read_domains = 0;
- obj->base.pending_write_domain = 0;
+ int offset = obj->exec_entry - exec;
ret = i915_gem_execbuffer_relocate_object_slow(obj, eb,
- reloc + total);
+ reloc + reloc_offset[offset]);
if (ret)
goto err;
-
- total += exec->relocation_count;
- exec++;
}
/* Leave the user relocations as are, this is the painfully slow path,
@@ -726,6 +727,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
err:
drm_free_large(reloc);
+ drm_free_large(reloc_offset);
return ret;
}
@@ -770,7 +772,8 @@ i915_gem_execbuffer_sync_rings(struct drm_i915_gem_object *obj,
if (from == NULL || to == from)
return 0;
- if (INTEL_INFO(obj->base.dev)->gen < 6)
+ /* XXX gpu semaphores are currently causing hard hangs on SNB mobile */
+ if (INTEL_INFO(obj->base.dev)->gen < 6 || IS_MOBILE(obj->base.dev))
return i915_gem_object_wait_rendering(obj, true);
idx = intel_ring_sync_index(from, to);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index e418e8bb61e6..b8e509ae065e 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -720,7 +720,7 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv,
if (obj->ring != ring)
continue;
- if (!i915_seqno_passed(obj->last_rendering_seqno, seqno))
+ if (i915_seqno_passed(seqno, obj->last_rendering_seqno))
continue;
if ((obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) == 0)
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index b0b1200ed650..0b44956c336b 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -264,17 +264,12 @@ parse_general_features(struct drm_i915_private *dev_priv,
dev_priv->int_crt_support = general->int_crt_support;
dev_priv->lvds_use_ssc = general->enable_ssc;
- if (dev_priv->lvds_use_ssc) {
- if (IS_I85X(dev))
- dev_priv->lvds_ssc_freq =
- general->ssc_freq ? 66 : 48;
- else if (IS_GEN5(dev) || IS_GEN6(dev))
- dev_priv->lvds_ssc_freq =
- general->ssc_freq ? 100 : 120;
- else
- dev_priv->lvds_ssc_freq =
- general->ssc_freq ? 100 : 96;
- }
+ if (IS_I85X(dev))
+ dev_priv->lvds_ssc_freq = general->ssc_freq ? 66 : 48;
+ else if (IS_GEN5(dev) || IS_GEN6(dev))
+ dev_priv->lvds_ssc_freq = general->ssc_freq ? 100 : 120;
+ else
+ dev_priv->lvds_ssc_freq = general->ssc_freq ? 100 : 96;
}
}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 25d96889d7d2..98967f3b7724 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3822,6 +3822,11 @@ static void intel_update_watermarks(struct drm_device *dev)
sr_hdisplay, sr_htotal, pixel_size);
}
+static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
+{
+ return dev_priv->lvds_use_ssc && i915_panel_use_ssc;
+}
+
static int intel_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
@@ -3884,7 +3889,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
num_connectors++;
}
- if (is_lvds && dev_priv->lvds_use_ssc && num_connectors < 2) {
+ if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
refclk = dev_priv->lvds_ssc_freq * 1000;
DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
refclk / 1000);
@@ -4059,7 +4064,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
udelay(200);
if (has_edp_encoder) {
- if (dev_priv->lvds_use_ssc) {
+ if (intel_panel_use_ssc(dev_priv)) {
temp |= DREF_SSC1_ENABLE;
I915_WRITE(PCH_DREF_CONTROL, temp);
@@ -4070,13 +4075,13 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* Enable CPU source on CPU attached eDP */
if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
- if (dev_priv->lvds_use_ssc)
+ if (intel_panel_use_ssc(dev_priv))
temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
else
temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
} else {
/* Enable SSC on PCH eDP if needed */
- if (dev_priv->lvds_use_ssc) {
+ if (intel_panel_use_ssc(dev_priv)) {
DRM_ERROR("enabling SSC on PCH\n");
temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
}
@@ -4104,7 +4109,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
int factor = 21;
if (is_lvds) {
- if ((dev_priv->lvds_use_ssc &&
+ if ((intel_panel_use_ssc(dev_priv) &&
dev_priv->lvds_ssc_freq == 100) ||
(I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP)
factor = 25;
@@ -4183,7 +4188,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* XXX: just matching BIOS for now */
/* dpll |= PLL_REF_INPUT_TVCLKINBC; */
dpll |= 3;
- else if (is_lvds && dev_priv->lvds_use_ssc && num_connectors < 2)
+ else if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2)
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
else
dpll |= PLL_REF_INPUT_DREFCLK;
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 8f4f6bd33ee9..ace8d5d30dd2 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -704,6 +704,14 @@ static const struct dmi_system_id intel_no_lvds[] = {
},
{
.callback = intel_no_lvds_dmi_callback,
+ .ident = "AOpen i915GMm-HFS",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
+ DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
+ },
+ },
+ {
+ .callback = intel_no_lvds_dmi_callback,
.ident = "Aopen i945GTt-VFA",
.matches = {
DMI_MATCH(DMI_PRODUCT_VERSION, "AO00001JW"),
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index e00d200df3db..c65992df458d 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -278,6 +278,6 @@ void intel_panel_setup_backlight(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
+ dev_priv->backlight_level = intel_panel_get_backlight(dev);
dev_priv->backlight_enabled = dev_priv->backlight_level != 0;
}
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index 53fab518b3da..986e5f62debe 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -29,6 +29,7 @@
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/pci.h>
+#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/slab.h>
@@ -40,6 +41,7 @@
MODULE_AUTHOR("Christer Weinigel <[email protected]>");
MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver");
+MODULE_ALIAS("platform:cs5535-smb");
MODULE_LICENSE("GPL");
#define MAX_DEVICES 4
@@ -84,10 +86,6 @@ struct scx200_acb_iface {
u8 *ptr;
char needs_reset;
unsigned len;
-
- /* PCI device info */
- struct pci_dev *pdev;
- int bar;
};
/* Register Definitions */
@@ -391,7 +389,7 @@ static const struct i2c_algorithm scx200_acb_algorithm = {
static struct scx200_acb_iface *scx200_acb_list;
static DEFINE_MUTEX(scx200_acb_list_mutex);
-static __init int scx200_acb_probe(struct scx200_acb_iface *iface)
+static __devinit int scx200_acb_probe(struct scx200_acb_iface *iface)
{
u8 val;
@@ -427,7 +425,7 @@ static __init int scx200_acb_probe(struct scx200_acb_iface *iface)
return 0;
}
-static __init struct scx200_acb_iface *scx200_create_iface(const char *text,
+static __devinit struct scx200_acb_iface *scx200_create_iface(const char *text,
struct device *dev, int index)
{
struct scx200_acb_iface *iface;
@@ -452,7 +450,7 @@ static __init struct scx200_acb_iface *scx200_create_iface(const char *text,
return iface;
}
-static int __init scx200_acb_create(struct scx200_acb_iface *iface)
+static int __devinit scx200_acb_create(struct scx200_acb_iface *iface)
{
struct i2c_adapter *adapter;
int rc;
@@ -472,183 +470,145 @@ static int __init scx200_acb_create(struct scx200_acb_iface *iface)
return -ENODEV;
}
- mutex_lock(&scx200_acb_list_mutex);
- iface->next = scx200_acb_list;
- scx200_acb_list = iface;
- mutex_unlock(&scx200_acb_list_mutex);
+ if (!adapter->dev.parent) {
+ /* If there's no dev, we're tracking (ISA) ifaces manually */
+ mutex_lock(&scx200_acb_list_mutex);
+ iface->next = scx200_acb_list;
+ scx200_acb_list = iface;
+ mutex_unlock(&scx200_acb_list_mutex);
+ }
return 0;
}
-static __init int scx200_create_pci(const char *text, struct pci_dev *pdev,
- int bar)
+static struct scx200_acb_iface * __devinit scx200_create_dev(const char *text,
+ unsigned long base, int index, struct device *dev)
{
struct scx200_acb_iface *iface;
int rc;
- iface = scx200_create_iface(text, &pdev->dev, 0);
+ iface = scx200_create_iface(text, dev, index);
if (iface == NULL)
- return -ENOMEM;
-
- iface->pdev = pdev;
- iface->bar = bar;
-
- rc = pci_enable_device_io(iface->pdev);
- if (rc)
- goto errout_free;
+ return NULL;
- rc = pci_request_region(iface->pdev, iface->bar, iface->adapter.name);
- if (rc) {
- printk(KERN_ERR NAME ": can't allocate PCI BAR %d\n",
- iface->bar);
+ if (!request_region(base, 8, iface->adapter.name)) {
+ printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n",
+ base, base + 8 - 1);
goto errout_free;
}
- iface->base = pci_resource_start(iface->pdev, iface->bar);
+ iface->base = base;
rc = scx200_acb_create(iface);
if (rc == 0)
- return 0;
+ return iface;
- pci_release_region(iface->pdev, iface->bar);
- pci_dev_put(iface->pdev);
+ release_region(base, 8);
errout_free:
kfree(iface);
- return rc;
+ return NULL;
}
-static int __init scx200_create_isa(const char *text, unsigned long base,
- int index)
+static int __devinit scx200_probe(struct platform_device *pdev)
{
struct scx200_acb_iface *iface;
- int rc;
-
- iface = scx200_create_iface(text, NULL, index);
-
- if (iface == NULL)
- return -ENOMEM;
+ struct resource *res;
- if (!request_region(base, 8, iface->adapter.name)) {
- printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n",
- base, base + 8 - 1);
- rc = -EBUSY;
- goto errout_free;
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't fetch device resource info\n");
+ return -ENODEV;
}
- iface->base = base;
- rc = scx200_acb_create(iface);
+ iface = scx200_create_dev("CS5535", res->start, 0, &pdev->dev);
+ if (!iface)
+ return -EIO;
- if (rc == 0)
- return 0;
+ dev_info(&pdev->dev, "SCx200 device '%s' registered\n",
+ iface->adapter.name);
+ platform_set_drvdata(pdev, iface);
- release_region(base, 8);
- errout_free:
- kfree(iface);
- return rc;
+ return 0;
}
-/* Driver data is an index into the scx200_data array that indicates
- * the name and the BAR where the I/O address resource is located. ISA
- * devices are flagged with a bar value of -1 */
-
-static const struct pci_device_id scx200_pci[] __initconst = {
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE),
- .driver_data = 0 },
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE),
- .driver_data = 0 },
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA),
- .driver_data = 1 },
- { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA),
- .driver_data = 2 },
- { 0, }
-};
-
-static struct {
- const char *name;
- int bar;
-} scx200_data[] = {
- { "SCx200", -1 },
- { "CS5535", 0 },
- { "CS5536", 0 }
-};
+static void __devexit scx200_cleanup_iface(struct scx200_acb_iface *iface)
+{
+ i2c_del_adapter(&iface->adapter);
+ release_region(iface->base, 8);
+ kfree(iface);
+}
-static __init int scx200_scan_pci(void)
+static int __devexit scx200_remove(struct platform_device *pdev)
{
- int data, dev;
- int rc = -ENODEV;
- struct pci_dev *pdev;
+ struct scx200_acb_iface *iface;
- for(dev = 0; dev < ARRAY_SIZE(scx200_pci); dev++) {
- pdev = pci_get_device(scx200_pci[dev].vendor,
- scx200_pci[dev].device, NULL);
+ iface = platform_get_drvdata(pdev);
+ platform_set_drvdata(pdev, NULL);
+ scx200_cleanup_iface(iface);
- if (pdev == NULL)
- continue;
+ return 0;
+}
- data = scx200_pci[dev].driver_data;
+static struct platform_driver scx200_pci_drv = {
+ .driver = {
+ .name = "cs5535-smb",
+ .owner = THIS_MODULE,
+ },
+ .probe = scx200_probe,
+ .remove = __devexit_p(scx200_remove),
+};
- /* if .bar is greater or equal to zero, this is a
- * PCI device - otherwise, we assume
- that the ports are ISA based
- */
+static const struct pci_device_id scx200_isa[] __initconst = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
+ { 0, }
+};
- if (scx200_data[data].bar >= 0)
- rc = scx200_create_pci(scx200_data[data].name, pdev,
- scx200_data[data].bar);
- else {
- int i;
+static __init void scx200_scan_isa(void)
+{
+ int i;
- pci_dev_put(pdev);
- for (i = 0; i < MAX_DEVICES; ++i) {
- if (base[i] == 0)
- continue;
+ if (!pci_dev_present(scx200_isa))
+ return;
- rc = scx200_create_isa(scx200_data[data].name,
- base[i],
- i);
- }
- }
+ for (i = 0; i < MAX_DEVICES; ++i) {
+ if (base[i] == 0)
+ continue;
- break;
+ /* XXX: should we care about failures? */
+ scx200_create_dev("SCx200", base[i], i, NULL);
}
-
- return rc;
}
static int __init scx200_acb_init(void)
{
- int rc;
-
pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
- rc = scx200_scan_pci();
+ /* First scan for ISA-based devices */
+ scx200_scan_isa(); /* XXX: should we care about errors? */
/* If at least one bus was created, init must succeed */
if (scx200_acb_list)
return 0;
- return rc;
+
+ /* No ISA devices; register the platform driver for PCI-based devices */
+ return platform_driver_register(&scx200_pci_drv);
}
static void __exit scx200_acb_cleanup(void)
{
struct scx200_acb_iface *iface;
+ platform_driver_unregister(&scx200_pci_drv);
+
mutex_lock(&scx200_acb_list_mutex);
while ((iface = scx200_acb_list) != NULL) {
scx200_acb_list = iface->next;
mutex_unlock(&scx200_acb_list_mutex);
- i2c_del_adapter(&iface->adapter);
-
- if (iface->pdev) {
- pci_release_region(iface->pdev, iface->bar);
- pci_dev_put(iface->pdev);
- }
- else
- release_region(iface->base, 8);
+ scx200_cleanup_iface(iface);
- kfree(iface);
mutex_lock(&scx200_acb_list_mutex);
}
mutex_unlock(&scx200_acb_list_mutex);
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index 789087cd6a9c..49f1b8f1418e 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -2184,9 +2184,7 @@ static int cafe_pci_resume(struct pci_dev *pdev)
struct cafe_camera *cam = to_cam(v4l2_dev);
int ret = 0;
- ret = pci_restore_state(pdev);
- if (ret)
- return ret;
+ pci_restore_state(pdev);
ret = pci_enable_device(pdev);
if (ret) {
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index 20895e7a99c9..793300c554b4 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -361,12 +361,6 @@ static struct pm860x_irq_data pm860x_irqs[] = {
},
};
-static inline struct pm860x_irq_data *irq_to_pm860x(struct pm860x_chip *chip,
- int irq)
-{
- return &pm860x_irqs[irq - chip->irq_base];
-}
-
static irqreturn_t pm860x_irq(int irq, void *data)
{
struct pm860x_chip *chip = data;
@@ -388,16 +382,16 @@ static irqreturn_t pm860x_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static void pm860x_irq_lock(unsigned int irq)
+static void pm860x_irq_lock(struct irq_data *data)
{
- struct pm860x_chip *chip = get_irq_chip_data(irq);
+ struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
mutex_lock(&chip->irq_lock);
}
-static void pm860x_irq_sync_unlock(unsigned int irq)
+static void pm860x_irq_sync_unlock(struct irq_data *data)
{
- struct pm860x_chip *chip = get_irq_chip_data(irq);
+ struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
struct pm860x_irq_data *irq_data;
struct i2c_client *i2c;
static unsigned char cached[3] = {0x0, 0x0, 0x0};
@@ -439,25 +433,25 @@ static void pm860x_irq_sync_unlock(unsigned int irq)
mutex_unlock(&chip->irq_lock);
}
-static void pm860x_irq_enable(unsigned int irq)
+static void pm860x_irq_enable(struct irq_data *data)
{
- struct pm860x_chip *chip = get_irq_chip_data(irq);
- pm860x_irqs[irq - chip->irq_base].enable
- = pm860x_irqs[irq - chip->irq_base].offs;
+ struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
+ pm860x_irqs[data->irq - chip->irq_base].enable
+ = pm860x_irqs[data->irq - chip->irq_base].offs;
}
-static void pm860x_irq_disable(unsigned int irq)
+static void pm860x_irq_disable(struct irq_data *data)
{
- struct pm860x_chip *chip = get_irq_chip_data(irq);
- pm860x_irqs[irq - chip->irq_base].enable = 0;
+ struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
+ pm860x_irqs[data->irq - chip->irq_base].enable = 0;
}
static struct irq_chip pm860x_irq_chip = {
.name = "88pm860x",
- .bus_lock = pm860x_irq_lock,
- .bus_sync_unlock = pm860x_irq_sync_unlock,
- .enable = pm860x_irq_enable,
- .disable = pm860x_irq_disable,
+ .irq_bus_lock = pm860x_irq_lock,
+ .irq_bus_sync_unlock = pm860x_irq_sync_unlock,
+ .irq_enable = pm860x_irq_enable,
+ .irq_disable = pm860x_irq_disable,
};
static int __devinit device_gpadc_init(struct pm860x_chip *chip,
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index da9d2971102e..fd018366d670 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -496,13 +496,13 @@ config EZX_PCAP
config AB8500_CORE
bool "ST-Ericsson AB8500 Mixed Signal Power Management chip"
- depends on GENERIC_HARDIRQS && ABX500_CORE && SPI_MASTER && ARCH_U8500
+ depends on GENERIC_HARDIRQS && ABX500_CORE
select MFD_CORE
help
Select this option to enable access to AB8500 power management
- chip. This connects to U8500 either on the SSP/SPI bus
- or the I2C bus via PRCMU. It also adds the irq_chip
- parts for handling the Mixed Signal chip events.
+ chip. This connects to U8500 either on the SSP/SPI bus (deprecated
+ since hardware version v1.0) or the I2C bus via PRCMU. It also adds
+ the irq_chip parts for handling the Mixed Signal chip events.
This chip embeds various other multimedia funtionalities as well.
config AB8500_I2C_CORE
@@ -537,6 +537,14 @@ config AB3550_CORE
LEDs, vibrator, system power and temperature, power management
and ALSA sound.
+config MFD_CS5535
+ tristate "Support for CS5535 and CS5536 southbridge core functions"
+ select MFD_CORE
+ depends on PCI
+ ---help---
+ This is the core driver for CS5535/CS5536 MFD functions. This is
+ necessary for using the board's GPIO and MFGPT functionality.
+
config MFD_TIMBERDALE
tristate "Support for the Timberdale FPGA"
select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 848e7eac75aa..a54e2c7c6a1c 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -70,7 +70,7 @@ obj-$(CONFIG_ABX500_CORE) += abx500-core.o
obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
obj-$(CONFIG_AB3550_CORE) += ab3550-core.o
-obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-spi.o
+obj-$(CONFIG_AB8500_CORE) += ab8500-core.o
obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o
obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o
obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
@@ -82,3 +82,4 @@ obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o
obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o
obj-$(CONFIG_MFD_VX855) += vx855.o
obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o
+obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
diff --git a/drivers/mfd/ab3550-core.c b/drivers/mfd/ab3550-core.c
index 8a98739e6d9c..5fbca346b998 100644
--- a/drivers/mfd/ab3550-core.c
+++ b/drivers/mfd/ab3550-core.c
@@ -1159,15 +1159,16 @@ static void ab3550_mask_work(struct work_struct *work)
}
}
-static void ab3550_mask(unsigned int irq)
+static void ab3550_mask(struct irq_data *data)
{
unsigned long flags;
struct ab3550 *ab;
struct ab3550_platform_data *plf_data;
+ int irq;
- ab = get_irq_chip_data(irq);
+ ab = irq_data_get_irq_chip_data(data);
plf_data = ab->i2c_client[0]->dev.platform_data;
- irq -= plf_data->irq.base;
+ irq = data->irq - plf_data->irq.base;
spin_lock_irqsave(&ab->event_lock, flags);
ab->event_mask[irq / 8] |= BIT(irq % 8);
@@ -1176,15 +1177,16 @@ static void ab3550_mask(unsigned int irq)
schedule_work(&ab->mask_work);
}
-static void ab3550_unmask(unsigned int irq)
+static void ab3550_unmask(struct irq_data *data)
{
unsigned long flags;
struct ab3550 *ab;
struct ab3550_platform_data *plf_data;
+ int irq;
- ab = get_irq_chip_data(irq);
+ ab = irq_data_get_irq_chip_data(data);
plf_data = ab->i2c_client[0]->dev.platform_data;
- irq -= plf_data->irq.base;
+ irq = data->irq - plf_data->irq.base;
spin_lock_irqsave(&ab->event_lock, flags);
ab->event_mask[irq / 8] &= ~BIT(irq % 8);
@@ -1193,20 +1195,16 @@ static void ab3550_unmask(unsigned int irq)
schedule_work(&ab->mask_work);
}
-static void noop(unsigned int irq)
+static void noop(struct irq_data *data)
{
}
static struct irq_chip ab3550_irq_chip = {
.name = "ab3550-core", /* Keep the same name as the request */
- .startup = NULL, /* defaults to enable */
- .shutdown = NULL, /* defaults to disable */
- .enable = NULL, /* defaults to unmask */
- .disable = ab3550_mask, /* No default to mask in chip.c */
- .ack = noop,
- .mask = ab3550_mask,
- .unmask = ab3550_unmask,
- .end = NULL,
+ .irq_disable = ab3550_mask, /* No default to mask in chip.c */
+ .irq_ack = noop,
+ .irq_mask = ab3550_mask,
+ .irq_unmask = ab3550_unmask,
};
struct ab_family_id {
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index d9640a623ff4..b6887014d687 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -52,6 +52,7 @@
#define AB8500_IT_LATCH8_REG 0x27
#define AB8500_IT_LATCH9_REG 0x28
#define AB8500_IT_LATCH10_REG 0x29
+#define AB8500_IT_LATCH12_REG 0x2B
#define AB8500_IT_LATCH19_REG 0x32
#define AB8500_IT_LATCH20_REG 0x33
#define AB8500_IT_LATCH21_REG 0x34
@@ -98,13 +99,17 @@
* offset 0.
*/
static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
- 0, 1, 2, 3, 4, 6, 7, 8, 9, 18, 19, 20, 21,
+ 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
};
static int ab8500_get_chip_id(struct device *dev)
{
- struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
- return (int)ab8500->chip_id;
+ struct ab8500 *ab8500;
+
+ if (!dev)
+ return -EINVAL;
+ ab8500 = dev_get_drvdata(dev->parent);
+ return ab8500 ? (int)ab8500->chip_id : -EINVAL;
}
static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
@@ -228,16 +233,16 @@ static struct abx500_ops ab8500_ops = {
.startup_irq_enabled = NULL,
};
-static void ab8500_irq_lock(unsigned int irq)
+static void ab8500_irq_lock(struct irq_data *data)
{
- struct ab8500 *ab8500 = get_irq_chip_data(irq);
+ struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
mutex_lock(&ab8500->irq_lock);
}
-static void ab8500_irq_sync_unlock(unsigned int irq)
+static void ab8500_irq_sync_unlock(struct irq_data *data)
{
- struct ab8500 *ab8500 = get_irq_chip_data(irq);
+ struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
@@ -248,6 +253,10 @@ static void ab8500_irq_sync_unlock(unsigned int irq)
if (new == old)
continue;
+ /* Interrupt register 12 does'nt exist prior to version 0x20 */
+ if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20)
+ continue;
+
ab8500->oldmask[i] = new;
reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i];
@@ -257,20 +266,20 @@ static void ab8500_irq_sync_unlock(unsigned int irq)
mutex_unlock(&ab8500->irq_lock);
}
-static void ab8500_irq_mask(unsigned int irq)
+static void ab8500_irq_mask(struct irq_data *data)
{
- struct ab8500 *ab8500 = get_irq_chip_data(irq);
- int offset = irq - ab8500->irq_base;
+ struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
+ int offset = data->irq - ab8500->irq_base;
int index = offset / 8;
int mask = 1 << (offset % 8);
ab8500->mask[index] |= mask;
}
-static void ab8500_irq_unmask(unsigned int irq)
+static void ab8500_irq_unmask(struct irq_data *data)
{
- struct ab8500 *ab8500 = get_irq_chip_data(irq);
- int offset = irq - ab8500->irq_base;
+ struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
+ int offset = data->irq - ab8500->irq_base;
int index = offset / 8;
int mask = 1 << (offset % 8);
@@ -279,10 +288,10 @@ static void ab8500_irq_unmask(unsigned int irq)
static struct irq_chip ab8500_irq_chip = {
.name = "ab8500",
- .bus_lock = ab8500_irq_lock,
- .bus_sync_unlock = ab8500_irq_sync_unlock,
- .mask = ab8500_irq_mask,
- .unmask = ab8500_irq_unmask,
+ .irq_bus_lock = ab8500_irq_lock,
+ .irq_bus_sync_unlock = ab8500_irq_sync_unlock,
+ .irq_mask = ab8500_irq_mask,
+ .irq_unmask = ab8500_irq_unmask,
};
static irqreturn_t ab8500_irq(int irq, void *dev)
@@ -297,6 +306,10 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
int status;
u8 value;
+ /* Interrupt register 12 does'nt exist prior to version 0x20 */
+ if (regoffset == 11 && ab8500->chip_id < 0x20)
+ continue;
+
status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
AB8500_IT_LATCH1_REG + regoffset, &value);
if (status < 0 || value == 0)
@@ -393,13 +406,195 @@ static struct resource ab8500_poweronkey_db_resources[] = {
},
};
+static struct resource ab8500_bm_resources[] = {
+ {
+ .name = "MAIN_EXT_CH_NOT_OK",
+ .start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+ .end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "BATT_OVV",
+ .start = AB8500_INT_BATT_OVV,
+ .end = AB8500_INT_BATT_OVV,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "MAIN_CH_UNPLUG_DET",
+ .start = AB8500_INT_MAIN_CH_UNPLUG_DET,
+ .end = AB8500_INT_MAIN_CH_UNPLUG_DET,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "MAIN_CHARGE_PLUG_DET",
+ .start = AB8500_INT_MAIN_CH_PLUG_DET,
+ .end = AB8500_INT_MAIN_CH_PLUG_DET,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_DET_F",
+ .start = AB8500_INT_VBUS_DET_F,
+ .end = AB8500_INT_VBUS_DET_F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_DET_R",
+ .start = AB8500_INT_VBUS_DET_R,
+ .end = AB8500_INT_VBUS_DET_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "BAT_CTRL_INDB",
+ .start = AB8500_INT_BAT_CTRL_INDB,
+ .end = AB8500_INT_BAT_CTRL_INDB,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "CH_WD_EXP",
+ .start = AB8500_INT_CH_WD_EXP,
+ .end = AB8500_INT_CH_WD_EXP,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_OVV",
+ .start = AB8500_INT_VBUS_OVV,
+ .end = AB8500_INT_VBUS_OVV,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "NCONV_ACCU",
+ .start = AB8500_INT_CCN_CONV_ACC,
+ .end = AB8500_INT_CCN_CONV_ACC,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "LOW_BAT_F",
+ .start = AB8500_INT_LOW_BAT_F,
+ .end = AB8500_INT_LOW_BAT_F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "LOW_BAT_R",
+ .start = AB8500_INT_LOW_BAT_R,
+ .end = AB8500_INT_LOW_BAT_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "BTEMP_LOW",
+ .start = AB8500_INT_BTEMP_LOW,
+ .end = AB8500_INT_BTEMP_LOW,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "BTEMP_HIGH",
+ .start = AB8500_INT_BTEMP_HIGH,
+ .end = AB8500_INT_BTEMP_HIGH,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "USB_CHARGER_NOT_OKR",
+ .start = AB8500_INT_USB_CHARGER_NOT_OK,
+ .end = AB8500_INT_USB_CHARGER_NOT_OK,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "USB_CHARGE_DET_DONE",
+ .start = AB8500_INT_USB_CHG_DET_DONE,
+ .end = AB8500_INT_USB_CHG_DET_DONE,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "USB_CH_TH_PROT_R",
+ .start = AB8500_INT_USB_CH_TH_PROT_R,
+ .end = AB8500_INT_USB_CH_TH_PROT_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "MAIN_CH_TH_PROT_R",
+ .start = AB8500_INT_MAIN_CH_TH_PROT_R,
+ .end = AB8500_INT_MAIN_CH_TH_PROT_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "USB_CHARGER_NOT_OKF",
+ .start = AB8500_INT_USB_CHARGER_NOT_OKF,
+ .end = AB8500_INT_USB_CHARGER_NOT_OKF,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource ab8500_debug_resources[] = {
+ {
+ .name = "IRQ_FIRST",
+ .start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+ .end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "IRQ_LAST",
+ .start = AB8500_INT_USB_CHARGER_NOT_OKF,
+ .end = AB8500_INT_USB_CHARGER_NOT_OKF,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource ab8500_usb_resources[] = {
+ {
+ .name = "ID_WAKEUP_R",
+ .start = AB8500_INT_ID_WAKEUP_R,
+ .end = AB8500_INT_ID_WAKEUP_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "ID_WAKEUP_F",
+ .start = AB8500_INT_ID_WAKEUP_F,
+ .end = AB8500_INT_ID_WAKEUP_F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_DET_F",
+ .start = AB8500_INT_VBUS_DET_F,
+ .end = AB8500_INT_VBUS_DET_F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_DET_R",
+ .start = AB8500_INT_VBUS_DET_R,
+ .end = AB8500_INT_VBUS_DET_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "USB_LINK_STATUS",
+ .start = AB8500_INT_USB_LINK_STATUS,
+ .end = AB8500_INT_USB_LINK_STATUS,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource ab8500_temp_resources[] = {
+ {
+ .name = "AB8500_TEMP_WARM",
+ .start = AB8500_INT_TEMP_WARM,
+ .end = AB8500_INT_TEMP_WARM,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
static struct mfd_cell ab8500_devs[] = {
#ifdef CONFIG_DEBUG_FS
{
.name = "ab8500-debug",
+ .num_resources = ARRAY_SIZE(ab8500_debug_resources),
+ .resources = ab8500_debug_resources,
},
#endif
{
+ .name = "ab8500-sysctrl",
+ },
+ {
+ .name = "ab8500-regulator",
+ },
+ {
.name = "ab8500-gpadc",
.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
.resources = ab8500_gpadc_resources,
@@ -410,6 +605,22 @@ static struct mfd_cell ab8500_devs[] = {
.resources = ab8500_rtc_resources,
},
{
+ .name = "ab8500-bm",
+ .num_resources = ARRAY_SIZE(ab8500_bm_resources),
+ .resources = ab8500_bm_resources,
+ },
+ { .name = "ab8500-codec", },
+ {
+ .name = "ab8500-usb",
+ .num_resources = ARRAY_SIZE(ab8500_usb_resources),
+ .resources = ab8500_usb_resources,
+ },
+ {
+ .name = "ab8500-poweron-key",
+ .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
+ .resources = ab8500_poweronkey_db_resources,
+ },
+ {
.name = "ab8500-pwm",
.id = 1,
},
@@ -421,17 +632,37 @@ static struct mfd_cell ab8500_devs[] = {
.name = "ab8500-pwm",
.id = 3,
},
- { .name = "ab8500-charger", },
- { .name = "ab8500-audio", },
- { .name = "ab8500-usb", },
- { .name = "ab8500-regulator", },
+ { .name = "ab8500-leds", },
{
- .name = "ab8500-poweron-key",
- .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
- .resources = ab8500_poweronkey_db_resources,
+ .name = "ab8500-denc",
+ },
+ {
+ .name = "ab8500-temp",
+ .num_resources = ARRAY_SIZE(ab8500_temp_resources),
+ .resources = ab8500_temp_resources,
},
};
+static ssize_t show_chip_id(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ab8500 *ab8500;
+
+ ab8500 = dev_get_drvdata(dev);
+ return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
+}
+
+static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
+
+static struct attribute *ab8500_sysfs_entries[] = {
+ &dev_attr_chip_id.attr,
+ NULL,
+};
+
+static struct attribute_group ab8500_attr_group = {
+ .attrs = ab8500_sysfs_entries,
+};
+
int __devinit ab8500_init(struct ab8500 *ab8500)
{
struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev);
@@ -454,8 +685,9 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
* 0x0 - Early Drop
* 0x10 - Cut 1.0
* 0x11 - Cut 1.1
+ * 0x20 - Cut 2.0
*/
- if (value == 0x0 || value == 0x10 || value == 0x11) {
+ if (value == 0x0 || value == 0x10 || value == 0x11 || value == 0x20) {
ab8500->revision = value;
dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
} else {
@@ -468,18 +700,16 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
plat->init(ab8500);
/* Clear and mask all interrupts */
- for (i = 0; i < 10; i++) {
- get_register_interruptible(ab8500, AB8500_INTERRUPT,
- AB8500_IT_LATCH1_REG + i, &value);
- set_register_interruptible(ab8500, AB8500_INTERRUPT,
- AB8500_IT_MASK1_REG + i, 0xff);
- }
+ for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
+ /* Interrupt register 12 does'nt exist prior to version 0x20 */
+ if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20)
+ continue;
- for (i = 18; i < 24; i++) {
get_register_interruptible(ab8500, AB8500_INTERRUPT,
- AB8500_IT_LATCH1_REG + i, &value);
+ AB8500_IT_LATCH1_REG + ab8500_irq_regoffset[i],
+ &value);
set_register_interruptible(ab8500, AB8500_INTERRUPT,
- AB8500_IT_MASK1_REG + i, 0xff);
+ AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i], 0xff);
}
ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
@@ -495,7 +725,8 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
return ret;
ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq,
- IRQF_ONESHOT, "ab8500", ab8500);
+ IRQF_ONESHOT | IRQF_NO_SUSPEND,
+ "ab8500", ab8500);
if (ret)
goto out_removeirq;
}
@@ -506,6 +737,10 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
if (ret)
goto out_freeirq;
+ ret = sysfs_create_group(&ab8500->dev->kobj, &ab8500_attr_group);
+ if (ret)
+ dev_err(ab8500->dev, "error creating sysfs entries\n");
+
return ret;
out_freeirq:
@@ -519,6 +754,7 @@ out_removeirq:
int __devexit ab8500_exit(struct ab8500 *ab8500)
{
+ sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
mfd_remove_devices(ab8500->dev);
if (ab8500->irq_base) {
free_irq(ab8500->irq, ab8500);
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 8d1e05a39815..3c1541ae7223 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -24,9 +24,9 @@ static u32 debug_address;
* @perm: access permissions for the range
*/
struct ab8500_reg_range {
- u8 first;
- u8 last;
- u8 perm;
+ u8 first;
+ u8 last;
+ u8 perm;
};
/**
@@ -36,9 +36,9 @@ struct ab8500_reg_range {
* @range: the list of register ranges
*/
struct ab8500_i2c_ranges {
- u8 num_ranges;
- u8 bankid;
- const struct ab8500_reg_range *range;
+ u8 num_ranges;
+ u8 bankid;
+ const struct ab8500_reg_range *range;
};
#define AB8500_NAME_STRING "ab8500"
@@ -47,521 +47,521 @@ struct ab8500_i2c_ranges {
#define AB8500_REV_REG 0x80
static struct ab8500_i2c_ranges debug_ranges[AB8500_NUM_BANKS] = {
- [0x0] = {
- .num_ranges = 0,
- .range = 0,
- },
- [AB8500_SYS_CTRL1_BLOCK] = {
- .num_ranges = 3,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x02,
- },
- {
- .first = 0x42,
- .last = 0x42,
- },
- {
- .first = 0x80,
- .last = 0x81,
- },
- },
- },
- [AB8500_SYS_CTRL2_BLOCK] = {
- .num_ranges = 4,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x0D,
- },
- {
- .first = 0x0F,
- .last = 0x17,
- },
- {
- .first = 0x30,
- .last = 0x30,
- },
- {
- .first = 0x32,
- .last = 0x33,
- },
- },
- },
- [AB8500_REGU_CTRL1] = {
- .num_ranges = 3,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x00,
- },
- {
- .first = 0x03,
- .last = 0x10,
- },
- {
- .first = 0x80,
- .last = 0x84,
- },
- },
- },
- [AB8500_REGU_CTRL2] = {
- .num_ranges = 5,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x15,
- },
- {
- .first = 0x17,
- .last = 0x19,
- },
- {
- .first = 0x1B,
- .last = 0x1D,
- },
- {
- .first = 0x1F,
- .last = 0x22,
- },
- {
- .first = 0x40,
- .last = 0x44,
- },
- /* 0x80-0x8B is SIM registers and should
- * not be accessed from here */
- },
- },
- [AB8500_USB] = {
- .num_ranges = 2,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x80,
- .last = 0x83,
- },
- {
- .first = 0x87,
- .last = 0x8A,
- },
- },
- },
- [AB8500_TVOUT] = {
- .num_ranges = 9,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x12,
- },
- {
- .first = 0x15,
- .last = 0x17,
- },
- {
- .first = 0x19,
- .last = 0x21,
- },
- {
- .first = 0x27,
- .last = 0x2C,
- },
- {
- .first = 0x41,
- .last = 0x41,
- },
- {
- .first = 0x45,
- .last = 0x5B,
- },
- {
- .first = 0x5D,
- .last = 0x5D,
- },
- {
- .first = 0x69,
- .last = 0x69,
- },
- {
- .first = 0x80,
- .last = 0x81,
- },
- },
- },
- [AB8500_DBI] = {
- .num_ranges = 0,
- .range = 0,
- },
- [AB8500_ECI_AV_ACC] = {
- .num_ranges = 1,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x80,
- .last = 0x82,
- },
- },
- },
- [0x9] = {
- .num_ranges = 0,
- .range = 0,
- },
- [AB8500_GPADC] = {
- .num_ranges = 1,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x08,
- },
- },
- },
- [AB8500_CHARGER] = {
- .num_ranges = 8,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x03,
- },
- {
- .first = 0x05,
- .last = 0x05,
- },
- {
- .first = 0x40,
- .last = 0x40,
- },
- {
- .first = 0x42,
- .last = 0x42,
- },
- {
- .first = 0x44,
- .last = 0x44,
- },
- {
- .first = 0x50,
- .last = 0x55,
- },
- {
- .first = 0x80,
- .last = 0x82,
- },
- {
- .first = 0xC0,
- .last = 0xC2,
- },
- },
- },
- [AB8500_GAS_GAUGE] = {
- .num_ranges = 3,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x00,
- },
- {
- .first = 0x07,
- .last = 0x0A,
- },
- {
- .first = 0x10,
- .last = 0x14,
- },
- },
- },
- [AB8500_AUDIO] = {
- .num_ranges = 1,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x6F,
- },
- },
- },
- [AB8500_INTERRUPT] = {
- .num_ranges = 0,
- .range = 0,
- },
- [AB8500_RTC] = {
- .num_ranges = 1,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x0F,
- },
- },
- },
- [AB8500_MISC] = {
- .num_ranges = 8,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x05,
- },
- {
- .first = 0x10,
- .last = 0x15,
- },
- {
- .first = 0x20,
- .last = 0x25,
- },
- {
- .first = 0x30,
- .last = 0x35,
- },
- {
- .first = 0x40,
- .last = 0x45,
- },
- {
- .first = 0x50,
- .last = 0x50,
- },
- {
- .first = 0x60,
- .last = 0x67,
- },
- {
- .first = 0x80,
- .last = 0x80,
- },
- },
- },
- [0x11] = {
- .num_ranges = 0,
- .range = 0,
- },
- [0x12] = {
- .num_ranges = 0,
- .range = 0,
- },
- [0x13] = {
- .num_ranges = 0,
- .range = 0,
- },
- [0x14] = {
- .num_ranges = 0,
- .range = 0,
- },
- [AB8500_OTP_EMUL] = {
- .num_ranges = 1,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x01,
- .last = 0x0F,
- },
- },
- },
+ [0x0] = {
+ .num_ranges = 0,
+ .range = 0,
+ },
+ [AB8500_SYS_CTRL1_BLOCK] = {
+ .num_ranges = 3,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x02,
+ },
+ {
+ .first = 0x42,
+ .last = 0x42,
+ },
+ {
+ .first = 0x80,
+ .last = 0x81,
+ },
+ },
+ },
+ [AB8500_SYS_CTRL2_BLOCK] = {
+ .num_ranges = 4,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x0D,
+ },
+ {
+ .first = 0x0F,
+ .last = 0x17,
+ },
+ {
+ .first = 0x30,
+ .last = 0x30,
+ },
+ {
+ .first = 0x32,
+ .last = 0x33,
+ },
+ },
+ },
+ [AB8500_REGU_CTRL1] = {
+ .num_ranges = 3,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x00,
+ },
+ {
+ .first = 0x03,
+ .last = 0x10,
+ },
+ {
+ .first = 0x80,
+ .last = 0x84,
+ },
+ },
+ },
+ [AB8500_REGU_CTRL2] = {
+ .num_ranges = 5,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x15,
+ },
+ {
+ .first = 0x17,
+ .last = 0x19,
+ },
+ {
+ .first = 0x1B,
+ .last = 0x1D,
+ },
+ {
+ .first = 0x1F,
+ .last = 0x22,
+ },
+ {
+ .first = 0x40,
+ .last = 0x44,
+ },
+ /* 0x80-0x8B is SIM registers and should
+ * not be accessed from here */
+ },
+ },
+ [AB8500_USB] = {
+ .num_ranges = 2,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x80,
+ .last = 0x83,
+ },
+ {
+ .first = 0x87,
+ .last = 0x8A,
+ },
+ },
+ },
+ [AB8500_TVOUT] = {
+ .num_ranges = 9,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x12,
+ },
+ {
+ .first = 0x15,
+ .last = 0x17,
+ },
+ {
+ .first = 0x19,
+ .last = 0x21,
+ },
+ {
+ .first = 0x27,
+ .last = 0x2C,
+ },
+ {
+ .first = 0x41,
+ .last = 0x41,
+ },
+ {
+ .first = 0x45,
+ .last = 0x5B,
+ },
+ {
+ .first = 0x5D,
+ .last = 0x5D,
+ },
+ {
+ .first = 0x69,
+ .last = 0x69,
+ },
+ {
+ .first = 0x80,
+ .last = 0x81,
+ },
+ },
+ },
+ [AB8500_DBI] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_ECI_AV_ACC] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x80,
+ .last = 0x82,
+ },
+ },
+ },
+ [0x9] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_GPADC] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x08,
+ },
+ },
+ },
+ [AB8500_CHARGER] = {
+ .num_ranges = 8,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x03,
+ },
+ {
+ .first = 0x05,
+ .last = 0x05,
+ },
+ {
+ .first = 0x40,
+ .last = 0x40,
+ },
+ {
+ .first = 0x42,
+ .last = 0x42,
+ },
+ {
+ .first = 0x44,
+ .last = 0x44,
+ },
+ {
+ .first = 0x50,
+ .last = 0x55,
+ },
+ {
+ .first = 0x80,
+ .last = 0x82,
+ },
+ {
+ .first = 0xC0,
+ .last = 0xC2,
+ },
+ },
+ },
+ [AB8500_GAS_GAUGE] = {
+ .num_ranges = 3,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x00,
+ },
+ {
+ .first = 0x07,
+ .last = 0x0A,
+ },
+ {
+ .first = 0x10,
+ .last = 0x14,
+ },
+ },
+ },
+ [AB8500_AUDIO] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x6F,
+ },
+ },
+ },
+ [AB8500_INTERRUPT] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_RTC] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x0F,
+ },
+ },
+ },
+ [AB8500_MISC] = {
+ .num_ranges = 8,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x05,
+ },
+ {
+ .first = 0x10,
+ .last = 0x15,
+ },
+ {
+ .first = 0x20,
+ .last = 0x25,
+ },
+ {
+ .first = 0x30,
+ .last = 0x35,
+ },
+ {
+ .first = 0x40,
+ .last = 0x45,
+ },
+ {
+ .first = 0x50,
+ .last = 0x50,
+ },
+ {
+ .first = 0x60,
+ .last = 0x67,
+ },
+ {
+ .first = 0x80,
+ .last = 0x80,
+ },
+ },
+ },
+ [0x11] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [0x12] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [0x13] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [0x14] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_OTP_EMUL] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x01,
+ .last = 0x0F,
+ },
+ },
+ },
};
static int ab8500_registers_print(struct seq_file *s, void *p)
{
- struct device *dev = s->private;
- unsigned int i;
- u32 bank = debug_bank;
-
- seq_printf(s, AB8500_NAME_STRING " register values:\n");
-
- seq_printf(s, " bank %u:\n", bank);
- for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
- u32 reg;
-
- for (reg = debug_ranges[bank].range[i].first;
- reg <= debug_ranges[bank].range[i].last;
- reg++) {
- u8 value;
- int err;
-
- err = abx500_get_register_interruptible(dev,
- (u8)bank, (u8)reg, &value);
- if (err < 0) {
- dev_err(dev, "ab->read fail %d\n", err);
- return err;
- }
-
- err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n", bank,
- reg, value);
- if (err < 0) {
- dev_err(dev, "seq_printf overflow\n");
- /* Error is not returned here since
- * the output is wanted in any case */
- return 0;
- }
- }
- }
- return 0;
+ struct device *dev = s->private;
+ unsigned int i;
+ u32 bank = debug_bank;
+
+ seq_printf(s, AB8500_NAME_STRING " register values:\n");
+
+ seq_printf(s, " bank %u:\n", bank);
+ for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
+ u32 reg;
+
+ for (reg = debug_ranges[bank].range[i].first;
+ reg <= debug_ranges[bank].range[i].last;
+ reg++) {
+ u8 value;
+ int err;
+
+ err = abx500_get_register_interruptible(dev,
+ (u8)bank, (u8)reg, &value);
+ if (err < 0) {
+ dev_err(dev, "ab->read fail %d\n", err);
+ return err;
+ }
+
+ err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n", bank,
+ reg, value);
+ if (err < 0) {
+ dev_err(dev, "seq_printf overflow\n");
+ /* Error is not returned here since
+ * the output is wanted in any case */
+ return 0;
+ }
+ }
+ }
+ return 0;
}
static int ab8500_registers_open(struct inode *inode, struct file *file)
{
- return single_open(file, ab8500_registers_print, inode->i_private);
+ return single_open(file, ab8500_registers_print, inode->i_private);
}
static const struct file_operations ab8500_registers_fops = {
- .open = ab8500_registers_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
+ .open = ab8500_registers_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
};
static int ab8500_bank_print(struct seq_file *s, void *p)
{
- return seq_printf(s, "%d\n", debug_bank);
+ return seq_printf(s, "%d\n", debug_bank);
}
static int ab8500_bank_open(struct inode *inode, struct file *file)
{
- return single_open(file, ab8500_bank_print, inode->i_private);
+ return single_open(file, ab8500_bank_print, inode->i_private);
}
static ssize_t ab8500_bank_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
{
- struct device *dev = ((struct seq_file *)(file->private_data))->private;
- char buf[32];
- int buf_size;
- unsigned long user_bank;
- int err;
-
- /* Get userspace string and assure termination */
- buf_size = min(count, (sizeof(buf) - 1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
- buf[buf_size] = 0;
-
- err = strict_strtoul(buf, 0, &user_bank);
- if (err)
- return -EINVAL;
-
- if (user_bank >= AB8500_NUM_BANKS) {
- dev_err(dev, "debugfs error input > number of banks\n");
- return -EINVAL;
- }
-
- debug_bank = user_bank;
-
- return buf_size;
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_bank;
+ int err;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf) - 1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ err = strict_strtoul(buf, 0, &user_bank);
+ if (err)
+ return -EINVAL;
+
+ if (user_bank >= AB8500_NUM_BANKS) {
+ dev_err(dev, "debugfs error input > number of banks\n");
+ return -EINVAL;
+ }
+
+ debug_bank = user_bank;
+
+ return buf_size;
}
static int ab8500_address_print(struct seq_file *s, void *p)
{
- return seq_printf(s, "0x%02X\n", debug_address);
+ return seq_printf(s, "0x%02X\n", debug_address);
}
static int ab8500_address_open(struct inode *inode, struct file *file)
{
- return single_open(file, ab8500_address_print, inode->i_private);
+ return single_open(file, ab8500_address_print, inode->i_private);
}
static ssize_t ab8500_address_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
{
- struct device *dev = ((struct seq_file *)(file->private_data))->private;
- char buf[32];
- int buf_size;
- unsigned long user_address;
- int err;
-
- /* Get userspace string and assure termination */
- buf_size = min(count, (sizeof(buf) - 1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
- buf[buf_size] = 0;
-
- err = strict_strtoul(buf, 0, &user_address);
- if (err)
- return -EINVAL;
- if (user_address > 0xff) {
- dev_err(dev, "debugfs error input > 0xff\n");
- return -EINVAL;
- }
- debug_address = user_address;
- return buf_size;
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_address;
+ int err;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf) - 1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ err = strict_strtoul(buf, 0, &user_address);
+ if (err)
+ return -EINVAL;
+ if (user_address > 0xff) {
+ dev_err(dev, "debugfs error input > 0xff\n");
+ return -EINVAL;
+ }
+ debug_address = user_address;
+ return buf_size;
}
static int ab8500_val_print(struct seq_file *s, void *p)
{
- struct device *dev = s->private;
- int ret;
- u8 regvalue;
-
- ret = abx500_get_register_interruptible(dev,
- (u8)debug_bank, (u8)debug_address, &regvalue);
- if (ret < 0) {
- dev_err(dev, "abx500_get_reg fail %d, %d\n",
- ret, __LINE__);
- return -EINVAL;
- }
- seq_printf(s, "0x%02X\n", regvalue);
-
- return 0;
+ struct device *dev = s->private;
+ int ret;
+ u8 regvalue;
+
+ ret = abx500_get_register_interruptible(dev,
+ (u8)debug_bank, (u8)debug_address, &regvalue);
+ if (ret < 0) {
+ dev_err(dev, "abx500_get_reg fail %d, %d\n",
+ ret, __LINE__);
+ return -EINVAL;
+ }
+ seq_printf(s, "0x%02X\n", regvalue);
+
+ return 0;
}
static int ab8500_val_open(struct inode *inode, struct file *file)
{
- return single_open(file, ab8500_val_print, inode->i_private);
+ return single_open(file, ab8500_val_print, inode->i_private);
}
static ssize_t ab8500_val_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
{
- struct device *dev = ((struct seq_file *)(file->private_data))->private;
- char buf[32];
- int buf_size;
- unsigned long user_val;
- int err;
-
- /* Get userspace string and assure termination */
- buf_size = min(count, (sizeof(buf)-1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
- buf[buf_size] = 0;
-
- err = strict_strtoul(buf, 0, &user_val);
- if (err)
- return -EINVAL;
- if (user_val > 0xff) {
- dev_err(dev, "debugfs error input > 0xff\n");
- return -EINVAL;
- }
- err = abx500_set_register_interruptible(dev,
- (u8)debug_bank, debug_address, (u8)user_val);
- if (err < 0) {
- printk(KERN_ERR "abx500_set_reg failed %d, %d", err, __LINE__);
- return -EINVAL;
- }
-
- return buf_size;
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_val;
+ int err;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf)-1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ err = strict_strtoul(buf, 0, &user_val);
+ if (err)
+ return -EINVAL;
+ if (user_val > 0xff) {
+ dev_err(dev, "debugfs error input > 0xff\n");
+ return -EINVAL;
+ }
+ err = abx500_set_register_interruptible(dev,
+ (u8)debug_bank, debug_address, (u8)user_val);
+ if (err < 0) {
+ printk(KERN_ERR "abx500_set_reg failed %d, %d", err, __LINE__);
+ return -EINVAL;
+ }
+
+ return buf_size;
}
static const struct file_operations ab8500_bank_fops = {
- .open = ab8500_bank_open,
- .write = ab8500_bank_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
+ .open = ab8500_bank_open,
+ .write = ab8500_bank_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
};
static const struct file_operations ab8500_address_fops = {
- .open = ab8500_address_open,
- .write = ab8500_address_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
+ .open = ab8500_address_open,
+ .write = ab8500_address_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
};
static const struct file_operations ab8500_val_fops = {
- .open = ab8500_val_open,
- .write = ab8500_val_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
+ .open = ab8500_val_open,
+ .write = ab8500_val_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
};
static struct dentry *ab8500_dir;
@@ -572,77 +572,77 @@ static struct dentry *ab8500_val_file;
static int __devinit ab8500_debug_probe(struct platform_device *plf)
{
- debug_bank = AB8500_MISC;
- debug_address = AB8500_REV_REG & 0x00FF;
+ debug_bank = AB8500_MISC;
+ debug_address = AB8500_REV_REG & 0x00FF;
- ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
- if (!ab8500_dir)
- goto exit_no_debugfs;
+ ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
+ if (!ab8500_dir)
+ goto exit_no_debugfs;
- ab8500_reg_file = debugfs_create_file("all-bank-registers",
- S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops);
- if (!ab8500_reg_file)
- goto exit_destroy_dir;
+ ab8500_reg_file = debugfs_create_file("all-bank-registers",
+ S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops);
+ if (!ab8500_reg_file)
+ goto exit_destroy_dir;
- ab8500_bank_file = debugfs_create_file("register-bank",
- (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_bank_fops);
- if (!ab8500_bank_file)
- goto exit_destroy_reg;
+ ab8500_bank_file = debugfs_create_file("register-bank",
+ (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_bank_fops);
+ if (!ab8500_bank_file)
+ goto exit_destroy_reg;
- ab8500_address_file = debugfs_create_file("register-address",
- (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev,
- &ab8500_address_fops);
- if (!ab8500_address_file)
- goto exit_destroy_bank;
+ ab8500_address_file = debugfs_create_file("register-address",
+ (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev,
+ &ab8500_address_fops);
+ if (!ab8500_address_file)
+ goto exit_destroy_bank;
- ab8500_val_file = debugfs_create_file("register-value",
- (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_val_fops);
- if (!ab8500_val_file)
- goto exit_destroy_address;
+ ab8500_val_file = debugfs_create_file("register-value",
+ (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_val_fops);
+ if (!ab8500_val_file)
+ goto exit_destroy_address;
- return 0;
+ return 0;
exit_destroy_address:
- debugfs_remove(ab8500_address_file);
+ debugfs_remove(ab8500_address_file);
exit_destroy_bank:
- debugfs_remove(ab8500_bank_file);
+ debugfs_remove(ab8500_bank_file);
exit_destroy_reg:
- debugfs_remove(ab8500_reg_file);
+ debugfs_remove(ab8500_reg_file);
exit_destroy_dir:
- debugfs_remove(ab8500_dir);
+ debugfs_remove(ab8500_dir);
exit_no_debugfs:
- dev_err(&plf->dev, "failed to create debugfs entries.\n");
- return -ENOMEM;
+ dev_err(&plf->dev, "failed to create debugfs entries.\n");
+ return -ENOMEM;
}
static int __devexit ab8500_debug_remove(struct platform_device *plf)
{
- debugfs_remove(ab8500_val_file);
- debugfs_remove(ab8500_address_file);
- debugfs_remove(ab8500_bank_file);
- debugfs_remove(ab8500_reg_file);
- debugfs_remove(ab8500_dir);
+ debugfs_remove(ab8500_val_file);
+ debugfs_remove(ab8500_address_file);
+ debugfs_remove(ab8500_bank_file);
+ debugfs_remove(ab8500_reg_file);
+ debugfs_remove(ab8500_dir);
- return 0;
+ return 0;
}
static struct platform_driver ab8500_debug_driver = {
- .driver = {
- .name = "ab8500-debug",
- .owner = THIS_MODULE,
- },
- .probe = ab8500_debug_probe,
- .remove = __devexit_p(ab8500_debug_remove)
+ .driver = {
+ .name = "ab8500-debug",
+ .owner = THIS_MODULE,
+ },
+ .probe = ab8500_debug_probe,
+ .remove = __devexit_p(ab8500_debug_remove)
};
static int __init ab8500_debug_init(void)
{
- return platform_driver_register(&ab8500_debug_driver);
+ return platform_driver_register(&ab8500_debug_driver);
}
static void __exit ab8500_debug_exit(void)
{
- platform_driver_unregister(&ab8500_debug_driver);
+ platform_driver_unregister(&ab8500_debug_driver);
}
subsys_initcall(ab8500_debug_init);
module_exit(ab8500_debug_exit);
diff --git a/drivers/mfd/ab8500-spi.c b/drivers/mfd/ab8500-spi.c
deleted file mode 100644
index b1653421edb5..000000000000
--- a/drivers/mfd/ab8500-spi.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License v2
- * Author: Srinidhi Kasagar <[email protected]>
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/mfd/ab8500.h>
-
-/*
- * This funtion writes to any AB8500 registers using
- * SPI protocol & before it writes it packs the data
- * in the below 24 bit frame format
- *
- * *|------------------------------------|
- * *| 23|22...18|17.......10|9|8|7......0|
- * *| r/w bank adr data |
- * * ------------------------------------
- *
- * This function shouldn't be called from interrupt
- * context
- */
-static int ab8500_spi_write(struct ab8500 *ab8500, u16 addr, u8 data)
-{
- struct spi_device *spi = container_of(ab8500->dev, struct spi_device,
- dev);
- unsigned long spi_data = addr << 10 | data;
- struct spi_transfer xfer;
- struct spi_message msg;
-
- ab8500->tx_buf[0] = spi_data;
- ab8500->rx_buf[0] = 0;
-
- xfer.tx_buf = ab8500->tx_buf;
- xfer.rx_buf = NULL;
- xfer.len = sizeof(unsigned long);
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfer, &msg);
-
- return spi_sync(spi, &msg);
-}
-
-static int ab8500_spi_read(struct ab8500 *ab8500, u16 addr)
-{
- struct spi_device *spi = container_of(ab8500->dev, struct spi_device,
- dev);
- unsigned long spi_data = 1 << 23 | addr << 10;
- struct spi_transfer xfer;
- struct spi_message msg;
- int ret;
-
- ab8500->tx_buf[0] = spi_data;
- ab8500->rx_buf[0] = 0;
-
- xfer.tx_buf = ab8500->tx_buf;
- xfer.rx_buf = ab8500->rx_buf;
- xfer.len = sizeof(unsigned long);
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfer, &msg);
-
- ret = spi_sync(spi, &msg);
- if (!ret)
- /*
- * Only the 8 lowermost bytes are
- * defined with value, the rest may
- * vary depending on chip/board noise.
- */
- ret = ab8500->rx_buf[0] & 0xFFU;
-
- return ret;
-}
-
-static int __devinit ab8500_spi_probe(struct spi_device *spi)
-{
- struct ab8500 *ab8500;
- int ret;
-
- spi->bits_per_word = 24;
- ret = spi_setup(spi);
- if (ret < 0)
- return ret;
-
- ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL);
- if (!ab8500)
- return -ENOMEM;
-
- ab8500->dev = &spi->dev;
- ab8500->irq = spi->irq;
-
- ab8500->read = ab8500_spi_read;
- ab8500->write = ab8500_spi_write;
-
- spi_set_drvdata(spi, ab8500);
-
- ret = ab8500_init(ab8500);
- if (ret)
- kfree(ab8500);
-
- return ret;
-}
-
-static int __devexit ab8500_spi_remove(struct spi_device *spi)
-{
- struct ab8500 *ab8500 = spi_get_drvdata(spi);
-
- ab8500_exit(ab8500);
- kfree(ab8500);
-
- return 0;
-}
-
-static struct spi_driver ab8500_spi_driver = {
- .driver = {
- .name = "ab8500-spi",
- .owner = THIS_MODULE,
- },
- .probe = ab8500_spi_probe,
- .remove = __devexit_p(ab8500_spi_remove)
-};
-
-static int __init ab8500_spi_init(void)
-{
- return spi_register_driver(&ab8500_spi_driver);
-}
-subsys_initcall(ab8500_spi_init);
-
-static void __exit ab8500_spi_exit(void)
-{
- spi_unregister_driver(&ab8500_spi_driver);
-}
-module_exit(ab8500_spi_exit);
-
-MODULE_AUTHOR("Srinidhi KASAGAR <[email protected]");
-MODULE_DESCRIPTION("AB8500 SPI");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index 7de708d15d72..6a1f94042612 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -57,7 +57,7 @@ struct asic3_clk {
.rate = _rate, \
}
-struct asic3_clk asic3_clk_init[] __initdata = {
+static struct asic3_clk asic3_clk_init[] __initdata = {
INIT_CDEX(SPI, 0),
INIT_CDEX(OWM, 5000000),
INIT_CDEX(PWM0, 0),
@@ -102,7 +102,7 @@ static inline u32 asic3_read_register(struct asic3 *asic,
(reg >> asic->bus_shift));
}
-void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set)
+static void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set)
{
unsigned long flags;
u32 val;
@@ -226,14 +226,14 @@ static inline int asic3_irq_to_index(struct asic3 *asic, int irq)
return (irq - asic->irq_base) & 0xf;
}
-static void asic3_mask_gpio_irq(unsigned int irq)
+static void asic3_mask_gpio_irq(struct irq_data *data)
{
- struct asic3 *asic = get_irq_chip_data(irq);
+ struct asic3 *asic = irq_data_get_irq_chip_data(data);
u32 val, bank, index;
unsigned long flags;
- bank = asic3_irq_to_bank(asic, irq);
- index = asic3_irq_to_index(asic, irq);
+ bank = asic3_irq_to_bank(asic, data->irq);
+ index = asic3_irq_to_index(asic, data->irq);
spin_lock_irqsave(&asic->lock, flags);
val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK);
@@ -242,9 +242,9 @@ static void asic3_mask_gpio_irq(unsigned int irq)
spin_unlock_irqrestore(&asic->lock, flags);
}
-static void asic3_mask_irq(unsigned int irq)
+static void asic3_mask_irq(struct irq_data *data)
{
- struct asic3 *asic = get_irq_chip_data(irq);
+ struct asic3 *asic = irq_data_get_irq_chip_data(data);
int regval;
unsigned long flags;
@@ -254,7 +254,7 @@ static void asic3_mask_irq(unsigned int irq)
ASIC3_INTR_INT_MASK);
regval &= ~(ASIC3_INTMASK_MASK0 <<
- (irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
+ (data->irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
asic3_write_register(asic,
ASIC3_INTR_BASE +
@@ -263,14 +263,14 @@ static void asic3_mask_irq(unsigned int irq)
spin_unlock_irqrestore(&asic->lock, flags);
}
-static void asic3_unmask_gpio_irq(unsigned int irq)
+static void asic3_unmask_gpio_irq(struct irq_data *data)
{
- struct asic3 *asic = get_irq_chip_data(irq);
+ struct asic3 *asic = irq_data_get_irq_chip_data(data);
u32 val, bank, index;
unsigned long flags;
- bank = asic3_irq_to_bank(asic, irq);
- index = asic3_irq_to_index(asic, irq);
+ bank = asic3_irq_to_bank(asic, data->irq);
+ index = asic3_irq_to_index(asic, data->irq);
spin_lock_irqsave(&asic->lock, flags);
val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK);
@@ -279,9 +279,9 @@ static void asic3_unmask_gpio_irq(unsigned int irq)
spin_unlock_irqrestore(&asic->lock, flags);
}
-static void asic3_unmask_irq(unsigned int irq)
+static void asic3_unmask_irq(struct irq_data *data)
{
- struct asic3 *asic = get_irq_chip_data(irq);
+ struct asic3 *asic = irq_data_get_irq_chip_data(data);
int regval;
unsigned long flags;
@@ -291,7 +291,7 @@ static void asic3_unmask_irq(unsigned int irq)
ASIC3_INTR_INT_MASK);
regval |= (ASIC3_INTMASK_MASK0 <<
- (irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
+ (data->irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
asic3_write_register(asic,
ASIC3_INTR_BASE +
@@ -300,15 +300,15 @@ static void asic3_unmask_irq(unsigned int irq)
spin_unlock_irqrestore(&asic->lock, flags);
}
-static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
+static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type)
{
- struct asic3 *asic = get_irq_chip_data(irq);
+ struct asic3 *asic = irq_data_get_irq_chip_data(data);
u32 bank, index;
u16 trigger, level, edge, bit;
unsigned long flags;
- bank = asic3_irq_to_bank(asic, irq);
- index = asic3_irq_to_index(asic, irq);
+ bank = asic3_irq_to_bank(asic, data->irq);
+ index = asic3_irq_to_index(asic, data->irq);
bit = 1<<index;
spin_lock_irqsave(&asic->lock, flags);
@@ -318,7 +318,7 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
bank + ASIC3_GPIO_EDGE_TRIGGER);
trigger = asic3_read_register(asic,
bank + ASIC3_GPIO_TRIGGER_TYPE);
- asic->irq_bothedge[(irq - asic->irq_base) >> 4] &= ~bit;
+ asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] &= ~bit;
if (type == IRQ_TYPE_EDGE_RISING) {
trigger |= bit;
@@ -328,11 +328,11 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
edge &= ~bit;
} else if (type == IRQ_TYPE_EDGE_BOTH) {
trigger |= bit;
- if (asic3_gpio_get(&asic->gpio, irq - asic->irq_base))
+ if (asic3_gpio_get(&asic->gpio, data->irq - asic->irq_base))
edge &= ~bit;
else
edge |= bit;
- asic->irq_bothedge[(irq - asic->irq_base) >> 4] |= bit;
+ asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] |= bit;
} else if (type == IRQ_TYPE_LEVEL_LOW) {
trigger &= ~bit;
level &= ~bit;
@@ -359,17 +359,17 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
static struct irq_chip asic3_gpio_irq_chip = {
.name = "ASIC3-GPIO",
- .ack = asic3_mask_gpio_irq,
- .mask = asic3_mask_gpio_irq,
- .unmask = asic3_unmask_gpio_irq,
- .set_type = asic3_gpio_irq_type,
+ .irq_ack = asic3_mask_gpio_irq,
+ .irq_mask = asic3_mask_gpio_irq,
+ .irq_unmask = asic3_unmask_gpio_irq,
+ .irq_set_type = asic3_gpio_irq_type,
};
static struct irq_chip asic3_irq_chip = {
.name = "ASIC3",
- .ack = asic3_mask_irq,
- .mask = asic3_mask_irq,
- .unmask = asic3_unmask_irq,
+ .irq_ack = asic3_mask_irq,
+ .irq_mask = asic3_mask_irq,
+ .irq_unmask = asic3_unmask_irq,
};
static int __init asic3_irq_probe(struct platform_device *pdev)
@@ -635,7 +635,7 @@ static struct resource ds1wm_resources[] = {
},
{
.start = ASIC3_IRQ_OWM,
- .start = ASIC3_IRQ_OWM,
+ .end = ASIC3_IRQ_OWM,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
},
};
diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c
new file mode 100644
index 000000000000..59ca6f151e78
--- /dev/null
+++ b/drivers/mfd/cs5535-mfd.c
@@ -0,0 +1,151 @@
+/*
+ * cs5535-mfd.c - core MFD driver for CS5535/CS5536 southbridges
+ *
+ * The CS5535 and CS5536 has an ISA bridge on the PCI bus that is
+ * used for accessing GPIOs, MFGPTs, ACPI, etc. Each subdevice has
+ * an IO range that's specified in a single BAR. The BAR order is
+ * hardcoded in the CS553x specifications.
+ *
+ * Copyright (c) 2010 Andres Salomon <[email protected]>
+ *
+ * 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.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#define DRV_NAME "cs5535-mfd"
+
+enum cs5535_mfd_bars {
+ SMB_BAR = 0,
+ GPIO_BAR = 1,
+ MFGPT_BAR = 2,
+ PMS_BAR = 4,
+ ACPI_BAR = 5,
+ NR_BARS,
+};
+
+static __devinitdata struct resource cs5535_mfd_resources[NR_BARS];
+
+static __devinitdata struct mfd_cell cs5535_mfd_cells[] = {
+ {
+ .id = SMB_BAR,
+ .name = "cs5535-smb",
+ .num_resources = 1,
+ .resources = &cs5535_mfd_resources[SMB_BAR],
+ },
+ {
+ .id = GPIO_BAR,
+ .name = "cs5535-gpio",
+ .num_resources = 1,
+ .resources = &cs5535_mfd_resources[GPIO_BAR],
+ },
+ {
+ .id = MFGPT_BAR,
+ .name = "cs5535-mfgpt",
+ .num_resources = 1,
+ .resources = &cs5535_mfd_resources[MFGPT_BAR],
+ },
+ {
+ .id = PMS_BAR,
+ .name = "cs5535-pms",
+ .num_resources = 1,
+ .resources = &cs5535_mfd_resources[PMS_BAR],
+ },
+ {
+ .id = ACPI_BAR,
+ .name = "cs5535-acpi",
+ .num_resources = 1,
+ .resources = &cs5535_mfd_resources[ACPI_BAR],
+ },
+};
+
+static int __devinit cs5535_mfd_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int err, i;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ /* fill in IO range for each cell; subdrivers handle the region */
+ for (i = 0; i < ARRAY_SIZE(cs5535_mfd_cells); i++) {
+ int bar = cs5535_mfd_cells[i].id;
+ struct resource *r = &cs5535_mfd_resources[bar];
+
+ r->flags = IORESOURCE_IO;
+ r->start = pci_resource_start(pdev, bar);
+ r->end = pci_resource_end(pdev, bar);
+
+ /* id is used for temporarily storing BAR; unset it now */
+ cs5535_mfd_cells[i].id = 0;
+ }
+
+ err = mfd_add_devices(&pdev->dev, -1, cs5535_mfd_cells,
+ ARRAY_SIZE(cs5535_mfd_cells), NULL, 0);
+ if (err) {
+ dev_err(&pdev->dev, "MFD add devices failed: %d\n", err);
+ goto err_disable;
+ }
+
+ dev_info(&pdev->dev, "%zu devices registered.\n",
+ ARRAY_SIZE(cs5535_mfd_cells));
+
+ return 0;
+
+err_disable:
+ pci_disable_device(pdev);
+ return err;
+}
+
+static void __devexit cs5535_mfd_remove(struct pci_dev *pdev)
+{
+ mfd_remove_devices(&pdev->dev);
+ pci_disable_device(pdev);
+}
+
+static struct pci_device_id cs5535_mfd_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, cs5535_mfd_pci_tbl);
+
+static struct pci_driver cs5535_mfd_drv = {
+ .name = DRV_NAME,
+ .id_table = cs5535_mfd_pci_tbl,
+ .probe = cs5535_mfd_probe,
+ .remove = __devexit_p(cs5535_mfd_remove),
+};
+
+static int __init cs5535_mfd_init(void)
+{
+ return pci_register_driver(&cs5535_mfd_drv);
+}
+
+static void __exit cs5535_mfd_exit(void)
+{
+ pci_unregister_driver(&cs5535_mfd_drv);
+}
+
+module_init(cs5535_mfd_init);
+module_exit(cs5535_mfd_exit);
+
+MODULE_AUTHOR("Andres Salomon <[email protected]>");
+MODULE_DESCRIPTION("MFD driver for CS5535/CS5536 southbridge's ISA PCI device");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c
index c2b698d69a93..9e2d8dd5f9e5 100644
--- a/drivers/mfd/ezx-pcap.c
+++ b/drivers/mfd/ezx-pcap.c
@@ -144,26 +144,26 @@ int pcap_to_irq(struct pcap_chip *pcap, int irq)
}
EXPORT_SYMBOL_GPL(pcap_to_irq);
-static void pcap_mask_irq(unsigned int irq)
+static void pcap_mask_irq(struct irq_data *d)
{
- struct pcap_chip *pcap = get_irq_chip_data(irq);
+ struct pcap_chip *pcap = irq_data_get_irq_chip_data(d);
- pcap->msr |= 1 << irq_to_pcap(pcap, irq);
+ pcap->msr |= 1 << irq_to_pcap(pcap, d->irq);
queue_work(pcap->workqueue, &pcap->msr_work);
}
-static void pcap_unmask_irq(unsigned int irq)
+static void pcap_unmask_irq(struct irq_data *d)
{
- struct pcap_chip *pcap = get_irq_chip_data(irq);
+ struct pcap_chip *pcap = irq_data_get_irq_chip_data(d);
- pcap->msr &= ~(1 << irq_to_pcap(pcap, irq));
+ pcap->msr &= ~(1 << irq_to_pcap(pcap, d->irq));
queue_work(pcap->workqueue, &pcap->msr_work);
}
static struct irq_chip pcap_irq_chip = {
- .name = "pcap",
- .mask = pcap_mask_irq,
- .unmask = pcap_unmask_irq,
+ .name = "pcap",
+ .irq_mask = pcap_mask_irq,
+ .irq_unmask = pcap_unmask_irq,
};
static void pcap_msr_work(struct work_struct *work)
@@ -199,8 +199,7 @@ static void pcap_isr_work(struct work_struct *work)
if (service & 1) {
struct irq_desc *desc = irq_to_desc(irq);
- if (WARN(!desc, KERN_WARNING
- "Invalid PCAP IRQ %d\n", irq))
+ if (WARN(!desc, "Invalid PCAP IRQ %d\n", irq))
break;
if (desc->status & IRQ_DISABLED)
@@ -218,7 +217,7 @@ static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc)
{
struct pcap_chip *pcap = get_irq_data(irq);
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
queue_work(pcap->workqueue, &pcap->isr_work);
return;
}
@@ -282,7 +281,7 @@ static irqreturn_t pcap_adc_irq(int irq, void *_pcap)
mutex_lock(&pcap->adc_mutex);
req = pcap->adc_queue[pcap->adc_head];
- if (WARN(!req, KERN_WARNING "adc irq without pending request\n")) {
+ if (WARN(!req, "adc irq without pending request\n")) {
mutex_unlock(&pcap->adc_mutex);
return IRQ_HANDLED;
}
diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c
index d3e74f8585e0..d00b6d1a69e5 100644
--- a/drivers/mfd/htc-egpio.c
+++ b/drivers/mfd/htc-egpio.c
@@ -70,31 +70,32 @@ static inline void ack_irqs(struct egpio_info *ei)
ei->ack_write, ei->ack_register << ei->bus_shift);
}
-static void egpio_ack(unsigned int irq)
+static void egpio_ack(struct irq_data *data)
{
}
/* There does not appear to be a way to proactively mask interrupts
* on the egpio chip itself. So, we simply ignore interrupts that
* aren't desired. */
-static void egpio_mask(unsigned int irq)
+static void egpio_mask(struct irq_data *data)
{
- struct egpio_info *ei = get_irq_chip_data(irq);
- ei->irqs_enabled &= ~(1 << (irq - ei->irq_start));
- pr_debug("EGPIO mask %d %04x\n", irq, ei->irqs_enabled);
+ struct egpio_info *ei = irq_data_get_irq_chip_data(data);
+ ei->irqs_enabled &= ~(1 << (data->irq - ei->irq_start));
+ pr_debug("EGPIO mask %d %04x\n", data->irq, ei->irqs_enabled);
}
-static void egpio_unmask(unsigned int irq)
+
+static void egpio_unmask(struct irq_data *data)
{
- struct egpio_info *ei = get_irq_chip_data(irq);
- ei->irqs_enabled |= 1 << (irq - ei->irq_start);
- pr_debug("EGPIO unmask %d %04x\n", irq, ei->irqs_enabled);
+ struct egpio_info *ei = irq_data_get_irq_chip_data(data);
+ ei->irqs_enabled |= 1 << (data->irq - ei->irq_start);
+ pr_debug("EGPIO unmask %d %04x\n", data->irq, ei->irqs_enabled);
}
static struct irq_chip egpio_muxed_chip = {
- .name = "htc-egpio",
- .ack = egpio_ack,
- .mask = egpio_mask,
- .unmask = egpio_unmask,
+ .name = "htc-egpio",
+ .irq_ack = egpio_ack,
+ .irq_mask = egpio_mask,
+ .irq_unmask = egpio_unmask,
};
static void egpio_handler(unsigned int irq, struct irq_desc *desc)
diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c
index 594c9a8e25e1..296ad1562f69 100644
--- a/drivers/mfd/htc-i2cpld.c
+++ b/drivers/mfd/htc-i2cpld.c
@@ -82,25 +82,25 @@ struct htcpld_data {
/* There does not appear to be a way to proactively mask interrupts
* on the htcpld chip itself. So, we simply ignore interrupts that
* aren't desired. */
-static void htcpld_mask(unsigned int irq)
+static void htcpld_mask(struct irq_data *data)
{
- struct htcpld_chip *chip = get_irq_chip_data(irq);
- chip->irqs_enabled &= ~(1 << (irq - chip->irq_start));
- pr_debug("HTCPLD mask %d %04x\n", irq, chip->irqs_enabled);
+ struct htcpld_chip *chip = irq_data_get_irq_chip_data(data);
+ chip->irqs_enabled &= ~(1 << (data->irq - chip->irq_start));
+ pr_debug("HTCPLD mask %d %04x\n", data->irq, chip->irqs_enabled);
}
-static void htcpld_unmask(unsigned int irq)
+static void htcpld_unmask(struct irq_data *data)
{
- struct htcpld_chip *chip = get_irq_chip_data(irq);
- chip->irqs_enabled |= 1 << (irq - chip->irq_start);
- pr_debug("HTCPLD unmask %d %04x\n", irq, chip->irqs_enabled);
+ struct htcpld_chip *chip = irq_data_get_irq_chip_data(data);
+ chip->irqs_enabled |= 1 << (data->irq - chip->irq_start);
+ pr_debug("HTCPLD unmask %d %04x\n", data->irq, chip->irqs_enabled);
}
-static int htcpld_set_type(unsigned int irq, unsigned int flags)
+static int htcpld_set_type(struct irq_data *data, unsigned int flags)
{
- struct irq_desc *d = irq_to_desc(irq);
+ struct irq_desc *d = irq_to_desc(data->irq);
if (!d) {
- pr_err("HTCPLD invalid IRQ: %d\n", irq);
+ pr_err("HTCPLD invalid IRQ: %d\n", data->irq);
return -EINVAL;
}
@@ -118,10 +118,10 @@ static int htcpld_set_type(unsigned int irq, unsigned int flags)
}
static struct irq_chip htcpld_muxed_chip = {
- .name = "htcpld",
- .mask = htcpld_mask,
- .unmask = htcpld_unmask,
- .set_type = htcpld_set_type,
+ .name = "htcpld",
+ .irq_mask = htcpld_mask,
+ .irq_unmask = htcpld_unmask,
+ .irq_set_type = htcpld_set_type,
};
/* To properly dispatch IRQ events, we need to read from the
@@ -235,7 +235,7 @@ static irqreturn_t htcpld_handler(int irq, void *dev)
* and that work is scheduled in the set routine. The kernel can then run
* the I2C functions, which will sleep, in process context.
*/
-void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val)
+static void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val)
{
struct i2c_client *client;
struct htcpld_chip *chip_data;
@@ -259,7 +259,7 @@ void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val)
schedule_work(&(chip_data->set_val_work));
}
-void htcpld_chip_set_ni(struct work_struct *work)
+static void htcpld_chip_set_ni(struct work_struct *work)
{
struct htcpld_chip *chip_data;
struct i2c_client *client;
@@ -269,7 +269,7 @@ void htcpld_chip_set_ni(struct work_struct *work)
i2c_smbus_read_byte_data(client, chip_data->cache_out);
}
-int htcpld_chip_get(struct gpio_chip *chip, unsigned offset)
+static int htcpld_chip_get(struct gpio_chip *chip, unsigned offset)
{
struct htcpld_chip *chip_data;
int val = 0;
@@ -316,7 +316,7 @@ static int htcpld_direction_input(struct gpio_chip *chip,
return (offset < chip->ngpio) ? 0 : -EINVAL;
}
-int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset)
+static int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct htcpld_chip *chip_data;
@@ -328,7 +328,7 @@ int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset)
return -EINVAL;
}
-void htcpld_chip_reset(struct i2c_client *client)
+static void htcpld_chip_reset(struct i2c_client *client)
{
struct htcpld_chip *chip_data = i2c_get_clientdata(client);
if (!chip_data)
diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c
index 9dd1b33f2275..0cc59795f600 100644
--- a/drivers/mfd/jz4740-adc.c
+++ b/drivers/mfd/jz4740-adc.c
@@ -84,31 +84,30 @@ static inline void jz4740_adc_irq_set_masked(struct jz4740_adc *adc, int irq,
spin_unlock_irqrestore(&adc->lock, flags);
}
-static void jz4740_adc_irq_mask(unsigned int irq)
+static void jz4740_adc_irq_mask(struct irq_data *data)
{
- struct jz4740_adc *adc = get_irq_chip_data(irq);
- jz4740_adc_irq_set_masked(adc, irq, true);
+ struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
+ jz4740_adc_irq_set_masked(adc, data->irq, true);
}
-static void jz4740_adc_irq_unmask(unsigned int irq)
+static void jz4740_adc_irq_unmask(struct irq_data *data)
{
- struct jz4740_adc *adc = get_irq_chip_data(irq);
- jz4740_adc_irq_set_masked(adc, irq, false);
+ struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
+ jz4740_adc_irq_set_masked(adc, data->irq, false);
}
-static void jz4740_adc_irq_ack(unsigned int irq)
+static void jz4740_adc_irq_ack(struct irq_data *data)
{
- struct jz4740_adc *adc = get_irq_chip_data(irq);
-
- irq -= adc->irq_base;
+ struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
+ unsigned int irq = data->irq - adc->irq_base;
writeb(BIT(irq), adc->base + JZ_REG_ADC_STATUS);
}
static struct irq_chip jz4740_adc_irq_chip = {
.name = "jz4740-adc",
- .mask = jz4740_adc_irq_mask,
- .unmask = jz4740_adc_irq_unmask,
- .ack = jz4740_adc_irq_ack,
+ .irq_mask = jz4740_adc_irq_mask,
+ .irq_unmask = jz4740_adc_irq_unmask,
+ .irq_ack = jz4740_adc_irq_ack,
};
static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc)
diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c
index 44695f5a1800..0e998dc4e7d8 100644
--- a/drivers/mfd/max8925-core.c
+++ b/drivers/mfd/max8925-core.c
@@ -407,16 +407,16 @@ static irqreturn_t max8925_tsc_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static void max8925_irq_lock(unsigned int irq)
+static void max8925_irq_lock(struct irq_data *data)
{
- struct max8925_chip *chip = get_irq_chip_data(irq);
+ struct max8925_chip *chip = irq_data_get_irq_chip_data(data);
mutex_lock(&chip->irq_lock);
}
-static void max8925_irq_sync_unlock(unsigned int irq)
+static void max8925_irq_sync_unlock(struct irq_data *data)
{
- struct max8925_chip *chip = get_irq_chip_data(irq);
+ struct max8925_chip *chip = irq_data_get_irq_chip_data(data);
struct max8925_irq_data *irq_data;
static unsigned char cache_chg[2] = {0xff, 0xff};
static unsigned char cache_on[2] = {0xff, 0xff};
@@ -492,25 +492,25 @@ static void max8925_irq_sync_unlock(unsigned int irq)
mutex_unlock(&chip->irq_lock);
}
-static void max8925_irq_enable(unsigned int irq)
+static void max8925_irq_enable(struct irq_data *data)
{
- struct max8925_chip *chip = get_irq_chip_data(irq);
- max8925_irqs[irq - chip->irq_base].enable
- = max8925_irqs[irq - chip->irq_base].offs;
+ struct max8925_chip *chip = irq_data_get_irq_chip_data(data);
+ max8925_irqs[data->irq - chip->irq_base].enable
+ = max8925_irqs[data->irq - chip->irq_base].offs;
}
-static void max8925_irq_disable(unsigned int irq)
+static void max8925_irq_disable(struct irq_data *data)
{
- struct max8925_chip *chip = get_irq_chip_data(irq);
- max8925_irqs[irq - chip->irq_base].enable = 0;
+ struct max8925_chip *chip = irq_data_get_irq_chip_data(data);
+ max8925_irqs[data->irq - chip->irq_base].enable = 0;
}
static struct irq_chip max8925_irq_chip = {
.name = "max8925",
- .bus_lock = max8925_irq_lock,
- .bus_sync_unlock = max8925_irq_sync_unlock,
- .enable = max8925_irq_enable,
- .disable = max8925_irq_disable,
+ .irq_bus_lock = max8925_irq_lock,
+ .irq_bus_sync_unlock = max8925_irq_sync_unlock,
+ .irq_enable = max8925_irq_enable,
+ .irq_disable = max8925_irq_disable,
};
static int max8925_irq_init(struct max8925_chip *chip, int irq,
diff --git a/drivers/mfd/max8998-irq.c b/drivers/mfd/max8998-irq.c
index 45bfe77b639b..3903e1fbb334 100644
--- a/drivers/mfd/max8998-irq.c
+++ b/drivers/mfd/max8998-irq.c
@@ -102,16 +102,16 @@ irq_to_max8998_irq(struct max8998_dev *max8998, int irq)
return &max8998_irqs[irq - max8998->irq_base];
}
-static void max8998_irq_lock(unsigned int irq)
+static void max8998_irq_lock(struct irq_data *data)
{
- struct max8998_dev *max8998 = get_irq_chip_data(irq);
+ struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
mutex_lock(&max8998->irqlock);
}
-static void max8998_irq_sync_unlock(unsigned int irq)
+static void max8998_irq_sync_unlock(struct irq_data *data)
{
- struct max8998_dev *max8998 = get_irq_chip_data(irq);
+ struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < ARRAY_SIZE(max8998->irq_masks_cur); i++) {
@@ -129,28 +129,30 @@ static void max8998_irq_sync_unlock(unsigned int irq)
mutex_unlock(&max8998->irqlock);
}
-static void max8998_irq_unmask(unsigned int irq)
+static void max8998_irq_unmask(struct irq_data *data)
{
- struct max8998_dev *max8998 = get_irq_chip_data(irq);
- struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, irq);
+ struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
+ struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998,
+ data->irq);
max8998->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
}
-static void max8998_irq_mask(unsigned int irq)
+static void max8998_irq_mask(struct irq_data *data)
{
- struct max8998_dev *max8998 = get_irq_chip_data(irq);
- struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, irq);
+ struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
+ struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998,
+ data->irq);
max8998->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
}
static struct irq_chip max8998_irq_chip = {
.name = "max8998",
- .bus_lock = max8998_irq_lock,
- .bus_sync_unlock = max8998_irq_sync_unlock,
- .mask = max8998_irq_mask,
- .unmask = max8998_irq_unmask,
+ .irq_bus_lock = max8998_irq_lock,
+ .irq_bus_sync_unlock = max8998_irq_sync_unlock,
+ .irq_mask = max8998_irq_mask,
+ .irq_unmask = max8998_irq_unmask,
};
static irqreturn_t max8998_irq_thread(int irq, void *data)
@@ -181,6 +183,13 @@ static irqreturn_t max8998_irq_thread(int irq, void *data)
return IRQ_HANDLED;
}
+int max8998_irq_resume(struct max8998_dev *max8998)
+{
+ if (max8998->irq && max8998->irq_base)
+ max8998_irq_thread(max8998->irq_base, max8998);
+ return 0;
+}
+
int max8998_irq_init(struct max8998_dev *max8998)
{
int i;
diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c
index bb9977bebe78..bbfe86732602 100644
--- a/drivers/mfd/max8998.c
+++ b/drivers/mfd/max8998.c
@@ -25,6 +25,8 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
#include <linux/mutex.h>
#include <linux/mfd/core.h>
#include <linux/mfd/max8998.h>
@@ -40,6 +42,14 @@ static struct mfd_cell max8998_devs[] = {
},
};
+static struct mfd_cell lp3974_devs[] = {
+ {
+ .name = "lp3974-pmic",
+ }, {
+ .name = "lp3974-rtc",
+ },
+};
+
int max8998_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest)
{
struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
@@ -135,6 +145,7 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
if (pdata) {
max8998->ono = pdata->ono;
max8998->irq_base = pdata->irq_base;
+ max8998->wakeup = pdata->wakeup;
}
mutex_init(&max8998->iolock);
@@ -143,9 +154,23 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
max8998_irq_init(max8998);
- ret = mfd_add_devices(max8998->dev, -1,
- max8998_devs, ARRAY_SIZE(max8998_devs),
- NULL, 0);
+ pm_runtime_set_active(max8998->dev);
+
+ switch (id->driver_data) {
+ case TYPE_LP3974:
+ ret = mfd_add_devices(max8998->dev, -1,
+ lp3974_devs, ARRAY_SIZE(lp3974_devs),
+ NULL, 0);
+ break;
+ case TYPE_MAX8998:
+ ret = mfd_add_devices(max8998->dev, -1,
+ max8998_devs, ARRAY_SIZE(max8998_devs),
+ NULL, 0);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
if (ret < 0)
goto err;
@@ -178,10 +203,113 @@ static const struct i2c_device_id max8998_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, max8998_i2c_id);
+static int max8998_suspend(struct device *dev)
+{
+ struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
+
+ if (max8998->wakeup)
+ set_irq_wake(max8998->irq, 1);
+ return 0;
+}
+
+static int max8998_resume(struct device *dev)
+{
+ struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
+
+ if (max8998->wakeup)
+ set_irq_wake(max8998->irq, 0);
+ /*
+ * In LP3974, if IRQ registers are not "read & clear"
+ * when it's set during sleep, the interrupt becomes
+ * disabled.
+ */
+ return max8998_irq_resume(i2c_get_clientdata(i2c));
+}
+
+struct max8998_reg_dump {
+ u8 addr;
+ u8 val;
+};
+#define SAVE_ITEM(x) { .addr = (x), .val = 0x0, }
+struct max8998_reg_dump max8998_dump[] = {
+ SAVE_ITEM(MAX8998_REG_IRQM1),
+ SAVE_ITEM(MAX8998_REG_IRQM2),
+ SAVE_ITEM(MAX8998_REG_IRQM3),
+ SAVE_ITEM(MAX8998_REG_IRQM4),
+ SAVE_ITEM(MAX8998_REG_STATUSM1),
+ SAVE_ITEM(MAX8998_REG_STATUSM2),
+ SAVE_ITEM(MAX8998_REG_CHGR1),
+ SAVE_ITEM(MAX8998_REG_CHGR2),
+ SAVE_ITEM(MAX8998_REG_LDO_ACTIVE_DISCHARGE1),
+ SAVE_ITEM(MAX8998_REG_LDO_ACTIVE_DISCHARGE1),
+ SAVE_ITEM(MAX8998_REG_BUCK_ACTIVE_DISCHARGE3),
+ SAVE_ITEM(MAX8998_REG_ONOFF1),
+ SAVE_ITEM(MAX8998_REG_ONOFF2),
+ SAVE_ITEM(MAX8998_REG_ONOFF3),
+ SAVE_ITEM(MAX8998_REG_ONOFF4),
+ SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE1),
+ SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE2),
+ SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE3),
+ SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE4),
+ SAVE_ITEM(MAX8998_REG_BUCK2_VOLTAGE1),
+ SAVE_ITEM(MAX8998_REG_BUCK2_VOLTAGE2),
+ SAVE_ITEM(MAX8998_REG_LDO2_LDO3),
+ SAVE_ITEM(MAX8998_REG_LDO4),
+ SAVE_ITEM(MAX8998_REG_LDO5),
+ SAVE_ITEM(MAX8998_REG_LDO6),
+ SAVE_ITEM(MAX8998_REG_LDO7),
+ SAVE_ITEM(MAX8998_REG_LDO8_LDO9),
+ SAVE_ITEM(MAX8998_REG_LDO10_LDO11),
+ SAVE_ITEM(MAX8998_REG_LDO12),
+ SAVE_ITEM(MAX8998_REG_LDO13),
+ SAVE_ITEM(MAX8998_REG_LDO14),
+ SAVE_ITEM(MAX8998_REG_LDO15),
+ SAVE_ITEM(MAX8998_REG_LDO16),
+ SAVE_ITEM(MAX8998_REG_LDO17),
+ SAVE_ITEM(MAX8998_REG_BKCHR),
+ SAVE_ITEM(MAX8998_REG_LBCNFG1),
+ SAVE_ITEM(MAX8998_REG_LBCNFG2),
+};
+/* Save registers before hibernation */
+static int max8998_freeze(struct device *dev)
+{
+ struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(max8998_dump); i++)
+ max8998_read_reg(i2c, max8998_dump[i].addr,
+ &max8998_dump[i].val);
+
+ return 0;
+}
+
+/* Restore registers after hibernation */
+static int max8998_restore(struct device *dev)
+{
+ struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(max8998_dump); i++)
+ max8998_write_reg(i2c, max8998_dump[i].addr,
+ max8998_dump[i].val);
+
+ return 0;
+}
+
+const struct dev_pm_ops max8998_pm = {
+ .suspend = max8998_suspend,
+ .resume = max8998_resume,
+ .freeze = max8998_freeze,
+ .restore = max8998_restore,
+};
+
static struct i2c_driver max8998_i2c_driver = {
.driver = {
.name = "max8998",
.owner = THIS_MODULE,
+ .pm = &max8998_pm,
},
.probe = max8998_i2c_probe,
.remove = max8998_i2c_remove,
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index a2ac2ed6d64c..b9fcaf0004da 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -749,7 +749,7 @@ static int mc13xxx_probe(struct spi_device *spi)
if (ret) {
err_mask:
err_revision:
- mutex_unlock(&mc13xxx->lock);
+ mc13xxx_unlock(mc13xxx);
dev_set_drvdata(&spi->dev, NULL);
kfree(mc13xxx);
return ret;
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index ec99f681e773..d83ad0f141af 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/mfd/core.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
static int mfd_add_device(struct device *parent, int id,
@@ -82,6 +83,9 @@ static int mfd_add_device(struct device *parent, int id,
if (ret)
goto fail_res;
+ if (cell->pm_runtime_no_callbacks)
+ pm_runtime_no_callbacks(&pdev->dev);
+
kfree(res);
return 0;
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index bc9275c12133..5de3a760ea1e 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -26,7 +26,7 @@
#include <linux/sm501-regs.h>
#include <linux/serial_8250.h>
-#include <asm/io.h>
+#include <linux/io.h>
struct sm501_device {
struct list_head list;
@@ -745,11 +745,8 @@ static int sm501_register_device(struct sm501_devdata *sm,
int ret;
for (ptr = 0; ptr < pdev->num_resources; ptr++) {
- printk(KERN_DEBUG "%s[%d] flags %08lx: %08llx..%08llx\n",
- pdev->name, ptr,
- pdev->resource[ptr].flags,
- (unsigned long long)pdev->resource[ptr].start,
- (unsigned long long)pdev->resource[ptr].end);
+ printk(KERN_DEBUG "%s[%d] %pR\n",
+ pdev->name, ptr, &pdev->resource[ptr]);
}
ret = platform_device_register(pdev);
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c
index b11487f1e1cb..3e5732b58c49 100644
--- a/drivers/mfd/stmpe.c
+++ b/drivers/mfd/stmpe.c
@@ -699,16 +699,16 @@ static irqreturn_t stmpe_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static void stmpe_irq_lock(unsigned int irq)
+static void stmpe_irq_lock(struct irq_data *data)
{
- struct stmpe *stmpe = get_irq_chip_data(irq);
+ struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
mutex_lock(&stmpe->irq_lock);
}
-static void stmpe_irq_sync_unlock(unsigned int irq)
+static void stmpe_irq_sync_unlock(struct irq_data *data)
{
- struct stmpe *stmpe = get_irq_chip_data(irq);
+ struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
struct stmpe_variant_info *variant = stmpe->variant;
int num = DIV_ROUND_UP(variant->num_irqs, 8);
int i;
@@ -727,20 +727,20 @@ static void stmpe_irq_sync_unlock(unsigned int irq)
mutex_unlock(&stmpe->irq_lock);
}
-static void stmpe_irq_mask(unsigned int irq)
+static void stmpe_irq_mask(struct irq_data *data)
{
- struct stmpe *stmpe = get_irq_chip_data(irq);
- int offset = irq - stmpe->irq_base;
+ struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
+ int offset = data->irq - stmpe->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
stmpe->ier[regoffset] &= ~mask;
}
-static void stmpe_irq_unmask(unsigned int irq)
+static void stmpe_irq_unmask(struct irq_data *data)
{
- struct stmpe *stmpe = get_irq_chip_data(irq);
- int offset = irq - stmpe->irq_base;
+ struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
+ int offset = data->irq - stmpe->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -749,10 +749,10 @@ static void stmpe_irq_unmask(unsigned int irq)
static struct irq_chip stmpe_irq_chip = {
.name = "stmpe",
- .bus_lock = stmpe_irq_lock,
- .bus_sync_unlock = stmpe_irq_sync_unlock,
- .mask = stmpe_irq_mask,
- .unmask = stmpe_irq_unmask,
+ .irq_bus_lock = stmpe_irq_lock,
+ .irq_bus_sync_unlock = stmpe_irq_sync_unlock,
+ .irq_mask = stmpe_irq_mask,
+ .irq_unmask = stmpe_irq_unmask,
};
static int __devinit stmpe_irq_init(struct stmpe *stmpe)
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c
index 006c121f3f0d..9caeb4ac6ea6 100644
--- a/drivers/mfd/t7l66xb.c
+++ b/drivers/mfd/t7l66xb.c
@@ -199,37 +199,37 @@ static void t7l66xb_irq(unsigned int irq, struct irq_desc *desc)
generic_handle_irq(irq_base + i);
}
-static void t7l66xb_irq_mask(unsigned int irq)
+static void t7l66xb_irq_mask(struct irq_data *data)
{
- struct t7l66xb *t7l66xb = get_irq_chip_data(irq);
+ struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data);
unsigned long flags;
u8 imr;
spin_lock_irqsave(&t7l66xb->lock, flags);
imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
- imr |= 1 << (irq - t7l66xb->irq_base);
+ imr |= 1 << (data->irq - t7l66xb->irq_base);
tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
spin_unlock_irqrestore(&t7l66xb->lock, flags);
}
-static void t7l66xb_irq_unmask(unsigned int irq)
+static void t7l66xb_irq_unmask(struct irq_data *data)
{
- struct t7l66xb *t7l66xb = get_irq_chip_data(irq);
+ struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data);
unsigned long flags;
u8 imr;
spin_lock_irqsave(&t7l66xb->lock, flags);
imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
- imr &= ~(1 << (irq - t7l66xb->irq_base));
+ imr &= ~(1 << (data->irq - t7l66xb->irq_base));
tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
spin_unlock_irqrestore(&t7l66xb->lock, flags);
}
static struct irq_chip t7l66xb_chip = {
- .name = "t7l66xb",
- .ack = t7l66xb_irq_mask,
- .mask = t7l66xb_irq_mask,
- .unmask = t7l66xb_irq_unmask,
+ .name = "t7l66xb",
+ .irq_ack = t7l66xb_irq_mask,
+ .irq_mask = t7l66xb_irq_mask,
+ .irq_unmask = t7l66xb_irq_unmask,
};
/*--------------------------------------------------------------------------*/
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
index 1ea80d8ad915..9a238633a54d 100644
--- a/drivers/mfd/tc6393xb.c
+++ b/drivers/mfd/tc6393xb.c
@@ -527,41 +527,41 @@ tc6393xb_irq(unsigned int irq, struct irq_desc *desc)
}
}
-static void tc6393xb_irq_ack(unsigned int irq)
+static void tc6393xb_irq_ack(struct irq_data *data)
{
}
-static void tc6393xb_irq_mask(unsigned int irq)
+static void tc6393xb_irq_mask(struct irq_data *data)
{
- struct tc6393xb *tc6393xb = get_irq_chip_data(irq);
+ struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data);
unsigned long flags;
u8 imr;
spin_lock_irqsave(&tc6393xb->lock, flags);
imr = tmio_ioread8(tc6393xb->scr + SCR_IMR);
- imr |= 1 << (irq - tc6393xb->irq_base);
+ imr |= 1 << (data->irq - tc6393xb->irq_base);
tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR);
spin_unlock_irqrestore(&tc6393xb->lock, flags);
}
-static void tc6393xb_irq_unmask(unsigned int irq)
+static void tc6393xb_irq_unmask(struct irq_data *data)
{
- struct tc6393xb *tc6393xb = get_irq_chip_data(irq);
+ struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data);
unsigned long flags;
u8 imr;
spin_lock_irqsave(&tc6393xb->lock, flags);
imr = tmio_ioread8(tc6393xb->scr + SCR_IMR);
- imr &= ~(1 << (irq - tc6393xb->irq_base));
+ imr &= ~(1 << (data->irq - tc6393xb->irq_base));
tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR);
spin_unlock_irqrestore(&tc6393xb->lock, flags);
}
static struct irq_chip tc6393xb_chip = {
- .name = "tc6393xb",
- .ack = tc6393xb_irq_ack,
- .mask = tc6393xb_irq_mask,
- .unmask = tc6393xb_irq_unmask,
+ .name = "tc6393xb",
+ .irq_ack = tc6393xb_irq_ack,
+ .irq_mask = tc6393xb_irq_mask,
+ .irq_unmask = tc6393xb_irq_unmask,
};
static void tc6393xb_attach_irq(struct platform_device *dev)
diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c
index 90187fe33e04..93d5fdf020c7 100644
--- a/drivers/mfd/tps65010.c
+++ b/drivers/mfd/tps65010.c
@@ -34,7 +34,7 @@
#include <linux/i2c/tps65010.h>
-#include <asm/gpio.h>
+#include <linux/gpio.h>
/*-------------------------------------------------------------------------*/
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c
index b4931ab34929..627cf577b16d 100644
--- a/drivers/mfd/tps6586x.c
+++ b/drivers/mfd/tps6586x.c
@@ -46,8 +46,6 @@
/* device id */
#define TPS6586X_VERSIONCRC 0xcd
-#define TPS658621A_VERSIONCRC 0x15
-#define TPS658621C_VERSIONCRC 0x2c
struct tps6586x_irq_data {
u8 mask_reg;
@@ -325,37 +323,37 @@ static int tps6586x_remove_subdevs(struct tps6586x *tps6586x)
return device_for_each_child(tps6586x->dev, NULL, __remove_subdev);
}
-static void tps6586x_irq_lock(unsigned int irq)
+static void tps6586x_irq_lock(struct irq_data *data)
{
- struct tps6586x *tps6586x = get_irq_chip_data(irq);
+ struct tps6586x *tps6586x = irq_data_get_irq_chip_data(data);
mutex_lock(&tps6586x->irq_lock);
}
-static void tps6586x_irq_enable(unsigned int irq)
+static void tps6586x_irq_enable(struct irq_data *irq_data)
{
- struct tps6586x *tps6586x = get_irq_chip_data(irq);
- unsigned int __irq = irq - tps6586x->irq_base;
+ struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data);
+ unsigned int __irq = irq_data->irq - tps6586x->irq_base;
const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq];
tps6586x->mask_reg[data->mask_reg] &= ~data->mask_mask;
tps6586x->irq_en |= (1 << __irq);
}
-static void tps6586x_irq_disable(unsigned int irq)
+static void tps6586x_irq_disable(struct irq_data *irq_data)
{
- struct tps6586x *tps6586x = get_irq_chip_data(irq);
+ struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data);
- unsigned int __irq = irq - tps6586x->irq_base;
+ unsigned int __irq = irq_data->irq - tps6586x->irq_base;
const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq];
tps6586x->mask_reg[data->mask_reg] |= data->mask_mask;
tps6586x->irq_en &= ~(1 << __irq);
}
-static void tps6586x_irq_sync_unlock(unsigned int irq)
+static void tps6586x_irq_sync_unlock(struct irq_data *data)
{
- struct tps6586x *tps6586x = get_irq_chip_data(irq);
+ struct tps6586x *tps6586x = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < ARRAY_SIZE(tps6586x->mask_reg); i++) {
@@ -421,10 +419,10 @@ static int __devinit tps6586x_irq_init(struct tps6586x *tps6586x, int irq,
tps6586x->irq_base = irq_base;
tps6586x->irq_chip.name = "tps6586x";
- tps6586x->irq_chip.enable = tps6586x_irq_enable;
- tps6586x->irq_chip.disable = tps6586x_irq_disable;
- tps6586x->irq_chip.bus_lock = tps6586x_irq_lock;
- tps6586x->irq_chip.bus_sync_unlock = tps6586x_irq_sync_unlock;
+ tps6586x->irq_chip.irq_enable = tps6586x_irq_enable;
+ tps6586x->irq_chip.irq_disable = tps6586x_irq_disable;
+ tps6586x->irq_chip.irq_bus_lock = tps6586x_irq_lock;
+ tps6586x->irq_chip.irq_bus_sync_unlock = tps6586x_irq_sync_unlock;
for (i = 0; i < ARRAY_SIZE(tps6586x_irqs); i++) {
int __irq = i + tps6586x->irq_base;
@@ -498,11 +496,7 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
return -EIO;
}
- if ((ret != TPS658621A_VERSIONCRC) &&
- (ret != TPS658621C_VERSIONCRC)) {
- dev_err(&client->dev, "Unsupported chip ID: %x\n", ret);
- return -ENODEV;
- }
+ dev_info(&client->dev, "VERSIONCRC is %02x\n", ret);
tps6586x = kzalloc(sizeof(struct tps6586x), GFP_KERNEL);
if (tps6586x == NULL)
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 12abd5b924b3..a35fa7dcbf53 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -1003,7 +1003,7 @@ static int twl_remove(struct i2c_client *client)
}
/* NOTE: this driver only handles a single twl4030/tps659x0 chip */
-static int __init
+static int __devinit
twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int status;
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c
index 5d3a1478004b..63a30e88908f 100644
--- a/drivers/mfd/twl4030-irq.c
+++ b/drivers/mfd/twl4030-irq.c
@@ -599,38 +599,38 @@ static void twl4030_sih_do_edge(struct work_struct *work)
* completion, potentially including some re-ordering, of these requests.
*/
-static void twl4030_sih_mask(unsigned irq)
+static void twl4030_sih_mask(struct irq_data *data)
{
- struct sih_agent *sih = get_irq_chip_data(irq);
+ struct sih_agent *sih = irq_data_get_irq_chip_data(data);
unsigned long flags;
spin_lock_irqsave(&sih_agent_lock, flags);
- sih->imr |= BIT(irq - sih->irq_base);
+ sih->imr |= BIT(data->irq - sih->irq_base);
sih->imr_change_pending = true;
queue_work(wq, &sih->mask_work);
spin_unlock_irqrestore(&sih_agent_lock, flags);
}
-static void twl4030_sih_unmask(unsigned irq)
+static void twl4030_sih_unmask(struct irq_data *data)
{
- struct sih_agent *sih = get_irq_chip_data(irq);
+ struct sih_agent *sih = irq_data_get_irq_chip_data(data);
unsigned long flags;
spin_lock_irqsave(&sih_agent_lock, flags);
- sih->imr &= ~BIT(irq - sih->irq_base);
+ sih->imr &= ~BIT(data->irq - sih->irq_base);
sih->imr_change_pending = true;
queue_work(wq, &sih->mask_work);
spin_unlock_irqrestore(&sih_agent_lock, flags);
}
-static int twl4030_sih_set_type(unsigned irq, unsigned trigger)
+static int twl4030_sih_set_type(struct irq_data *data, unsigned trigger)
{
- struct sih_agent *sih = get_irq_chip_data(irq);
- struct irq_desc *desc = irq_to_desc(irq);
+ struct sih_agent *sih = irq_data_get_irq_chip_data(data);
+ struct irq_desc *desc = irq_to_desc(data->irq);
unsigned long flags;
if (!desc) {
- pr_err("twl4030: Invalid IRQ: %d\n", irq);
+ pr_err("twl4030: Invalid IRQ: %d\n", data->irq);
return -EINVAL;
}
@@ -641,7 +641,7 @@ static int twl4030_sih_set_type(unsigned irq, unsigned trigger)
if ((desc->status & IRQ_TYPE_SENSE_MASK) != trigger) {
desc->status &= ~IRQ_TYPE_SENSE_MASK;
desc->status |= trigger;
- sih->edge_change |= BIT(irq - sih->irq_base);
+ sih->edge_change |= BIT(data->irq - sih->irq_base);
queue_work(wq, &sih->edge_work);
}
spin_unlock_irqrestore(&sih_agent_lock, flags);
@@ -650,9 +650,9 @@ static int twl4030_sih_set_type(unsigned irq, unsigned trigger)
static struct irq_chip twl4030_sih_irq_chip = {
.name = "twl4030",
- .mask = twl4030_sih_mask,
- .unmask = twl4030_sih_unmask,
- .set_type = twl4030_sih_set_type,
+ .irq_mask = twl4030_sih_mask,
+ .irq_unmask = twl4030_sih_unmask,
+ .irq_set_type = twl4030_sih_set_type,
};
/*----------------------------------------------------------------------*/
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index 06c8955907e9..4082ed73613f 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -332,7 +332,7 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
*/
twl6030_irq_chip = dummy_irq_chip;
twl6030_irq_chip.name = "twl6030";
- twl6030_irq_chip.set_type = NULL;
+ twl6030_irq_chip.irq_set_type = NULL;
for (i = irq_base; i < irq_end; i++) {
set_irq_chip_and_handler(i, &twl6030_irq_chip,
diff --git a/drivers/mfd/vx855.c b/drivers/mfd/vx855.c
index ebb059765edd..348052aa5dbf 100644
--- a/drivers/mfd/vx855.c
+++ b/drivers/mfd/vx855.c
@@ -112,7 +112,7 @@ out:
return ret;
}
-static void vx855_remove(struct pci_dev *pdev)
+static void __devexit vx855_remove(struct pci_dev *pdev)
{
mfd_remove_devices(&pdev->dev);
pci_disable_device(pdev);
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index 76cadcf3b1fe..3fe9a58fe6c7 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -1541,6 +1541,12 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
dev_info(wm831x->dev, "WM8325 revision %c\n", 'A' + rev);
break;
+ case WM8326:
+ parent = WM8326;
+ wm831x->num_gpio = 12;
+ dev_info(wm831x->dev, "WM8326 revision %c\n", 'A' + rev);
+ break;
+
default:
dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
ret = -EINVAL;
@@ -1610,18 +1616,9 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
break;
case WM8320:
- ret = mfd_add_devices(wm831x->dev, -1,
- wm8320_devs, ARRAY_SIZE(wm8320_devs),
- NULL, 0);
- break;
-
case WM8321:
- ret = mfd_add_devices(wm831x->dev, -1,
- wm8320_devs, ARRAY_SIZE(wm8320_devs),
- NULL, 0);
- break;
-
case WM8325:
+ case WM8326:
ret = mfd_add_devices(wm831x->dev, -1,
wm8320_devs, ARRAY_SIZE(wm8320_devs),
NULL, wm831x->irq_base);
diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c
index 156b19859e81..3853fa8e7cc2 100644
--- a/drivers/mfd/wm831x-i2c.c
+++ b/drivers/mfd/wm831x-i2c.c
@@ -94,9 +94,9 @@ static int wm831x_i2c_remove(struct i2c_client *i2c)
return 0;
}
-static int wm831x_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg)
+static int wm831x_i2c_suspend(struct device *dev)
{
- struct wm831x *wm831x = i2c_get_clientdata(i2c);
+ struct wm831x *wm831x = dev_get_drvdata(dev);
return wm831x_device_suspend(wm831x);
}
@@ -108,19 +108,23 @@ static const struct i2c_device_id wm831x_i2c_id[] = {
{ "wm8320", WM8320 },
{ "wm8321", WM8321 },
{ "wm8325", WM8325 },
+ { "wm8326", WM8326 },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);
+static const struct dev_pm_ops wm831x_pm_ops = {
+ .suspend = wm831x_i2c_suspend,
+};
static struct i2c_driver wm831x_i2c_driver = {
.driver = {
- .name = "wm831x",
- .owner = THIS_MODULE,
+ .name = "wm831x",
+ .owner = THIS_MODULE,
+ .pm = &wm831x_pm_ops,
},
.probe = wm831x_i2c_probe,
.remove = wm831x_i2c_remove,
- .suspend = wm831x_i2c_suspend,
.id_table = wm831x_i2c_id,
};
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c
index 294183b6260b..f7192d438aab 100644
--- a/drivers/mfd/wm831x-irq.c
+++ b/drivers/mfd/wm831x-irq.c
@@ -345,16 +345,16 @@ static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x,
return &wm831x_irqs[irq - wm831x->irq_base];
}
-static void wm831x_irq_lock(unsigned int irq)
+static void wm831x_irq_lock(struct irq_data *data)
{
- struct wm831x *wm831x = get_irq_chip_data(irq);
+ struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
mutex_lock(&wm831x->irq_lock);
}
-static void wm831x_irq_sync_unlock(unsigned int irq)
+static void wm831x_irq_sync_unlock(struct irq_data *data)
{
- struct wm831x *wm831x = get_irq_chip_data(irq);
+ struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) {
@@ -371,28 +371,30 @@ static void wm831x_irq_sync_unlock(unsigned int irq)
mutex_unlock(&wm831x->irq_lock);
}
-static void wm831x_irq_unmask(unsigned int irq)
+static void wm831x_irq_unmask(struct irq_data *data)
{
- struct wm831x *wm831x = get_irq_chip_data(irq);
- struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq);
+ struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
+ struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x,
+ data->irq);
wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
}
-static void wm831x_irq_mask(unsigned int irq)
+static void wm831x_irq_mask(struct irq_data *data)
{
- struct wm831x *wm831x = get_irq_chip_data(irq);
- struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq);
+ struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
+ struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x,
+ data->irq);
wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
}
-static int wm831x_irq_set_type(unsigned int irq, unsigned int type)
+static int wm831x_irq_set_type(struct irq_data *data, unsigned int type)
{
- struct wm831x *wm831x = get_irq_chip_data(irq);
- int val;
+ struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
+ int val, irq;
- irq = irq - wm831x->irq_base;
+ irq = data->irq - wm831x->irq_base;
if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11) {
/* Ignore internal-only IRQs */
@@ -421,12 +423,12 @@ static int wm831x_irq_set_type(unsigned int irq, unsigned int type)
}
static struct irq_chip wm831x_irq_chip = {
- .name = "wm831x",
- .bus_lock = wm831x_irq_lock,
- .bus_sync_unlock = wm831x_irq_sync_unlock,
- .mask = wm831x_irq_mask,
- .unmask = wm831x_irq_unmask,
- .set_type = wm831x_irq_set_type,
+ .name = "wm831x",
+ .irq_bus_lock = wm831x_irq_lock,
+ .irq_bus_sync_unlock = wm831x_irq_sync_unlock,
+ .irq_mask = wm831x_irq_mask,
+ .irq_unmask = wm831x_irq_unmask,
+ .irq_set_type = wm831x_irq_set_type,
};
/* The processing of the primary interrupt occurs in a thread so that
@@ -515,6 +517,17 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
return 0;
}
+ /* Try to flag /IRQ as a wake source; there are a number of
+ * unconditional wake sources in the PMIC so this isn't
+ * conditional but we don't actually care *too* much if it
+ * fails.
+ */
+ ret = enable_irq_wake(irq);
+ if (ret != 0) {
+ dev_warn(wm831x->dev, "Can't enable IRQ as wake source: %d\n",
+ ret);
+ }
+
wm831x->irq = irq;
wm831x->irq_base = pdata->irq_base;
diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c
index 2789b151b0f9..0a8f772be88c 100644
--- a/drivers/mfd/wm831x-spi.c
+++ b/drivers/mfd/wm831x-spi.c
@@ -81,6 +81,8 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi)
type = WM8321;
else if (strcmp(spi->modalias, "wm8325") == 0)
type = WM8325;
+ else if (strcmp(spi->modalias, "wm8326") == 0)
+ type = WM8326;
else {
dev_err(&spi->dev, "Unknown device type\n");
return -EINVAL;
@@ -184,6 +186,17 @@ static struct spi_driver wm8325_spi_driver = {
.suspend = wm831x_spi_suspend,
};
+static struct spi_driver wm8326_spi_driver = {
+ .driver = {
+ .name = "wm8326",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = wm831x_spi_probe,
+ .remove = __devexit_p(wm831x_spi_remove),
+ .suspend = wm831x_spi_suspend,
+};
+
static int __init wm831x_spi_init(void)
{
int ret;
@@ -212,12 +225,17 @@ static int __init wm831x_spi_init(void)
if (ret != 0)
pr_err("Failed to register WM8325 SPI driver: %d\n", ret);
+ ret = spi_register_driver(&wm8326_spi_driver);
+ if (ret != 0)
+ pr_err("Failed to register WM8326 SPI driver: %d\n", ret);
+
return 0;
}
subsys_initcall(wm831x_spi_init);
static void __exit wm831x_spi_exit(void)
{
+ spi_unregister_driver(&wm8326_spi_driver);
spi_unregister_driver(&wm8325_spi_driver);
spi_unregister_driver(&wm8321_spi_driver);
spi_unregister_driver(&wm8320_spi_driver);
diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c
index f56c9adf9493..5839966ebd85 100644
--- a/drivers/mfd/wm8350-irq.c
+++ b/drivers/mfd/wm8350-irq.c
@@ -417,16 +417,16 @@ static irqreturn_t wm8350_irq(int irq, void *irq_data)
return IRQ_HANDLED;
}
-static void wm8350_irq_lock(unsigned int irq)
+static void wm8350_irq_lock(struct irq_data *data)
{
- struct wm8350 *wm8350 = get_irq_chip_data(irq);
+ struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
mutex_lock(&wm8350->irq_lock);
}
-static void wm8350_irq_sync_unlock(unsigned int irq)
+static void wm8350_irq_sync_unlock(struct irq_data *data)
{
- struct wm8350 *wm8350 = get_irq_chip_data(irq);
+ struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) {
@@ -442,28 +442,30 @@ static void wm8350_irq_sync_unlock(unsigned int irq)
mutex_unlock(&wm8350->irq_lock);
}
-static void wm8350_irq_enable(unsigned int irq)
+static void wm8350_irq_enable(struct irq_data *data)
{
- struct wm8350 *wm8350 = get_irq_chip_data(irq);
- struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq);
+ struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
+ struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350,
+ data->irq);
wm8350->irq_masks[irq_data->reg] &= ~irq_data->mask;
}
-static void wm8350_irq_disable(unsigned int irq)
+static void wm8350_irq_disable(struct irq_data *data)
{
- struct wm8350 *wm8350 = get_irq_chip_data(irq);
- struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq);
+ struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
+ struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350,
+ data->irq);
wm8350->irq_masks[irq_data->reg] |= irq_data->mask;
}
static struct irq_chip wm8350_irq_chip = {
- .name = "wm8350",
- .bus_lock = wm8350_irq_lock,
- .bus_sync_unlock = wm8350_irq_sync_unlock,
- .disable = wm8350_irq_disable,
- .enable = wm8350_irq_enable,
+ .name = "wm8350",
+ .irq_bus_lock = wm8350_irq_lock,
+ .irq_bus_sync_unlock = wm8350_irq_sync_unlock,
+ .irq_disable = wm8350_irq_disable,
+ .irq_enable = wm8350_irq_enable,
};
int wm8350_irq_init(struct wm8350 *wm8350, int irq,
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index 8d221ba5e38d..41233c7fa581 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -18,6 +18,7 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/mfd/core.h>
+#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/machine.h>
@@ -169,8 +170,16 @@ out:
EXPORT_SYMBOL_GPL(wm8994_set_bits);
static struct mfd_cell wm8994_regulator_devs[] = {
- { .name = "wm8994-ldo", .id = 1 },
- { .name = "wm8994-ldo", .id = 2 },
+ {
+ .name = "wm8994-ldo",
+ .id = 1,
+ .pm_runtime_no_callbacks = true,
+ },
+ {
+ .name = "wm8994-ldo",
+ .id = 2,
+ .pm_runtime_no_callbacks = true,
+ },
};
static struct resource wm8994_codec_resources[] = {
@@ -200,6 +209,7 @@ static struct mfd_cell wm8994_devs[] = {
.name = "wm8994-gpio",
.num_resources = ARRAY_SIZE(wm8994_gpio_resources),
.resources = wm8994_gpio_resources,
+ .pm_runtime_no_callbacks = true,
},
};
@@ -231,7 +241,7 @@ static const char *wm8958_main_supplies[] = {
};
#ifdef CONFIG_PM
-static int wm8994_device_suspend(struct device *dev)
+static int wm8994_suspend(struct device *dev)
{
struct wm8994 *wm8994 = dev_get_drvdata(dev);
int ret;
@@ -261,7 +271,7 @@ static int wm8994_device_suspend(struct device *dev)
return 0;
}
-static int wm8994_device_resume(struct device *dev)
+static int wm8994_resume(struct device *dev)
{
struct wm8994 *wm8994 = dev_get_drvdata(dev);
int ret;
@@ -471,6 +481,9 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
goto err_irq;
}
+ pm_runtime_enable(wm8994->dev);
+ pm_runtime_resume(wm8994->dev);
+
return 0;
err_irq:
@@ -490,6 +503,7 @@ err:
static void wm8994_device_exit(struct wm8994 *wm8994)
{
+ pm_runtime_disable(wm8994->dev);
mfd_remove_devices(wm8994->dev);
wm8994_irq_exit(wm8994);
regulator_bulk_disable(wm8994->num_supplies,
@@ -573,21 +587,6 @@ static int wm8994_i2c_remove(struct i2c_client *i2c)
return 0;
}
-#ifdef CONFIG_PM
-static int wm8994_i2c_suspend(struct i2c_client *i2c, pm_message_t state)
-{
- return wm8994_device_suspend(&i2c->dev);
-}
-
-static int wm8994_i2c_resume(struct i2c_client *i2c)
-{
- return wm8994_device_resume(&i2c->dev);
-}
-#else
-#define wm8994_i2c_suspend NULL
-#define wm8994_i2c_resume NULL
-#endif
-
static const struct i2c_device_id wm8994_i2c_id[] = {
{ "wm8994", WM8994 },
{ "wm8958", WM8958 },
@@ -595,15 +594,16 @@ static const struct i2c_device_id wm8994_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id);
+UNIVERSAL_DEV_PM_OPS(wm8994_pm_ops, wm8994_suspend, wm8994_resume, NULL);
+
static struct i2c_driver wm8994_i2c_driver = {
.driver = {
- .name = "wm8994",
- .owner = THIS_MODULE,
+ .name = "wm8994",
+ .owner = THIS_MODULE,
+ .pm = &wm8994_pm_ops,
},
.probe = wm8994_i2c_probe,
.remove = wm8994_i2c_remove,
- .suspend = wm8994_i2c_suspend,
- .resume = wm8994_i2c_resume,
.id_table = wm8994_i2c_id,
};
diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c
index 8400eb1ee5db..29e8faf9c01c 100644
--- a/drivers/mfd/wm8994-irq.c
+++ b/drivers/mfd/wm8994-irq.c
@@ -156,16 +156,16 @@ static inline struct wm8994_irq_data *irq_to_wm8994_irq(struct wm8994 *wm8994,
return &wm8994_irqs[irq - wm8994->irq_base];
}
-static void wm8994_irq_lock(unsigned int irq)
+static void wm8994_irq_lock(struct irq_data *data)
{
- struct wm8994 *wm8994 = get_irq_chip_data(irq);
+ struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
mutex_lock(&wm8994->irq_lock);
}
-static void wm8994_irq_sync_unlock(unsigned int irq)
+static void wm8994_irq_sync_unlock(struct irq_data *data)
{
- struct wm8994 *wm8994 = get_irq_chip_data(irq);
+ struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
@@ -182,28 +182,30 @@ static void wm8994_irq_sync_unlock(unsigned int irq)
mutex_unlock(&wm8994->irq_lock);
}
-static void wm8994_irq_unmask(unsigned int irq)
+static void wm8994_irq_unmask(struct irq_data *data)
{
- struct wm8994 *wm8994 = get_irq_chip_data(irq);
- struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, irq);
+ struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
+ struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
+ data->irq);
wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
}
-static void wm8994_irq_mask(unsigned int irq)
+static void wm8994_irq_mask(struct irq_data *data)
{
- struct wm8994 *wm8994 = get_irq_chip_data(irq);
- struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, irq);
+ struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
+ struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
+ data->irq);
wm8994->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
}
static struct irq_chip wm8994_irq_chip = {
- .name = "wm8994",
- .bus_lock = wm8994_irq_lock,
- .bus_sync_unlock = wm8994_irq_sync_unlock,
- .mask = wm8994_irq_mask,
- .unmask = wm8994_irq_unmask,
+ .name = "wm8994",
+ .irq_bus_lock = wm8994_irq_lock,
+ .irq_bus_sync_unlock = wm8994_irq_sync_unlock,
+ .irq_mask = wm8994_irq_mask,
+ .irq_unmask = wm8994_irq_unmask,
};
/* The processing of the primary interrupt occurs in a thread so that
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 1e1a4be8eb6c..cc8e49db45fe 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -64,7 +64,7 @@ config ATMEL_PWM
config AB8500_PWM
bool "AB8500 PWM support"
- depends on AB8500_CORE
+ depends on AB8500_CORE && ARCH_U8500
select HAVE_PWM
help
This driver exports functions to enable/disble/config/free Pulse
diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c
index 6f6218061b0d..d02d302ee6d5 100644
--- a/drivers/misc/cs5535-mfgpt.c
+++ b/drivers/misc/cs5535-mfgpt.c
@@ -16,12 +16,11 @@
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/module.h>
-#include <linux/pci.h>
+#include <linux/platform_device.h>
#include <linux/cs5535.h>
#include <linux/slab.h>
#define DRV_NAME "cs5535-mfgpt"
-#define MFGPT_BAR 2
static int mfgpt_reset_timers;
module_param_named(mfgptfix, mfgpt_reset_timers, int, 0644);
@@ -37,7 +36,7 @@ static struct cs5535_mfgpt_chip {
DECLARE_BITMAP(avail, MFGPT_MAX_TIMERS);
resource_size_t base;
- struct pci_dev *pdev;
+ struct platform_device *pdev;
spinlock_t lock;
int initialized;
} cs5535_mfgpt_chip;
@@ -290,10 +289,10 @@ static int __init scan_timers(struct cs5535_mfgpt_chip *mfgpt)
return timers;
}
-static int __init cs5535_mfgpt_probe(struct pci_dev *pdev,
- const struct pci_device_id *pci_id)
+static int __devinit cs5535_mfgpt_probe(struct platform_device *pdev)
{
- int err, t;
+ struct resource *res;
+ int err = -EIO, t;
/* There are two ways to get the MFGPT base address; one is by
* fetching it from MSR_LBAR_MFGPT, the other is by reading the
@@ -302,29 +301,27 @@ static int __init cs5535_mfgpt_probe(struct pci_dev *pdev,
* it turns out to be unreliable in the face of crappy BIOSes, we
* can always go back to using MSRs.. */
- err = pci_enable_device_io(pdev);
- if (err) {
- dev_err(&pdev->dev, "can't enable device IO\n");
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't fetch device resource info\n");
goto done;
}
- err = pci_request_region(pdev, MFGPT_BAR, DRV_NAME);
- if (err) {
- dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", MFGPT_BAR);
+ if (!request_region(res->start, resource_size(res), pdev->name)) {
+ dev_err(&pdev->dev, "can't request region\n");
goto done;
}
/* set up the driver-specific struct */
- cs5535_mfgpt_chip.base = pci_resource_start(pdev, MFGPT_BAR);
+ cs5535_mfgpt_chip.base = res->start;
cs5535_mfgpt_chip.pdev = pdev;
spin_lock_init(&cs5535_mfgpt_chip.lock);
- dev_info(&pdev->dev, "allocated PCI BAR #%d: base 0x%llx\n", MFGPT_BAR,
- (unsigned long long) cs5535_mfgpt_chip.base);
+ dev_info(&pdev->dev, "reserved resource region %pR\n", res);
/* detect the available timers */
t = scan_timers(&cs5535_mfgpt_chip);
- dev_info(&pdev->dev, DRV_NAME ": %d MFGPT timers available\n", t);
+ dev_info(&pdev->dev, "%d MFGPT timers available\n", t);
cs5535_mfgpt_chip.initialized = 1;
return 0;
@@ -332,47 +329,18 @@ done:
return err;
}
-static struct pci_device_id cs5535_mfgpt_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
- { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
- { 0, },
+static struct platform_driver cs5535_mfgpt_drv = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = cs5535_mfgpt_probe,
};
-MODULE_DEVICE_TABLE(pci, cs5535_mfgpt_pci_tbl);
-/*
- * Just like with the cs5535-gpio driver, we can't use the standard PCI driver
- * registration stuff. It only allows only one driver to bind to each PCI
- * device, and we want the GPIO and MFGPT drivers to be able to share a PCI
- * device. Instead, we manually scan for the PCI device, request a single
- * region, and keep track of the devices that we're using.
- */
-
-static int __init cs5535_mfgpt_scan_pci(void)
-{
- struct pci_dev *pdev;
- int err = -ENODEV;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(cs5535_mfgpt_pci_tbl); i++) {
- pdev = pci_get_device(cs5535_mfgpt_pci_tbl[i].vendor,
- cs5535_mfgpt_pci_tbl[i].device, NULL);
- if (pdev) {
- err = cs5535_mfgpt_probe(pdev,
- &cs5535_mfgpt_pci_tbl[i]);
- if (err)
- pci_dev_put(pdev);
-
- /* we only support a single CS5535/6 southbridge */
- break;
- }
- }
-
- return err;
-}
static int __init cs5535_mfgpt_init(void)
{
- return cs5535_mfgpt_scan_pci();
+ return platform_driver_register(&cs5535_mfgpt_drv);
}
module_init(cs5535_mfgpt_init);
@@ -380,3 +348,4 @@ module_init(cs5535_mfgpt_init);
MODULE_AUTHOR("Andres Salomon <[email protected]>");
MODULE_DESCRIPTION("CS5535/CS5536 MFGPT timer driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index a37fcf11ab36..ea5cfe2c3a04 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -3403,9 +3403,7 @@ static int myri10ge_resume(struct pci_dev *pdev)
return -EIO;
}
- status = pci_restore_state(pdev);
- if (status)
- return status;
+ pci_restore_state(pdev);
status = pci_enable_device(pdev);
if (status) {
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 70e4f7dcce81..61ddd2c6e750 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -1107,22 +1107,9 @@ static int __falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
/* Restore PCI configuration if needed */
if (method == RESET_TYPE_WORLD) {
- if (efx_nic_is_dual_func(efx)) {
- rc = pci_restore_state(nic_data->pci_dev2);
- if (rc) {
- netif_err(efx, drv, efx->net_dev,
- "failed to restore PCI config for "
- "the secondary function\n");
- goto fail3;
- }
- }
- rc = pci_restore_state(efx->pci_dev);
- if (rc) {
- netif_err(efx, drv, efx->net_dev,
- "failed to restore PCI config for the "
- "primary function\n");
- goto fail4;
- }
+ if (efx_nic_is_dual_func(efx))
+ pci_restore_state(nic_data->pci_dev2);
+ pci_restore_state(efx->pci_dev);
netif_dbg(efx, drv, efx->net_dev,
"successfully restored PCI config\n");
}
@@ -1133,7 +1120,7 @@ static int __falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
rc = -ETIMEDOUT;
netif_err(efx, hw, efx->net_dev,
"timed out waiting for hardware reset\n");
- goto fail5;
+ goto fail3;
}
netif_dbg(efx, hw, efx->net_dev, "hardware reset complete\n");
@@ -1141,11 +1128,9 @@ static int __falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
/* pci_save_state() and pci_restore_state() MUST be called in pairs */
fail2:
-fail3:
pci_restore_state(efx->pci_dev);
fail1:
-fail4:
-fail5:
+fail3:
return rc;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 73631c6fbb30..ace0b668c04e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -363,12 +363,12 @@ int rt2x00pci_resume(struct pci_dev *pci_dev)
struct rt2x00_dev *rt2x00dev = hw->priv;
if (pci_set_power_state(pci_dev, PCI_D0) ||
- pci_enable_device(pci_dev) ||
- pci_restore_state(pci_dev)) {
+ pci_enable_device(pci_dev)) {
ERROR(rt2x00dev, "Failed to resume device.\n");
return -EIO;
}
+ pci_restore_state(pci_dev);
return rt2x00lib_resume(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00pci_resume);
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 7c24dcef2989..44b0aeee83e5 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -168,8 +168,9 @@ static u32 __msix_mask_irq(struct msi_desc *desc, u32 flag)
u32 mask_bits = desc->masked;
unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
PCI_MSIX_ENTRY_VECTOR_CTRL;
- mask_bits &= ~1;
- mask_bits |= flag;
+ mask_bits &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
+ if (flag)
+ mask_bits |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
writel(mask_bits, desc->mask_base + offset);
return mask_bits;
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h
index feff3bee6fe5..65c42f80f23e 100644
--- a/drivers/pci/msi.h
+++ b/drivers/pci/msi.h
@@ -6,12 +6,6 @@
#ifndef MSI_H
#define MSI_H
-#define PCI_MSIX_ENTRY_SIZE 16
-#define PCI_MSIX_ENTRY_LOWER_ADDR 0
-#define PCI_MSIX_ENTRY_UPPER_ADDR 4
-#define PCI_MSIX_ENTRY_DATA 8
-#define PCI_MSIX_ENTRY_VECTOR_CTRL 12
-
#define msi_control_reg(base) (base + PCI_MSI_FLAGS)
#define msi_lower_address_reg(base) (base + PCI_MSI_ADDRESS_LO)
#define msi_upper_address_reg(base) (base + PCI_MSI_ADDRESS_HI)
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 24e19c594e57..6fe0772e0e7d 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -46,9 +46,9 @@ static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
struct pci_dev *pci_dev = context;
if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_dev) {
+ pci_wakeup_event(pci_dev);
pci_check_pme_status(pci_dev);
pm_runtime_resume(&pci_dev->dev);
- pci_wakeup_event(pci_dev);
if (pci_dev->subordinate)
pci_pme_wakeup_bus(pci_dev->subordinate);
}
@@ -399,6 +399,7 @@ static int __init acpi_pci_init(void)
if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n");
+ pcie_clear_aspm();
pcie_no_aspm();
}
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 8a6f797de8e5..88246dd46452 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -338,7 +338,7 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
}
/**
- * __pci_device_probe()
+ * __pci_device_probe - check if a driver wants to claim a specific PCI device
* @drv: driver to call to check if it wants the PCI device
* @pci_dev: PCI device being probed
*
@@ -449,7 +449,8 @@ static int pci_restore_standard_config(struct pci_dev *pci_dev)
return error;
}
- return pci_restore_state(pci_dev);
+ pci_restore_state(pci_dev);
+ return 0;
}
static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
diff --git a/drivers/pci/pci-stub.c b/drivers/pci/pci-stub.c
index f7b68ca6cc98..775e933c2225 100644
--- a/drivers/pci/pci-stub.c
+++ b/drivers/pci/pci-stub.c
@@ -47,6 +47,10 @@ static int __init pci_stub_init(void)
if (rc)
return rc;
+ /* no ids passed actually */
+ if (ids[0] == '\0')
+ return 0;
+
/* add ids specified in the module parameter */
p = ids;
while ((id = strsep(&p, ","))) {
@@ -54,6 +58,9 @@ static int __init pci_stub_init(void)
subdevice = PCI_ANY_ID, class=0, class_mask=0;
int fields;
+ if (!strlen(id))
+ continue;
+
fields = sscanf(id, "%x:%x:%x:%x:%x:%x",
&vendor, &device, &subvendor, &subdevice,
&class, &class_mask);
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 63d5042f2079..8ecaac983923 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -1149,7 +1149,7 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
sysfs_bin_attr_init(attr);
attr->size = rom_size;
attr->attr.name = "rom";
- attr->attr.mode = S_IRUSR;
+ attr->attr.mode = S_IRUSR | S_IWUSR;
attr->read = pci_read_rom;
attr->write = pci_write_rom;
retval = sysfs_create_bin_file(&pdev->dev.kobj, attr);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 710c8a29be0d..b714d787bddd 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -937,14 +937,13 @@ pci_save_state(struct pci_dev *dev)
* pci_restore_state - Restore the saved state of a PCI device
* @dev: - PCI device that we're dealing with
*/
-int
-pci_restore_state(struct pci_dev *dev)
+void pci_restore_state(struct pci_dev *dev)
{
int i;
u32 val;
if (!dev->state_saved)
- return 0;
+ return;
/* PCI Express register must be restored first */
pci_restore_pcie_state(dev);
@@ -968,8 +967,6 @@ pci_restore_state(struct pci_dev *dev)
pci_restore_iov_state(dev);
dev->state_saved = false;
-
- return 0;
}
static int do_pci_enable_device(struct pci_dev *dev, int bars)
@@ -1300,22 +1297,6 @@ bool pci_check_pme_status(struct pci_dev *dev)
return ret;
}
-/*
- * Time to wait before the system can be put into a sleep state after reporting
- * a wakeup event signaled by a PCI device.
- */
-#define PCI_WAKEUP_COOLDOWN 100
-
-/**
- * pci_wakeup_event - Report a wakeup event related to a given PCI device.
- * @dev: Device to report the wakeup event for.
- */
-void pci_wakeup_event(struct pci_dev *dev)
-{
- if (device_may_wakeup(&dev->dev))
- pm_wakeup_event(&dev->dev, PCI_WAKEUP_COOLDOWN);
-}
-
/**
* pci_pme_wakeup - Wake up a PCI device if its PME Status bit is set.
* @dev: Device to handle.
@@ -1327,8 +1308,8 @@ void pci_wakeup_event(struct pci_dev *dev)
static int pci_pme_wakeup(struct pci_dev *dev, void *ign)
{
if (pci_check_pme_status(dev)) {
- pm_request_resume(&dev->dev);
pci_wakeup_event(dev);
+ pm_request_resume(&dev->dev);
}
return 0;
}
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 7d33f6673868..f69d6e0fda75 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -74,6 +74,12 @@ extern void pci_pm_init(struct pci_dev *dev);
extern void platform_pci_wakeup_init(struct pci_dev *dev);
extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
+static inline void pci_wakeup_event(struct pci_dev *dev)
+{
+ /* Wait 100 ms before the system can be put into a sleep state. */
+ pm_wakeup_event(&dev->dev, 100);
+}
+
static inline bool pci_is_bridge(struct pci_dev *pci_dev)
{
return !!(pci_dev->subordinate);
@@ -140,14 +146,6 @@ static inline void pci_no_msi(void) { }
static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
#endif
-#ifdef CONFIG_PCIEAER
-void pci_no_aer(void);
-bool pci_aer_available(void);
-#else
-static inline void pci_no_aer(void) { }
-static inline bool pci_aer_available(void) { return false; }
-#endif
-
static inline int pci_no_d1d2(struct pci_dev *dev)
{
unsigned int parent_dstates = 0;
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index 2b2b6508efde..58ad7917553c 100644
--- a/drivers/pci/pcie/aer/aerdrv.c
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/pci-acpi.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h
index 9656e3060412..80c11d131499 100644
--- a/drivers/pci/pcie/aer/aerdrv.h
+++ b/drivers/pci/pcie/aer/aerdrv.h
@@ -132,7 +132,6 @@ static inline int aer_osc_setup(struct pcie_device *pciedev)
#ifdef CONFIG_ACPI_APEI
extern int pcie_aer_get_firmware_first(struct pci_dev *pci_dev);
-extern bool aer_acpi_firmware_first(void);
#else
static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev)
{
@@ -140,8 +139,6 @@ static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev)
return pci_dev->__aer_firmware_first;
return 0;
}
-
-static inline bool aer_acpi_firmware_first(void) { return false; }
#endif
static inline void pcie_aer_force_firmware_first(struct pci_dev *pci_dev,
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 71222814c1ec..3188cd96b338 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -68,7 +68,7 @@ struct pcie_link_state {
struct aspm_latency acceptable[8];
};
-static int aspm_disabled, aspm_force;
+static int aspm_disabled, aspm_force, aspm_clear_state;
static DEFINE_MUTEX(aspm_lock);
static LIST_HEAD(link_list);
@@ -139,7 +139,7 @@ static void pcie_set_clkpm(struct pcie_link_state *link, int enable)
{
/* Don't enable Clock PM if the link is not Clock PM capable */
if (!link->clkpm_capable && enable)
- return;
+ enable = 0;
/* Need nothing if the specified equals to current state */
if (link->clkpm_enabled == enable)
return;
@@ -498,6 +498,10 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev)
struct pci_dev *child;
int pos;
u32 reg32;
+
+ if (aspm_clear_state)
+ return -EINVAL;
+
/*
* Some functions in a slot might not all be PCIe functions,
* very strange. Disable ASPM for the whole slot
@@ -563,12 +567,15 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
struct pcie_link_state *link;
int blacklist = !!pcie_aspm_sanity_check(pdev);
- if (aspm_disabled || !pci_is_pcie(pdev) || pdev->link_state)
+ if (!pci_is_pcie(pdev) || pdev->link_state)
return;
if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
return;
+ if (aspm_disabled && !aspm_clear_state)
+ return;
+
/* VIA has a strange chipset, root port is under a bridge */
if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT &&
pdev->bus->self)
@@ -641,7 +648,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
struct pci_dev *parent = pdev->bus->self;
struct pcie_link_state *link, *root, *parent_link;
- if (aspm_disabled || !pci_is_pcie(pdev) ||
+ if ((aspm_disabled && !aspm_clear_state) || !pci_is_pcie(pdev) ||
!parent || !parent->link_state)
return;
if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
@@ -899,6 +906,12 @@ static int __init pcie_aspm_disable(char *str)
__setup("pcie_aspm=", pcie_aspm_disable);
+void pcie_clear_aspm(void)
+{
+ if (!aspm_force)
+ aspm_clear_state = 1;
+}
+
void pcie_no_aspm(void)
{
if (!aspm_force)
diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c
index 2f3c90407227..0057344a3fcb 100644
--- a/drivers/pci/pcie/pme.c
+++ b/drivers/pci/pcie/pme.c
@@ -26,9 +26,6 @@
#include "../pci.h"
#include "portdrv.h"
-#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */
-#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */
-
/*
* If this switch is set, MSI will not be used for PCIe PME signaling. This
* causes the PCIe port driver to use INTx interrupts only, but it turns out
@@ -74,22 +71,6 @@ void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable)
}
/**
- * pcie_pme_clear_status - Clear root port PME interrupt status.
- * @dev: PCIe root port or event collector.
- */
-static void pcie_pme_clear_status(struct pci_dev *dev)
-{
- int rtsta_pos;
- u32 rtsta;
-
- rtsta_pos = pci_pcie_cap(dev) + PCI_EXP_RTSTA;
-
- pci_read_config_dword(dev, rtsta_pos, &rtsta);
- rtsta |= PCI_EXP_RTSTA_PME;
- pci_write_config_dword(dev, rtsta_pos, rtsta);
-}
-
-/**
* pcie_pme_walk_bus - Scan a PCI bus for devices asserting PME#.
* @bus: PCI bus to scan.
*
@@ -103,8 +84,8 @@ static bool pcie_pme_walk_bus(struct pci_bus *bus)
list_for_each_entry(dev, &bus->devices, bus_list) {
/* Skip PCIe devices in case we started from a root port. */
if (!pci_is_pcie(dev) && pci_check_pme_status(dev)) {
- pm_request_resume(&dev->dev);
pci_wakeup_event(dev);
+ pm_request_resume(&dev->dev);
ret = true;
}
@@ -206,8 +187,8 @@ static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id)
/* The device is there, but we have to check its PME status. */
found = pci_check_pme_status(dev);
if (found) {
- pm_request_resume(&dev->dev);
pci_wakeup_event(dev);
+ pm_request_resume(&dev->dev);
}
pci_dev_put(dev);
} else if (devfn) {
@@ -253,7 +234,7 @@ static void pcie_pme_work_fn(struct work_struct *work)
* Clear PME status of the port. If there are other
* pending PMEs, the status will be set again.
*/
- pcie_pme_clear_status(port);
+ pcie_clear_root_pme_status(port);
spin_unlock_irq(&data->lock);
pcie_pme_handle_request(port, rtsta & 0xffff);
@@ -378,7 +359,7 @@ static int pcie_pme_probe(struct pcie_device *srv)
port = srv->port;
pcie_pme_interrupt_enable(port, false);
- pcie_pme_clear_status(port);
+ pcie_clear_root_pme_status(port);
ret = request_irq(srv->irq, pcie_pme_irq, IRQF_SHARED, "PCIe PME", srv);
if (ret) {
@@ -402,7 +383,7 @@ static int pcie_pme_suspend(struct pcie_device *srv)
spin_lock_irq(&data->lock);
pcie_pme_interrupt_enable(port, false);
- pcie_pme_clear_status(port);
+ pcie_clear_root_pme_status(port);
data->noirq = true;
spin_unlock_irq(&data->lock);
@@ -422,7 +403,7 @@ static int pcie_pme_resume(struct pcie_device *srv)
spin_lock_irq(&data->lock);
data->noirq = false;
- pcie_pme_clear_status(port);
+ pcie_clear_root_pme_status(port);
pcie_pme_interrupt_enable(port, true);
spin_unlock_irq(&data->lock);
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
index 7b5aba0a3291..bd00a01aef14 100644
--- a/drivers/pci/pcie/portdrv.h
+++ b/drivers/pci/pcie/portdrv.h
@@ -20,9 +20,6 @@
#define get_descriptor_id(type, service) (((type - 4) << 4) | service)
-extern bool pcie_ports_disabled;
-extern bool pcie_ports_auto;
-
extern struct bus_type pcie_port_bus_type;
extern int pcie_port_device_register(struct pci_dev *dev);
#ifdef CONFIG_PM
@@ -35,6 +32,8 @@ extern void pcie_port_bus_unregister(void);
struct pci_dev;
+extern void pcie_clear_root_pme_status(struct pci_dev *dev);
+
#ifdef CONFIG_PCIE_PME
extern bool pcie_pme_msi_disabled;
diff --git a/drivers/pci/pcie/portdrv_acpi.c b/drivers/pci/pcie/portdrv_acpi.c
index 5982b6a63b89..a86b56e5f2f2 100644
--- a/drivers/pci/pcie/portdrv_acpi.c
+++ b/drivers/pci/pcie/portdrv_acpi.c
@@ -33,7 +33,7 @@
*/
int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
{
- acpi_status status;
+ struct acpi_pci_root *root;
acpi_handle handle;
u32 flags;
@@ -44,26 +44,11 @@ int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
if (!handle)
return -EINVAL;
- flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL
- | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL
- | OSC_PCI_EXPRESS_PME_CONTROL;
-
- if (pci_aer_available()) {
- if (aer_acpi_firmware_first())
- dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n");
- else
- flags |= OSC_PCI_EXPRESS_AER_CONTROL;
- }
-
- status = acpi_pci_osc_control_set(handle, &flags,
- OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
- if (ACPI_FAILURE(status)) {
- dev_dbg(&port->dev, "ACPI _OSC request failed (code %d)\n",
- status);
+ root = acpi_pci_find_root(handle);
+ if (!root)
return -ENODEV;
- }
- dev_info(&port->dev, "ACPI _OSC control granted for 0x%02x\n", flags);
+ flags = root->osc_control_set;
*srv_mask = PCIE_PORT_SERVICE_VC;
if (flags & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index a9c222d79ebc..5130d0d22390 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -241,17 +241,17 @@ static int get_port_device_capability(struct pci_dev *dev)
int cap_mask;
int err;
+ if (pcie_ports_disabled)
+ return 0;
+
err = pcie_port_platform_notify(dev, &cap_mask);
- if (pcie_ports_auto) {
- if (err) {
- pcie_no_aspm();
- return 0;
- }
- } else {
+ if (!pcie_ports_auto) {
cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP
| PCIE_PORT_SERVICE_VC;
if (pci_aer_available())
cap_mask |= PCIE_PORT_SERVICE_AER;
+ } else if (err) {
+ return 0;
}
pos = pci_pcie_cap(dev);
@@ -349,15 +349,18 @@ int pcie_port_device_register(struct pci_dev *dev)
int status, capabilities, i, nr_service;
int irqs[PCIE_PORT_DEVICE_MAXSERVICES];
- /* Get and check PCI Express port services */
- capabilities = get_port_device_capability(dev);
- if (!capabilities)
- return -ENODEV;
-
/* Enable PCI Express port device */
status = pci_enable_device(dev);
if (status)
return status;
+
+ /* Get and check PCI Express port services */
+ capabilities = get_port_device_capability(dev);
+ if (!capabilities) {
+ pcie_no_aspm();
+ return 0;
+ }
+
pci_set_master(dev);
/*
* Initialize service irqs. Don't use service devices that
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index f9033e190fb6..e0610bda1dea 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -57,6 +57,22 @@ __setup("pcie_ports=", pcie_port_setup);
/* global data */
+/**
+ * pcie_clear_root_pme_status - Clear root port PME interrupt status.
+ * @dev: PCIe root port or event collector.
+ */
+void pcie_clear_root_pme_status(struct pci_dev *dev)
+{
+ int rtsta_pos;
+ u32 rtsta;
+
+ rtsta_pos = pci_pcie_cap(dev) + PCI_EXP_RTSTA;
+
+ pci_read_config_dword(dev, rtsta_pos, &rtsta);
+ rtsta |= PCI_EXP_RTSTA_PME;
+ pci_write_config_dword(dev, rtsta_pos, rtsta);
+}
+
static int pcie_portdrv_restore_config(struct pci_dev *dev)
{
int retval;
@@ -69,6 +85,20 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev)
}
#ifdef CONFIG_PM
+static int pcie_port_resume_noirq(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ /*
+ * Some BIOSes forget to clear Root PME Status bits after system wakeup
+ * which breaks ACPI-based runtime wakeup on PCI Express, so clear those
+ * bits now just in case (shouldn't hurt).
+ */
+ if(pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
+ pcie_clear_root_pme_status(pdev);
+ return 0;
+}
+
static const struct dev_pm_ops pcie_portdrv_pm_ops = {
.suspend = pcie_port_device_suspend,
.resume = pcie_port_device_resume,
@@ -76,6 +106,7 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = {
.thaw = pcie_port_device_resume,
.poweroff = pcie_port_device_suspend,
.restore = pcie_port_device_resume,
+ .resume_noirq = pcie_port_resume_noirq,
};
#define PCIE_PORTDRV_PM_OPS (&pcie_portdrv_pm_ops)
@@ -327,10 +358,8 @@ static int __init pcie_portdrv_init(void)
{
int retval;
- if (pcie_ports_disabled) {
- pcie_no_aspm();
- return -EACCES;
- }
+ if (pcie_ports_disabled)
+ return pci_register_driver(&pcie_portdriver);
dmi_check_system(pcie_portdrv_dmi_table);
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 60d83d983a36..61bf5d724139 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -136,6 +136,16 @@ config BATTERY_MAX17040
in handheld and portable equipment. The MAX17040 is configured
to operate with a single lithium cell
+config BATTERY_MAX17042
+ tristate "Maxim MAX17042/8997/8966 Fuel Gauge"
+ depends on I2C
+ help
+ MAX17042 is fuel-gauge systems for lithium-ion (Li+) batteries
+ in handheld and portable equipment. The MAX17042 is configured
+ to operate with a single lithium cell. MAX8997 and MAX8966 are
+ multi-function devices that include fuel gauages that are compatible
+ with MAX17042.
+
config BATTERY_Z2
tristate "Z2 battery driver"
depends on I2C && MACH_ZIPIT2
@@ -185,4 +195,14 @@ config CHARGER_TWL4030
help
Say Y here to enable support for TWL4030 Battery Charge Interface.
+config CHARGER_GPIO
+ tristate "GPIO charger"
+ depends on GPIOLIB
+ help
+ Say Y to include support for chargers which report their online status
+ through a GPIO pin.
+
+ This driver can be build as a module. If so, the module will be
+ called gpio-charger.
+
endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index c75772eb157c..8385bfae8728 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_BATTERY_BQ20Z75) += bq20z75.o
obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
+obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
obj-$(CONFIG_BATTERY_Z2) += z2_battery.o
obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
@@ -32,3 +33,4 @@ obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o
obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
+obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
diff --git a/drivers/power/collie_battery.c b/drivers/power/collie_battery.c
index 039f41ae217d..548d263b1ad0 100644
--- a/drivers/power/collie_battery.c
+++ b/drivers/power/collie_battery.c
@@ -295,7 +295,7 @@ static struct {
static int collie_bat_suspend(struct ucb1x00_dev *dev, pm_message_t state)
{
/* flush all pending status updates */
- flush_scheduled_work();
+ flush_work_sync(&bat_work);
return 0;
}
@@ -362,7 +362,7 @@ err_psy_reg_bu:
err_psy_reg_main:
/* see comment in collie_bat_remove */
- flush_scheduled_work();
+ cancel_work_sync(&bat_work);
i--;
err_gpio:
@@ -382,12 +382,11 @@ static void __devexit collie_bat_remove(struct ucb1x00_dev *dev)
power_supply_unregister(&collie_bat_main.psy);
/*
- * now flush all pending work.
- * we won't get any more schedules, since all
- * sources (isr and external_power_changed)
- * are unregistered now.
+ * Now cancel the bat_work. We won't get any more schedules,
+ * since all sources (isr and external_power_changed) are
+ * unregistered now.
*/
- flush_scheduled_work();
+ cancel_work_sync(&bat_work);
for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--)
gpio_free(gpios[i].gpio);
diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c
index e7f89785beef..e534290f3256 100644
--- a/drivers/power/ds2760_battery.c
+++ b/drivers/power/ds2760_battery.c
@@ -212,7 +212,7 @@ static int ds2760_battery_read_status(struct ds2760_device_info *di)
if (di->rem_capacity > 100)
di->rem_capacity = 100;
- if (di->current_uA >= 100L)
+ if (di->current_uA < -100L)
di->life_sec = -((di->accum_current_uAh - di->empty_uAh) * 36L)
/ (di->current_uA / 100L);
else
diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c
new file mode 100644
index 000000000000..25b88ac1d44c
--- /dev/null
+++ b/drivers/power/gpio-charger.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <[email protected]>
+ * Driver for chargers which report their online status through a GPIO pin
+ *
+ * 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.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+
+#include <linux/power/gpio-charger.h>
+
+struct gpio_charger {
+ const struct gpio_charger_platform_data *pdata;
+ unsigned int irq;
+
+ struct power_supply charger;
+};
+
+static irqreturn_t gpio_charger_irq(int irq, void *devid)
+{
+ struct power_supply *charger = devid;
+
+ power_supply_changed(charger);
+
+ return IRQ_HANDLED;
+}
+
+static inline struct gpio_charger *psy_to_gpio_charger(struct power_supply *psy)
+{
+ return container_of(psy, struct gpio_charger, charger);
+}
+
+static int gpio_charger_get_property(struct power_supply *psy,
+ enum power_supply_property psp, union power_supply_propval *val)
+{
+ struct gpio_charger *gpio_charger = psy_to_gpio_charger(psy);
+ const struct gpio_charger_platform_data *pdata = gpio_charger->pdata;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = gpio_get_value(pdata->gpio);
+ val->intval ^= pdata->gpio_active_low;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static enum power_supply_property gpio_charger_properties[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static int __devinit gpio_charger_probe(struct platform_device *pdev)
+{
+ const struct gpio_charger_platform_data *pdata = pdev->dev.platform_data;
+ struct gpio_charger *gpio_charger;
+ struct power_supply *charger;
+ int ret;
+ int irq;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform data\n");
+ return -EINVAL;
+ }
+
+ if (!gpio_is_valid(pdata->gpio)) {
+ dev_err(&pdev->dev, "Invalid gpio pin\n");
+ return -EINVAL;
+ }
+
+ gpio_charger = kzalloc(sizeof(*gpio_charger), GFP_KERNEL);
+ if (!gpio_charger) {
+ dev_err(&pdev->dev, "Failed to alloc driver structure\n");
+ return -ENOMEM;
+ }
+
+ charger = &gpio_charger->charger;
+
+ charger->name = pdata->name ? pdata->name : "gpio-charger";
+ charger->type = pdata->type;
+ charger->properties = gpio_charger_properties;
+ charger->num_properties = ARRAY_SIZE(gpio_charger_properties);
+ charger->get_property = gpio_charger_get_property;
+ charger->supplied_to = pdata->supplied_to;
+ charger->num_supplicants = pdata->num_supplicants;
+
+ ret = gpio_request(pdata->gpio, dev_name(&pdev->dev));
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request gpio pin: %d\n", ret);
+ goto err_free;
+ }
+ ret = gpio_direction_input(pdata->gpio);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to set gpio to input: %d\n", ret);
+ goto err_gpio_free;
+ }
+
+ gpio_charger->pdata = pdata;
+
+ ret = power_supply_register(&pdev->dev, charger);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register power supply: %d\n",
+ ret);
+ goto err_gpio_free;
+ }
+
+ irq = gpio_to_irq(pdata->gpio);
+ if (irq > 0) {
+ ret = request_any_context_irq(irq, gpio_charger_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ dev_name(&pdev->dev), charger);
+ if (ret)
+ dev_warn(&pdev->dev, "Failed to request irq: %d\n", ret);
+ else
+ gpio_charger->irq = irq;
+ }
+
+ platform_set_drvdata(pdev, gpio_charger);
+
+ return 0;
+
+err_gpio_free:
+ gpio_free(pdata->gpio);
+err_free:
+ kfree(gpio_charger);
+ return ret;
+}
+
+static int __devexit gpio_charger_remove(struct platform_device *pdev)
+{
+ struct gpio_charger *gpio_charger = platform_get_drvdata(pdev);
+
+ if (gpio_charger->irq)
+ free_irq(gpio_charger->irq, &gpio_charger->charger);
+
+ power_supply_unregister(&gpio_charger->charger);
+
+ gpio_free(gpio_charger->pdata->gpio);
+
+ platform_set_drvdata(pdev, NULL);
+ kfree(gpio_charger);
+
+ return 0;
+}
+
+static struct platform_driver gpio_charger_driver = {
+ .probe = gpio_charger_probe,
+ .remove = __devexit_p(gpio_charger_remove),
+ .driver = {
+ .name = "gpio-charger",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init gpio_charger_init(void)
+{
+ return platform_driver_register(&gpio_charger_driver);
+}
+module_init(gpio_charger_init);
+
+static void __exit gpio_charger_exit(void)
+{
+ platform_driver_unregister(&gpio_charger_driver);
+}
+module_exit(gpio_charger_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
+MODULE_DESCRIPTION("Driver for chargers which report their online status through a GPIO");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-charger");
diff --git a/drivers/power/intel_mid_battery.c b/drivers/power/intel_mid_battery.c
index 36cf402c0677..bce3a01da2f0 100644
--- a/drivers/power/intel_mid_battery.c
+++ b/drivers/power/intel_mid_battery.c
@@ -765,7 +765,7 @@ static int __devexit platform_pmic_battery_remove(struct platform_device *pdev)
power_supply_unregister(&pbi->usb);
power_supply_unregister(&pbi->batt);
- flush_scheduled_work();
+ cancel_work_sync(&pbi->handler);
kfree(pbi);
return 0;
}
diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c
index 72512185f3e2..2ad9b14a5ce3 100644
--- a/drivers/power/isp1704_charger.c
+++ b/drivers/power/isp1704_charger.c
@@ -59,11 +59,61 @@ struct isp1704_charger {
struct notifier_block nb;
struct work_struct work;
- char model[7];
+ /* properties */
+ char model[8];
unsigned present:1;
+ unsigned online:1;
+ unsigned current_max;
+
+ /* temp storage variables */
+ unsigned long event;
+ unsigned max_power;
};
/*
+ * Determine is the charging port DCP (dedicated charger) or CDP (Host/HUB
+ * chargers).
+ *
+ * REVISIT: The method is defined in Battery Charging Specification and is
+ * applicable to any ULPI transceiver. Nothing isp170x specific here.
+ */
+static inline int isp1704_charger_type(struct isp1704_charger *isp)
+{
+ u8 reg;
+ u8 func_ctrl;
+ u8 otg_ctrl;
+ int type = POWER_SUPPLY_TYPE_USB_DCP;
+
+ func_ctrl = otg_io_read(isp->otg, ULPI_FUNC_CTRL);
+ otg_ctrl = otg_io_read(isp->otg, ULPI_OTG_CTRL);
+
+ /* disable pulldowns */
+ reg = ULPI_OTG_CTRL_DM_PULLDOWN | ULPI_OTG_CTRL_DP_PULLDOWN;
+ otg_io_write(isp->otg, ULPI_CLR(ULPI_OTG_CTRL), reg);
+
+ /* full speed */
+ otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL),
+ ULPI_FUNC_CTRL_XCVRSEL_MASK);
+ otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL),
+ ULPI_FUNC_CTRL_FULL_SPEED);
+
+ /* Enable strong pull-up on DP (1.5K) and reset */
+ reg = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET;
+ otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL), reg);
+ usleep_range(1000, 2000);
+
+ reg = otg_io_read(isp->otg, ULPI_DEBUG);
+ if ((reg & 3) != 3)
+ type = POWER_SUPPLY_TYPE_USB_CDP;
+
+ /* recover original state */
+ otg_io_write(isp->otg, ULPI_FUNC_CTRL, func_ctrl);
+ otg_io_write(isp->otg, ULPI_OTG_CTRL, otg_ctrl);
+
+ return type;
+}
+
+/*
* ISP1704 detects PS/2 adapters as charger. To make sure the detected charger
* is actually a dedicated charger, the following steps need to be taken.
*/
@@ -127,16 +177,19 @@ static inline int isp1704_charger_verify(struct isp1704_charger *isp)
static inline int isp1704_charger_detect(struct isp1704_charger *isp)
{
unsigned long timeout;
- u8 r;
+ u8 pwr_ctrl;
int ret = 0;
+ pwr_ctrl = otg_io_read(isp->otg, ISP1704_PWR_CTRL);
+
/* set SW control bit in PWR_CTRL register */
otg_io_write(isp->otg, ISP1704_PWR_CTRL,
ISP1704_PWR_CTRL_SWCTRL);
/* enable manual charger detection */
- r = (ISP1704_PWR_CTRL_SWCTRL | ISP1704_PWR_CTRL_DPVSRC_EN);
- otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL), r);
+ otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL),
+ ISP1704_PWR_CTRL_SWCTRL
+ | ISP1704_PWR_CTRL_DPVSRC_EN);
usleep_range(1000, 2000);
timeout = jiffies + msecs_to_jiffies(300);
@@ -147,7 +200,10 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp)
ret = isp1704_charger_verify(isp);
break;
}
- } while (!time_after(jiffies, timeout));
+ } while (!time_after(jiffies, timeout) && isp->online);
+
+ /* recover original state */
+ otg_io_write(isp->otg, ISP1704_PWR_CTRL, pwr_ctrl);
return ret;
}
@@ -155,52 +211,92 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp)
static void isp1704_charger_work(struct work_struct *data)
{
int detect;
+ unsigned long event;
+ unsigned power;
struct isp1704_charger *isp =
container_of(data, struct isp1704_charger, work);
+ static DEFINE_MUTEX(lock);
- /*
- * FIXME Only supporting dedicated chargers even though isp1704 can
- * detect HUB and HOST chargers. If the device has already been
- * enumerated, the detection will break the connection.
- */
- if (isp->otg->state != OTG_STATE_B_IDLE)
- return;
+ event = isp->event;
+ power = isp->max_power;
- /* disable data pullups */
- if (isp->otg->gadget)
- usb_gadget_disconnect(isp->otg->gadget);
+ mutex_lock(&lock);
+
+ switch (event) {
+ case USB_EVENT_VBUS:
+ isp->online = true;
+
+ /* detect charger */
+ detect = isp1704_charger_detect(isp);
+
+ if (detect) {
+ isp->present = detect;
+ isp->psy.type = isp1704_charger_type(isp);
+ }
- /* detect charger */
- detect = isp1704_charger_detect(isp);
- if (detect) {
- isp->present = detect;
- power_supply_changed(&isp->psy);
+ switch (isp->psy.type) {
+ case POWER_SUPPLY_TYPE_USB_DCP:
+ isp->current_max = 1800;
+ break;
+ case POWER_SUPPLY_TYPE_USB_CDP:
+ /*
+ * Only 500mA here or high speed chirp
+ * handshaking may break
+ */
+ isp->current_max = 500;
+ /* FALLTHROUGH */
+ case POWER_SUPPLY_TYPE_USB:
+ default:
+ /* enable data pullups */
+ if (isp->otg->gadget)
+ usb_gadget_connect(isp->otg->gadget);
+ }
+ break;
+ case USB_EVENT_NONE:
+ isp->online = false;
+ isp->current_max = 0;
+ isp->present = 0;
+ isp->current_max = 0;
+ isp->psy.type = POWER_SUPPLY_TYPE_USB;
+
+ /*
+ * Disable data pullups. We need to prevent the controller from
+ * enumerating.
+ *
+ * FIXME: This is here to allow charger detection with Host/HUB
+ * chargers. The pullups may be enabled elsewhere, so this can
+ * not be the final solution.
+ */
+ if (isp->otg->gadget)
+ usb_gadget_disconnect(isp->otg->gadget);
+ break;
+ case USB_EVENT_ENUMERATED:
+ if (isp->present)
+ isp->current_max = 1800;
+ else
+ isp->current_max = power;
+ break;
+ default:
+ goto out;
}
- /* enable data pullups */
- if (isp->otg->gadget)
- usb_gadget_connect(isp->otg->gadget);
+ power_supply_changed(&isp->psy);
+out:
+ mutex_unlock(&lock);
}
static int isp1704_notifier_call(struct notifier_block *nb,
- unsigned long event, void *unused)
+ unsigned long event, void *power)
{
struct isp1704_charger *isp =
container_of(nb, struct isp1704_charger, nb);
- switch (event) {
- case USB_EVENT_VBUS:
- schedule_work(&isp->work);
- break;
- case USB_EVENT_NONE:
- if (isp->present) {
- isp->present = 0;
- power_supply_changed(&isp->psy);
- }
- break;
- default:
- return NOTIFY_DONE;
- }
+ isp->event = event;
+
+ if (power)
+ isp->max_power = *((unsigned *)power);
+
+ schedule_work(&isp->work);
return NOTIFY_OK;
}
@@ -216,6 +312,12 @@ static int isp1704_charger_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_PRESENT:
val->intval = isp->present;
break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = isp->online;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ val->intval = isp->current_max;
+ break;
case POWER_SUPPLY_PROP_MODEL_NAME:
val->strval = isp->model;
break;
@@ -230,6 +332,8 @@ static int isp1704_charger_get_property(struct power_supply *psy,
static enum power_supply_property power_props[] = {
POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER,
};
@@ -287,13 +391,13 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
if (!isp->otg)
goto fail0;
+ isp->dev = &pdev->dev;
+ platform_set_drvdata(pdev, isp);
+
ret = isp1704_test_ulpi(isp);
if (ret < 0)
goto fail1;
- isp->dev = &pdev->dev;
- platform_set_drvdata(pdev, isp);
-
isp->psy.name = "isp1704";
isp->psy.type = POWER_SUPPLY_TYPE_USB;
isp->psy.properties = power_props;
@@ -318,6 +422,23 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
dev_info(isp->dev, "registered with product id %s\n", isp->model);
+ /*
+ * Taking over the D+ pullup.
+ *
+ * FIXME: The device will be disconnected if it was already
+ * enumerated. The charger driver should be always loaded before any
+ * gadget is loaded.
+ */
+ if (isp->otg->gadget)
+ usb_gadget_disconnect(isp->otg->gadget);
+
+ /* Detect charger if VBUS is valid (the cable was already plugged). */
+ ret = otg_io_read(isp->otg, ULPI_USB_INT_STS);
+ if ((ret & ULPI_INT_VBUS_VALID) && !isp->otg->default_a) {
+ isp->event = USB_EVENT_VBUS;
+ schedule_work(&isp->work);
+ }
+
return 0;
fail2:
power_supply_unregister(&isp->psy);
diff --git a/drivers/power/jz4740-battery.c b/drivers/power/jz4740-battery.c
index a8108a73593e..02414db6a94c 100644
--- a/drivers/power/jz4740-battery.c
+++ b/drivers/power/jz4740-battery.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/gpio.h>
@@ -47,6 +48,8 @@ struct jz_battery {
struct power_supply battery;
struct delayed_work work;
+
+ struct mutex lock;
};
static inline struct jz_battery *psy_to_jz_battery(struct power_supply *psy)
@@ -68,6 +71,8 @@ static long jz_battery_read_voltage(struct jz_battery *battery)
unsigned long val;
long voltage;
+ mutex_lock(&battery->lock);
+
INIT_COMPLETION(battery->read_completion);
enable_irq(battery->irq);
@@ -91,6 +96,8 @@ static long jz_battery_read_voltage(struct jz_battery *battery)
battery->cell->disable(battery->pdev);
disable_irq(battery->irq);
+ mutex_unlock(&battery->lock);
+
return voltage;
}
@@ -240,6 +247,11 @@ static int __devinit jz_battery_probe(struct platform_device *pdev)
struct jz_battery *jz_battery;
struct power_supply *battery;
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform_data supplied\n");
+ return -ENXIO;
+ }
+
jz_battery = kzalloc(sizeof(*jz_battery), GFP_KERNEL);
if (!jz_battery) {
dev_err(&pdev->dev, "Failed to allocate driver structure\n");
@@ -291,6 +303,7 @@ static int __devinit jz_battery_probe(struct platform_device *pdev)
jz_battery->pdev = pdev;
init_completion(&jz_battery->read_completion);
+ mutex_init(&jz_battery->lock);
INIT_DELAYED_WORK(&jz_battery->work, jz_battery_work);
diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c
new file mode 100644
index 000000000000..c5c8805156cb
--- /dev/null
+++ b/drivers/power/max17042_battery.c
@@ -0,0 +1,239 @@
+/*
+ * Fuel gauge driver for Maxim 17042 / 8966 / 8997
+ * Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * MyungJoo Ham <[email protected]>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * This driver is based on max17040_battery.c
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/power_supply.h>
+#include <linux/power/max17042_battery.h>
+
+enum max17042_register {
+ MAX17042_STATUS = 0x00,
+ MAX17042_VALRT_Th = 0x01,
+ MAX17042_TALRT_Th = 0x02,
+ MAX17042_SALRT_Th = 0x03,
+ MAX17042_AtRate = 0x04,
+ MAX17042_RepCap = 0x05,
+ MAX17042_RepSOC = 0x06,
+ MAX17042_Age = 0x07,
+ MAX17042_TEMP = 0x08,
+ MAX17042_VCELL = 0x09,
+ MAX17042_Current = 0x0A,
+ MAX17042_AvgCurrent = 0x0B,
+ MAX17042_Qresidual = 0x0C,
+ MAX17042_SOC = 0x0D,
+ MAX17042_AvSOC = 0x0E,
+ MAX17042_RemCap = 0x0F,
+ MAX17402_FullCAP = 0x10,
+ MAX17042_TTE = 0x11,
+ MAX17042_V_empty = 0x12,
+
+ MAX17042_RSLOW = 0x14,
+
+ MAX17042_AvgTA = 0x16,
+ MAX17042_Cycles = 0x17,
+ MAX17042_DesignCap = 0x18,
+ MAX17042_AvgVCELL = 0x19,
+ MAX17042_MinMaxTemp = 0x1A,
+ MAX17042_MinMaxVolt = 0x1B,
+ MAX17042_MinMaxCurr = 0x1C,
+ MAX17042_CONFIG = 0x1D,
+ MAX17042_ICHGTerm = 0x1E,
+ MAX17042_AvCap = 0x1F,
+ MAX17042_ManName = 0x20,
+ MAX17042_DevName = 0x21,
+ MAX17042_DevChem = 0x22,
+
+ MAX17042_TempNom = 0x24,
+ MAX17042_TempCold = 0x25,
+ MAX17042_TempHot = 0x26,
+ MAX17042_AIN = 0x27,
+ MAX17042_LearnCFG = 0x28,
+ MAX17042_SHFTCFG = 0x29,
+ MAX17042_RelaxCFG = 0x2A,
+ MAX17042_MiscCFG = 0x2B,
+ MAX17042_TGAIN = 0x2C,
+ MAx17042_TOFF = 0x2D,
+ MAX17042_CGAIN = 0x2E,
+ MAX17042_COFF = 0x2F,
+
+ MAX17042_Q_empty = 0x33,
+ MAX17042_T_empty = 0x34,
+
+ MAX17042_RCOMP0 = 0x38,
+ MAX17042_TempCo = 0x39,
+ MAX17042_Rx = 0x3A,
+ MAX17042_T_empty0 = 0x3B,
+ MAX17042_TaskPeriod = 0x3C,
+ MAX17042_FSTAT = 0x3D,
+
+ MAX17042_SHDNTIMER = 0x3F,
+
+ MAX17042_VFRemCap = 0x4A,
+
+ MAX17042_QH = 0x4D,
+ MAX17042_QL = 0x4E,
+};
+
+struct max17042_chip {
+ struct i2c_client *client;
+ struct power_supply battery;
+ struct max17042_platform_data *pdata;
+};
+
+static int max17042_write_reg(struct i2c_client *client, u8 reg, u16 value)
+{
+ int ret = i2c_smbus_write_word_data(client, reg, value);
+
+ if (ret < 0)
+ dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int max17042_read_reg(struct i2c_client *client, u8 reg)
+{
+ int ret = i2c_smbus_read_word_data(client, reg);
+
+ if (ret < 0)
+ dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+
+ return ret;
+}
+
+static enum power_supply_property max17042_battery_props[] = {
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_VOLTAGE_AVG,
+ POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static int max17042_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct max17042_chip *chip = container_of(psy,
+ struct max17042_chip, battery);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = max17042_read_reg(chip->client,
+ MAX17042_VCELL) * 83; /* 1000 / 12 = 83 */
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+ val->intval = max17042_read_reg(chip->client,
+ MAX17042_AvgVCELL) * 83;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = max17042_read_reg(chip->client,
+ MAX17042_SOC) / 256;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int __devinit max17042_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct max17042_chip *chip;
+ int ret;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
+ return -EIO;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->client = client;
+ chip->pdata = client->dev.platform_data;
+
+ i2c_set_clientdata(client, chip);
+
+ chip->battery.name = "max17042_battery";
+ chip->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+ chip->battery.get_property = max17042_get_property;
+ chip->battery.properties = max17042_battery_props;
+ chip->battery.num_properties = ARRAY_SIZE(max17042_battery_props);
+
+ ret = power_supply_register(&client->dev, &chip->battery);
+ if (ret) {
+ dev_err(&client->dev, "failed: power supply register\n");
+ i2c_set_clientdata(client, NULL);
+ kfree(chip);
+ return ret;
+ }
+
+ if (!chip->pdata->enable_current_sense) {
+ max17042_write_reg(client, MAX17042_CGAIN, 0x0000);
+ max17042_write_reg(client, MAX17042_MiscCFG, 0x0003);
+ max17042_write_reg(client, MAX17042_LearnCFG, 0x0007);
+ }
+
+ return 0;
+}
+
+static int __devexit max17042_remove(struct i2c_client *client)
+{
+ struct max17042_chip *chip = i2c_get_clientdata(client);
+
+ power_supply_unregister(&chip->battery);
+ i2c_set_clientdata(client, NULL);
+ kfree(chip);
+ return 0;
+}
+
+static const struct i2c_device_id max17042_id[] = {
+ { "max17042", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max17042_id);
+
+static struct i2c_driver max17042_i2c_driver = {
+ .driver = {
+ .name = "max17042",
+ },
+ .probe = max17042_probe,
+ .remove = __devexit_p(max17042_remove),
+ .id_table = max17042_id,
+};
+
+static int __init max17042_init(void)
+{
+ return i2c_add_driver(&max17042_i2c_driver);
+}
+module_init(max17042_init);
+
+static void __exit max17042_exit(void)
+{
+ i2c_del_driver(&max17042_i2c_driver);
+}
+module_exit(max17042_exit);
+
+MODULE_AUTHOR("MyungJoo Ham <[email protected]>");
+MODULE_DESCRIPTION("MAX17042 Fuel Gauge");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c
index 5bc1dcf7785e..0b0ff3a936a6 100644
--- a/drivers/power/olpc_battery.c
+++ b/drivers/power/olpc_battery.c
@@ -201,6 +201,72 @@ static int olpc_bat_get_tech(union power_supply_propval *val)
return ret;
}
+static int olpc_bat_get_charge_full_design(union power_supply_propval *val)
+{
+ uint8_t ec_byte;
+ union power_supply_propval tech;
+ int ret, mfr;
+
+ ret = olpc_bat_get_tech(&tech);
+ if (ret)
+ return ret;
+
+ ec_byte = BAT_ADDR_MFR_TYPE;
+ ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
+ if (ret)
+ return ret;
+
+ mfr = ec_byte >> 4;
+
+ switch (tech.intval) {
+ case POWER_SUPPLY_TECHNOLOGY_NiMH:
+ switch (mfr) {
+ case 1: /* Gold Peak */
+ val->intval = 3000000*.8;
+ break;
+ default:
+ return -EIO;
+ }
+ break;
+
+ case POWER_SUPPLY_TECHNOLOGY_LiFe:
+ switch (mfr) {
+ case 1: /* Gold Peak */
+ val->intval = 2800000;
+ break;
+ case 2: /* BYD */
+ val->intval = 3100000;
+ break;
+ default:
+ return -EIO;
+ }
+ break;
+
+ default:
+ return -EIO;
+ }
+
+ return ret;
+}
+
+static int olpc_bat_get_charge_now(union power_supply_propval *val)
+{
+ uint8_t soc;
+ union power_supply_propval full;
+ int ret;
+
+ ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &soc, 1);
+ if (ret)
+ return ret;
+
+ ret = olpc_bat_get_charge_full_design(&full);
+ if (ret)
+ return ret;
+
+ val->intval = soc * (full.intval / 100);
+ return 0;
+}
+
/*********************************************************************
* Battery properties
*********************************************************************/
@@ -267,6 +333,7 @@ static int olpc_bat_get_property(struct power_supply *psy,
return ret;
break;
case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *)&ec_word, 2);
if (ret)
return ret;
@@ -274,6 +341,7 @@ static int olpc_bat_get_property(struct power_supply *psy,
val->intval = (s16)be16_to_cpu(ec_word) * 9760L / 32;
break;
case POWER_SUPPLY_PROP_CURRENT_AVG:
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2);
if (ret)
return ret;
@@ -294,6 +362,16 @@ static int olpc_bat_get_property(struct power_supply *psy,
else
val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+ ret = olpc_bat_get_charge_full_design(val);
+ if (ret)
+ return ret;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ ret = olpc_bat_get_charge_now(val);
+ if (ret)
+ return ret;
+ break;
case POWER_SUPPLY_PROP_TEMP:
ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
if (ret)
@@ -331,16 +409,20 @@ static int olpc_bat_get_property(struct power_supply *psy,
return ret;
}
-static enum power_supply_property olpc_bat_props[] = {
+static enum power_supply_property olpc_xo1_bat_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_CHARGE_TYPE,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_VOLTAGE_AVG,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_TEMP_AMBIENT,
POWER_SUPPLY_PROP_MANUFACTURER,
@@ -348,6 +430,27 @@ static enum power_supply_property olpc_bat_props[] = {
POWER_SUPPLY_PROP_CHARGE_COUNTER,
};
+/* XO-1.5 does not have ambient temperature property */
+static enum power_supply_property olpc_xo15_bat_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_VOLTAGE_AVG,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+ POWER_SUPPLY_PROP_SERIAL_NUMBER,
+ POWER_SUPPLY_PROP_CHARGE_COUNTER,
+};
+
/* EEPROM reading goes completely around the power_supply API, sadly */
#define EEPROM_START 0x20
@@ -419,8 +522,6 @@ static struct device_attribute olpc_bat_error = {
static struct platform_device *bat_pdev;
static struct power_supply olpc_bat = {
- .properties = olpc_bat_props,
- .num_properties = ARRAY_SIZE(olpc_bat_props),
.get_property = olpc_bat_get_property,
.use_for_apm = 1,
};
@@ -466,6 +567,13 @@ static int __init olpc_bat_init(void)
goto ac_failed;
olpc_bat.name = bat_pdev->name;
+ if (olpc_board_at_least(olpc_board_pre(0xd0))) { /* XO-1.5 */
+ olpc_bat.properties = olpc_xo15_bat_props;
+ olpc_bat.num_properties = ARRAY_SIZE(olpc_xo15_bat_props);
+ } else { /* XO-1 */
+ olpc_bat.properties = olpc_xo1_bat_props;
+ olpc_bat.num_properties = ARRAY_SIZE(olpc_xo1_bat_props);
+ }
ret = power_supply_register(&bat_pdev->dev, &olpc_bat);
if (ret)
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 91606bb55318..970f7335d3a7 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -190,10 +190,10 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
goto success;
create_triggers_failed:
- device_unregister(psy->dev);
+ device_del(dev);
kobject_set_name_failed:
device_add_failed:
- kfree(dev);
+ put_device(dev);
success:
return rc;
}
@@ -201,7 +201,7 @@ EXPORT_SYMBOL_GPL(power_supply_register);
void power_supply_unregister(struct power_supply *psy)
{
- flush_scheduled_work();
+ cancel_work_sync(&psy->changed_work);
power_supply_remove_triggers(psy);
device_unregister(psy->dev);
}
diff --git a/drivers/power/s3c_adc_battery.c b/drivers/power/s3c_adc_battery.c
index 4a8ae3935b3b..4255f2358b13 100644
--- a/drivers/power/s3c_adc_battery.c
+++ b/drivers/power/s3c_adc_battery.c
@@ -112,6 +112,13 @@ static int calc_full_volt(int volt_val, int cur_val, int impedance)
return volt_val + cur_val * impedance / 1000;
}
+static int charge_finished(struct s3c_adc_bat *bat)
+{
+ return bat->pdata->gpio_inverted ?
+ !gpio_get_value(bat->pdata->gpio_charge_finished) :
+ gpio_get_value(bat->pdata->gpio_charge_finished);
+}
+
static int s3c_adc_bat_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -140,7 +147,7 @@ static int s3c_adc_bat_get_property(struct power_supply *psy,
if (bat->cable_plugged &&
((bat->pdata->gpio_charge_finished < 0) ||
- !gpio_get_value(bat->pdata->gpio_charge_finished))) {
+ !charge_finished(bat))) {
lut = bat->pdata->lut_acin;
lut_size = bat->pdata->lut_acin_cnt;
}
@@ -236,8 +243,7 @@ static void s3c_adc_bat_work(struct work_struct *work)
}
} else {
if ((bat->pdata->gpio_charge_finished >= 0) && is_plugged) {
- is_charged = gpio_get_value(
- main_bat.pdata->gpio_charge_finished);
+ is_charged = charge_finished(&main_bat);
if (is_charged) {
if (bat->pdata->disable_charger)
bat->pdata->disable_charger();
diff --git a/drivers/power/tosa_battery.c b/drivers/power/tosa_battery.c
index ee04936b2db5..53f0d3524fcd 100644
--- a/drivers/power/tosa_battery.c
+++ b/drivers/power/tosa_battery.c
@@ -332,7 +332,7 @@ static struct {
static int tosa_bat_suspend(struct platform_device *dev, pm_message_t state)
{
/* flush all pending status updates */
- flush_scheduled_work();
+ flush_work_sync(&bat_work);
return 0;
}
@@ -422,7 +422,7 @@ err_psy_reg_jacket:
err_psy_reg_main:
/* see comment in tosa_bat_remove */
- flush_scheduled_work();
+ cancel_work_sync(&bat_work);
i--;
err_gpio:
@@ -445,12 +445,11 @@ static int __devexit tosa_bat_remove(struct platform_device *dev)
power_supply_unregister(&tosa_bat_main.psy);
/*
- * now flush all pending work.
- * we won't get any more schedules, since all
- * sources (isr and external_power_changed)
- * are unregistered now.
+ * Now cancel the bat_work. We won't get any more schedules,
+ * since all sources (isr and external_power_changed) are
+ * unregistered now.
*/
- flush_scheduled_work();
+ cancel_work_sync(&bat_work);
for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--)
gpio_free(gpios[i].gpio);
diff --git a/drivers/power/wm97xx_battery.c b/drivers/power/wm97xx_battery.c
index 5071d85ec12d..156559e56fa5 100644
--- a/drivers/power/wm97xx_battery.c
+++ b/drivers/power/wm97xx_battery.c
@@ -147,7 +147,7 @@ static irqreturn_t wm97xx_chrg_irq(int irq, void *data)
#ifdef CONFIG_PM
static int wm97xx_bat_suspend(struct device *dev)
{
- flush_scheduled_work();
+ flush_work_sync(&bat_work);
return 0;
}
@@ -273,7 +273,7 @@ static int __devexit wm97xx_bat_remove(struct platform_device *dev)
free_irq(gpio_to_irq(pdata->charge_gpio), dev);
gpio_free(pdata->charge_gpio);
}
- flush_scheduled_work();
+ cancel_work_sync(&bat_work);
power_supply_unregister(&bat_ps);
kfree(prop);
return 0;
diff --git a/drivers/power/z2_battery.c b/drivers/power/z2_battery.c
index 85064a9f649e..e5ed52d71937 100644
--- a/drivers/power/z2_battery.c
+++ b/drivers/power/z2_battery.c
@@ -254,7 +254,7 @@ static int __devexit z2_batt_remove(struct i2c_client *client)
struct z2_charger *charger = i2c_get_clientdata(client);
struct z2_battery_info *info = charger->info;
- flush_scheduled_work();
+ cancel_work_sync(&charger->bat_work);
power_supply_unregister(&charger->batt_ps);
kfree(charger->batt_ps.properties);
@@ -271,7 +271,9 @@ static int __devexit z2_batt_remove(struct i2c_client *client)
#ifdef CONFIG_PM
static int z2_batt_suspend(struct i2c_client *client, pm_message_t state)
{
- flush_scheduled_work();
+ struct z2_charger *charger = i2c_get_clientdata(client);
+
+ flush_work_sync(&charger->bat_work);
return 0;
}
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c
index 7568df6122ab..0ec49ca527a8 100644
--- a/drivers/regulator/max8998.c
+++ b/drivers/regulator/max8998.c
@@ -424,6 +424,9 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev,
}
}
+ if (pdata->buck_voltage_lock)
+ return -EINVAL;
+
/* no predefine regulator found */
max8998->buck1_idx = (buck1_last_val % 2) + 2;
dev_dbg(max8998->dev, "max8998->buck1_idx:%d\n",
@@ -451,18 +454,26 @@ buck1_exit:
"BUCK2, i:%d buck2_vol1:%d, buck2_vol2:%d\n"
, i, max8998->buck2_vol[0], max8998->buck2_vol[1]);
if (gpio_is_valid(pdata->buck2_set3)) {
- if (max8998->buck2_vol[0] == i) {
- max8998->buck1_idx = 0;
- buck2_gpio_set(pdata->buck2_set3, 0);
- } else {
- max8998->buck1_idx = 1;
- ret = max8998_get_voltage_register(rdev, &reg,
- &shift,
- &mask);
- ret = max8998_write_reg(i2c, reg, i);
- max8998->buck2_vol[1] = i;
- buck2_gpio_set(pdata->buck2_set3, 1);
+
+ /* check if requested voltage */
+ /* value is already defined */
+ for (j = 0; j < ARRAY_SIZE(max8998->buck2_vol); j++) {
+ if (max8998->buck2_vol[j] == i) {
+ max8998->buck2_idx = j;
+ buck2_gpio_set(pdata->buck2_set3, j);
+ goto buck2_exit;
+ }
}
+
+ if (pdata->buck_voltage_lock)
+ return -EINVAL;
+
+ max8998_get_voltage_register(rdev,
+ &reg, &shift, &mask);
+ ret = max8998_write_reg(i2c, reg, i);
+ max8998->buck2_vol[max8998->buck2_idx] = i;
+ buck2_gpio_set(pdata->buck2_set3, max8998->buck2_idx);
+buck2_exit:
dev_dbg(max8998->dev, "%s: SET3:%d\n", i2c->name,
gpio_get_value(pdata->buck2_set3));
} else {
@@ -707,6 +718,9 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, max8998);
i2c = max8998->iodev->i2c;
+ max8998->buck1_idx = pdata->buck1_default_idx;
+ max8998->buck2_idx = pdata->buck2_default_idx;
+
/* NOTE: */
/* For unused GPIO NOT marked as -1 (thereof equal to 0) WARN_ON */
/* will be displayed */
@@ -739,23 +753,46 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
i = 0;
while (buck12_voltage_map_desc.min +
buck12_voltage_map_desc.step*i
- != (pdata->buck1_max_voltage1 / 1000))
+ < (pdata->buck1_voltage1 / 1000))
i++;
- printk(KERN_ERR "i:%d, buck1_idx:%d\n", i, max8998->buck1_idx);
max8998->buck1_vol[0] = i;
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i);
+ if (ret)
+ return ret;
/* Set predefined value for BUCK1 register 2 */
i = 0;
while (buck12_voltage_map_desc.min +
buck12_voltage_map_desc.step*i
- != (pdata->buck1_max_voltage2 / 1000))
+ < (pdata->buck1_voltage2 / 1000))
i++;
max8998->buck1_vol[1] = i;
- printk(KERN_ERR "i:%d, buck1_idx:%d\n", i, max8998->buck1_idx);
- ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i)
- + ret;
+ ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i);
+ if (ret)
+ return ret;
+
+ /* Set predefined value for BUCK1 register 3 */
+ i = 0;
+ while (buck12_voltage_map_desc.min +
+ buck12_voltage_map_desc.step*i
+ < (pdata->buck1_voltage3 / 1000))
+ i++;
+
+ max8998->buck1_vol[2] = i;
+ ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE3, i);
+ if (ret)
+ return ret;
+
+ /* Set predefined value for BUCK1 register 4 */
+ i = 0;
+ while (buck12_voltage_map_desc.min +
+ buck12_voltage_map_desc.step*i
+ < (pdata->buck1_voltage4 / 1000))
+ i++;
+
+ max8998->buck1_vol[3] = i;
+ ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE4, i);
if (ret)
return ret;
@@ -772,18 +809,28 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
gpio_direction_output(pdata->buck2_set3,
max8998->buck2_idx & 0x1);
- /* BUCK2 - set preset default voltage value to buck2_vol[0] */
+ /* BUCK2 register 1 */
i = 0;
while (buck12_voltage_map_desc.min +
buck12_voltage_map_desc.step*i
- != (pdata->buck2_max_voltage / 1000))
+ < (pdata->buck2_voltage1 / 1000))
i++;
- printk(KERN_ERR "i:%d, buck2_idx:%d\n", i, max8998->buck2_idx);
max8998->buck2_vol[0] = i;
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i);
if (ret)
return ret;
+ /* BUCK2 register 2 */
+ i = 0;
+ while (buck12_voltage_map_desc.min +
+ buck12_voltage_map_desc.step*i
+ < (pdata->buck2_voltage2 / 1000))
+ i++;
+ printk(KERN_ERR "i2:%d, buck2_idx:%d\n", i, max8998->buck2_idx);
+ max8998->buck2_vol[1] = i;
+ ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE2, i);
+ if (ret)
+ return ret;
}
for (i = 0; i < pdata->num_regulators; i++) {
@@ -835,6 +882,12 @@ static int __devexit max8998_pmic_remove(struct platform_device *pdev)
return 0;
}
+static const struct platform_device_id max8998_pmic_id[] = {
+ { "max8998-pmic", TYPE_MAX8998 },
+ { "lp3974-pmic", TYPE_LP3974 },
+ { }
+};
+
static struct platform_driver max8998_pmic_driver = {
.driver = {
.name = "max8998-pmic",
@@ -842,6 +895,7 @@ static struct platform_driver max8998_pmic_driver = {
},
.probe = max8998_pmic_probe,
.remove = __devexit_p(max8998_pmic_remove),
+ .id_table = max8998_pmic_id,
};
static int __init max8998_pmic_init(void)
diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c
index f22dee35f330..3f7bc6b9fefa 100644
--- a/drivers/rtc/rtc-max8998.c
+++ b/drivers/rtc/rtc-max8998.c
@@ -20,6 +20,7 @@
#include <linux/platform_device.h>
#include <linux/mfd/max8998.h>
#include <linux/mfd/max8998-private.h>
+#include <linux/delay.h>
#define MAX8998_RTC_SEC 0x00
#define MAX8998_RTC_MIN 0x01
@@ -73,6 +74,7 @@ struct max8998_rtc_info {
struct i2c_client *rtc;
struct rtc_device *rtc_dev;
int irq;
+ bool lp3974_bug_workaround;
};
static void max8998_data_to_tm(u8 *data, struct rtc_time *tm)
@@ -124,10 +126,16 @@ static int max8998_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct max8998_rtc_info *info = dev_get_drvdata(dev);
u8 data[8];
+ int ret;
max8998_tm_to_data(tm, data);
- return max8998_bulk_write(info->rtc, MAX8998_RTC_SEC, 8, data);
+ ret = max8998_bulk_write(info->rtc, MAX8998_RTC_SEC, 8, data);
+
+ if (info->lp3974_bug_workaround)
+ msleep(2000);
+
+ return ret;
}
static int max8998_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
@@ -163,12 +171,29 @@ static int max8998_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
static int max8998_rtc_stop_alarm(struct max8998_rtc_info *info)
{
- return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0);
+ int ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0);
+
+ if (info->lp3974_bug_workaround)
+ msleep(2000);
+
+ return ret;
}
static int max8998_rtc_start_alarm(struct max8998_rtc_info *info)
{
- return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0x77);
+ int ret;
+ u8 alarm0_conf = 0x77;
+
+ /* LP3974 with delay bug chips has rtc alarm bugs with "MONTH" field */
+ if (info->lp3974_bug_workaround)
+ alarm0_conf = 0x57;
+
+ ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, alarm0_conf);
+
+ if (info->lp3974_bug_workaround)
+ msleep(2000);
+
+ return ret;
}
static int max8998_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
@@ -187,10 +212,13 @@ static int max8998_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
if (ret < 0)
return ret;
+ if (info->lp3974_bug_workaround)
+ msleep(2000);
+
if (alrm->enabled)
- return max8998_rtc_start_alarm(info);
+ ret = max8998_rtc_start_alarm(info);
- return 0;
+ return ret;
}
static int max8998_rtc_alarm_irq_enable(struct device *dev,
@@ -224,6 +252,7 @@ static const struct rtc_class_ops max8998_rtc_ops = {
static int __devinit max8998_rtc_probe(struct platform_device *pdev)
{
struct max8998_dev *max8998 = dev_get_drvdata(pdev->dev.parent);
+ struct max8998_platform_data *pdata = dev_get_platdata(max8998->dev);
struct max8998_rtc_info *info;
int ret;
@@ -249,10 +278,18 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev)
ret = request_threaded_irq(info->irq, NULL, max8998_rtc_alarm_irq, 0,
"rtc-alarm0", info);
+
if (ret < 0)
dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
info->irq, ret);
+ dev_info(&pdev->dev, "RTC CHIP NAME: %s\n", pdev->id_entry->name);
+ if (pdata->rtc_delay) {
+ info->lp3974_bug_workaround = true;
+ dev_warn(&pdev->dev, "LP3974 with RTC REGERR option."
+ " RTC updates will be extremely slow.\n");
+ }
+
return 0;
out_rtc:
@@ -273,6 +310,12 @@ static int __devexit max8998_rtc_remove(struct platform_device *pdev)
return 0;
}
+static const struct platform_device_id max8998_rtc_id[] = {
+ { "max8998-rtc", TYPE_MAX8998 },
+ { "lp3974-rtc", TYPE_LP3974 },
+ { }
+};
+
static struct platform_driver max8998_rtc_driver = {
.driver = {
.name = "max8998-rtc",
@@ -280,6 +323,7 @@ static struct platform_driver max8998_rtc_driver = {
},
.probe = max8998_rtc_probe,
.remove = __devexit_p(max8998_rtc_remove),
+ .id_table = max8998_rtc_id,
};
static int __init max8998_rtc_init(void)
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index e8391b89eff4..b7eaff9ca19e 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1835,6 +1835,7 @@ static void __ccw_device_pm_restore(struct ccw_device *cdev)
* available again. Kick re-detection.
*/
cdev->private->flags.resuming = 1;
+ cdev->private->path_new_mask = LPM_ANYPATH;
css_schedule_eval(sch->schid);
spin_unlock_irq(sch->lock);
css_complete_work();
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index d3c5905b22ec..9c5c8be72231 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -7515,16 +7515,10 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
{
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
volatile u32 int_reg;
- int rc;
ENTER;
ioa_cfg->pdev->state_saved = true;
- rc = pci_restore_state(ioa_cfg->pdev);
-
- if (rc != PCIBIOS_SUCCESSFUL) {
- ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
- return IPR_RC_JOB_CONTINUE;
- }
+ pci_restore_state(ioa_cfg->pdev);
if (ipr_set_pcix_cmd_reg(ioa_cfg)) {
ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index 300d59f389da..321cf3ae8630 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -2228,12 +2228,7 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd)
/* Once either bist or pci reset is done, restore PCI config
* space. If this fails, proceed with hard reset again
*/
- if (pci_restore_state(pinstance->pdev)) {
- pmcraid_info("config-space error resetting again\n");
- pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT;
- pmcraid_reset_alert(cmd);
- break;
- }
+ pci_restore_state(pinstance->pdev);
/* fail all pending commands */
pmcraid_fail_outstanding_cmds(pinstance);
diff --git a/drivers/staging/sm7xx/smtcfb.c b/drivers/staging/sm7xx/smtcfb.c
index f4b163f7338a..0bc113c44d39 100644
--- a/drivers/staging/sm7xx/smtcfb.c
+++ b/drivers/staging/sm7xx/smtcfb.c
@@ -1071,7 +1071,7 @@ static int __maybe_unused smtcfb_resume(struct pci_dev *pdev)
/* when resuming, restore pci data and fb cursor */
if (pdev->dev.power.power_state.event != PM_EVENT_FREEZE) {
retv = pci_set_power_state(pdev, PCI_D0);
- retv = pci_restore_state(pdev);
+ pci_restore_state(pdev);
if (pci_enable_device(pdev))
return -1;
pci_set_master(pdev);
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c
index a3bcec75c54a..1c8c6cc6de30 100644
--- a/fs/afs/cmservice.c
+++ b/fs/afs/cmservice.c
@@ -289,7 +289,7 @@ static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
call->server = server;
INIT_WORK(&call->work, SRXAFSCB_CallBack);
- schedule_work(&call->work);
+ queue_work(afs_wq, &call->work);
return 0;
}
@@ -336,7 +336,7 @@ static int afs_deliver_cb_init_call_back_state(struct afs_call *call,
call->server = server;
INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
- schedule_work(&call->work);
+ queue_work(afs_wq, &call->work);
return 0;
}
@@ -367,7 +367,7 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call,
call->server = server;
INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
- schedule_work(&call->work);
+ queue_work(afs_wq, &call->work);
return 0;
}
@@ -400,7 +400,7 @@ static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb,
call->state = AFS_CALL_REPLYING;
INIT_WORK(&call->work, SRXAFSCB_Probe);
- schedule_work(&call->work);
+ queue_work(afs_wq, &call->work);
return 0;
}
@@ -496,7 +496,7 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call, struct sk_buff *skb,
call->state = AFS_CALL_REPLYING;
INIT_WORK(&call->work, SRXAFSCB_ProbeUuid);
- schedule_work(&call->work);
+ queue_work(afs_wq, &call->work);
return 0;
}
@@ -580,6 +580,6 @@ static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call,
call->state = AFS_CALL_REPLYING;
INIT_WORK(&call->work, SRXAFSCB_TellMeAboutYourself);
- schedule_work(&call->work);
+ queue_work(afs_wq, &call->work);
return 0;
}
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index ab6db5abaf53..58c633b80246 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -577,6 +577,7 @@ extern int afs_drop_inode(struct inode *);
/*
* main.c
*/
+extern struct workqueue_struct *afs_wq;
extern struct afs_uuid afs_uuid;
/*
diff --git a/fs/afs/main.c b/fs/afs/main.c
index cfd1cbe25b22..42dd2e499ed8 100644
--- a/fs/afs/main.c
+++ b/fs/afs/main.c
@@ -30,6 +30,7 @@ module_param(rootcell, charp, 0);
MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list");
struct afs_uuid afs_uuid;
+struct workqueue_struct *afs_wq;
/*
* get a client UUID
@@ -87,10 +88,16 @@ static int __init afs_init(void)
if (ret < 0)
return ret;
+ /* create workqueue */
+ ret = -ENOMEM;
+ afs_wq = alloc_workqueue("afs", 0, 0);
+ if (!afs_wq)
+ return ret;
+
/* register the /proc stuff */
ret = afs_proc_init();
if (ret < 0)
- return ret;
+ goto error_proc;
#ifdef CONFIG_AFS_FSCACHE
/* we want to be able to cache */
@@ -140,6 +147,8 @@ error_cell_init:
error_cache:
#endif
afs_proc_cleanup();
+error_proc:
+ destroy_workqueue(afs_wq);
rcu_barrier();
printk(KERN_ERR "kAFS: failed to register: %d\n", ret);
return ret;
@@ -163,7 +172,7 @@ static void __exit afs_exit(void)
afs_purge_servers();
afs_callback_update_kill();
afs_vlocation_purge();
- flush_scheduled_work();
+ destroy_workqueue(afs_wq);
afs_cell_purge();
#ifdef CONFIG_AFS_FSCACHE
fscache_unregister_netfs(&afs_cache_netfs);
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index 6153417caf57..e83c0336e7b5 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -268,8 +268,8 @@ static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd)
path_put(&nd->path);
nd->path.mnt = newmnt;
nd->path.dentry = dget(newmnt->mnt_root);
- schedule_delayed_work(&afs_mntpt_expiry_timer,
- afs_mntpt_expiry_timeout * HZ);
+ queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer,
+ afs_mntpt_expiry_timeout * HZ);
break;
case -EBUSY:
/* someone else made a mount here whilst we were busy */
@@ -295,8 +295,8 @@ static void afs_mntpt_expiry_timed_out(struct work_struct *work)
if (!list_empty(&afs_vfsmounts)) {
mark_mounts_for_expiry(&afs_vfsmounts);
- schedule_delayed_work(&afs_mntpt_expiry_timer,
- afs_mntpt_expiry_timeout * HZ);
+ queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer,
+ afs_mntpt_expiry_timeout * HZ);
}
_leave("");
@@ -310,6 +310,5 @@ void afs_mntpt_kill_timer(void)
_enter("");
ASSERT(list_empty(&afs_vfsmounts));
- cancel_delayed_work(&afs_mntpt_expiry_timer);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&afs_mntpt_expiry_timer);
}
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index 654d8fdbf01f..e45a323aebb4 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -410,7 +410,7 @@ static void afs_rx_interceptor(struct sock *sk, unsigned long user_call_ID,
if (!call) {
/* its an incoming call for our callback service */
skb_queue_tail(&afs_incoming_calls, skb);
- schedule_work(&afs_collect_incoming_call_work);
+ queue_work(afs_wq, &afs_collect_incoming_call_work);
} else {
/* route the messages directly to the appropriate call */
skb_queue_tail(&call->rx_queue, skb);
diff --git a/fs/afs/server.c b/fs/afs/server.c
index 9fdc7fe3a7bc..d59b7516e943 100644
--- a/fs/afs/server.c
+++ b/fs/afs/server.c
@@ -238,8 +238,8 @@ void afs_put_server(struct afs_server *server)
if (atomic_read(&server->usage) == 0) {
list_move_tail(&server->grave, &afs_server_graveyard);
server->time_of_death = get_seconds();
- schedule_delayed_work(&afs_server_reaper,
- afs_server_timeout * HZ);
+ queue_delayed_work(afs_wq, &afs_server_reaper,
+ afs_server_timeout * HZ);
}
spin_unlock(&afs_server_graveyard_lock);
_leave(" [dead]");
@@ -285,10 +285,11 @@ static void afs_reap_server(struct work_struct *work)
expiry = server->time_of_death + afs_server_timeout;
if (expiry > now) {
delay = (expiry - now) * HZ;
- if (!schedule_delayed_work(&afs_server_reaper, delay)) {
+ if (!queue_delayed_work(afs_wq, &afs_server_reaper,
+ delay)) {
cancel_delayed_work(&afs_server_reaper);
- schedule_delayed_work(&afs_server_reaper,
- delay);
+ queue_delayed_work(afs_wq, &afs_server_reaper,
+ delay);
}
break;
}
@@ -323,5 +324,5 @@ void __exit afs_purge_servers(void)
{
afs_server_timeout = 0;
cancel_delayed_work(&afs_server_reaper);
- schedule_delayed_work(&afs_server_reaper, 0);
+ queue_delayed_work(afs_wq, &afs_server_reaper, 0);
}
diff --git a/fs/afs/vlocation.c b/fs/afs/vlocation.c
index 9ac260d1361d..431984d2e372 100644
--- a/fs/afs/vlocation.c
+++ b/fs/afs/vlocation.c
@@ -507,8 +507,8 @@ void afs_put_vlocation(struct afs_vlocation *vl)
_debug("buried");
list_move_tail(&vl->grave, &afs_vlocation_graveyard);
vl->time_of_death = get_seconds();
- schedule_delayed_work(&afs_vlocation_reap,
- afs_vlocation_timeout * HZ);
+ queue_delayed_work(afs_wq, &afs_vlocation_reap,
+ afs_vlocation_timeout * HZ);
/* suspend updates on this record */
if (!list_empty(&vl->update)) {
@@ -561,11 +561,11 @@ static void afs_vlocation_reaper(struct work_struct *work)
if (expiry > now) {
delay = (expiry - now) * HZ;
_debug("delay %lu", delay);
- if (!schedule_delayed_work(&afs_vlocation_reap,
- delay)) {
+ if (!queue_delayed_work(afs_wq, &afs_vlocation_reap,
+ delay)) {
cancel_delayed_work(&afs_vlocation_reap);
- schedule_delayed_work(&afs_vlocation_reap,
- delay);
+ queue_delayed_work(afs_wq, &afs_vlocation_reap,
+ delay);
}
break;
}
@@ -620,7 +620,7 @@ void afs_vlocation_purge(void)
destroy_workqueue(afs_vlocation_update_worker);
cancel_delayed_work(&afs_vlocation_reap);
- schedule_delayed_work(&afs_vlocation_reap, 0);
+ queue_delayed_work(afs_wq, &afs_vlocation_reap, 0);
}
/*
diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c
index b9f34eaede09..48a18f184d50 100644
--- a/fs/fscache/operation.c
+++ b/fs/fscache/operation.c
@@ -101,7 +101,7 @@ int fscache_submit_exclusive_op(struct fscache_object *object,
object->n_ops++;
object->n_exclusive++; /* reads and writes must wait */
- if (object->n_ops > 0) {
+ if (object->n_ops > 1) {
atomic_inc(&op->usage);
list_add_tail(&op->pend_link, &object->pending_ops);
fscache_stat(&fscache_n_op_pend);
diff --git a/fs/namei.c b/fs/namei.c
index 86643302079e..8df7a78ace58 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -779,7 +779,8 @@ static void path_put_conditional(struct path *path, struct nameidata *nd)
mntput(path->mnt);
}
-static inline void path_to_nameidata(struct path *path, struct nameidata *nd)
+static inline void path_to_nameidata(const struct path *path,
+ struct nameidata *nd)
{
if (!(nd->flags & LOOKUP_RCU)) {
dput(nd->path.dentry);
@@ -791,20 +792,20 @@ static inline void path_to_nameidata(struct path *path, struct nameidata *nd)
}
static __always_inline int
-__do_follow_link(struct path *path, struct nameidata *nd, void **p)
+__do_follow_link(const struct path *link, struct nameidata *nd, void **p)
{
int error;
- struct dentry *dentry = path->dentry;
+ struct dentry *dentry = link->dentry;
- touch_atime(path->mnt, dentry);
+ touch_atime(link->mnt, dentry);
nd_set_link(nd, NULL);
- if (path->mnt != nd->path.mnt) {
- path_to_nameidata(path, nd);
+ if (link->mnt != nd->path.mnt) {
+ path_to_nameidata(link, nd);
nd->inode = nd->path.dentry->d_inode;
dget(dentry);
}
- mntget(path->mnt);
+ mntget(link->mnt);
nd->last_type = LAST_BIND;
*p = dentry->d_inode->i_op->follow_link(dentry, nd);
@@ -2348,11 +2349,12 @@ reval:
nd.flags = flags;
filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);
while (unlikely(!filp)) { /* trailing symlink */
- struct path holder;
+ struct path link = path;
+ struct inode *linki = link.dentry->d_inode;
void *cookie;
error = -ELOOP;
/* S_ISDIR part is a temporary automount kludge */
- if (!(nd.flags & LOOKUP_FOLLOW) && !S_ISDIR(nd.inode->i_mode))
+ if (!(nd.flags & LOOKUP_FOLLOW) && !S_ISDIR(linki->i_mode))
goto exit_dput;
if (count++ == 32)
goto exit_dput;
@@ -2368,23 +2370,22 @@ reval:
* just set LAST_BIND.
*/
nd.flags |= LOOKUP_PARENT;
- error = security_inode_follow_link(path.dentry, &nd);
+ error = security_inode_follow_link(link.dentry, &nd);
if (error)
goto exit_dput;
- error = __do_follow_link(&path, &nd, &cookie);
+ error = __do_follow_link(&link, &nd, &cookie);
if (unlikely(error)) {
- if (!IS_ERR(cookie) && nd.inode->i_op->put_link)
- nd.inode->i_op->put_link(path.dentry, &nd, cookie);
+ if (!IS_ERR(cookie) && linki->i_op->put_link)
+ linki->i_op->put_link(link.dentry, &nd, cookie);
/* nd.path had been dropped */
- nd.path = path;
+ nd.path = link;
goto out_path;
}
- holder = path;
nd.flags &= ~LOOKUP_PARENT;
filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);
- if (nd.inode->i_op->put_link)
- nd.inode->i_op->put_link(holder.dentry, &nd, cookie);
- path_put(&holder);
+ if (linki->i_op->put_link)
+ linki->i_op->put_link(link.dentry, &nd, cookie);
+ path_put(&link);
}
out:
if (nd.root.mnt)
diff --git a/include/acpi/apei.h b/include/acpi/apei.h
index b3365025ff8d..c4dbb132d902 100644
--- a/include/acpi/apei.h
+++ b/include/acpi/apei.h
@@ -19,6 +19,12 @@
extern int hest_disable;
extern int erst_disable;
+#ifdef CONFIG_ACPI_APEI
+void __init acpi_hest_init(void);
+#else
+static inline void acpi_hest_init(void) { return; }
+#endif
+
typedef int (*apei_hest_func_t)(struct acpi_hest_header *hest_hdr, void *data);
int apei_hest_parse(apei_hest_func_t func, void *data);
diff --git a/include/linux/gpio.h b/include/linux/gpio.h
index 4b47ed96f131..32720baf70f1 100644
--- a/include/linux/gpio.h
+++ b/include/linux/gpio.h
@@ -35,13 +35,13 @@ static inline int gpio_request(unsigned gpio, const char *label)
return -ENOSYS;
}
-static inline int __must_check gpio_request_one(unsigned gpio,
+static inline int gpio_request_one(unsigned gpio,
unsigned long flags, const char *label)
{
return -ENOSYS;
}
-static inline int __must_check gpio_request_array(struct gpio *array, size_t num)
+static inline int gpio_request_array(struct gpio *array, size_t num)
{
return -ENOSYS;
}
diff --git a/include/linux/list_bl.h b/include/linux/list_bl.h
index b2adbb4b2f73..5bad17d1acde 100644
--- a/include/linux/list_bl.h
+++ b/include/linux/list_bl.h
@@ -16,7 +16,7 @@
* some fast and compact auxiliary data.
*/
-#if defined(CONFIG_SMP)
+#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
#define LIST_BL_LOCKMASK 1UL
#else
#define LIST_BL_LOCKMASK 0UL
diff --git a/include/linux/mfd/ab8500.h b/include/linux/mfd/ab8500.h
index 85cf2c28fac6..37f56b7c4c15 100644
--- a/include/linux/mfd/ab8500.h
+++ b/include/linux/mfd/ab8500.h
@@ -74,30 +74,37 @@
#define AB8500_INT_ACC_DETECT_21DB_F 37
#define AB8500_INT_ACC_DETECT_21DB_R 38
#define AB8500_INT_GP_SW_ADC_CONV_END 39
-#define AB8500_INT_BTEMP_LOW 72
-#define AB8500_INT_BTEMP_LOW_MEDIUM 73
-#define AB8500_INT_BTEMP_MEDIUM_HIGH 74
-#define AB8500_INT_BTEMP_HIGH 75
-#define AB8500_INT_USB_CHARGER_NOT_OK 81
-#define AB8500_INT_ID_WAKEUP_R 82
-#define AB8500_INT_ID_DET_R1R 84
-#define AB8500_INT_ID_DET_R2R 85
-#define AB8500_INT_ID_DET_R3R 86
-#define AB8500_INT_ID_DET_R4R 87
-#define AB8500_INT_ID_WAKEUP_F 88
-#define AB8500_INT_ID_DET_R1F 90
-#define AB8500_INT_ID_DET_R2F 91
-#define AB8500_INT_ID_DET_R3F 92
-#define AB8500_INT_ID_DET_R4F 93
-#define AB8500_INT_USB_CHG_DET_DONE 94
-#define AB8500_INT_USB_CH_TH_PROT_F 96
-#define AB8500_INT_USB_CH_TH_PROP_R 97
-#define AB8500_INT_MAIN_CH_TH_PROP_F 98
-#define AB8500_INT_MAIN_CH_TH_PROT_R 99
-#define AB8500_INT_USB_CHARGER_NOT_OKF 103
+#define AB8500_INT_ADP_SOURCE_ERROR 72
+#define AB8500_INT_ADP_SINK_ERROR 73
+#define AB8500_INT_ADP_PROBE_PLUG 74
+#define AB8500_INT_ADP_PROBE_UNPLUG 75
+#define AB8500_INT_ADP_SENSE_OFF 76
+#define AB8500_INT_USB_PHY_POWER_ERR 78
+#define AB8500_INT_USB_LINK_STATUS 79
+#define AB8500_INT_BTEMP_LOW 80
+#define AB8500_INT_BTEMP_LOW_MEDIUM 81
+#define AB8500_INT_BTEMP_MEDIUM_HIGH 82
+#define AB8500_INT_BTEMP_HIGH 83
+#define AB8500_INT_USB_CHARGER_NOT_OK 89
+#define AB8500_INT_ID_WAKEUP_R 90
+#define AB8500_INT_ID_DET_R1R 92
+#define AB8500_INT_ID_DET_R2R 93
+#define AB8500_INT_ID_DET_R3R 94
+#define AB8500_INT_ID_DET_R4R 95
+#define AB8500_INT_ID_WAKEUP_F 96
+#define AB8500_INT_ID_DET_R1F 98
+#define AB8500_INT_ID_DET_R2F 99
+#define AB8500_INT_ID_DET_R3F 100
+#define AB8500_INT_ID_DET_R4F 101
+#define AB8500_INT_USB_CHG_DET_DONE 102
+#define AB8500_INT_USB_CH_TH_PROT_F 104
+#define AB8500_INT_USB_CH_TH_PROT_R 105
+#define AB8500_INT_MAIN_CH_TH_PROT_F 106
+#define AB8500_INT_MAIN_CH_TH_PROT_R 107
+#define AB8500_INT_USB_CHARGER_NOT_OKF 111
-#define AB8500_NR_IRQS 104
-#define AB8500_NUM_IRQ_REGS 13
+#define AB8500_NR_IRQS 112
+#define AB8500_NUM_IRQ_REGS 14
/**
* struct ab8500 - ab8500 internal structure
diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
index 5582ab3d3e48..835996e167e1 100644
--- a/include/linux/mfd/core.h
+++ b/include/linux/mfd/core.h
@@ -47,6 +47,12 @@ struct mfd_cell {
/* don't check for resource conflicts */
bool ignore_resource_conflicts;
+
+ /*
+ * Disable runtime PM callbacks for this subdevice - see
+ * pm_runtime_no_callbacks().
+ */
+ bool pm_runtime_no_callbacks;
};
extern int mfd_add_devices(struct device *parent, int id,
diff --git a/include/linux/mfd/max8998-private.h b/include/linux/mfd/max8998-private.h
index 7363dea6bbcd..effa5d3b96ae 100644
--- a/include/linux/mfd/max8998-private.h
+++ b/include/linux/mfd/max8998-private.h
@@ -159,10 +159,12 @@ struct max8998_dev {
u8 irq_masks_cur[MAX8998_NUM_IRQ_REGS];
u8 irq_masks_cache[MAX8998_NUM_IRQ_REGS];
int type;
+ bool wakeup;
};
int max8998_irq_init(struct max8998_dev *max8998);
void max8998_irq_exit(struct max8998_dev *max8998);
+int max8998_irq_resume(struct max8998_dev *max8998);
extern int max8998_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest);
extern int max8998_bulk_read(struct i2c_client *i2c, u8 reg, int count,
diff --git a/include/linux/mfd/max8998.h b/include/linux/mfd/max8998.h
index f8c9f884aff2..61daa167b576 100644
--- a/include/linux/mfd/max8998.h
+++ b/include/linux/mfd/max8998.h
@@ -70,24 +70,43 @@ struct max8998_regulator_data {
* @num_regulators: number of regultors used
* @irq_base: base IRQ number for max8998, required for IRQs
* @ono: power onoff IRQ number for max8998
- * @buck1_max_voltage1: BUCK1 maximum alowed voltage register 1
- * @buck1_max_voltage2: BUCK1 maximum alowed voltage register 2
- * @buck2_max_voltage: BUCK2 maximum alowed voltage
+ * @buck_voltage_lock: Do NOT change the values of the following six
+ * registers set by buck?_voltage?. The voltage of BUCK1/2 cannot
+ * be other than the preset values.
+ * @buck1_voltage1: BUCK1 DVS mode 1 voltage register
+ * @buck1_voltage2: BUCK1 DVS mode 2 voltage register
+ * @buck1_voltage3: BUCK1 DVS mode 3 voltage register
+ * @buck1_voltage4: BUCK1 DVS mode 4 voltage register
+ * @buck2_voltage1: BUCK2 DVS mode 1 voltage register
+ * @buck2_voltage2: BUCK2 DVS mode 2 voltage register
* @buck1_set1: BUCK1 gpio pin 1 to set output voltage
* @buck1_set2: BUCK1 gpio pin 2 to set output voltage
+ * @buck1_default_idx: Default for BUCK1 gpio pin 1, 2
* @buck2_set3: BUCK2 gpio pin to set output voltage
+ * @buck2_default_idx: Default for BUCK2 gpio pin.
+ * @wakeup: Allow to wake up from suspend
+ * @rtc_delay: LP3974 RTC chip bug that requires delay after a register
+ * write before reading it.
*/
struct max8998_platform_data {
struct max8998_regulator_data *regulators;
int num_regulators;
int irq_base;
int ono;
- int buck1_max_voltage1;
- int buck1_max_voltage2;
- int buck2_max_voltage;
+ bool buck_voltage_lock;
+ int buck1_voltage1;
+ int buck1_voltage2;
+ int buck1_voltage3;
+ int buck1_voltage4;
+ int buck2_voltage1;
+ int buck2_voltage2;
int buck1_set1;
int buck1_set2;
+ int buck1_default_idx;
int buck2_set3;
+ int buck2_default_idx;
+ bool wakeup;
+ bool rtc_delay;
};
#endif /* __LINUX_MFD_MAX8998_H */
diff --git a/include/linux/mfd/wm831x/core.h b/include/linux/mfd/wm831x/core.h
index a1239c48b41a..903280d21866 100644
--- a/include/linux/mfd/wm831x/core.h
+++ b/include/linux/mfd/wm831x/core.h
@@ -245,6 +245,7 @@ enum wm831x_parent {
WM8320 = 0x8320,
WM8321 = 0x8321,
WM8325 = 0x8325,
+ WM8326 = 0x8326,
};
struct wm831x {
diff --git a/include/linux/page_cgroup.h b/include/linux/page_cgroup.h
index 5b0c971d7cae..6d6cb7a57bb3 100644
--- a/include/linux/page_cgroup.h
+++ b/include/linux/page_cgroup.h
@@ -42,9 +42,6 @@ enum {
/* flags for mem_cgroup and file and I/O status */
PCG_MOVE_LOCK, /* For race between move_account v.s. following bits */
PCG_FILE_MAPPED, /* page is accounted as "mapped" */
- PCG_FILE_DIRTY, /* page is dirty */
- PCG_FILE_WRITEBACK, /* page is under writeback */
- PCG_FILE_UNSTABLE_NFS, /* page is NFS unstable */
/* No lock in page_cgroup */
PCG_ACCT_LRU, /* page has been accounted for (under lru_lock) */
};
@@ -65,10 +62,6 @@ static inline void ClearPageCgroup##uname(struct page_cgroup *pc) \
static inline int TestClearPageCgroup##uname(struct page_cgroup *pc) \
{ return test_and_clear_bit(PCG_##lname, &pc->flags); }
-#define TESTSETPCGFLAG(uname, lname) \
-static inline int TestSetPageCgroup##uname(struct page_cgroup *pc) \
- { return test_and_set_bit(PCG_##lname, &pc->flags); }
-
/* Cache flag is set only once (at allocation) */
TESTPCGFLAG(Cache, CACHE)
CLEARPCGFLAG(Cache, CACHE)
@@ -88,22 +81,6 @@ SETPCGFLAG(FileMapped, FILE_MAPPED)
CLEARPCGFLAG(FileMapped, FILE_MAPPED)
TESTPCGFLAG(FileMapped, FILE_MAPPED)
-SETPCGFLAG(FileDirty, FILE_DIRTY)
-CLEARPCGFLAG(FileDirty, FILE_DIRTY)
-TESTPCGFLAG(FileDirty, FILE_DIRTY)
-TESTCLEARPCGFLAG(FileDirty, FILE_DIRTY)
-TESTSETPCGFLAG(FileDirty, FILE_DIRTY)
-
-SETPCGFLAG(FileWriteback, FILE_WRITEBACK)
-CLEARPCGFLAG(FileWriteback, FILE_WRITEBACK)
-TESTPCGFLAG(FileWriteback, FILE_WRITEBACK)
-
-SETPCGFLAG(FileUnstableNFS, FILE_UNSTABLE_NFS)
-CLEARPCGFLAG(FileUnstableNFS, FILE_UNSTABLE_NFS)
-TESTPCGFLAG(FileUnstableNFS, FILE_UNSTABLE_NFS)
-TESTCLEARPCGFLAG(FileUnstableNFS, FILE_UNSTABLE_NFS)
-TESTSETPCGFLAG(FileUnstableNFS, FILE_UNSTABLE_NFS)
-
SETPCGFLAG(Migration, MIGRATION)
CLEARPCGFLAG(Migration, MIGRATION)
TESTPCGFLAG(Migration, MIGRATION)
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index c8b6473c5f42..479d9bb88e11 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -40,4 +40,10 @@ static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
{ return NULL; }
#endif
+#ifdef CONFIG_ACPI_APEI
+extern bool aer_acpi_firmware_first(void);
+#else
+static inline bool aer_acpi_firmware_first(void) { return false; }
+#endif
+
#endif /* _PCI_ACPI_H_ */
diff --git a/include/linux/pci-aspm.h b/include/linux/pci-aspm.h
index 91ba0b338b47..ce6810512c66 100644
--- a/include/linux/pci-aspm.h
+++ b/include/linux/pci-aspm.h
@@ -27,6 +27,7 @@ extern void pcie_aspm_init_link_state(struct pci_dev *pdev);
extern void pcie_aspm_exit_link_state(struct pci_dev *pdev);
extern void pcie_aspm_pm_state_change(struct pci_dev *pdev);
extern void pci_disable_link_state(struct pci_dev *pdev, int state);
+extern void pcie_clear_aspm(void);
extern void pcie_no_aspm(void);
#else
static inline void pcie_aspm_init_link_state(struct pci_dev *pdev)
@@ -41,7 +42,9 @@ static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev)
static inline void pci_disable_link_state(struct pci_dev *pdev, int state)
{
}
-
+static inline void pcie_clear_aspm(void)
+{
+}
static inline void pcie_no_aspm(void)
{
}
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 7454408c41b6..9e67dcd054c4 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -806,7 +806,7 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size);
/* Power management related routines */
int pci_save_state(struct pci_dev *dev);
-int pci_restore_state(struct pci_dev *dev);
+void pci_restore_state(struct pci_dev *dev);
int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state);
int pci_set_power_state(struct pci_dev *dev, pci_power_t state);
pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);
@@ -820,7 +820,6 @@ int pci_prepare_to_sleep(struct pci_dev *dev);
int pci_back_from_sleep(struct pci_dev *dev);
bool pci_dev_run_wake(struct pci_dev *dev);
bool pci_check_pme_status(struct pci_dev *dev);
-void pci_wakeup_event(struct pci_dev *dev);
void pci_pme_wakeup_bus(struct pci_bus *bus);
static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state,
@@ -994,6 +993,9 @@ extern void pci_restore_msi_state(struct pci_dev *dev);
extern int pci_msi_enabled(void);
#endif
+extern bool pcie_ports_disabled;
+extern bool pcie_ports_auto;
+
#ifndef CONFIG_PCIEASPM
static inline int pcie_aspm_enabled(void)
{
@@ -1003,6 +1005,14 @@ static inline int pcie_aspm_enabled(void)
extern int pcie_aspm_enabled(void);
#endif
+#ifdef CONFIG_PCIEAER
+void pci_no_aer(void);
+bool pci_aer_available(void);
+#else
+static inline void pci_no_aer(void) { }
+static inline bool pci_aer_available(void) { return false; }
+#endif
+
#ifndef CONFIG_PCIE_ECRC
static inline void pcie_set_ecrc_checking(struct pci_dev *dev)
{
@@ -1168,10 +1178,8 @@ static inline int pci_save_state(struct pci_dev *dev)
return 0;
}
-static inline int pci_restore_state(struct pci_dev *dev)
-{
- return 0;
-}
+static inline void pci_restore_state(struct pci_dev *dev)
+{ }
static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
{
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index ae0dc453e3e2..3adb06ebf841 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2478,7 +2478,8 @@
#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN 0x1c41
#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX 0x1c5f
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22
-#define PCI_DEVICE_ID_INTEL_PATSBURG_LPC 0x1d40
+#define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_0 0x1d40
+#define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_1 0x1d41
#define PCI_DEVICE_ID_INTEL_82801AA_0 0x2410
#define PCI_DEVICE_ID_INTEL_82801AA_1 0x2411
#define PCI_DEVICE_ID_INTEL_82801AA_3 0x2413
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index af83076c31a6..5b7e6b1ba54f 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -309,6 +309,14 @@
#define PCI_MSIX_PBA 8
#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
+/* MSI-X entry's format */
+#define PCI_MSIX_ENTRY_SIZE 16
+#define PCI_MSIX_ENTRY_LOWER_ADDR 0
+#define PCI_MSIX_ENTRY_UPPER_ADDR 4
+#define PCI_MSIX_ENTRY_DATA 8
+#define PCI_MSIX_ENTRY_VECTOR_CTRL 12
+#define PCI_MSIX_ENTRY_CTRL_MASKBIT 1
+
/* CompactPCI Hotswap Register */
#define PCI_CHSWP_CSR 2 /* Control and Status Register */
@@ -496,6 +504,8 @@
#define PCI_EXP_RTCTL_CRSSVE 0x10 /* CRS Software Visibility Enable */
#define PCI_EXP_RTCAP 30 /* Root Capabilities */
#define PCI_EXP_RTSTA 32 /* Root Status */
+#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */
+#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */
#define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */
#define PCI_EXP_DEVCAP2_ARI 0x20 /* Alternative Routing-ID */
#define PCI_EXP_DEVCTL2 40 /* Device Control 2 */
diff --git a/include/linux/power/gpio-charger.h b/include/linux/power/gpio-charger.h
new file mode 100644
index 000000000000..de1dfe09a03d
--- /dev/null
+++ b/include/linux/power/gpio-charger.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <[email protected]>
+ *
+ * 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.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __LINUX_POWER_GPIO_CHARGER_H__
+#define __LINUX_POWER_GPIO_CHARGER_H__
+
+#include <linux/power_supply.h>
+#include <linux/types.h>
+
+/**
+ * struct gpio_charger_platform_data - platform_data for gpio_charger devices
+ * @name: Name for the chargers power_supply device
+ * @type: Type of the charger
+ * @gpio: GPIO which is used to indicate the chargers status
+ * @gpio_active_low: Should be set to 1 if the GPIO is active low otherwise 0
+ * @supplied_to: Array of battery names to which this chargers supplies power
+ * @num_supplicants: Number of entries in the supplied_to array
+ */
+struct gpio_charger_platform_data {
+ const char *name;
+ enum power_supply_type type;
+
+ int gpio;
+ int gpio_active_low;
+
+ char **supplied_to;
+ size_t num_supplicants;
+};
+
+#endif
diff --git a/include/linux/power/max17042_battery.h b/include/linux/power/max17042_battery.h
new file mode 100644
index 000000000000..7995deb8bfc1
--- /dev/null
+++ b/include/linux/power/max17042_battery.h
@@ -0,0 +1,30 @@
+/*
+ * Fuel gauge driver for Maxim 17042 / 8966 / 8997
+ * Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * MyungJoo Ham <[email protected]>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __MAX17042_BATTERY_H_
+#define __MAX17042_BATTERY_H_
+
+struct max17042_platform_data {
+ bool enable_current_sense;
+};
+
+#endif /* __MAX17042_BATTERY_H_ */
diff --git a/include/linux/s3c_adc_battery.h b/include/linux/s3c_adc_battery.h
index dbce22faa660..fbe58b7e63eb 100644
--- a/include/linux/s3c_adc_battery.h
+++ b/include/linux/s3c_adc_battery.h
@@ -14,6 +14,7 @@ struct s3c_adc_bat_pdata {
void (*disable_charger)(void);
int gpio_charge_finished;
+ int gpio_inverted;
const struct s3c_adc_bat_thresh *lut_noac;
unsigned int lut_noac_cnt;
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 5c5f4cc2e99a..b24d7027b83c 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -764,6 +764,7 @@ EXPORT_SYMBOL_GPL(cgroup_unlock);
*/
static int cgroup_mkdir(struct inode *dir, struct dentry *dentry, int mode);
+static struct dentry *cgroup_lookup(struct inode *, struct dentry *, struct nameidata *);
static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry);
static int cgroup_populate_dir(struct cgroup *cgrp);
static const struct inode_operations cgroup_dir_inode_operations;
@@ -860,6 +861,11 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
iput(inode);
}
+static int cgroup_delete(const struct dentry *d)
+{
+ return 1;
+}
+
static void remove_dir(struct dentry *d)
{
struct dentry *parent = dget(d->d_parent);
@@ -910,7 +916,7 @@ static void cgroup_d_remove_dir(struct dentry *dentry)
parent = dentry->d_parent;
spin_lock(&parent->d_lock);
- spin_lock(&dentry->d_lock);
+ spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
list_del_init(&dentry->d_u.d_child);
spin_unlock(&dentry->d_lock);
spin_unlock(&parent->d_lock);
@@ -1451,6 +1457,7 @@ static int cgroup_get_rootdir(struct super_block *sb)
{
static const struct dentry_operations cgroup_dops = {
.d_iput = cgroup_diput,
+ .d_delete = cgroup_delete,
};
struct inode *inode =
@@ -2195,12 +2202,20 @@ static const struct file_operations cgroup_file_operations = {
};
static const struct inode_operations cgroup_dir_inode_operations = {
- .lookup = simple_lookup,
+ .lookup = cgroup_lookup,
.mkdir = cgroup_mkdir,
.rmdir = cgroup_rmdir,
.rename = cgroup_rename,
};
+static struct dentry *cgroup_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+{
+ if (dentry->d_name.len > NAME_MAX)
+ return ERR_PTR(-ENAMETOOLONG);
+ d_add(dentry, NULL);
+ return NULL;
+}
+
/*
* Check if a file is a control file
*/
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index 0b9bb2085ce4..74c064c0dfdd 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -808,7 +808,7 @@ static int __init af_rxrpc_init(void)
goto error_call_jar;
}
- rxrpc_workqueue = create_workqueue("krxrpcd");
+ rxrpc_workqueue = alloc_workqueue("krxrpcd", 0, 1);
if (!rxrpc_workqueue) {
printk(KERN_NOTICE "RxRPC: Failed to allocate work queue\n");
goto error_work_queue;
diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c
index a3301cc4ab82..185b00088320 100644
--- a/sound/pci/cs5535audio/cs5535audio_pm.c
+++ b/sound/pci/cs5535audio/cs5535audio_pm.c
@@ -90,12 +90,7 @@ int snd_cs5535audio_resume(struct pci_dev *pci)
int i;
pci_set_power_state(pci, PCI_D0);
- if (pci_restore_state(pci) < 0) {
- printk(KERN_ERR "cs5535audio: pci_restore_state failed, "
- "disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
+ pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
printk(KERN_ERR "cs5535audio: pci_enable_device failed, "
"disabling device\n");