Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 25 May 2010 15:17:01 +0000 (08:17 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 25 May 2010 15:17:01 +0000 (08:17 -0700)
* 'for-linus' of git://oss.sgi.com/xfs/xfs:
  xfs: Ensure inode allocation buffers are fully replayed
  xfs: enable background pushing of the CIL
  xfs: forced unmounts need to push the CIL
  xfs: Introduce delayed logging core code
  xfs: Delayed logging design documentation
  xfs: Improve scalability of busy extent tracking
  xfs: make the log ticket ID available outside the log infrastructure
  xfs: clean up log ticket overrun debug output
  xfs: Clean up XFS_BLI_* flag namespace
  xfs: modify buffer item reference counting
  xfs: allow log ticket allocation to take allocation flags
  xfs: Don't reuse the same transaction ID for duplicated transactions.

164 files changed:
Documentation/ABI/testing/sysfs-devices-node [new file with mode: 0644]
Documentation/filesystems/tmpfs.txt
Documentation/sysctl/vm.txt
arch/alpha/math-emu/sfp-util.h
arch/arm/plat-samsung/include/plat/regs-rtc.h
arch/frv/include/asm/cache.h
arch/frv/include/asm/gdb-stub.h
arch/frv/kernel/gdb-io.c
arch/frv/kernel/gdb-stub.c
arch/mn10300/include/asm/atomic.h
arch/mn10300/include/asm/cache.h
arch/powerpc/include/asm/sfp-machine.h
arch/s390/include/asm/sfp-util.h
arch/sh/math-emu/sfp-util.h
arch/sparc/math-emu/sfp-util_32.h
arch/sparc/math-emu/sfp-util_64.h
arch/x86/boot/compressed/relocs.c
arch/x86/include/asm/msr-index.h
arch/xtensa/include/asm/cache.h
arch/xtensa/include/asm/hardirq.h
arch/xtensa/kernel/irq.c
arch/xtensa/kernel/vectors.S
drivers/acpi/bus.c
drivers/auxdisplay/cfag12864bfb.c
drivers/base/node.c
drivers/char/hangcheck-timer.c
drivers/char/hvsi.c
drivers/char/misc.c
drivers/cpuidle/governors/menu.c
drivers/dma/timb_dma.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/ads7871.c [new file with mode: 0644]
drivers/hwmon/coretemp.c
drivers/hwmon/lis3lv02d.c
drivers/hwmon/lis3lv02d.h
drivers/isdn/gigaset/capi.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/ad525x_dpot-i2c.c [new file with mode: 0644]
drivers/misc/ad525x_dpot-spi.c [new file with mode: 0644]
drivers/misc/ad525x_dpot.c
drivers/misc/ad525x_dpot.h [new file with mode: 0644]
drivers/net/wireless/airo.c
drivers/power/power_supply_sysfs.c
drivers/rtc/Kconfig
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-ds1302.c
drivers/rtc/rtc-isl1208.c
drivers/rtc/rtc-mxc.c
drivers/rtc/rtc-s3c.c
drivers/rtc/rtc-wm831x.c
drivers/scsi/fcoe/fcoe.c
drivers/scsi/mpt2sas/mpt2sas_base.c
drivers/scsi/mpt2sas/mpt2sas_config.c
drivers/serial/68328serial.c
drivers/staging/rt2860/common/rtmp_init.c
drivers/staging/rt2860/rtmp.h
drivers/usb/atm/speedtch.c
drivers/vhost/vhost.c
drivers/video/arcfb.c
drivers/video/aty/atyfb_base.c
drivers/video/bfin-lq035q1-fb.c
drivers/video/da8xx-fb.c
drivers/video/fb_defio.c
drivers/video/hgafb.c
drivers/video/hitfb.c
drivers/video/intelfb/intelfb.h
drivers/video/nuc900fb.c
drivers/video/s3c2410fb.c
drivers/video/sgivwfb.c
drivers/video/sis/sis_main.c
drivers/video/vfb.c
drivers/video/vga16fb.c
drivers/video/w100fb.c
drivers/xen/manage.c
fs/exec.c
fs/fat/cache.c
fs/fat/fat.h
fs/fat/inode.c
fs/fat/misc.c
fs/fs-writeback.c
fs/nfs/super.c
fs/nfsd/nfsctl.c
fs/ntfs/file.c
fs/ocfs2/blockcheck.c
fs/partitions/ldm.c
fs/proc/task_mmu.c
fs/smbfs/symlink.c
include/asm-generic/atomic.h
include/asm-generic/kmap_types.h
include/linux/byteorder/big_endian.h
include/linux/byteorder/little_endian.h
include/linux/compaction.h [new file with mode: 0644]
include/linux/cpuset.h
include/linux/dynamic_debug.h
include/linux/err.h
include/linux/fb.h
include/linux/gfp.h
include/linux/highmem.h
include/linux/ivtvfb.h
include/linux/kernel.h
include/linux/lis3lv02d.h
include/linux/matroxfb.h
include/linux/memcontrol.h
include/linux/memory_hotplug.h
include/linux/mempolicy.h
include/linux/migrate.h
include/linux/mm.h
include/linux/mmzone.h
include/linux/ratelimit.h
include/linux/rmap.h
include/linux/sched.h
include/linux/swap.h
include/linux/vmstat.h
include/net/ip.h
include/net/ipv6.h
include/video/da8xx-fb.h
include/video/sh_mobile_lcdc.h
init/main.c
ipc/msg.c
ipc/util.c
kernel/cpu.c
kernel/cpuset.c
kernel/exit.c
kernel/module.c
kernel/sysctl.c
kernel/sysctl_binary.c
lib/Kconfig.debug
lib/crc32.c
lib/dynamic_debug.c
lib/gen_crc32table.c
lib/hexdump.c
lib/vsprintf.c
mm/Kconfig
mm/Makefile
mm/compaction.c [new file with mode: 0644]
mm/filemap.c
mm/highmem.c
mm/hugetlb.c
mm/ksm.c
mm/memory.c
mm/memory_hotplug.c
mm/mempolicy.c
mm/migrate.c
mm/mincore.c
mm/page_alloc.c
mm/readahead.c
mm/rmap.c
mm/shmem.c
mm/slab.c
mm/slub.c
mm/sparse.c
mm/vmscan.c
mm/vmstat.c
net/9p/protocol.c
net/dccp/options.c
net/ipv4/udp.c
net/mac80211/sta_info.c
net/sunrpc/rpcb_clnt.c
net/sunrpc/xprt.c
scripts/checkpatch.pl
scripts/get_maintainer.pl
security/keys/keyring.c

diff --git a/Documentation/ABI/testing/sysfs-devices-node b/Documentation/ABI/testing/sysfs-devices-node
new file mode 100644 (file)
index 0000000..453a210
--- /dev/null
@@ -0,0 +1,7 @@
+What:          /sys/devices/system/node/nodeX/compact
+Date:          February 2010
+Contact:       Mel Gorman <mel@csn.ul.ie>
+Description:
+               When this file is written to, all memory within that node
+               will be compacted. When it completes, memory will be freed
+               into blocks which have as many contiguous pages as possible
index fe09a2c..98ef551 100644 (file)
@@ -94,11 +94,19 @@ NodeList format is a comma-separated list of decimal numbers and ranges,
 a range being two hyphen-separated decimal numbers, the smallest and
 largest node numbers in the range.  For example, mpol=bind:0-3,5,7,9-15
 
+A memory policy with a valid NodeList will be saved, as specified, for
+use at file creation time.  When a task allocates a file in the file
+system, the mount option memory policy will be applied with a NodeList,
+if any, modified by the calling task's cpuset constraints
+[See Documentation/cgroups/cpusets.txt] and any optional flags, listed
+below.  If the resulting NodeLists is the empty set, the effective memory
+policy for the file will revert to "default" policy.
+
 NUMA memory allocation policies have optional flags that can be used in
 conjunction with their modes.  These optional flags can be specified
 when tmpfs is mounted by appending them to the mode before the NodeList.
 See Documentation/vm/numa_memory_policy.txt for a list of all available
-memory allocation policy mode flags.
+memory allocation policy mode flags and their effect on memory policy.
 
        =static         is equivalent to        MPOL_F_STATIC_NODES
        =relative       is equivalent to        MPOL_F_RELATIVE_NODES
index 6c7d18c..5fdbb61 100644 (file)
@@ -19,6 +19,7 @@ files can be found in mm/swap.c.
 Currently, these files are in /proc/sys/vm:
 
 - block_dump
+- compact_memory
 - dirty_background_bytes
 - dirty_background_ratio
 - dirty_bytes
@@ -26,6 +27,7 @@ Currently, these files are in /proc/sys/vm:
 - dirty_ratio
 - dirty_writeback_centisecs
 - drop_caches
+- extfrag_threshold
 - hugepages_treat_as_movable
 - hugetlb_shm_group
 - laptop_mode
@@ -64,6 +66,15 @@ information on block I/O debugging is in Documentation/laptops/laptop-mode.txt.
 
 ==============================================================
 
+compact_memory
+
+Available only when CONFIG_COMPACTION is set. When 1 is written to the file,
+all zones are compacted such that free memory is available in contiguous
+blocks where possible. This can be important for example in the allocation of
+huge pages although processes will also directly compact memory as required.
+
+==============================================================
+
 dirty_background_bytes
 
 Contains the amount of dirty memory at which the pdflush background writeback
@@ -139,6 +150,20 @@ user should run `sync' first.
 
 ==============================================================
 
+extfrag_threshold
+
+This parameter affects whether the kernel will compact memory or direct
+reclaim to satisfy a high-order allocation. /proc/extfrag_index shows what
+the fragmentation index for each order is in each zone in the system. Values
+tending towards 0 imply allocations would fail due to lack of memory,
+values towards 1000 imply failures are due to fragmentation and -1 implies
+that the allocation will succeed as long as watermarks are met.
+
+The kernel will not compact memory in a zone if the
+fragmentation index is <= extfrag_threshold. The default value is 500.
+
+==============================================================
+
 hugepages_treat_as_movable
 
 This parameter is only useful when kernelcore= is specified at boot time to
index f53707f..d4c6ae7 100644 (file)
@@ -28,8 +28,3 @@ extern unsigned long __udiv_qrnnd (unsigned long *, unsigned long,
 #define UDIV_NEEDS_NORMALIZATION 1  
 
 #define abort()                        goto bad_insn
-
-#ifndef __LITTLE_ENDIAN
-#define __LITTLE_ENDIAN -1
-#endif
-#define __BYTE_ORDER __LITTLE_ENDIAN
index d5837cf..65c190d 100644 (file)
 #define S3C2410_RTCCON_CLKSEL (1<<1)
 #define S3C2410_RTCCON_CNTSEL (1<<2)
 #define S3C2410_RTCCON_CLKRST (1<<3)
+#define S3C64XX_RTCCON_TICEN  (1<<8)
+
+#define S3C64XX_RTCCON_TICMSK (0xF<<7)
+#define S3C64XX_RTCCON_TICSHT (7)
 
 #define S3C2410_TICNT        S3C2410_RTCREG(0x44)
 #define S3C2410_TICNT_ENABLE  (1<<7)
index 2797163..7dc0f0f 100644 (file)
@@ -17,6 +17,8 @@
 #define L1_CACHE_SHIFT         (CONFIG_FRV_L1_CACHE_SHIFT)
 #define L1_CACHE_BYTES         (1 << L1_CACHE_SHIFT)
 
+#define ARCH_KMALLOC_MINALIGN  L1_CACHE_BYTES
+
 #define __cacheline_aligned    __attribute__((aligned(L1_CACHE_BYTES)))
 #define ____cacheline_aligned  __attribute__((aligned(L1_CACHE_BYTES)))
 
index 2da7164..e6bedd0 100644 (file)
@@ -12,6 +12,7 @@
 #ifndef __ASM_GDB_STUB_H
 #define __ASM_GDB_STUB_H
 
+#undef GDBSTUB_DEBUG_IO
 #undef GDBSTUB_DEBUG_PROTOCOL
 
 #include <asm/ptrace.h>
@@ -108,6 +109,12 @@ extern void gdbstub_printk(const char *fmt, ...);
 extern void debug_to_serial(const char *p, int n);
 extern void console_set_baud(unsigned baud);
 
+#ifdef GDBSTUB_DEBUG_IO
+#define gdbstub_io(FMT,...) gdbstub_printk(FMT, ##__VA_ARGS__)
+#else
+#define gdbstub_io(FMT,...) ({ 0; })
+#endif
+
 #ifdef GDBSTUB_DEBUG_PROTOCOL
 #define gdbstub_proto(FMT,...) gdbstub_printk(FMT,##__VA_ARGS__)
 #else
index c997bcc..2ca641d 100644 (file)
@@ -171,11 +171,11 @@ int gdbstub_rx_char(unsigned char *_ch, int nonblock)
                return -EINTR;
        }
        else if (st & (UART_LSR_FE|UART_LSR_OE|UART_LSR_PE)) {
-               gdbstub_proto("### GDB Rx Error (st=%02x) ###\n",st);
+               gdbstub_io("### GDB Rx Error (st=%02x) ###\n",st);
                return -EIO;
        }
        else {
-               gdbstub_proto("### GDB Rx %02x (st=%02x) ###\n",ch,st);
+               gdbstub_io("### GDB Rx %02x (st=%02x) ###\n",ch,st);
                *_ch = ch & 0x7f;
                return 0;
        }
index 7ca8a6b..84d103c 100644 (file)
@@ -1344,6 +1344,44 @@ void gdbstub_get_mmu_state(void)
 
 } /* end gdbstub_get_mmu_state() */
 
+/*
+ * handle general query commands of the form 'qXXXXX'
+ */
+static void gdbstub_handle_query(void)
+{
+       if (strcmp(input_buffer, "qAttached") == 0) {
+               /* return current thread ID */
+               sprintf(output_buffer, "1");
+               return;
+       }
+
+       if (strcmp(input_buffer, "qC") == 0) {
+               /* return current thread ID */
+               sprintf(output_buffer, "QC 0");
+               return;
+       }
+
+       if (strcmp(input_buffer, "qOffsets") == 0) {
+               /* return relocation offset of text and data segments */
+               sprintf(output_buffer, "Text=0;Data=0;Bss=0");
+               return;
+       }
+
+       if (strcmp(input_buffer, "qSymbol::") == 0) {
+               sprintf(output_buffer, "OK");
+               return;
+       }
+
+       if (strcmp(input_buffer, "qSupported") == 0) {
+               /* query of supported features */
+               sprintf(output_buffer, "PacketSize=%u;ReverseContinue-;ReverseStep-",
+                       sizeof(input_buffer));
+               return;
+       }
+
+       gdbstub_strcpy(output_buffer,"E01");
+}
+
 /*****************************************************************************/
 /*
  * handle event interception and GDB remote protocol processing
@@ -1840,6 +1878,10 @@ void gdbstub(int sigval)
                case 'k' :
                        goto done;      /* just continue */
 
+                       /* detach */
+               case 'D':
+                       gdbstub_strcpy(output_buffer, "OK");
+                       break;
 
                        /* reset the whole machine (FIXME: system dependent) */
                case 'r':
@@ -1852,6 +1894,14 @@ void gdbstub(int sigval)
                        __debug_status.dcr |= DCR_SE;
                        goto done;
 
+                       /* extended command */
+               case 'v':
+                       if (strcmp(input_buffer, "vCont?") == 0) {
+                               output_buffer[0] = 0;
+                               break;
+                       }
+                       goto unsupported_cmd;
+
                        /* set baud rate (bBB) */
                case 'b':
                        ptr = &input_buffer[1];
@@ -1923,8 +1973,19 @@ void gdbstub(int sigval)
                        gdbstub_strcpy(output_buffer,"OK");
                        break;
 
+                       /* Thread-setting packet */
+               case 'H':
+                       gdbstub_strcpy(output_buffer, "OK");
+                       break;
+
+               case 'q':
+                       gdbstub_handle_query();
+                       break;
+
                default:
+               unsupported_cmd:
                        gdbstub_proto("### GDB Unsupported Cmd '%s'\n",input_buffer);
+                       gdbstub_strcpy(output_buffer,"E01");
                        break;
                }
 
index e41222d..f0cc1f8 100644 (file)
@@ -1,157 +1 @@
-/* MN10300 Atomic counter operations
- *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-#ifndef _ASM_ATOMIC_H
-#define _ASM_ATOMIC_H
-
-#ifdef CONFIG_SMP
-#error not SMP safe
-#endif
-
-/*
- * Atomic operations that C can't guarantee us.  Useful for
- * resource counting etc..
- */
-
-#define ATOMIC_INIT(i) { (i) }
-
-#ifdef __KERNEL__
-
-/**
- * atomic_read - read atomic variable
- * @v: pointer of type atomic_t
- *
- * Atomically reads the value of @v.  Note that the guaranteed
- * useful range of an atomic_t is only 24 bits.
- */
-#define atomic_read(v) (*(volatile int *)&(v)->counter)
-
-/**
- * atomic_set - set atomic variable
- * @v: pointer of type atomic_t
- * @i: required value
- *
- * Atomically sets the value of @v to @i.  Note that the guaranteed
- * useful range of an atomic_t is only 24 bits.
- */
-#define atomic_set(v, i) (((v)->counter) = (i))
-
-#include <asm/system.h>
-
-/**
- * atomic_add_return - add integer to atomic variable
- * @i: integer value to add
- * @v: pointer of type atomic_t
- *
- * Atomically adds @i to @v and returns the result
- * Note that the guaranteed useful range of an atomic_t is only 24 bits.
- */
-static inline int atomic_add_return(int i, atomic_t *v)
-{
-       unsigned long flags;
-       int temp;
-
-       local_irq_save(flags);
-       temp = v->counter;
-       temp += i;
-       v->counter = temp;
-       local_irq_restore(flags);
-
-       return temp;
-}
-
-/**
- * atomic_sub_return - subtract integer from atomic variable
- * @i: integer value to subtract
- * @v: pointer of type atomic_t
- *
- * Atomically subtracts @i from @v and returns the result
- * Note that the guaranteed useful range of an atomic_t is only 24 bits.
- */
-static inline int atomic_sub_return(int i, atomic_t *v)
-{
-       unsigned long flags;
-       int temp;
-
-       local_irq_save(flags);
-       temp = v->counter;
-       temp -= i;
-       v->counter = temp;
-       local_irq_restore(flags);
-
-       return temp;
-}
-
-static inline int atomic_add_negative(int i, atomic_t *v)
-{
-       return atomic_add_return(i, v) < 0;
-}
-
-static inline void atomic_add(int i, atomic_t *v)
-{
-       atomic_add_return(i, v);
-}
-
-static inline void atomic_sub(int i, atomic_t *v)
-{
-       atomic_sub_return(i, v);
-}
-
-static inline void atomic_inc(atomic_t *v)
-{
-       atomic_add_return(1, v);
-}
-
-static inline void atomic_dec(atomic_t *v)
-{
-       atomic_sub_return(1, v);
-}
-
-#define atomic_dec_return(v)           atomic_sub_return(1, (v))
-#define atomic_inc_return(v)           atomic_add_return(1, (v))
-
-#define atomic_sub_and_test(i, v)      (atomic_sub_return((i), (v)) == 0)
-#define atomic_dec_and_test(v)         (atomic_sub_return(1, (v)) == 0)
-#define atomic_inc_and_test(v)         (atomic_add_return(1, (v)) == 0)
-
-#define atomic_add_unless(v, a, u)                             \
-({                                                             \
-       int c, old;                                             \
-       c = atomic_read(v);                                     \
-       while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
-               c = old;                                        \
-       c != (u);                                               \
-})
-
-#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
-
-static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
-{
-       unsigned long flags;
-
-       mask = ~mask;
-       local_irq_save(flags);
-       *addr &= mask;
-       local_irq_restore(flags);
-}
-
-#define atomic_xchg(ptr, v)            (xchg(&(ptr)->counter, (v)))
-#define atomic_cmpxchg(v, old, new)    (cmpxchg(&((v)->counter), (old), (new)))
-
-/* Atomic operations are already serializing on MN10300??? */
-#define smp_mb__before_atomic_dec()    barrier()
-#define smp_mb__after_atomic_dec()     barrier()
-#define smp_mb__before_atomic_inc()    barrier()
-#define smp_mb__after_atomic_inc()     barrier()
-
-#include <asm-generic/atomic-long.h>
-
-#endif /* __KERNEL__ */
-#endif /* _ASM_ATOMIC_H */
+#include <asm-generic/atomic.h>
index e03cfa2..6e2fe28 100644 (file)
@@ -21,6 +21,8 @@
 #define L1_CACHE_DISPARITY     L1_CACHE_NENTRIES * L1_CACHE_BYTES
 #endif
 
+#define ARCH_KMALLOC_MINALIGN  L1_CACHE_BYTES
+
 /* data cache purge registers
  * - read from the register to unconditionally purge that cache line
  * - write address & 0xffffff00 to conditionally purge that cache line
index 3a7a67a..8b8fab9 100644 (file)
 #define abort()                                                                \
        return 0
 
-#ifdef __BIG_ENDIAN
-#define __BYTE_ORDER __BIG_ENDIAN
-#else
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#endif
-
 /* Exception flags. */
 #define EFLAG_INVALID          (1 << (31 - 2))
 #define EFLAG_OVERFLOW         (1 << (31 - 3))
index 0addc64..7d43fee 100644 (file)
@@ -73,5 +73,3 @@ extern unsigned long __udiv_qrnnd (unsigned int *, unsigned int,
 #define UDIV_NEEDS_NORMALIZATION 0
 
 #define abort() return 0
-
-#define __BYTE_ORDER __BIG_ENDIAN
index 8ae1bd3..e852602 100644 (file)
@@ -66,7 +66,3 @@
   } while (0)
 
 #define abort()        return 0
-
-#define __BYTE_ORDER __LITTLE_ENDIAN
-
-
index d1b2aff..0ea35af 100644 (file)
 
 #define abort()                                                                \
        return 0
-
-#ifdef __BIG_ENDIAN
-#define __BYTE_ORDER __BIG_ENDIAN
-#else
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#endif
index 425d3cf..d17c9bc 100644 (file)
 
 #define abort() \
        return 0
-
-#ifdef __BIG_ENDIAN
-#define __BYTE_ORDER __BIG_ENDIAN
-#else
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#endif
index 89bbf4e..7b1aaa2 100644 (file)
@@ -195,11 +195,11 @@ static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
 
 
 
-#if BYTE_ORDER == LITTLE_ENDIAN
+#if __BYTE_ORDER == __LITTLE_ENDIAN
 #define le16_to_cpu(val) (val)
 #define le32_to_cpu(val) (val)
 #endif
-#if BYTE_ORDER == BIG_ENDIAN
+#if __BYTE_ORDER == __BIG_ENDIAN
 #define le16_to_cpu(val) bswap_16(val)
 #define le32_to_cpu(val) bswap_32(val)
 #endif
index f932485..b49d8ca 100644 (file)
 
 #define MSR_IA32_MISC_ENABLE           0x000001a0
 
+#define MSR_IA32_TEMPERATURE_TARGET    0x000001a2
+
 /* MISC_ENABLE bits: architectural */
 #define MSR_IA32_MISC_ENABLE_FAST_STRING       (1ULL << 0)
 #define MSR_IA32_MISC_ENABLE_TCC               (1ULL << 1)
index f04c989..ed8cd3c 100644 (file)
@@ -29,5 +29,6 @@
 # define CACHE_WAY_SIZE ICACHE_WAY_SIZE
 #endif
 
+#define ARCH_KMALLOC_MINALIGN  L1_CACHE_BYTES
 
 #endif /* _XTENSA_CACHE_H */
index 87cb19d..26664ce 100644 (file)
 #ifndef _XTENSA_HARDIRQ_H
 #define _XTENSA_HARDIRQ_H
 
-#include <linux/cache.h>
-#include <asm/irq.h>
-
-/* headers.S is sensitive to the offsets of these fields */
-typedef struct {
-       unsigned int __softirq_pending;
-       unsigned int __syscall_count;
-       struct task_struct * __ksoftirqd_task; /* waitqueue is too large */
-       unsigned int __nmi_count;              /* arch dependent */
-} ____cacheline_aligned irq_cpustat_t;
-
 void ack_bad_irq(unsigned int irq);
-#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+#define ack_bad_irq ack_bad_irq
+
+#include <asm-generic/hardirq.h>
 
 #endif /* _XTENSA_HARDIRQ_H */
index 8cd3848..c64a5d3 100644 (file)
@@ -26,15 +26,6 @@ static unsigned int cached_irq_mask;
 
 atomic_t irq_err_count;
 
-/*
- * 'what should we do if we get a hw irq event on an illegal vector'.
- * each architecture has to answer this themselves.
- */
-void ack_bad_irq(unsigned int irq)
-{
-          printk("unexpected IRQ trap at vector %02x\n", irq);
-}
-
 /*
  * do_IRQ handles all normal device IRQ's (the special
  * SMP cross-CPU interrupts have their own specific
index 74a7518..70066e3 100644 (file)
 
 #include <linux/linkage.h>
 #include <asm/ptrace.h>
-#include <asm/ptrace.h>
 #include <asm/current.h>
 #include <asm/asm-offsets.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/thread_info.h>
-#include <asm/processor.h>
 
 #define WINDOW_VECTORS_SIZE   0x180
 
index 9042a85..c1d23cd 100644 (file)
@@ -401,11 +401,6 @@ static void acpi_print_osc_error(acpi_handle handle,
        printk("\n");
 }
 
-static u8 hex_val(unsigned char c)
-{
-       return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10;
-}
-
 static acpi_status acpi_str_to_uuid(char *str, u8 *uuid)
 {
        int i;
@@ -422,8 +417,8 @@ static acpi_status acpi_str_to_uuid(char *str, u8 *uuid)
                        return AE_BAD_PARAMETER;
        }
        for (i = 0; i < 16; i++) {
-               uuid[i] = hex_val(str[opc_map_to_uuid[i]]) << 4;
-               uuid[i] |= hex_val(str[opc_map_to_uuid[i] + 1]);
+               uuid[i] = hex_to_bin(str[opc_map_to_uuid[i]]) << 4;
+               uuid[i] |= hex_to_bin(str[opc_map_to_uuid[i] + 1]);
        }
        return AE_OK;
 }
index 3fecfb4..5ad3bad 100644 (file)
@@ -37,7 +37,7 @@
 
 #define CFAG12864BFB_NAME "cfag12864bfb"
 
-static struct fb_fix_screeninfo cfag12864bfb_fix __initdata = {
+static struct fb_fix_screeninfo cfag12864bfb_fix __devinitdata = {
        .id = "cfag12864b",
        .type = FB_TYPE_PACKED_PIXELS,
        .visual = FB_VISUAL_MONO10,
@@ -48,7 +48,7 @@ static struct fb_fix_screeninfo cfag12864bfb_fix __initdata = {
        .accel = FB_ACCEL_NONE,
 };
 
-static struct fb_var_screeninfo cfag12864bfb_var __initdata = {
+static struct fb_var_screeninfo cfag12864bfb_var __devinitdata = {
        .xres = CFAG12864B_WIDTH,
        .yres = CFAG12864B_HEIGHT,
        .xres_virtual = CFAG12864B_WIDTH,
@@ -114,7 +114,7 @@ none:
        return ret;
 }
 
-static int cfag12864bfb_remove(struct platform_device *device)
+static int __devexit cfag12864bfb_remove(struct platform_device *device)
 {
        struct fb_info *info = platform_get_drvdata(device);
 
@@ -128,7 +128,7 @@ static int cfag12864bfb_remove(struct platform_device *device)
 
 static struct platform_driver cfag12864bfb_driver = {
        .probe  = cfag12864bfb_probe,
-       .remove = cfag12864bfb_remove,
+       .remove = __devexit_p(cfag12864bfb_remove),
        .driver = {
                .name   = CFAG12864BFB_NAME,
        },
index 057979a..2bdd8a9 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/memory.h>
 #include <linux/node.h>
 #include <linux/hugetlb.h>
+#include <linux/compaction.h>
 #include <linux/cpumask.h>
 #include <linux/topology.h>
 #include <linux/nodemask.h>
@@ -246,6 +247,8 @@ int register_node(struct node *node, int num, struct node *parent)
                scan_unevictable_register_node(node);
 
                hugetlb_register_node(node);
+
+               compaction_register_node(node);
        }
        return error;
 }
index 712d9f2..e024972 100644 (file)
@@ -49,8 +49,9 @@
 #include <asm/uaccess.h>
 #include <linux/sysrq.h>
 #include <linux/timer.h>
+#include <linux/time.h>
 
-#define VERSION_STR "0.9.0"
+#define VERSION_STR "0.9.1"
 
 #define DEFAULT_IOFENCE_MARGIN 60      /* Default fudge factor, in seconds */
 #define DEFAULT_IOFENCE_TICK 180       /* Default timer timeout, in seconds */
@@ -119,10 +120,8 @@ __setup("hcheck_dump_tasks", hangcheck_parse_dump_tasks);
 #if defined(CONFIG_S390)
 # define HAVE_MONOTONIC
 # define TIMER_FREQ 1000000000ULL
-#elif defined(CONFIG_IA64)
-# define TIMER_FREQ ((unsigned long long)local_cpu_data->itc_freq)
 #else
-# define TIMER_FREQ (HZ*loops_per_jiffy)
+# define TIMER_FREQ 1000000000ULL
 #endif
 
 #ifdef HAVE_MONOTONIC
@@ -130,7 +129,9 @@ extern unsigned long long monotonic_clock(void);
 #else
 static inline unsigned long long monotonic_clock(void)
 {
-       return get_cycles();
+       struct timespec ts;
+       getrawmonotonic(&ts);
+       return timespec_to_ns(&ts);
 }
 #endif  /* HAVE_MONOTONIC */
 
@@ -168,6 +169,13 @@ static void hangcheck_fire(unsigned long data)
                        printk(KERN_CRIT "Hangcheck: hangcheck value past margin!\n");
                }
        }
+#if 0
+       /*
+        * Enable to investigate delays in detail
+        */
+       printk("Hangcheck: called %Ld ns since last time (%Ld ns overshoot)\n",
+                       tsc_diff, tsc_diff - hangcheck_tick*TIMER_FREQ);
+#endif
        mod_timer(&hangcheck_ticktock, jiffies + (hangcheck_tick*HZ));
        hangcheck_tsc = monotonic_clock();
 }
@@ -180,7 +188,7 @@ static int __init hangcheck_init(void)
 #if defined (HAVE_MONOTONIC)
        printk("Hangcheck: Using monotonic_clock().\n");
 #else
-       printk("Hangcheck: Using get_cycles().\n");
+       printk("Hangcheck: Using getrawmonotonic().\n");
 #endif  /* HAVE_MONOTONIC */
        hangcheck_tsc_margin =
                (unsigned long long)(hangcheck_margin + hangcheck_tick);
index 793b236..d4b14ff 100644 (file)
@@ -194,10 +194,8 @@ static inline void print_state(struct hvsi_struct *hp)
                "HVSI_WAIT_FOR_MCTRL_RESPONSE",
                "HVSI_FSP_DIED",
        };
-       const char *name = state_names[hp->state];
-
-       if (hp->state > ARRAY_SIZE(state_names))
-               name = "UNKNOWN";
+       const char *name = (hp->state < ARRAY_SIZE(state_names))
+               ? state_names[hp->state] : "UNKNOWN";
 
        pr_debug("hvsi%i: state = %s\n", hp->index, name);
 #endif /* DEBUG */
index 92ab03d..cd650ca 100644 (file)
@@ -144,6 +144,7 @@ static int misc_open(struct inode * inode, struct file * file)
        old_fops = file->f_op;
        file->f_op = new_fops;
        if (file->f_op->open) {
+               file->private_data = c;
                err=file->f_op->open(inode,file);
                if (err) {
                        fops_put(file->f_op);
index b81ad9c..52ff8aa 100644 (file)
 #include <linux/math64.h>
 
 #define BUCKETS 12
+#define INTERVALS 8
 #define RESOLUTION 1024
-#define DECAY 4
+#define DECAY 8
 #define MAX_INTERESTING 50000
+#define STDDEV_THRESH 400
+
 
 /*
  * Concepts and ideas behind the menu governor
  * indexed based on the magnitude of the expected duration as well as the
  * "is IO outstanding" property.
  *
+ * Repeatable-interval-detector
+ * ----------------------------
+ * There are some cases where "next timer" is a completely unusable predictor:
+ * Those cases where the interval is fixed, for example due to hardware
+ * interrupt mitigation, but also due to fixed transfer rate devices such as
+ * mice.
+ * For this, we use a different predictor: We track the duration of the last 8
+ * intervals and if the stand deviation of these 8 intervals is below a
+ * threshold value, we use the average of these intervals as prediction.
+ *
  * Limiting Performance Impact
  * ---------------------------
  * C states, especially those with large exit latencies, can have a real
@@ -104,6 +117,8 @@ struct menu_device {
        unsigned int    exit_us;
        unsigned int    bucket;
        u64             correction_factor[BUCKETS];
+       u32             intervals[INTERVALS];
+       int             interval_ptr;
 };
 
 
@@ -175,6 +190,42 @@ static u64 div_round64(u64 dividend, u32 divisor)
        return div_u64(dividend + (divisor / 2), divisor);
 }
 
+/*
+ * Try detecting repeating patterns by keeping track of the last 8
+ * intervals, and checking if the standard deviation of that set
+ * of points is below a threshold. If it is... then use the
+ * average of these 8 points as the estimated value.
+ */
+static void detect_repeating_patterns(struct menu_device *data)
+{
+       int i;
+       uint64_t avg = 0;
+       uint64_t stddev = 0; /* contains the square of the std deviation */
+
+       /* first calculate average and standard deviation of the past */
+       for (i = 0; i < INTERVALS; i++)
+               avg += data->intervals[i];
+       avg = avg / INTERVALS;
+
+       /* if the avg is beyond the known next tick, it's worthless */
+       if (avg > data->expected_us)
+               return;
+
+       for (i = 0; i < INTERVALS; i++)
+               stddev += (data->intervals[i] - avg) *
+                         (data->intervals[i] - avg);
+
+       stddev = stddev / INTERVALS;
+
+       /*
+        * now.. if stddev is small.. then assume we have a
+        * repeating pattern and predict we keep doing this.
+        */
+
+       if (avg && stddev < STDDEV_THRESH)
+               data->predicted_us = avg;
+}
+
 /**
  * menu_select - selects the next idle state to enter
  * @dev: the CPU
@@ -218,6 +269,8 @@ static int menu_select(struct cpuidle_device *dev)
        data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket],
                                         RESOLUTION * DECAY);
 
+       detect_repeating_patterns(data);
+
        /*
         * We want to default to C1 (hlt), not to busy polling
         * unless the timer is happening really really soon.
@@ -310,6 +363,11 @@ static void menu_update(struct cpuidle_device *dev)
                new_factor = 1;
 
        data->correction_factor[data->bucket] = new_factor;
+
+       /* update the repeating-pattern data */
+       data->intervals[data->interval_ptr++] = last_idle_us;
+       if (data->interval_ptr >= INTERVALS)
+               data->interval_ptr = 0;
 }
 
 /**
index 0172fa3..a1bf77c 100644 (file)
@@ -188,7 +188,7 @@ static void __td_unmap_descs(struct timb_dma_desc *td_desc, bool single)
 static int td_fill_desc(struct timb_dma_chan *td_chan, u8 *dma_desc,
        struct scatterlist *sg, bool last)
 {
-       if (sg_dma_len(sg) > USHORT_MAX) {
+       if (sg_dma_len(sg) > USHRT_MAX) {
                dev_err(chan2dev(&td_chan->chan), "Too big sg element\n");
                return -EINVAL;
        }
index 9be8e17..6a9ac75 100644 (file)
@@ -802,6 +802,15 @@ config SENSORS_ADS7828
          This driver can also be built as a module.  If so, the module
          will be called ads7828.
 
+config SENSORS_ADS7871
+       tristate "Texas Instruments ADS7871 A/D converter"
+       depends on SPI
+       help
+         If you say yes here you get support for TI ADS7871 & ADS7870
+
+         This driver can also be built as a module.  If so, the module
+         will be called ads7871.
+
 config SENSORS_AMC6821
        tristate "Texas Instruments AMC6821"
        depends on I2C  && EXPERIMENTAL
index 4aa1a3d..86920fb 100644 (file)
@@ -29,6 +29,7 @@ obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o
 obj-$(CONFIG_SENSORS_ADM1031)  += adm1031.o
 obj-$(CONFIG_SENSORS_ADM9240)  += adm9240.o
 obj-$(CONFIG_SENSORS_ADS7828)  += ads7828.o
+obj-$(CONFIG_SENSORS_ADS7871)  += ads7871.o
 obj-$(CONFIG_SENSORS_ADT7411)  += adt7411.o
 obj-$(CONFIG_SENSORS_ADT7462)  += adt7462.o
 obj-$(CONFIG_SENSORS_ADT7470)  += adt7470.o
diff --git a/drivers/hwmon/ads7871.c b/drivers/hwmon/ads7871.c
new file mode 100644 (file)
index 0000000..b300a20
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ *  ads7871 - driver for TI ADS7871 A/D converter
+ *
+ *  Copyright (c) 2010 Paul Thomas <pthomas8589@gmail.com>
+ *
+ *  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.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 or
+ *  later as publishhed by the Free Software Foundation.
+ *
+ *     You need to have something like this in struct spi_board_info
+ *     {
+ *             .modalias       = "ads7871",
+ *             .max_speed_hz   = 2*1000*1000,
+ *             .chip_select    = 0,
+ *             .bus_num        = 1,
+ *     },
+ */
+
+/*From figure 18 in the datasheet*/
+/*Register addresses*/
+#define REG_LS_BYTE    0 /*A/D Output Data, LS Byte*/
+#define REG_MS_BYTE    1 /*A/D Output Data, MS Byte*/
+#define REG_PGA_VALID  2 /*PGA Valid Register*/
+#define REG_AD_CONTROL 3 /*A/D Control Register*/
+#define REG_GAIN_MUX   4 /*Gain/Mux Register*/
+#define REG_IO_STATE   5 /*Digital I/O State Register*/
+#define REG_IO_CONTROL 6 /*Digital I/O Control Register*/
+#define REG_OSC_CONTROL        7 /*Rev/Oscillator Control Register*/
+#define REG_SER_CONTROL 24 /*Serial Interface Control Register*/
+#define REG_ID         31 /*ID Register*/
+
+/*From figure 17 in the datasheet
+* These bits get ORed with the address to form
+* the instruction byte */
+/*Instruction Bit masks*/
+#define INST_MODE_bm   (1<<7)
+#define INST_READ_bm   (1<<6)
+#define INST_16BIT_bm  (1<<5)
+
+/*From figure 18 in the datasheet*/
+/*bit masks for Rev/Oscillator Control Register*/
+#define MUX_CNV_bv     7
+#define MUX_CNV_bm     (1<<MUX_CNV_bv)
+#define MUX_M3_bm      (1<<3) /*M3 selects single ended*/
+#define MUX_G_bv       4 /*allows for reg = (gain << MUX_G_bv) | ...*/
+
+/*From figure 18 in the datasheet*/
+/*bit masks for Rev/Oscillator Control Register*/
+#define OSC_OSCR_bm    (1<<5)
+#define OSC_OSCE_bm    (1<<4)
+#define OSC_REFE_bm    (1<<3)
+#define OSC_BUFE_bm    (1<<2)
+#define OSC_R2V_bm     (1<<1)
+#define OSC_RBG_bm     (1<<0)
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spi/spi.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+#define DEVICE_NAME    "ads7871"
+
+struct ads7871_data {
+       struct device   *hwmon_dev;
+       struct mutex    update_lock;
+};
+
+static int ads7871_read_reg8(struct spi_device *spi, int reg)
+{
+       int ret;
+       reg = reg | INST_READ_bm;
+       ret = spi_w8r8(spi, reg);
+       return ret;
+}
+
+static int ads7871_read_reg16(struct spi_device *spi, int reg)
+{
+       int ret;
+       reg = reg | INST_READ_bm | INST_16BIT_bm;
+       ret = spi_w8r16(spi, reg);
+       return ret;
+}
+
+static int ads7871_write_reg8(struct spi_device *spi, int reg, u8 val)
+{
+       u8 tmp[2] = {reg, val};
+       return spi_write(spi, tmp, sizeof(tmp));
+}
+
+static ssize_t show_voltage(struct device *dev,
+               struct device_attribute *da, char *buf)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int ret, val, i = 0;
+       uint8_t channel, mux_cnv;
+
+       channel = attr->index;
+       /*TODO: add support for conversions
+        *other than single ended with a gain of 1*/
+       /*MUX_M3_bm forces single ended*/
+       /*This is also where the gain of the PGA would be set*/
+       ads7871_write_reg8(spi, REG_GAIN_MUX,
+               (MUX_CNV_bm | MUX_M3_bm | channel));
+
+       ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
+       mux_cnv = ((ret & MUX_CNV_bm)>>MUX_CNV_bv);
+       /*on 400MHz arm9 platform the conversion
+        *is already done when we do this test*/
+       while ((i < 2) && mux_cnv) {
+               i++;
+               ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
+               mux_cnv = ((ret & MUX_CNV_bm)>>MUX_CNV_bv);
+               msleep_interruptible(1);
+       }
+
+       if (mux_cnv == 0) {
+               val = ads7871_read_reg16(spi, REG_LS_BYTE);
+               /*result in volts*10000 = (val/8192)*2.5*10000*/
+               val = ((val>>2) * 25000) / 8192;
+               return sprintf(buf, "%d\n", val);
+       } else {
+               return -1;
+       }
+}
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_voltage, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_voltage, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_voltage, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_voltage, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_voltage, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_voltage, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_voltage, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_voltage, NULL, 7);
+
+static struct attribute *ads7871_attributes[] = {
+       &sensor_dev_attr_in0_input.dev_attr.attr,
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in3_input.dev_attr.attr,
+       &sensor_dev_attr_in4_input.dev_attr.attr,
+       &sensor_dev_attr_in5_input.dev_attr.attr,
+       &sensor_dev_attr_in6_input.dev_attr.attr,
+       &sensor_dev_attr_in7_input.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group ads7871_group = {
+       .attrs = ads7871_attributes,
+};
+
+static int __devinit ads7871_probe(struct spi_device *spi)
+{
+       int status, ret, err = 0;
+       uint8_t val;
+       struct ads7871_data *pdata;
+
+       dev_dbg(&spi->dev, "probe\n");
+
+       pdata = kzalloc(sizeof(struct ads7871_data), GFP_KERNEL);
+       if (!pdata) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       status = sysfs_create_group(&spi->dev.kobj, &ads7871_group);
+       if (status < 0)
+               goto error_free;
+
+       pdata->hwmon_dev = hwmon_device_register(&spi->dev);
+       if (IS_ERR(pdata->hwmon_dev)) {
+               err = PTR_ERR(pdata->hwmon_dev);
+               goto error_remove;
+       }
+
+       spi_set_drvdata(spi, pdata);
+
+       /* Configure the SPI bus */
+       spi->mode = (SPI_MODE_0);
+       spi->bits_per_word = 8;
+       spi_setup(spi);
+
+       ads7871_write_reg8(spi, REG_SER_CONTROL, 0);
+       ads7871_write_reg8(spi, REG_AD_CONTROL, 0);
+
+       val = (OSC_OSCR_bm | OSC_OSCE_bm | OSC_REFE_bm | OSC_BUFE_bm);
+       ads7871_write_reg8(spi, REG_OSC_CONTROL, val);
+       ret = ads7871_read_reg8(spi, REG_OSC_CONTROL);
+
+       dev_dbg(&spi->dev, "REG_OSC_CONTROL write:%x, read:%x\n", val, ret);
+       /*because there is no other error checking on an SPI bus
+       we need to make sure we really have a chip*/
+       if (val != ret) {
+               err = -ENODEV;
+               goto error_remove;
+       }
+
+       return 0;
+
+error_remove:
+       sysfs_remove_group(&spi->dev.kobj, &ads7871_group);
+error_free:
+       kfree(pdata);
+exit:
+       return err;
+}
+
+static int __devexit ads7871_remove(struct spi_device *spi)
+{
+       struct ads7871_data *pdata = spi_get_drvdata(spi);
+
+       hwmon_device_unregister(pdata->hwmon_dev);
+       sysfs_remove_group(&spi->dev.kobj, &ads7871_group);
+       kfree(pdata);
+       return 0;
+}
+
+static struct spi_driver ads7871_driver = {
+       .driver = {
+               .name = DEVICE_NAME,
+               .bus = &spi_bus_type,
+               .owner = THIS_MODULE,
+       },
+
+       .probe = ads7871_probe,
+       .remove = __devexit_p(ads7871_remove),
+};
+
+static int __init ads7871_init(void)
+{
+       return spi_register_driver(&ads7871_driver);
+}
+
+static void __exit ads7871_exit(void)
+{
+       spi_unregister_driver(&ads7871_driver);
+}
+
+module_init(ads7871_init);
+module_exit(ads7871_exit);
+
+MODULE_AUTHOR("Paul Thomas <pthomas8589@gmail.com>");
+MODULE_DESCRIPTION("TI ADS7871 A/D driver");
+MODULE_LICENSE("GPL");
index e9b7fbc..2988da1 100644 (file)
@@ -241,6 +241,55 @@ static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *
        return tjmax;
 }
 
+static int __devinit get_tjmax(struct cpuinfo_x86 *c, u32 id,
+                              struct device *dev)
+{
+       /* The 100C is default for both mobile and non mobile CPUs */
+       int err;
+       u32 eax, edx;
+       u32 val;
+
+       /* A new feature of current Intel(R) processors, the
+          IA32_TEMPERATURE_TARGET contains the TjMax value */
+       err = rdmsr_safe_on_cpu(id, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
+       if (err) {
+               dev_warn(dev, "Unable to read TjMax from CPU.\n");
+       } else {
+               val = (eax >> 16) & 0xff;
+               /*
+                * If the TjMax is not plausible, an assumption
+                * will be used
+                */
+               if ((val > 80) && (val < 120)) {
+                       dev_info(dev, "TjMax is %d C.\n", val);
+                       return val * 1000;
+               }
+       }
+
+       /*
+        * An assumption is made for early CPUs and unreadable MSR.
+        * NOTE: the given value may not be correct.
+        */
+
+       switch (c->x86_model) {
+       case 0xe:
+       case 0xf:
+       case 0x16:
+       case 0x1a:
+               dev_warn(dev, "TjMax is assumed as 100 C!\n");
+               return 100000;
+               break;
+       case 0x17:
+       case 0x1c:              /* Atom CPUs */
+               return adjust_tjmax(c, id, dev);
+               break;
+       default:
+               dev_warn(dev, "CPU (model=0x%x) is not supported yet,"
+                       " using default TjMax of 100C.\n", c->x86_model);
+               return 100000;
+       }
+}
+
 static int __devinit coretemp_probe(struct platform_device *pdev)
 {
        struct coretemp_data *data;
@@ -283,14 +332,18 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
                }
        }
 
-       data->tjmax = adjust_tjmax(c, data->id, &pdev->dev);
+       data->tjmax = get_tjmax(c, data->id, &pdev->dev);
        platform_set_drvdata(pdev, data);
 
-       /* read the still undocumented IA32_TEMPERATURE_TARGET it exists
-          on older CPUs but not in this register, Atoms don't have it either */
+       /*
+        * read the still undocumented IA32_TEMPERATURE_TARGET. It exists
+        * on older CPUs but not in this register,
+        * Atoms don't have it either.
+        */
 
        if ((c->x86_model > 0xe) && (c->x86_model != 0x1c)) {
-               err = rdmsr_safe_on_cpu(data->id, 0x1a2, &eax, &edx);
+               err = rdmsr_safe_on_cpu(data->id, MSR_IA32_TEMPERATURE_TARGET,
+                   &eax, &edx);
                if (err) {
                        dev_warn(&pdev->dev, "Unable to read"
                                        " IA32_TEMPERATURE_TARGET MSR\n");
@@ -451,28 +504,20 @@ static int __init coretemp_init(void)
 
        for_each_online_cpu(i) {
                struct cpuinfo_x86 *c = &cpu_data(i);
+               /*
+                * CPUID.06H.EAX[0] indicates whether the CPU has thermal
+                * sensors. We check this bit only, all the early CPUs
+                * without thermal sensors will be filtered out.
+                */
+               if (c->cpuid_level >= 6 && (cpuid_eax(0x06) & 0x01)) {
+                       err = coretemp_device_add(i);
+                       if (err)
+                               goto exit_devices_unreg;
 
-               /* check if family 6, models 0xe (Pentium M DC),
-                 0xf (Core 2 DC 65nm), 0x16 (Core 2 SC 65nm),
-                 0x17 (Penryn 45nm), 0x1a (Nehalem), 0x1c (Atom),
-                 0x1e (Lynnfield) */
-               if ((c->cpuid_level < 0) || (c->x86 != 0x6) ||
-                   !((c->x86_model == 0xe) || (c->x86_model == 0xf) ||
-                       (c->x86_model == 0x16) || (c->x86_model == 0x17) ||
-                       (c->x86_model == 0x1a) || (c->x86_model == 0x1c) ||
-                       (c->x86_model == 0x1e))) {
-
-                       /* supported CPU not found, but report the unknown
-                          family 6 CPU */
-                       if ((c->x86 == 0x6) && (c->x86_model > 0xf))
-                               printk(KERN_WARNING DRVNAME ": Unknown CPU "
-                                       "model 0x%x\n", c->x86_model);
-                       continue;
+               } else {
+                       printk(KERN_INFO DRVNAME ": CPU (model=0x%x)"
+                               " has no thermal sensor.\n", c->x86_model);
                }
-
-               err = coretemp_device_add(i);
-               if (err)
-                       goto exit_devices_unreg;
        }
        if (list_empty(&pdev_list)) {
                err = -ENODEV;
index b2f2277..6138f03 100644 (file)
@@ -41,6 +41,8 @@
 
 /* joystick device poll interval in milliseconds */
 #define MDPS_POLL_INTERVAL 50
+#define MDPS_POLL_MIN     0
+#define MDPS_POLL_MAX     2000
 /*
  * The sensor can also generate interrupts (DRDY) but it's pretty pointless
  * because they are generated even if the data do not change. So it's better
@@ -121,11 +123,9 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
        int position[3];
        int i;
 
-       mutex_lock(&lis3->mutex);
        position[0] = lis3->read_data(lis3, OUTX);
        position[1] = lis3->read_data(lis3, OUTY);
        position[2] = lis3->read_data(lis3, OUTZ);
-       mutex_unlock(&lis3->mutex);
 
        for (i = 0; i < 3; i++)
                position[i] = (position[i] * lis3->scale) / LIS3_ACCURACY;
@@ -249,8 +249,24 @@ void lis3lv02d_poweron(struct lis3lv02d *lis3)
 EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
 
 
+static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev)
+{
+       int x, y, z;
+
+       mutex_lock(&lis3_dev.mutex);
+       lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
+       input_report_abs(pidev->input, ABS_X, x);
+       input_report_abs(pidev->input, ABS_Y, y);
+       input_report_abs(pidev->input, ABS_Z, z);
+       input_sync(pidev->input);
+       mutex_unlock(&lis3_dev.mutex);
+}
+
 static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
 {
+       if (!test_bit(0, &lis3_dev.misc_opened))
+               goto out;
+
        /*
         * Be careful: on some HP laptops the bios force DD when on battery and
         * the lid is closed. This leads to interrupts as soon as a little move
@@ -260,44 +276,93 @@ static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
 
        wake_up_interruptible(&lis3_dev.misc_wait);
        kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN);
+out:
+       if (lis3_dev.whoami == WAI_8B && lis3_dev.idev &&
+           lis3_dev.idev->input->users)
+               return IRQ_WAKE_THREAD;
        return IRQ_HANDLED;
 }
 
-static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
+static void lis302dl_interrupt_handle_click(struct lis3lv02d *lis3)
 {
-       int ret;
+       struct input_dev *dev = lis3->idev->input;
+       u8 click_src;
 
-       if (test_and_set_bit(0, &lis3_dev.misc_opened))
-               return -EBUSY; /* already open */
+       mutex_lock(&lis3->mutex);
+       lis3->read(lis3, CLICK_SRC, &click_src);
 
-       atomic_set(&lis3_dev.count, 0);
+       if (click_src & CLICK_SINGLE_X) {
+               input_report_key(dev, lis3->mapped_btns[0], 1);
+               input_report_key(dev, lis3->mapped_btns[0], 0);
+       }
 
-       /*
-        * The sensor can generate interrupts for free-fall and direction
-        * detection (distinguishable with FF_WU_SRC and DD_SRC) but to keep
-        * the things simple and _fast_ we activate it only for free-fall, so
-        * no need to read register (very slow with ACPI). For the same reason,
-        * we forbid shared interrupts.
-        *
-        * IRQF_TRIGGER_RISING seems pointless on HP laptops because the
-        * io-apic is not configurable (and generates a warning) but I keep it
-        * in case of support for other hardware.
-        */
-       ret = request_irq(lis3_dev.irq, lis302dl_interrupt, IRQF_TRIGGER_RISING,
-                         DRIVER_NAME, &lis3_dev);
+       if (click_src & CLICK_SINGLE_Y) {
+               input_report_key(dev, lis3->mapped_btns[1], 1);
+               input_report_key(dev, lis3->mapped_btns[1], 0);
+       }
 
-       if (ret) {
-               clear_bit(0, &lis3_dev.misc_opened);
-               printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", lis3_dev.irq);
-               return -EBUSY;
+       if (click_src & CLICK_SINGLE_Z) {
+               input_report_key(dev, lis3->mapped_btns[2], 1);
+               input_report_key(dev, lis3->mapped_btns[2], 0);
        }
+       input_sync(dev);
+       mutex_unlock(&lis3->mutex);
+}
+
+static void lis302dl_interrupt_handle_ff_wu(struct lis3lv02d *lis3)
+{
+       u8 wu1_src;
+       u8 wu2_src;
+
+       lis3->read(lis3, FF_WU_SRC_1, &wu1_src);
+       lis3->read(lis3, FF_WU_SRC_2, &wu2_src);
+
+       wu1_src = wu1_src & FF_WU_SRC_IA ? wu1_src : 0;
+       wu2_src = wu2_src & FF_WU_SRC_IA ? wu2_src : 0;
+
+       /* joystick poll is internally protected by the lis3->mutex. */
+       if (wu1_src || wu2_src)
+               lis3lv02d_joystick_poll(lis3_dev.idev);
+}
+
+static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data)
+{
+
+       struct lis3lv02d *lis3 = data;
+
+       if ((lis3->pdata->irq_cfg & LIS3_IRQ1_MASK) == LIS3_IRQ1_CLICK)
+               lis302dl_interrupt_handle_click(lis3);
+       else
+               lis302dl_interrupt_handle_ff_wu(lis3);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data)
+{
+
+       struct lis3lv02d *lis3 = data;
+
+       if ((lis3->pdata->irq_cfg & LIS3_IRQ2_MASK) == LIS3_IRQ2_CLICK)
+               lis302dl_interrupt_handle_click(lis3);
+       else
+               lis302dl_interrupt_handle_ff_wu(lis3);
+
+       return IRQ_HANDLED;
+}
+
+static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(0, &lis3_dev.misc_opened))
+               return -EBUSY; /* already open */
+
+       atomic_set(&lis3_dev.count, 0);
        return 0;
 }
 
 static int lis3lv02d_misc_release(struct inode *inode, struct file *file)
 {
        fasync_helper(-1, file, 0, &lis3_dev.async_queue);
-       free_irq(lis3_dev.irq, &lis3_dev);
        clear_bit(0, &lis3_dev.misc_opened); /* release the device */
        return 0;
 }
@@ -380,22 +445,12 @@ static struct miscdevice lis3lv02d_misc_device = {
        .fops    = &lis3lv02d_misc_fops,
 };
 
-static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev)
-{
-       int x, y, z;
-
-       lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
-       input_report_abs(pidev->input, ABS_X, x);
-       input_report_abs(pidev->input, ABS_Y, y);
-       input_report_abs(pidev->input, ABS_Z, z);
-       input_sync(pidev->input);
-}
-
 int lis3lv02d_joystick_enable(void)
 {
        struct input_dev *input_dev;
        int err;
        int max_val, fuzz, flat;
+       int btns[] = {BTN_X, BTN_Y, BTN_Z};
 
        if (lis3_dev.idev)
                return -EINVAL;
@@ -406,6 +461,8 @@ int lis3lv02d_joystick_enable(void)
 
        lis3_dev.idev->poll = lis3lv02d_joystick_poll;
        lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL;
+       lis3_dev.idev->poll_interval_min = MDPS_POLL_MIN;
+       lis3_dev.idev->poll_interval_max = MDPS_POLL_MAX;
        input_dev = lis3_dev.idev->input;
 
        input_dev->name       = "ST LIS3LV02DL Accelerometer";
@@ -422,6 +479,10 @@ int lis3lv02d_joystick_enable(void)
        input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat);
        input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat);
 
+       lis3_dev.mapped_btns[0] = lis3lv02d_get_axis(abs(lis3_dev.ac.x), btns);
+       lis3_dev.mapped_btns[1] = lis3lv02d_get_axis(abs(lis3_dev.ac.y), btns);
+       lis3_dev.mapped_btns[2] = lis3lv02d_get_axis(abs(lis3_dev.ac.z), btns);
+
        err = input_register_polled_device(lis3_dev.idev);
        if (err) {
                input_free_polled_device(lis3_dev.idev);
@@ -434,6 +495,11 @@ EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable);
 
 void lis3lv02d_joystick_disable(void)
 {
+       if (lis3_dev.irq)
+               free_irq(lis3_dev.irq, &lis3_dev);
+       if (lis3_dev.pdata && lis3_dev.pdata->irq2)
+               free_irq(lis3_dev.pdata->irq2, &lis3_dev);
+
        if (!lis3_dev.idev)
                return;
 
@@ -462,7 +528,9 @@ static ssize_t lis3lv02d_position_show(struct device *dev,
 {
        int x, y, z;
 
+       mutex_lock(&lis3_dev.mutex);
        lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
+       mutex_unlock(&lis3_dev.mutex);
        return sprintf(buf, "(%d,%d,%d)\n", x, y, z);
 }
 
@@ -521,12 +589,70 @@ int lis3lv02d_remove_fs(struct lis3lv02d *lis3)
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs);
 
+static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
+                               struct lis3lv02d_platform_data *p)
+{
+       int err;
+       int ctrl2 = p->hipass_ctrl;
+
+       if (p->click_flags) {
+               dev->write(dev, CLICK_CFG, p->click_flags);
+               dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit);
+               dev->write(dev, CLICK_LATENCY, p->click_latency);
+               dev->write(dev, CLICK_WINDOW, p->click_window);
+               dev->write(dev, CLICK_THSZ, p->click_thresh_z & 0xf);
+               dev->write(dev, CLICK_THSY_X,
+                       (p->click_thresh_x & 0xf) |
+                       (p->click_thresh_y << 4));
+
+               if (dev->idev) {
+                       struct input_dev *input_dev = lis3_dev.idev->input;
+                       input_set_capability(input_dev, EV_KEY, BTN_X);
+                       input_set_capability(input_dev, EV_KEY, BTN_Y);
+                       input_set_capability(input_dev, EV_KEY, BTN_Z);
+               }
+       }
+
+       if (p->wakeup_flags) {
+               dev->write(dev, FF_WU_CFG_1, p->wakeup_flags);
+               dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f);
+               /* default to 2.5ms for now */
+               dev->write(dev, FF_WU_DURATION_1, 1);
+               ctrl2 ^= HP_FF_WU1; /* Xor to keep compatible with old pdata*/
+       }
+
+       if (p->wakeup_flags2) {
+               dev->write(dev, FF_WU_CFG_2, p->wakeup_flags2);
+               dev->write(dev, FF_WU_THS_2, p->wakeup_thresh2 & 0x7f);
+               /* default to 2.5ms for now */
+               dev->write(dev, FF_WU_DURATION_2, 1);
+               ctrl2 ^= HP_FF_WU2; /* Xor to keep compatible with old pdata*/
+       }
+       /* Configure hipass filters */
+       dev->write(dev, CTRL_REG2, ctrl2);
+
+       if (p->irq2) {
+               err = request_threaded_irq(p->irq2,
+                                       NULL,
+                                       lis302dl_interrupt_thread2_8b,
+                                       IRQF_TRIGGER_RISING |
+                                       IRQF_ONESHOT,
+                                       DRIVER_NAME, &lis3_dev);
+               if (err < 0)
+                       printk(KERN_ERR DRIVER_NAME
+                               "No second IRQ. Limited functionality\n");
+       }
+}
+
 /*
  * Initialise the accelerometer and the various subsystems.
  * Should be rather independent of the bus system.
  */
 int lis3lv02d_init_device(struct lis3lv02d *dev)
 {
+       int err;
+       irq_handler_t thread_fn;
+
        dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I);
 
        switch (dev->whoami) {
@@ -567,25 +693,8 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
        if (dev->pdata) {
                struct lis3lv02d_platform_data *p = dev->pdata;
 
-               if (p->click_flags && (dev->whoami == WAI_8B)) {
-                       dev->write(dev, CLICK_CFG, p->click_flags);
-                       dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit);
-                       dev->write(dev, CLICK_LATENCY, p->click_latency);
-                       dev->write(dev, CLICK_WINDOW, p->click_window);
-                       dev->write(dev, CLICK_THSZ, p->click_thresh_z & 0xf);
-                       dev->write(dev, CLICK_THSY_X,
-                                       (p->click_thresh_x & 0xf) |
-                                       (p->click_thresh_y << 4));
-               }
-
-               if (p->wakeup_flags && (dev->whoami == WAI_8B)) {
-                       dev->write(dev, FF_WU_CFG_1, p->wakeup_flags);
-                       dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f);
-                       /* default to 2.5ms for now */
-                       dev->write(dev, FF_WU_DURATION_1, 1);
-                       /* enable high pass filter for both free-fall units */
-                       dev->write(dev, CTRL_REG2, HP_FF_WU1 | HP_FF_WU2);
-               }
+               if (dev->whoami == WAI_8B)
+                       lis3lv02d_8b_configure(dev, p);
 
                if (p->irq_cfg)
                        dev->write(dev, CTRL_REG3, p->irq_cfg);
@@ -598,6 +707,32 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
                goto out;
        }
 
+       /*
+        * The sensor can generate interrupts for free-fall and direction
+        * detection (distinguishable with FF_WU_SRC and DD_SRC) but to keep
+        * the things simple and _fast_ we activate it only for free-fall, so
+        * no need to read register (very slow with ACPI). For the same reason,
+        * we forbid shared interrupts.
+        *
+        * IRQF_TRIGGER_RISING seems pointless on HP laptops because the
+        * io-apic is not configurable (and generates a warning) but I keep it
+        * in case of support for other hardware.
+        */
+       if (dev->whoami == WAI_8B)
+               thread_fn = lis302dl_interrupt_thread1_8b;
+       else
+               thread_fn = NULL;
+
+       err = request_threaded_irq(dev->irq, lis302dl_interrupt,
+                               thread_fn,
+                               IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                               DRIVER_NAME, &lis3_dev);
+
+       if (err < 0) {
+               printk(KERN_ERR DRIVER_NAME "Cannot get IRQ\n");
+               goto out;
+       }
+
        if (misc_register(&lis3lv02d_misc_device))
                printk(KERN_ERR DRIVER_NAME ": misc_register failed\n");
 out:
index e6a01f4..8540913 100644 (file)
@@ -196,6 +196,16 @@ enum lis3lv02d_dd_src {
        DD_SRC_IA       = 0x40,
 };
 
+enum lis3lv02d_click_src_8b {
+       CLICK_SINGLE_X  = 0x01,
+       CLICK_DOUBLE_X  = 0x02,
+       CLICK_SINGLE_Y  = 0x04,
+       CLICK_DOUBLE_Y  = 0x08,
+       CLICK_SINGLE_Z  = 0x10,
+       CLICK_DOUBLE_Z  = 0x20,
+       CLICK_IA        = 0x40,
+};
+
 struct axis_conversion {
        s8      x;
        s8      y;
@@ -223,6 +233,7 @@ struct lis3lv02d {
        struct platform_device  *pdev;     /* platform device */
        atomic_t                count;     /* interrupt count after last read */
        struct axis_conversion  ac;        /* hw -> logical axis */
+       int                     mapped_btns[3];
 
        u32                     irq;       /* IRQ number */
        struct fasync_struct    *async_queue; /* queue for the misc device */
index 964a55f..ac4cfee 100644 (file)
@@ -169,17 +169,6 @@ static inline void ignore_cstruct_param(struct cardstate *cs, _cstruct param,
                         msgname, paramname);
 }
 
-/*
- * convert hex to binary
- */
-static inline u8 hex2bin(char c)
-{
-       int result = c & 0x0f;
-       if (c & 0x40)
-               result += 9;
-       return result;
-}
-
 /*
  * convert an IE from Gigaset hex string to ETSI binary representation
  * including length byte
@@ -191,7 +180,7 @@ static int encode_ie(char *in, u8 *out, int maxlen)
        while (*in) {
                if (!isxdigit(in[0]) || !isxdigit(in[1]) || l >= maxlen)
                        return -1;
-               out[++l] = (hex2bin(in[0]) << 4) + hex2bin(in[1]);
+               out[++l] = (hex_to_bin(in[0]) << 4) + hex_to_bin(in[1]);
                in += 2;
        }
        out[0] = l;
index 0d0d625..26386a9 100644 (file)
@@ -14,11 +14,17 @@ menuconfig MISC_DEVICES
 if MISC_DEVICES
 
 config AD525X_DPOT
-       tristate "Analog Devices AD525x Digital Potentiometers"
-       depends on I2C && SYSFS
+       tristate "Analog Devices Digital Potentiometers"
+       depends on (I2C || SPI) && SYSFS
        help
          If you say yes here, you get support for the Analog Devices
-         AD5258, AD5259, AD5251, AD5252, AD5253, AD5254 and AD5255
+         AD5258, AD5259, AD5251, AD5252, AD5253, AD5254, AD5255
+         AD5160, AD5161, AD5162, AD5165, AD5200, AD5201, AD5203,
+         AD5204, AD5206, AD5207, AD5231, AD5232, AD5233, AD5235,
+         AD5260, AD5262, AD5263, AD5290, AD5291, AD5292, AD5293,
+         AD7376, AD8400, AD8402, AD8403, ADN2850, AD5241, AD5242,
+         AD5243, AD5245, AD5246, AD5247, AD5248, AD5280, AD5282,
+         ADN2860, AD5273, AD5171, AD5170, AD5172, AD5173
          digital potentiometer chips.
 
          See Documentation/misc-devices/ad525x_dpot.txt for the
@@ -27,6 +33,26 @@ config AD525X_DPOT
          This driver can also be built as a module.  If so, the module
          will be called ad525x_dpot.
 
+config AD525X_DPOT_I2C
+       tristate "support I2C bus connection"
+       depends on AD525X_DPOT && I2C
+       help
+         Say Y here if you have a digital potentiometers hooked to an I2C bus.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ad525x_dpot-i2c.
+
+config AD525X_DPOT_SPI
+       tristate "support SPI bus connection"
+       depends on AD525X_DPOT && SPI_MASTER
+       help
+         Say Y here if you have a digital potentiometers hooked to an SPI bus.
+
+         If unsure, say N (but it's safe to say "Y").
+
+         To compile this driver as a module, choose M here: the
+         module will be called ad525x_dpot-spi.
+
 config ATMEL_PWM
        tristate "Atmel AT32/AT91 PWM support"
        depends on AVR32 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9
index f12dc3e..6ed06a1 100644 (file)
@@ -4,6 +4,8 @@
 
 obj-$(CONFIG_IBM_ASM)          += ibmasm/
 obj-$(CONFIG_AD525X_DPOT)      += ad525x_dpot.o
+obj-$(CONFIG_AD525X_DPOT_I2C)  += ad525x_dpot-i2c.o
+obj-$(CONFIG_AD525X_DPOT_SPI)  += ad525x_dpot-spi.o
 obj-$(CONFIG_ATMEL_PWM)                += atmel_pwm.o
 obj-$(CONFIG_ATMEL_SSC)                += atmel-ssc.o
 obj-$(CONFIG_ATMEL_TCLIB)      += atmel_tclib.o
diff --git a/drivers/misc/ad525x_dpot-i2c.c b/drivers/misc/ad525x_dpot-i2c.c
new file mode 100644 (file)
index 0000000..374352a
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Driver for the Analog Devices digital potentiometers (I2C bus)
+ *
+ * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+
+#include "ad525x_dpot.h"
+
+/* ------------------------------------------------------------------------- */
+/* I2C bus functions */
+static int write_d8(void *client, u8 val)
+{
+       return i2c_smbus_write_byte(client, val);
+}
+
+static int write_r8d8(void *client, u8 reg, u8 val)
+{
+       return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+static int write_r8d16(void *client, u8 reg, u16 val)
+{
+       return i2c_smbus_write_word_data(client, reg, val);
+}
+
+static int read_d8(void *client)
+{
+       return i2c_smbus_read_byte(client);
+}
+
+static int read_r8d8(void *client, u8 reg)
+{
+       return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int read_r8d16(void *client, u8 reg)
+{
+       return i2c_smbus_read_word_data(client, reg);
+}
+
+static const struct ad_dpot_bus_ops bops = {
+       .read_d8        = read_d8,
+       .read_r8d8      = read_r8d8,
+       .read_r8d16     = read_r8d16,
+       .write_d8       = write_d8,
+       .write_r8d8     = write_r8d8,
+       .write_r8d16    = write_r8d16,
+};
+
+static int __devinit ad_dpot_i2c_probe(struct i2c_client *client,
+                                     const struct i2c_device_id *id)
+{
+       struct ad_dpot_bus_data bdata = {
+               .client = client,
+               .bops = &bops,
+       };
+
+       struct ad_dpot_id dpot_id = {
+               .name = (char *) &id->name,
+               .devid = id->driver_data,
+       };
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_WORD_DATA)) {
+               dev_err(&client->dev, "SMBUS Word Data not Supported\n");
+               return -EIO;
+       }
+
+       return ad_dpot_probe(&client->dev, &bdata, &dpot_id);
+}
+
+static int __devexit ad_dpot_i2c_remove(struct i2c_client *client)
+{
+       return ad_dpot_remove(&client->dev);
+}
+
+static const struct i2c_device_id ad_dpot_id[] = {
+       {"ad5258", AD5258_ID},
+       {"ad5259", AD5259_ID},
+       {"ad5251", AD5251_ID},
+       {"ad5252", AD5252_ID},
+       {"ad5253", AD5253_ID},
+       {"ad5254", AD5254_ID},
+       {"ad5255", AD5255_ID},
+       {"ad5241", AD5241_ID},
+       {"ad5242", AD5242_ID},
+       {"ad5243", AD5243_ID},
+       {"ad5245", AD5245_ID},
+       {"ad5246", AD5246_ID},
+       {"ad5247", AD5247_ID},
+       {"ad5248", AD5248_ID},
+       {"ad5280", AD5280_ID},
+       {"ad5282", AD5282_ID},
+       {"adn2860", ADN2860_ID},
+       {"ad5273", AD5273_ID},
+       {"ad5171", AD5171_ID},
+       {"ad5170", AD5170_ID},
+       {"ad5172", AD5172_ID},
+       {"ad5173", AD5173_ID},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, ad_dpot_id);
+
+static struct i2c_driver ad_dpot_i2c_driver = {
+       .driver = {
+               .name   = "ad_dpot",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ad_dpot_i2c_probe,
+       .remove         = __devexit_p(ad_dpot_i2c_remove),
+       .id_table       = ad_dpot_id,
+};
+
+static int __init ad_dpot_i2c_init(void)
+{
+       return i2c_add_driver(&ad_dpot_i2c_driver);
+}
+module_init(ad_dpot_i2c_init);
+
+static void __exit ad_dpot_i2c_exit(void)
+{
+       i2c_del_driver(&ad_dpot_i2c_driver);
+}
+module_exit(ad_dpot_i2c_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("digital potentiometer I2C bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("i2c:ad_dpot");
diff --git a/drivers/misc/ad525x_dpot-spi.c b/drivers/misc/ad525x_dpot-spi.c
new file mode 100644 (file)
index 0000000..b8c6df9
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Driver for the Analog Devices digital potentiometers (SPI bus)
+ *
+ * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/spi/spi.h>
+#include <linux/module.h>
+
+#include "ad525x_dpot.h"
+
+static const struct ad_dpot_id ad_dpot_spi_devlist[] = {
+       {.name = "ad5160", .devid = AD5160_ID},
+       {.name = "ad5161", .devid = AD5161_ID},
+       {.name = "ad5162", .devid = AD5162_ID},
+       {.name = "ad5165", .devid = AD5165_ID},
+       {.name = "ad5200", .devid = AD5200_ID},
+       {.name = "ad5201", .devid = AD5201_ID},
+       {.name = "ad5203", .devid = AD5203_ID},
+       {.name = "ad5204", .devid = AD5204_ID},
+       {.name = "ad5206", .devid = AD5206_ID},
+       {.name = "ad5207", .devid = AD5207_ID},
+       {.name = "ad5231", .devid = AD5231_ID},
+       {.name = "ad5232", .devid = AD5232_ID},
+       {.name = "ad5233", .devid = AD5233_ID},
+       {.name = "ad5235", .devid = AD5235_ID},
+       {.name = "ad5260", .devid = AD5260_ID},
+       {.name = "ad5262", .devid = AD5262_ID},
+       {.name = "ad5263", .devid = AD5263_ID},
+       {.name = "ad5290", .devid = AD5290_ID},
+       {.name = "ad5291", .devid = AD5291_ID},
+       {.name = "ad5292", .devid = AD5292_ID},
+       {.name = "ad5293", .devid = AD5293_ID},
+       {.name = "ad7376", .devid = AD7376_ID},
+       {.name = "ad8400", .devid = AD8400_ID},
+       {.name = "ad8402", .devid = AD8402_ID},
+       {.name = "ad8403", .devid = AD8403_ID},
+       {.name = "adn2850", .devid = ADN2850_ID},
+       {}
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* SPI bus functions */
+static int write8(void *client, u8 val)
+{
+       u8 data = val;
+       return spi_write(client, &data, 1);
+}
+
+static int write16(void *client, u8 reg, u8 val)
+{
+       u8 data[2] = {reg, val};
+       return spi_write(client, data, 1);
+}
+
+static int write24(void *client, u8 reg, u16 val)
+{
+       u8 data[3] = {reg, val >> 8, val};
+       return spi_write(client, data, 1);
+}
+
+static int read8(void *client)
+{
+       int ret;
+       u8 data;
+       ret = spi_read(client, &data, 1);
+       if (ret < 0)
+               return ret;
+
+       return data;
+}
+
+static int read16(void *client, u8 reg)
+{
+       int ret;
+       u8 buf_rx[2];
+
+       write16(client, reg, 0);
+       ret = spi_read(client, buf_rx, 2);
+       if (ret < 0)
+               return ret;
+
+       return (buf_rx[0] << 8) |  buf_rx[1];
+}
+
+static int read24(void *client, u8 reg)
+{
+       int ret;
+       u8 buf_rx[3];
+
+       write24(client, reg, 0);
+       ret = spi_read(client, buf_rx, 3);
+       if (ret < 0)
+               return ret;
+
+       return (buf_rx[1] << 8) |  buf_rx[2];
+}
+
+static const struct ad_dpot_bus_ops bops = {
+       .read_d8        = read8,
+       .read_r8d8      = read16,
+       .read_r8d16     = read24,
+       .write_d8       = write8,
+       .write_r8d8     = write16,
+       .write_r8d16    = write24,
+};
+
+static const struct ad_dpot_id *dpot_match_id(const struct ad_dpot_id *id,
+                                               char *name)
+{
+       while (id->name && id->name[0]) {
+               if (strcmp(name, id->name) == 0)
+                       return id;
+               id++;
+       }
+       return NULL;
+}
+
+static int __devinit ad_dpot_spi_probe(struct spi_device *spi)
+{
+       char *name = spi->dev.platform_data;
+       const struct ad_dpot_id *dpot_id;
+
+       struct ad_dpot_bus_data bdata = {
+               .client = spi,
+               .bops = &bops,
+       };
+
+       dpot_id = dpot_match_id(ad_dpot_spi_devlist, name);
+
+       if (dpot_id == NULL) {
+               dev_err(&spi->dev, "%s not in supported device list", name);
+               return -ENODEV;
+       }
+
+       return ad_dpot_probe(&spi->dev, &bdata, dpot_id);
+}
+
+static int __devexit ad_dpot_spi_remove(struct spi_device *spi)
+{
+       return ad_dpot_remove(&spi->dev);
+}
+
+static struct spi_driver ad_dpot_spi_driver = {
+       .driver = {
+               .name   = "ad_dpot",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ad_dpot_spi_probe,
+       .remove         = __devexit_p(ad_dpot_spi_remove),
+};
+
+static int __init ad_dpot_spi_init(void)
+{
+       return spi_register_driver(&ad_dpot_spi_driver);
+}
+module_init(ad_dpot_spi_init);
+
+static void __exit ad_dpot_spi_exit(void)
+{
+       spi_unregister_driver(&ad_dpot_spi_driver);
+}
+module_exit(ad_dpot_spi_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("digital potentiometer SPI bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:ad_dpot");
index 30a59f2..5e6fa84 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * ad525x_dpot: Driver for the Analog Devices AD525x digital potentiometers
- * Copyright (c) 2009 Analog Devices, Inc.
+ * ad525x_dpot: Driver for the Analog Devices digital potentiometers
+ * Copyright (c) 2009-2010 Analog Devices, Inc.
  * Author: Michael Hennerich <hennerich@blackfin.uclinux.org>
  *
  * DEVID               #Wipers         #Positions      Resistor Options (kOhm)
  * AD5255              3               512             25, 250
  * AD5253              4               64              1, 10, 50, 100
  * AD5254              4               256             1, 10, 50, 100
+ * AD5160              1               256             5, 10, 50, 100
+ * AD5161              1               256             5, 10, 50, 100
+ * AD5162              2               256             2.5, 10, 50, 100
+ * AD5165              1               256             100
+ * AD5200              1               256             10, 50
+ * AD5201              1               33              10, 50
+ * AD5203              4               64              10, 100
+ * AD5204              4               256             10, 50, 100
+ * AD5206              6               256             10, 50, 100
+ * AD5207              2               256             10, 50, 100
+ * AD5231              1               1024            10, 50, 100
+ * AD5232              2               256             10, 50, 100
+ * AD5233              4               64              10, 50, 100
+ * AD5235              2               1024            25, 250
+ * AD5260              1               256             20, 50, 200
+ * AD5262              2               256             20, 50, 200
+ * AD5263              4               256             20, 50, 200
+ * AD5290              1               256             10, 50, 100
+ * AD5291              1               256             20
+ * AD5292              1               1024            20
+ * AD5293              1               1024            20
+ * AD7376              1               128             10, 50, 100, 1M
+ * AD8400              1               256             1, 10, 50, 100
+ * AD8402              2               256             1, 10, 50, 100
+ * AD8403              4               256             1, 10, 50, 100
+ * ADN2850             3               512             25, 250
+ * AD5241              1               256             10, 100, 1M
+ * AD5246              1               128             5, 10, 50, 100
+ * AD5247              1               128             5, 10, 50, 100
+ * AD5245              1               256             5, 10, 50, 100
+ * AD5243              2               256             2.5, 10, 50, 100
+ * AD5248              2               256             2.5, 10, 50, 100
+ * AD5242              2               256             20, 50, 200
+ * AD5280              1               256             20, 50, 200
+ * AD5282              2               256             20, 50, 200
+ * ADN2860             3               512             25, 250
+ * AD5273              1               64              1, 10, 50, 100 (OTP)
+ * AD5171              1               64              5, 10, 50, 100 (OTP)
+ * AD5170              1               256             2.5, 10, 50, 100 (OTP)
+ * AD5172              2               256             2.5, 10, 50, 100 (OTP)
+ * AD5173              2               256             2.5, 10, 50, 100 (OTP)
  *
  * See Documentation/misc-devices/ad525x_dpot.txt for more info.
  *
 #include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
 #include <linux/delay.h>
+#include <linux/slab.h>
 
-#define DRIVER_NAME                    "ad525x_dpot"
-#define DRIVER_VERSION                 "0.1"
-
-enum dpot_devid {
-       AD5258_ID,
-       AD5259_ID,
-       AD5251_ID,
-       AD5252_ID,
-       AD5253_ID,
-       AD5254_ID,
-       AD5255_ID,
-};
+#define DRIVER_VERSION                 "0.2"
 
-#define AD5258_MAX_POSITION            64
-#define AD5259_MAX_POSITION            256
-#define AD5251_MAX_POSITION            64
-#define AD5252_MAX_POSITION            256
-#define AD5253_MAX_POSITION            64
-#define AD5254_MAX_POSITION            256
-#define AD5255_MAX_POSITION            512
-
-#define AD525X_RDAC0           0
-#define AD525X_RDAC1           1
-#define AD525X_RDAC2           2
-#define AD525X_RDAC3           3
-
-#define AD525X_REG_TOL         0x18
-#define AD525X_TOL_RDAC0       (AD525X_REG_TOL | AD525X_RDAC0)
-#define AD525X_TOL_RDAC1       (AD525X_REG_TOL | AD525X_RDAC1)
-#define AD525X_TOL_RDAC2       (AD525X_REG_TOL | AD525X_RDAC2)
-#define AD525X_TOL_RDAC3       (AD525X_REG_TOL | AD525X_RDAC3)
-
-/* RDAC-to-EEPROM Interface Commands */
-#define AD525X_I2C_RDAC                (0x00 << 5)
-#define AD525X_I2C_EEPROM      (0x01 << 5)
-#define AD525X_I2C_CMD         (0x80)
-
-#define AD525X_DEC_ALL_6DB     (AD525X_I2C_CMD | (0x4 << 3))
-#define AD525X_INC_ALL_6DB     (AD525X_I2C_CMD | (0x9 << 3))
-#define AD525X_DEC_ALL         (AD525X_I2C_CMD | (0x6 << 3))
-#define AD525X_INC_ALL         (AD525X_I2C_CMD | (0xB << 3))
-
-static s32 ad525x_read(struct i2c_client *client, u8 reg);
-static s32 ad525x_write(struct i2c_client *client, u8 reg, u8 value);
+#include "ad525x_dpot.h"
 
 /*
  * Client data (each client gets its own)
  */
 
 struct dpot_data {
+       struct ad_dpot_bus_data bdata;
        struct mutex update_lock;
        unsigned rdac_mask;
        unsigned max_pos;
-       unsigned devid;
+       unsigned long devid;
+       unsigned uid;
+       unsigned feat;
+       unsigned wipers;
+       u16 rdac_cache[MAX_RDACS];
+       DECLARE_BITMAP(otp_en_mask, MAX_RDACS);
 };
 
+static inline int dpot_read_d8(struct dpot_data *dpot)
+{
+       return dpot->bdata.bops->read_d8(dpot->bdata.client);
+}
+
+static inline int dpot_read_r8d8(struct dpot_data *dpot, u8 reg)
+{
+       return dpot->bdata.bops->read_r8d8(dpot->bdata.client, reg);
+}
+
+static inline int dpot_read_r8d16(struct dpot_data *dpot, u8 reg)
+{
+       return dpot->bdata.bops->read_r8d16(dpot->bdata.client, reg);
+}
+
+static inline int dpot_write_d8(struct dpot_data *dpot, u8 val)
+{
+       return dpot->bdata.bops->write_d8(dpot->bdata.client, val);
+}
+
+static inline int dpot_write_r8d8(struct dpot_data *dpot, u8 reg, u16 val)
+{
+       return dpot->bdata.bops->write_r8d8(dpot->bdata.client, reg, val);
+}
+
+static inline int dpot_write_r8d16(struct dpot_data *dpot, u8 reg, u16 val)
+{
+       return dpot->bdata.bops->write_r8d16(dpot->bdata.client, reg, val);
+}
+
+static s32 dpot_read_spi(struct dpot_data *dpot, u8 reg)
+{
+       unsigned ctrl = 0;
+
+       if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) {
+
+               if (dpot->feat & F_RDACS_WONLY)
+                       return dpot->rdac_cache[reg & DPOT_RDAC_MASK];
+
+               if (dpot->uid == DPOT_UID(AD5291_ID) ||
+                       dpot->uid == DPOT_UID(AD5292_ID) ||
+                       dpot->uid == DPOT_UID(AD5293_ID))
+                       return dpot_read_r8d8(dpot,
+                               DPOT_AD5291_READ_RDAC << 2);
+
+               ctrl = DPOT_SPI_READ_RDAC;
+       } else if (reg & DPOT_ADDR_EEPROM) {
+               ctrl = DPOT_SPI_READ_EEPROM;
+       }
+
+       if (dpot->feat & F_SPI_16BIT)
+               return dpot_read_r8d8(dpot, ctrl);
+       else if (dpot->feat & F_SPI_24BIT)
+               return dpot_read_r8d16(dpot, ctrl);
+
+       return -EFAULT;
+}
+
+static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg)
+{
+       unsigned ctrl = 0;
+       switch (dpot->uid) {
+       case DPOT_UID(AD5246_ID):
+       case DPOT_UID(AD5247_ID):
+               return dpot_read_d8(dpot);
+       case DPOT_UID(AD5245_ID):
+       case DPOT_UID(AD5241_ID):
+       case DPOT_UID(AD5242_ID):
+       case DPOT_UID(AD5243_ID):
+       case DPOT_UID(AD5248_ID):
+       case DPOT_UID(AD5280_ID):
+       case DPOT_UID(AD5282_ID):
+               ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
+                       0 : DPOT_AD5291_RDAC_AB;
+               return dpot_read_r8d8(dpot, ctrl);
+       case DPOT_UID(AD5170_ID):
+       case DPOT_UID(AD5171_ID):
+       case DPOT_UID(AD5273_ID):
+                       return dpot_read_d8(dpot);
+       case DPOT_UID(AD5172_ID):
+       case DPOT_UID(AD5173_ID):
+               ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
+                       0 : DPOT_AD5272_3_A0;
+               return dpot_read_r8d8(dpot, ctrl);
+       default:
+               if ((reg & DPOT_REG_TOL) || (dpot->max_pos > 256))
+                       return dpot_read_r8d16(dpot, (reg & 0xF8) |
+                                       ((reg & 0x7) << 1));
+               else
+                       return dpot_read_r8d8(dpot, reg);
+       }
+}
+
+static s32 dpot_read(struct dpot_data *dpot, u8 reg)
+{
+       if (dpot->feat & F_SPI)
+               return dpot_read_spi(dpot, reg);
+       else
+               return dpot_read_i2c(dpot, reg);
+}
+
+static s32 dpot_write_spi(struct dpot_data *dpot, u8 reg, u16 value)
+{
+       unsigned val = 0;
+
+       if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) {
+               if (dpot->feat & F_RDACS_WONLY)
+                       dpot->rdac_cache[reg & DPOT_RDAC_MASK] = value;
+
+               if (dpot->feat & F_AD_APPDATA) {
+                       if (dpot->feat & F_SPI_8BIT) {
+                               val = ((reg & DPOT_RDAC_MASK) <<
+                                       DPOT_MAX_POS(dpot->devid)) |
+                                       value;
+                               return dpot_write_d8(dpot, val);
+                       } else if (dpot->feat & F_SPI_16BIT) {
+                               val = ((reg & DPOT_RDAC_MASK) <<
+                                       DPOT_MAX_POS(dpot->devid)) |
+                                       value;
+                               return dpot_write_r8d8(dpot, val >> 8,
+                                       val & 0xFF);
+                       } else
+                               BUG();
+               } else {
+                       if (dpot->uid == DPOT_UID(AD5291_ID) ||
+                               dpot->uid == DPOT_UID(AD5292_ID) ||
+                               dpot->uid == DPOT_UID(AD5293_ID))
+                               return dpot_write_r8d8(dpot,
+                                       (DPOT_AD5291_RDAC << 2) |
+                                       (value >> 8), value & 0xFF);
+
+                       val = DPOT_SPI_RDAC | (reg & DPOT_RDAC_MASK);
+               }
+       } else if (reg & DPOT_ADDR_EEPROM) {
+               val = DPOT_SPI_EEPROM | (reg & DPOT_RDAC_MASK);
+       } else if (reg & DPOT_ADDR_CMD) {
+               switch (reg) {
+               case DPOT_DEC_ALL_6DB:
+                       val = DPOT_SPI_DEC_ALL_6DB;
+                       break;
+               case DPOT_INC_ALL_6DB:
+                       val = DPOT_SPI_INC_ALL_6DB;
+                       break;
+               case DPOT_DEC_ALL:
+                       val = DPOT_SPI_DEC_ALL;
+                       break;
+               case DPOT_INC_ALL:
+                       val = DPOT_SPI_INC_ALL;
+                       break;
+               }
+       } else
+               BUG();
+
+       if (dpot->feat & F_SPI_16BIT)
+               return dpot_write_r8d8(dpot, val, value);
+       else if (dpot->feat & F_SPI_24BIT)
+               return dpot_write_r8d16(dpot, val, value);
+
+       return -EFAULT;
+}
+
+static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
+{
+       /* Only write the instruction byte for certain commands */
+       unsigned tmp = 0, ctrl = 0;
+
+       switch (dpot->uid) {
+       case DPOT_UID(AD5246_ID):
+       case DPOT_UID(AD5247_ID):
+               return dpot_write_d8(dpot, value);
+               break;
+
+       case DPOT_UID(AD5245_ID):
+       case DPOT_UID(AD5241_ID):
+       case DPOT_UID(AD5242_ID):
+       case DPOT_UID(AD5243_ID):
+       case DPOT_UID(AD5248_ID):
+       case DPOT_UID(AD5280_ID):
+       case DPOT_UID(AD5282_ID):
+               ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
+                       0 : DPOT_AD5291_RDAC_AB;
+               return dpot_write_r8d8(dpot, ctrl, value);
+               break;
+       case DPOT_UID(AD5171_ID):
+       case DPOT_UID(AD5273_ID):
+               if (reg & DPOT_ADDR_OTP) {
+                       tmp = dpot_read_d8(dpot);
+                       if (tmp >> 6) /* Ready to Program? */
+                               return -EFAULT;
+                       ctrl = DPOT_AD5273_FUSE;
+               }
+               return dpot_write_r8d8(dpot, ctrl, value);
+               break;
+       case DPOT_UID(AD5172_ID):
+       case DPOT_UID(AD5173_ID):
+               ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
+                       0 : DPOT_AD5272_3_A0;
+               if (reg & DPOT_ADDR_OTP) {
+                       tmp = dpot_read_r8d16(dpot, ctrl);
+                       if (tmp >> 14) /* Ready to Program? */
+                               return -EFAULT;
+                       ctrl |= DPOT_AD5270_2_3_FUSE;
+               }
+               return dpot_write_r8d8(dpot, ctrl, value);
+               break;
+       case DPOT_UID(AD5170_ID):
+               if (reg & DPOT_ADDR_OTP) {
+                       tmp = dpot_read_r8d16(dpot, tmp);
+                       if (tmp >> 14) /* Ready to Program? */
+                               return -EFAULT;
+                       ctrl = DPOT_AD5270_2_3_FUSE;
+               }
+               return dpot_write_r8d8(dpot, ctrl, value);
+               break;
+       default:
+               if (reg & DPOT_ADDR_CMD)
+                       return dpot_write_d8(dpot, reg);
+
+               if (dpot->max_pos > 256)
+                       return dpot_write_r8d16(dpot, (reg & 0xF8) |
+                                               ((reg & 0x7) << 1), value);
+               else
+                       /* All other registers require instruction + data bytes */
+                       return dpot_write_r8d8(dpot, reg, value);
+       }
+}
+
+
+static s32 dpot_write(struct dpot_data *dpot, u8 reg, u16 value)
+{
+       if (dpot->feat & F_SPI)
+               return dpot_write_spi(dpot, reg, value);
+       else
+               return dpot_write_i2c(dpot, reg, value);
+}
+
 /* sysfs functions */
 
 static ssize_t sysfs_show_reg(struct device *dev,
-                             struct device_attribute *attr, char *buf, u32 reg)
+                             struct device_attribute *attr,
+                             char *buf, u32 reg)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct dpot_data *data = i2c_get_clientdata(client);
+       struct dpot_data *data = dev_get_drvdata(dev);
        s32 value;
 
+       if (reg & DPOT_ADDR_OTP_EN)
+               return sprintf(buf, "%s\n",
+                       test_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask) ?
+                       "enabled" : "disabled");
+
+
        mutex_lock(&data->update_lock);
-       value = ad525x_read(client, reg);
+       value = dpot_read(data, reg);
        mutex_unlock(&data->update_lock);
 
        if (value < 0)
@@ -111,7 +358,7 @@ static ssize_t sysfs_show_reg(struct device *dev,
         * datasheet (Rev. A) for more details.
         */
 
-       if (reg & AD525X_REG_TOL)
+       if (reg & DPOT_REG_TOL)
                return sprintf(buf, "0x%04x\n", value & 0xFFFF);
        else
                return sprintf(buf, "%u\n", value & data->rdac_mask);
@@ -121,11 +368,23 @@ static ssize_t sysfs_set_reg(struct device *dev,
                             struct device_attribute *attr,
                             const char *buf, size_t count, u32 reg)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct dpot_data *data = i2c_get_clientdata(client);
+       struct dpot_data *data = dev_get_drvdata(dev);
        unsigned long value;
        int err;
 
+       if (reg & DPOT_ADDR_OTP_EN) {
+               if (!strncmp(buf, "enabled", sizeof("enabled")))
+                       set_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask);
+               else
+                       clear_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask);
+
+               return count;
+       }
+
+       if ((reg & DPOT_ADDR_OTP) &&
+               !test_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask))
+               return -EPERM;
+
        err = strict_strtoul(buf, 10, &value);
        if (err)
                return err;
@@ -134,9 +393,11 @@ static ssize_t sysfs_set_reg(struct device *dev,
                value = data->rdac_mask;
 
        mutex_lock(&data->update_lock);
-       ad525x_write(client, reg, value);
-       if (reg & AD525X_I2C_EEPROM)
+       dpot_write(data, reg, value);
+       if (reg & DPOT_ADDR_EEPROM)
                msleep(26);     /* Sleep while the EEPROM updates */
+       else if (reg & DPOT_ADDR_OTP)
+               msleep(400);    /* Sleep while the OTP updates */
        mutex_unlock(&data->update_lock);
 
        return count;
@@ -146,11 +407,10 @@ static ssize_t sysfs_do_cmd(struct device *dev,
                            struct device_attribute *attr,
                            const char *buf, size_t count, u32 reg)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct dpot_data *data = i2c_get_clientdata(client);
+       struct dpot_data *data = dev_get_drvdata(dev);
 
        mutex_lock(&data->update_lock);
-       ad525x_write(client, reg, 0);
+       dpot_write(data, reg, 0);
        mutex_unlock(&data->update_lock);
 
        return count;
@@ -158,244 +418,131 @@ static ssize_t sysfs_do_cmd(struct device *dev,
 
 /* ------------------------------------------------------------------------- */
 
-static ssize_t show_rdac0(struct device *dev,
-                         struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf, AD525X_I2C_RDAC | AD525X_RDAC0);
-}
-
-static ssize_t set_rdac0(struct device *dev,
-                        struct device_attribute *attr,
-                        const char *buf, size_t count)
-{
-       return sysfs_set_reg(dev, attr, buf, count,
-                            AD525X_I2C_RDAC | AD525X_RDAC0);
-}
-
-static DEVICE_ATTR(rdac0, S_IWUSR | S_IRUGO, show_rdac0, set_rdac0);
-
-static ssize_t show_eeprom0(struct device *dev,
-                           struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf, AD525X_I2C_EEPROM | AD525X_RDAC0);
-}
-
-static ssize_t set_eeprom0(struct device *dev,
-                          struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-       return sysfs_set_reg(dev, attr, buf, count,
-                            AD525X_I2C_EEPROM | AD525X_RDAC0);
-}
-
-static DEVICE_ATTR(eeprom0, S_IWUSR | S_IRUGO, show_eeprom0, set_eeprom0);
-
-static ssize_t show_tolerance0(struct device *dev,
-                              struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf,
-                             AD525X_I2C_EEPROM | AD525X_TOL_RDAC0);
-}
-
-static DEVICE_ATTR(tolerance0, S_IRUGO, show_tolerance0, NULL);
-
-/* ------------------------------------------------------------------------- */
-
-static ssize_t show_rdac1(struct device *dev,
-                         struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf, AD525X_I2C_RDAC | AD525X_RDAC1);
-}
-
-static ssize_t set_rdac1(struct device *dev,
-                        struct device_attribute *attr,
-                        const char *buf, size_t count)
-{
-       return sysfs_set_reg(dev, attr, buf, count,
-                            AD525X_I2C_RDAC | AD525X_RDAC1);
-}
-
-static DEVICE_ATTR(rdac1, S_IWUSR | S_IRUGO, show_rdac1, set_rdac1);
-
-static ssize_t show_eeprom1(struct device *dev,
-                           struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf, AD525X_I2C_EEPROM | AD525X_RDAC1);
-}
-
-static ssize_t set_eeprom1(struct device *dev,
-                          struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-       return sysfs_set_reg(dev, attr, buf, count,
-                            AD525X_I2C_EEPROM | AD525X_RDAC1);
-}
-
-static DEVICE_ATTR(eeprom1, S_IWUSR | S_IRUGO, show_eeprom1, set_eeprom1);
-
-static ssize_t show_tolerance1(struct device *dev,
-                              struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf,
-                             AD525X_I2C_EEPROM | AD525X_TOL_RDAC1);
-}
-
-static DEVICE_ATTR(tolerance1, S_IRUGO, show_tolerance1, NULL);
-
-/* ------------------------------------------------------------------------- */
-
-static ssize_t show_rdac2(struct device *dev,
-                         struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf, AD525X_I2C_RDAC | AD525X_RDAC2);
-}
-
-static ssize_t set_rdac2(struct device *dev,
-                        struct device_attribute *attr,
-                        const char *buf, size_t count)
-{
-       return sysfs_set_reg(dev, attr, buf, count,
-                            AD525X_I2C_RDAC | AD525X_RDAC2);
-}
-
-static DEVICE_ATTR(rdac2, S_IWUSR | S_IRUGO, show_rdac2, set_rdac2);
-
-static ssize_t show_eeprom2(struct device *dev,
-                           struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf, AD525X_I2C_EEPROM | AD525X_RDAC2);
-}
-
-static ssize_t set_eeprom2(struct device *dev,
-                          struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-       return sysfs_set_reg(dev, attr, buf, count,
-                            AD525X_I2C_EEPROM | AD525X_RDAC2);
-}
-
-static DEVICE_ATTR(eeprom2, S_IWUSR | S_IRUGO, show_eeprom2, set_eeprom2);
-
-static ssize_t show_tolerance2(struct device *dev,
-                              struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf,
-                             AD525X_I2C_EEPROM | AD525X_TOL_RDAC2);
-}
-
-static DEVICE_ATTR(tolerance2, S_IRUGO, show_tolerance2, NULL);
-
-/* ------------------------------------------------------------------------- */
-
-static ssize_t show_rdac3(struct device *dev,
-                         struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf, AD525X_I2C_RDAC | AD525X_RDAC3);
-}
-
-static ssize_t set_rdac3(struct device *dev,
-                        struct device_attribute *attr,
-                        const char *buf, size_t count)
-{
-       return sysfs_set_reg(dev, attr, buf, count,
-                            AD525X_I2C_RDAC | AD525X_RDAC3);
-}
-
-static DEVICE_ATTR(rdac3, S_IWUSR | S_IRUGO, show_rdac3, set_rdac3);
-
-static ssize_t show_eeprom3(struct device *dev,
-                           struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf, AD525X_I2C_EEPROM | AD525X_RDAC3);
-}
-
-static ssize_t set_eeprom3(struct device *dev,
-                          struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-       return sysfs_set_reg(dev, attr, buf, count,
-                            AD525X_I2C_EEPROM | AD525X_RDAC3);
-}
+#define DPOT_DEVICE_SHOW(_name, _reg) static ssize_t \
+show_##_name(struct device *dev, \
+                         struct device_attribute *attr, char *buf) \
+{ \
+       return sysfs_show_reg(dev, attr, buf, _reg); \
+}
+
+#define DPOT_DEVICE_SET(_name, _reg) static ssize_t \
+set_##_name(struct device *dev, \
+                        struct device_attribute *attr, \
+                        const char *buf, size_t count) \
+{ \
+       return sysfs_set_reg(dev, attr, buf, count, _reg); \
+}
+
+#define DPOT_DEVICE_SHOW_SET(name, reg) \
+DPOT_DEVICE_SHOW(name, reg) \
+DPOT_DEVICE_SET(name, reg) \
+static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, set_##name);
+
+#define DPOT_DEVICE_SHOW_ONLY(name, reg) \
+DPOT_DEVICE_SHOW(name, reg) \
+static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, NULL);
+
+DPOT_DEVICE_SHOW_SET(rdac0, DPOT_ADDR_RDAC | DPOT_RDAC0);
+DPOT_DEVICE_SHOW_SET(eeprom0, DPOT_ADDR_EEPROM | DPOT_RDAC0);
+DPOT_DEVICE_SHOW_ONLY(tolerance0, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC0);
+DPOT_DEVICE_SHOW_SET(otp0, DPOT_ADDR_OTP | DPOT_RDAC0);
+DPOT_DEVICE_SHOW_SET(otp0en, DPOT_ADDR_OTP_EN | DPOT_RDAC0);
+
+DPOT_DEVICE_SHOW_SET(rdac1, DPOT_ADDR_RDAC | DPOT_RDAC1);
+DPOT_DEVICE_SHOW_SET(eeprom1, DPOT_ADDR_EEPROM | DPOT_RDAC1);
+DPOT_DEVICE_SHOW_ONLY(tolerance1, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC1);
+DPOT_DEVICE_SHOW_SET(otp1, DPOT_ADDR_OTP | DPOT_RDAC1);
+DPOT_DEVICE_SHOW_SET(otp1en, DPOT_ADDR_OTP_EN | DPOT_RDAC1);
+
+DPOT_DEVICE_SHOW_SET(rdac2, DPOT_ADDR_RDAC | DPOT_RDAC2);
+DPOT_DEVICE_SHOW_SET(eeprom2, DPOT_ADDR_EEPROM | DPOT_RDAC2);
+DPOT_DEVICE_SHOW_ONLY(tolerance2, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC2);
+DPOT_DEVICE_SHOW_SET(otp2, DPOT_ADDR_OTP | DPOT_RDAC2);
+DPOT_DEVICE_SHOW_SET(otp2en, DPOT_ADDR_OTP_EN | DPOT_RDAC2);
+
+DPOT_DEVICE_SHOW_SET(rdac3, DPOT_ADDR_RDAC | DPOT_RDAC3);
+DPOT_DEVICE_SHOW_SET(eeprom3, DPOT_ADDR_EEPROM | DPOT_RDAC3);
+DPOT_DEVICE_SHOW_ONLY(tolerance3, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC3);
+DPOT_DEVICE_SHOW_SET(otp3, DPOT_ADDR_OTP | DPOT_RDAC3);
+DPOT_DEVICE_SHOW_SET(otp3en, DPOT_ADDR_OTP_EN | DPOT_RDAC3);
+
+DPOT_DEVICE_SHOW_SET(rdac4, DPOT_ADDR_RDAC | DPOT_RDAC4);
+DPOT_DEVICE_SHOW_SET(eeprom4, DPOT_ADDR_EEPROM | DPOT_RDAC4);
+DPOT_DEVICE_SHOW_ONLY(tolerance4, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC4);
+DPOT_DEVICE_SHOW_SET(otp4, DPOT_ADDR_OTP | DPOT_RDAC4);
+DPOT_DEVICE_SHOW_SET(otp4en, DPOT_ADDR_OTP_EN | DPOT_RDAC4);
+
+DPOT_DEVICE_SHOW_SET(rdac5, DPOT_ADDR_RDAC | DPOT_RDAC5);
+DPOT_DEVICE_SHOW_SET(eeprom5, DPOT_ADDR_EEPROM | DPOT_RDAC5);
+DPOT_DEVICE_SHOW_ONLY(tolerance5, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC5);
+DPOT_DEVICE_SHOW_SET(otp5, DPOT_ADDR_OTP | DPOT_RDAC5);
+DPOT_DEVICE_SHOW_SET(otp5en, DPOT_ADDR_OTP_EN | DPOT_RDAC5);
+
+static const struct attribute *dpot_attrib_wipers[] = {
+       &dev_attr_rdac0.attr,
+       &dev_attr_rdac1.attr,
+       &dev_attr_rdac2.attr,
+       &dev_attr_rdac3.attr,
+       &dev_attr_rdac4.attr,
+       &dev_attr_rdac5.attr,
+       NULL
+};
 
-static DEVICE_ATTR(eeprom3, S_IWUSR | S_IRUGO, show_eeprom3, set_eeprom3);
+static const struct attribute *dpot_attrib_eeprom[] = {
+       &dev_attr_eeprom0.attr,
+       &dev_attr_eeprom1.attr,
+       &dev_attr_eeprom2.attr,
+       &dev_attr_eeprom3.attr,
+       &dev_attr_eeprom4.attr,
+       &dev_attr_eeprom5.attr,
+       NULL
+};
 
-static ssize_t show_tolerance3(struct device *dev,
-                              struct device_attribute *attr, char *buf)
-{
-       return sysfs_show_reg(dev, attr, buf,
-                             AD525X_I2C_EEPROM | AD525X_TOL_RDAC3);
-}
+static const struct attribute *dpot_attrib_otp[] = {
+       &dev_attr_otp0.attr,
+       &dev_attr_otp1.attr,
+       &dev_attr_otp2.attr,
+       &dev_attr_otp3.attr,
+       &dev_attr_otp4.attr,
+       &dev_attr_otp5.attr,
+       NULL
+};
 
-static DEVICE_ATTR(tolerance3, S_IRUGO, show_tolerance3, NULL);
-
-static struct attribute *ad525x_attributes_wipers[4][4] = {
-       {
-               &dev_attr_rdac0.attr,
-               &dev_attr_eeprom0.attr,
-               &dev_attr_tolerance0.attr,
-               NULL
-       }, {
-               &dev_attr_rdac1.attr,
-               &dev_attr_eeprom1.attr,
-               &dev_attr_tolerance1.attr,
-               NULL
-       }, {
-               &dev_attr_rdac2.attr,
-               &dev_attr_eeprom2.attr,
-               &dev_attr_tolerance2.attr,
-               NULL
-       }, {
-               &dev_attr_rdac3.attr,
-               &dev_attr_eeprom3.attr,
-               &dev_attr_tolerance3.attr,
-               NULL
-       }
+static const struct attribute *dpot_attrib_otp_en[] = {
+       &dev_attr_otp0en.attr,
+       &dev_attr_otp1en.attr,
+       &dev_attr_otp2en.attr,
+       &dev_attr_otp3en.attr,
+       &dev_attr_otp4en.attr,
+       &dev_attr_otp5en.attr,
+       NULL
 };
 
-static const struct attribute_group ad525x_group_wipers[] = {
-       {.attrs = ad525x_attributes_wipers[AD525X_RDAC0]},
-       {.attrs = ad525x_attributes_wipers[AD525X_RDAC1]},
-       {.attrs = ad525x_attributes_wipers[AD525X_RDAC2]},
-       {.attrs = ad525x_attributes_wipers[AD525X_RDAC3]},
+static const struct attribute *dpot_attrib_tolerance[] = {
+       &dev_attr_tolerance0.attr,
+       &dev_attr_tolerance1.attr,
+       &dev_attr_tolerance2.attr,
+       &dev_attr_tolerance3.attr,
+       &dev_attr_tolerance4.attr,
+       &dev_attr_tolerance5.attr,
+       NULL
 };
 
 /* ------------------------------------------------------------------------- */
 
-static ssize_t set_inc_all(struct device *dev,
-                          struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-       return sysfs_do_cmd(dev, attr, buf, count, AD525X_INC_ALL);
-}
+#define DPOT_DEVICE_DO_CMD(_name, _cmd) static ssize_t \
+set_##_name(struct device *dev, \
+                        struct device_attribute *attr, \
+                        const char *buf, size_t count) \
+{ \
+       return sysfs_do_cmd(dev, attr, buf, count, _cmd); \
+} \
+static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, NULL, set_##_name);
 
-static DEVICE_ATTR(inc_all, S_IWUSR, NULL, set_inc_all);
-
-static ssize_t set_dec_all(struct device *dev,
-                          struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-       return sysfs_do_cmd(dev, attr, buf, count, AD525X_DEC_ALL);
-}
-
-static DEVICE_ATTR(dec_all, S_IWUSR, NULL, set_dec_all);
-
-static ssize_t set_inc_all_6db(struct device *dev,
-                              struct device_attribute *attr,
-                              const char *buf, size_t count)
-{
-       return sysfs_do_cmd(dev, attr, buf, count, AD525X_INC_ALL_6DB);
-}
-
-static DEVICE_ATTR(inc_all_6db, S_IWUSR, NULL, set_inc_all_6db);
-
-static ssize_t set_dec_all_6db(struct device *dev,
-                              struct device_attribute *attr,
-                              const char *buf, size_t count)
-{
-       return sysfs_do_cmd(dev, attr, buf, count, AD525X_DEC_ALL_6DB);
-}
-
-static DEVICE_ATTR(dec_all_6db, S_IWUSR, NULL, set_dec_all_6db);
+DPOT_DEVICE_DO_CMD(inc_all, DPOT_INC_ALL);
+DPOT_DEVICE_DO_CMD(dec_all, DPOT_DEC_ALL);
+DPOT_DEVICE_DO_CMD(inc_all_6db, DPOT_INC_ALL_6DB);
+DPOT_DEVICE_DO_CMD(dec_all_6db, DPOT_DEC_ALL_6DB);
 
 static struct attribute *ad525x_attributes_commands[] = {
        &dev_attr_inc_all.attr,
@@ -409,74 +556,56 @@ static const struct attribute_group ad525x_group_commands = {
        .attrs = ad525x_attributes_commands,
 };
 
-/* ------------------------------------------------------------------------- */
-
-/* i2c device functions */
+__devinit int ad_dpot_add_files(struct device *dev,
+               unsigned features, unsigned rdac)
+{
+       int err = sysfs_create_file(&dev->kobj,
+               dpot_attrib_wipers[rdac]);
+       if (features & F_CMD_EEP)
+               err |= sysfs_create_file(&dev->kobj,
+                       dpot_attrib_eeprom[rdac]);
+       if (features & F_CMD_TOL)
+               err |= sysfs_create_file(&dev->kobj,
+                       dpot_attrib_tolerance[rdac]);
+       if (features & F_CMD_OTP) {
+               err |= sysfs_create_file(&dev->kobj,
+                       dpot_attrib_otp_en[rdac]);
+               err |= sysfs_create_file(&dev->kobj,
+                       dpot_attrib_otp[rdac]);
+       }
 
-/**
- * ad525x_read - return the value contained in the specified register
- * on the AD5258 device.
- * @client: value returned from i2c_new_device()
- * @reg: the register to read
- *
- * If the tolerance register is specified, 2 bytes are returned.
- * Otherwise, 1 byte is returned.  A negative value indicates an error
- * occurred while reading the register.
- */
-static s32 ad525x_read(struct i2c_client *client, u8 reg)
-{
-       struct dpot_data *data = i2c_get_clientdata(client);
+       if (err)
+               dev_err(dev, "failed to register sysfs hooks for RDAC%d\n",
+                       rdac);
 
-       if ((reg & AD525X_REG_TOL) || (data->max_pos > 256))
-               return i2c_smbus_read_word_data(client, (reg & 0xF8) |
-                                               ((reg & 0x7) << 1));
-       else
-               return i2c_smbus_read_byte_data(client, reg);
+       return err;
 }
 
-/**
- * ad525x_write - store the given value in the specified register on
- * the AD5258 device.
- * @client: value returned from i2c_new_device()
- * @reg: the register to write
- * @value: the byte to store in the register
- *
- * For certain instructions that do not require a data byte, "NULL"
- * should be specified for the "value" parameter.  These instructions
- * include NOP, RESTORE_FROM_EEPROM, and STORE_TO_EEPROM.
- *
- * A negative return value indicates an error occurred while reading
- * the register.
- */
-static s32 ad525x_write(struct i2c_client *client, u8 reg, u8 value)
-{
-       struct dpot_data *data = i2c_get_clientdata(client);
-
-       /* Only write the instruction byte for certain commands */
-       if (reg & AD525X_I2C_CMD)
-               return i2c_smbus_write_byte(client, reg);
-
-       if (data->max_pos > 256)
-               return i2c_smbus_write_word_data(client, (reg & 0xF8) |
-                                               ((reg & 0x7) << 1), value);
-       else
-               /* All other registers require instruction + data bytes */
-               return i2c_smbus_write_byte_data(client, reg, value);
+inline void ad_dpot_remove_files(struct device *dev,
+               unsigned features, unsigned rdac)
+{
+       sysfs_remove_file(&dev->kobj,
+               dpot_attrib_wipers[rdac]);
+       if (features & F_CMD_EEP)
+               sysfs_remove_file(&dev->kobj,
+                       dpot_attrib_eeprom[rdac]);
+       if (features & F_CMD_TOL)
+               sysfs_remove_file(&dev->kobj,
+                       dpot_attrib_tolerance[rdac]);
+       if (features & F_CMD_OTP) {
+               sysfs_remove_file(&dev->kobj,
+                       dpot_attrib_otp_en[rdac]);
+               sysfs_remove_file(&dev->kobj,
+                       dpot_attrib_otp[rdac]);
+       }
 }
 
-static int ad525x_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+__devinit int ad_dpot_probe(struct device *dev,
+               struct ad_dpot_bus_data *bdata, const struct ad_dpot_id *id)
 {
-       struct device *dev = &client->dev;
-       struct dpot_data *data;
-       int err = 0;
 
-       dev_dbg(dev, "%s\n", __func__);
-
-       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
-               dev_err(dev, "missing I2C functionality for this driver\n");
-               goto exit;
-       }
+       struct dpot_data *data;
+       int i, err = 0;
 
        data = kzalloc(sizeof(struct dpot_data), GFP_KERNEL);
        if (!data) {
@@ -484,183 +613,74 @@ static int ad525x_probe(struct i2c_client *client,
                goto exit;
        }
 
-       i2c_set_clientdata(client, data);
+       dev_set_drvdata(dev, data);
        mutex_init(&data->update_lock);
 
-       switch (id->driver_data) {
-       case AD5258_ID:
-               data->max_pos = AD5258_MAX_POSITION;
-               err = sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC0]);
-               break;
-       case AD5259_ID:
-               data->max_pos = AD5259_MAX_POSITION;
-               err = sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC0]);
-               break;
-       case AD5251_ID:
-               data->max_pos = AD5251_MAX_POSITION;
-               err = sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC1]);
-               err |= sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC3]);
-               err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands);
-               break;
-       case AD5252_ID:
-               data->max_pos = AD5252_MAX_POSITION;
-               err = sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC1]);
-               err |= sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC3]);
-               err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands);
-               break;
-       case AD5253_ID:
-               data->max_pos = AD5253_MAX_POSITION;
-               err = sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC0]);
-               err |= sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC1]);
-               err |= sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC2]);
-               err |= sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC3]);
-               err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands);
-               break;
-       case AD5254_ID:
-               data->max_pos = AD5254_MAX_POSITION;
-               err = sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC0]);
-               err |= sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC1]);
-               err |= sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC2]);
-               err |= sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC3]);
-               err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands);
-               break;
-       case AD5255_ID:
-               data->max_pos = AD5255_MAX_POSITION;
-               err = sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC0]);
-               err |= sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC1]);
-               err |= sysfs_create_group(&dev->kobj,
-                                      &ad525x_group_wipers[AD525X_RDAC2]);
-               err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands);
-               break;
-       default:
-               err = -ENODEV;
-               goto exit_free;
-       }
+       data->bdata = *bdata;
+       data->devid = id->devid;
+
+       data->max_pos = 1 << DPOT_MAX_POS(data->devid);
+       data->rdac_mask = data->max_pos - 1;
+       data->feat = DPOT_FEAT(data->devid);
+       data->uid = DPOT_UID(data->devid);
+       data->wipers = DPOT_WIPERS(data->devid);
+
+       for (i = DPOT_RDAC0; i < MAX_RDACS; i++)
+               if (data->wipers & (1 << i)) {
+                       err = ad_dpot_add_files(dev, data->feat, i);
+                       if (err)
+                               goto exit_remove_files;
+                       /* power-up midscale */
+                       if (data->feat & F_RDACS_WONLY)
+                               data->rdac_cache[i] = data->max_pos / 2;
+               }
+
+       if (data->feat & F_CMD_INC)
+               err = sysfs_create_group(&dev->kobj, &ad525x_group_commands);
 
        if (err) {
                dev_err(dev, "failed to register sysfs hooks\n");
                goto exit_free;
        }
 
-       data->devid = id->driver_data;
-       data->rdac_mask = data->max_pos - 1;
-
        dev_info(dev, "%s %d-Position Digital Potentiometer registered\n",
                 id->name, data->max_pos);
 
        return 0;
 
+exit_remove_files:
+       for (i = DPOT_RDAC0; i < MAX_RDACS; i++)
+               if (data->wipers & (1 << i))
+                       ad_dpot_remove_files(dev, data->feat, i);
+
 exit_free:
        kfree(data);
-       i2c_set_clientdata(client, NULL);
+       dev_set_drvdata(dev, NULL);
 exit:
-       dev_err(dev, "failed to create client\n");
+       dev_err(dev, "failed to create client for %s ID 0x%lX\n",
+                       id->name, id->devid);
        return err;
 }
+EXPORT_SYMBOL(ad_dpot_probe);
 
-static int __devexit ad525x_remove(struct i2c_client *client)
+__devexit int ad_dpot_remove(struct device *dev)
 {
-       struct dpot_data *data = i2c_get_clientdata(client);
-       struct device *dev = &client->dev;
-
-       switch (data->devid) {
-       case AD5258_ID:
-       case AD5259_ID:
-               sysfs_remove_group(&dev->kobj,
-                                  &ad525x_group_wipers[AD525X_RDAC0]);
-               break;
-       case AD5251_ID:
-       case AD5252_ID:
-               sysfs_remove_group(&dev->kobj,
-                                  &ad525x_group_wipers[AD525X_RDAC1]);
-               sysfs_remove_group(&dev->kobj,
-                                  &ad525x_group_wipers[AD525X_RDAC3]);
-               sysfs_remove_group(&dev->kobj, &ad525x_group_commands);
-               break;
-       case AD5253_ID:
-       case AD5254_ID:
-               sysfs_remove_group(&dev->kobj,
-                                  &ad525x_group_wipers[AD525X_RDAC0]);
-               sysfs_remove_group(&dev->kobj,
-                                  &ad525x_group_wipers[AD525X_RDAC1]);
-               sysfs_remove_group(&dev->kobj,
-                                  &ad525x_group_wipers[AD525X_RDAC2]);
-               sysfs_remove_group(&dev->kobj,
-                                  &ad525x_group_wipers[AD525X_RDAC3]);
-               sysfs_remove_group(&dev->kobj, &ad525x_group_commands);
-               break;
-       case AD5255_ID:
-               sysfs_remove_group(&dev->kobj,
-                                  &ad525x_group_wipers[AD525X_RDAC0]);
-               sysfs_remove_group(&dev->kobj,
-                                  &ad525x_group_wipers[AD525X_RDAC1]);
-               sysfs_remove_group(&dev->kobj,
-                                  &ad525x_group_wipers[AD525X_RDAC2]);
-               sysfs_remove_group(&dev->kobj, &ad525x_group_commands);
-               break;
-       }
+       struct dpot_data *data = dev_get_drvdata(dev);
+       int i;
+
+       for (i = DPOT_RDAC0; i < MAX_RDACS; i++)
+               if (data->wipers & (1 << i))
+                       ad_dpot_remove_files(dev, data->feat, i);
 
-       i2c_set_clientdata(client, NULL);
        kfree(data);
 
        return 0;
 }
+EXPORT_SYMBOL(ad_dpot_remove);
 
-static const struct i2c_device_id ad525x_idtable[] = {
-       {"ad5258", AD5258_ID},
-       {"ad5259", AD5259_ID},
-       {"ad5251", AD5251_ID},
-       {"ad5252", AD5252_ID},
-       {"ad5253", AD5253_ID},
-       {"ad5254", AD5254_ID},
-       {"ad5255", AD5255_ID},
-       {}
-};
-
-MODULE_DEVICE_TABLE(i2c, ad525x_idtable);
-
-static struct i2c_driver ad525x_driver = {
-       .driver = {
-                  .owner = THIS_MODULE,
-                  .name = DRIVER_NAME,
-                  },
-       .id_table = ad525x_idtable,
-       .probe = ad525x_probe,
-       .remove = __devexit_p(ad525x_remove),
-};
-
-static int __init ad525x_init(void)
-{
-       return i2c_add_driver(&ad525x_driver);
-}
-
-module_init(ad525x_init);
-
-static void __exit ad525x_exit(void)
-{
-       i2c_del_driver(&ad525x_driver);
-}
-
-module_exit(ad525x_exit);
 
 MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>, "
-             "Michael Hennerich <hennerich@blackfin.uclinux.org>");
-MODULE_DESCRIPTION("AD5258/9 digital potentiometer driver");
+             "Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Digital potentiometer driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/misc/ad525x_dpot.h b/drivers/misc/ad525x_dpot.h
new file mode 100644 (file)
index 0000000..78b89fd
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Driver for the Analog Devices digital potentiometers
+ *
+ * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _AD_DPOT_H_
+#define _AD_DPOT_H_
+
+#include <linux/types.h>
+
+#define DPOT_CONF(features, wipers, max_pos, uid) \
+               (((features) << 18) | (((wipers) & 0xFF) << 10) | \
+               ((max_pos & 0xF) << 6) | (uid & 0x3F))
+
+#define DPOT_UID(conf)         (conf & 0x3F)
+#define DPOT_MAX_POS(conf)     ((conf >> 6) & 0xF)
+#define DPOT_WIPERS(conf)      ((conf >> 10) & 0xFF)
+#define DPOT_FEAT(conf)                (conf >> 18)
+
+#define BRDAC0                 (1 << 0)
+#define BRDAC1                 (1 << 1)
+#define BRDAC2                 (1 << 2)
+#define BRDAC3                 (1 << 3)
+#define BRDAC4                 (1 << 4)
+#define BRDAC5                 (1 << 5)
+#define MAX_RDACS              6
+
+#define F_CMD_INC              (1 << 0)        /* Features INC/DEC ALL, 6dB */
+#define F_CMD_EEP              (1 << 1)        /* Features EEPROM */
+#define F_CMD_OTP              (1 << 2)        /* Features OTP */
+#define F_CMD_TOL              (1 << 3)        /* RDACS feature Tolerance REG */
+#define F_RDACS_RW             (1 << 4)        /* RDACS are Read/Write  */
+#define F_RDACS_WONLY          (1 << 5)        /* RDACS are Write only */
+#define F_AD_APPDATA           (1 << 6)        /* RDAC Address append to data */
+#define F_SPI_8BIT             (1 << 7)        /* All SPI XFERS are 8-bit */
+#define F_SPI_16BIT            (1 << 8)        /* All SPI XFERS are 16-bit */
+#define F_SPI_24BIT            (1 << 9)        /* All SPI XFERS are 24-bit */
+
+#define F_RDACS_RW_TOL (F_RDACS_RW | F_CMD_EEP | F_CMD_TOL)
+#define F_RDACS_RW_EEP (F_RDACS_RW | F_CMD_EEP)
+#define F_SPI          (F_SPI_8BIT | F_SPI_16BIT | F_SPI_24BIT)
+
+enum dpot_devid {
+       AD5258_ID = DPOT_CONF(F_RDACS_RW_TOL, BRDAC0, 6, 0), /* I2C */
+       AD5259_ID = DPOT_CONF(F_RDACS_RW_TOL, BRDAC0, 8, 1),
+       AD5251_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
+                       BRDAC0 | BRDAC3, 6, 2),
+       AD5252_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
+                       BRDAC0 | BRDAC3, 8, 3),
+       AD5253_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
+                       BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 6, 4),
+       AD5254_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
+                       BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 8, 5),
+       AD5255_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
+                       BRDAC0 | BRDAC1 | BRDAC2, 9, 6),
+       AD5160_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
+                       BRDAC0, 8, 7), /* SPI */
+       AD5161_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
+                       BRDAC0, 8, 8),
+       AD5162_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
+                       BRDAC0 | BRDAC1, 8, 9),
+       AD5165_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
+                       BRDAC0, 8, 10),
+       AD5200_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
+                       BRDAC0, 8, 11),
+       AD5201_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
+                       BRDAC0, 5, 12),
+       AD5203_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
+                       BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 6, 13),
+       AD5204_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
+                       BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 8, 14),
+       AD5206_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
+                       BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3 | BRDAC4 | BRDAC5,
+                       8, 15),
+       AD5207_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
+                       BRDAC0 | BRDAC1, 8, 16),
+       AD5231_ID = DPOT_CONF(F_RDACS_RW_EEP | F_CMD_INC | F_SPI_24BIT,
+                       BRDAC0, 10, 17),
+       AD5232_ID = DPOT_CONF(F_RDACS_RW_EEP | F_CMD_INC | F_SPI_16BIT,
+                       BRDAC0 | BRDAC1, 8, 18),
+       AD5233_ID = DPOT_CONF(F_RDACS_RW_EEP | F_CMD_INC | F_SPI_16BIT,
+                       BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 6, 19),
+       AD5235_ID = DPOT_CONF(F_RDACS_RW_EEP | F_CMD_INC | F_SPI_24BIT,
+                       BRDAC0 | BRDAC1, 10, 20),
+       AD5260_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
+                       BRDAC0, 8, 21),
+       AD5262_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
+                       BRDAC0 | BRDAC1, 8, 22),
+       AD5263_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
+                       BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 8, 23),
+       AD5290_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
+                       BRDAC0, 8, 24),
+       AD5291_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 8, 25),
+       AD5292_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 10, 26),
+       AD5293_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 10, 27),
+       AD7376_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
+                       BRDAC0, 7, 28),
+       AD8400_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
+                       BRDAC0, 8, 29),
+       AD8402_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
+                       BRDAC0 | BRDAC1, 8, 30),
+       AD8403_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
+                       BRDAC0 | BRDAC1 | BRDAC2, 8, 31),
+       ADN2850_ID = DPOT_CONF(F_RDACS_RW_EEP | F_CMD_INC | F_SPI_24BIT,
+                       BRDAC0 | BRDAC1, 10, 32),
+       AD5241_ID = DPOT_CONF(F_RDACS_RW, BRDAC0, 8, 33),
+       AD5242_ID = DPOT_CONF(F_RDACS_RW, BRDAC0 | BRDAC1, 8, 34),
+       AD5243_ID = DPOT_CONF(F_RDACS_RW, BRDAC0 | BRDAC1, 8, 35),
+       AD5245_ID = DPOT_CONF(F_RDACS_RW, BRDAC0, 8, 36),
+       AD5246_ID = DPOT_CONF(F_RDACS_RW, BRDAC0, 7, 37),
+       AD5247_ID = DPOT_CONF(F_RDACS_RW, BRDAC0, 7, 38),
+       AD5248_ID = DPOT_CONF(F_RDACS_RW, BRDAC0 | BRDAC1, 8, 39),
+       AD5280_ID = DPOT_CONF(F_RDACS_RW, BRDAC0, 8, 40),
+       AD5282_ID = DPOT_CONF(F_RDACS_RW, BRDAC0 | BRDAC1, 8, 41),
+       ADN2860_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
+                       BRDAC0 | BRDAC1 | BRDAC2, 9, 42),
+       AD5273_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0, 6, 43),
+       AD5171_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0, 6, 44),
+       AD5170_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0, 8, 45),
+       AD5172_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0 | BRDAC1, 8, 46),
+       AD5173_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0 | BRDAC1, 8, 47),
+};
+
+#define DPOT_RDAC0             0
+#define DPOT_RDAC1             1
+#define DPOT_RDAC2             2
+#define DPOT_RDAC3             3
+#define DPOT_RDAC4             4
+#define DPOT_RDAC5             5
+
+#define DPOT_RDAC_MASK         0x1F
+
+#define DPOT_REG_TOL           0x18
+#define DPOT_TOL_RDAC0         (DPOT_REG_TOL | DPOT_RDAC0)
+#define DPOT_TOL_RDAC1         (DPOT_REG_TOL | DPOT_RDAC1)
+#define DPOT_TOL_RDAC2         (DPOT_REG_TOL | DPOT_RDAC2)
+#define DPOT_TOL_RDAC3         (DPOT_REG_TOL | DPOT_RDAC3)
+#define DPOT_TOL_RDAC4         (DPOT_REG_TOL | DPOT_RDAC4)
+#define DPOT_TOL_RDAC5         (DPOT_REG_TOL | DPOT_RDAC5)
+
+/* RDAC-to-EEPROM Interface Commands */
+#define DPOT_ADDR_RDAC         (0x0 << 5)
+#define DPOT_ADDR_EEPROM       (0x1 << 5)
+#define DPOT_ADDR_OTP          (0x1 << 6)
+#define DPOT_ADDR_CMD          (0x1 << 7)
+#define DPOT_ADDR_OTP_EN       (0x1 << 9)
+
+#define DPOT_DEC_ALL_6DB       (DPOT_ADDR_CMD | (0x4 << 3))
+#define DPOT_INC_ALL_6DB       (DPOT_ADDR_CMD | (0x9 << 3))
+#define DPOT_DEC_ALL           (DPOT_ADDR_CMD | (0x6 << 3))
+#define DPOT_INC_ALL           (DPOT_ADDR_CMD | (0xB << 3))
+
+#define DPOT_SPI_RDAC          0xB0
+#define DPOT_SPI_EEPROM                0x30
+#define DPOT_SPI_READ_RDAC     0xA0
+#define DPOT_SPI_READ_EEPROM   0x90
+#define DPOT_SPI_DEC_ALL_6DB   0x50
+#define DPOT_SPI_INC_ALL_6DB   0xD0
+#define DPOT_SPI_DEC_ALL       0x70
+#define DPOT_SPI_INC_ALL       0xF0
+
+/* AD5291/2/3 use special commands */
+#define DPOT_AD5291_RDAC       0x01
+#define DPOT_AD5291_READ_RDAC  0x02
+
+/* AD524x use special commands */
+#define DPOT_AD5291_RDAC_AB    0x80
+
+#define DPOT_AD5273_FUSE       0x80
+#define DPOT_AD5270_2_3_FUSE   0x20
+#define DPOT_AD5270_2_3_OW     0x08
+#define DPOT_AD5272_3_A0       0x08
+#define DPOT_AD5270_2FUSE      0x80
+
+struct dpot_data;
+
+struct ad_dpot_bus_ops {
+       int (*read_d8) (void *client);
+       int (*read_r8d8) (void *client, u8 reg);
+       int (*read_r8d16) (void *client, u8 reg);
+       int (*write_d8) (void *client, u8 val);
+       int (*write_r8d8) (void *client, u8 reg, u8 val);
+       int (*write_r8d16) (void *client, u8 reg, u16 val);
+};
+
+struct ad_dpot_bus_data {
+       void *client;
+       const struct ad_dpot_bus_ops *bops;
+};
+
+struct ad_dpot_id {
+       char *name;
+       unsigned long devid;
+};
+
+int ad_dpot_probe(struct device *dev, struct ad_dpot_bus_data *bdata, const struct ad_dpot_id *id);
+int ad_dpot_remove(struct device *dev);
+
+#endif
index a441aad..3b7ab20 100644 (file)
@@ -5162,13 +5162,6 @@ static void proc_SSID_on_close(struct inode *inode, struct file *file)
        enable_MAC(ai, 1);
 }
 
-static inline u8 hexVal(char c) {
-       if (c>='0' && c<='9') return c -= '0';
-       if (c>='a' && c<='f') return c -= 'a'-10;
-       if (c>='A' && c<='F') return c -= 'A'-10;
-       return 0;
-}
-
 static void proc_APList_on_close( struct inode *inode, struct file *file ) {
        struct proc_data *data = (struct proc_data *)file->private_data;
        struct proc_dir_entry *dp = PDE(inode);
@@ -5188,11 +5181,11 @@ static void proc_APList_on_close( struct inode *inode, struct file *file ) {
                        switch(j%3) {
                        case 0:
                                APList_rid.ap[i][j/3]=
-                                       hexVal(data->wbuffer[j+i*6*3])<<4;
+                                       hex_to_bin(data->wbuffer[j+i*6*3])<<4;
                                break;
                        case 1:
                                APList_rid.ap[i][j/3]|=
-                                       hexVal(data->wbuffer[j+i*6*3]);
+                                       hex_to_bin(data->wbuffer[j+i*6*3]);
                                break;
                        }
                }
@@ -5340,10 +5333,10 @@ static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
        for( i = 0; i < 16*3 && data->wbuffer[i+j]; i++ ) {
                switch(i%3) {
                case 0:
-                       key[i/3] = hexVal(data->wbuffer[i+j])<<4;
+                       key[i/3] = hex_to_bin(data->wbuffer[i+j])<<4;
                        break;
                case 1:
-                       key[i/3] |= hexVal(data->wbuffer[i+j]);
+                       key[i/3] |= hex_to_bin(data->wbuffer[i+j]);
                        break;
                }
        }
index 6a86cdf..9d30eeb 100644 (file)
@@ -179,14 +179,16 @@ static mode_t power_supply_attr_is_visible(struct kobject *kobj,
 {
        struct device *dev = container_of(kobj, struct device, kobj);
        struct power_supply *psy = dev_get_drvdata(dev);
+       mode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
        int i;
 
+       if (attrno == POWER_SUPPLY_PROP_TYPE)
+               return mode;
+
        for (i = 0; i < psy->num_properties; i++) {
                int property = psy->properties[i];
 
                if (property == attrno) {
-                       mode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
-
                        if (psy->property_is_writeable &&
                            psy->property_is_writeable(psy, property) > 0)
                                mode |= S_IWUSR;
index 50ac047..f159832 100644 (file)
@@ -640,7 +640,7 @@ config RTC_DRV_OMAP
 
 config RTC_DRV_S3C
        tristate "Samsung S3C series SoC RTC"
-       depends on ARCH_S3C2410
+       depends on ARCH_S3C2410 || ARCH_S3C64XX
        help
          RTC (Realtime Clock) driver for the clock inbuilt into the
          Samsung S3C24XX series of SoCs. This can provide periodic
index 96e8e70..11b8ea2 100644 (file)
@@ -719,6 +719,9 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
                }
        }
 
+       cmos_rtc.dev = dev;
+       dev_set_drvdata(dev, &cmos_rtc);
+
        cmos_rtc.rtc = rtc_device_register(driver_name, dev,
                                &cmos_rtc_ops, THIS_MODULE);
        if (IS_ERR(cmos_rtc.rtc)) {
@@ -726,8 +729,6 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
                goto cleanup0;
        }
 
-       cmos_rtc.dev = dev;
-       dev_set_drvdata(dev, &cmos_rtc);
        rename_region(ports, dev_name(&cmos_rtc.rtc->dev));
 
        spin_lock_irq(&rtc_lock);
index 532acf9..359d1e0 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/rtc.h>
 #include <linux/io.h>
 #include <linux/bcd.h>
-#include <asm/rtc.h>
 
 #define DRV_NAME       "rtc-ds1302"
 #define DRV_VERSION    "0.1.1"
 #define        RTC_ADDR_MIN    0x01            /* Address of minute register */
 #define        RTC_ADDR_SEC    0x00            /* Address of second register */
 
+#ifdef CONFIG_SH_SECUREEDGE5410
+#include <asm/rtc.h>
+#include <mach/snapgear.h>
+
 #define        RTC_RESET       0x1000
 #define        RTC_IODATA      0x0800
 #define        RTC_SCLK        0x0400
 
-#ifdef CONFIG_SH_SECUREEDGE5410
-#include <mach/snapgear.h>
 #define set_dp(x)      SECUREEDGE_WRITE_IOPORT(x, 0x1c00)
 #define get_dp()       SECUREEDGE_READ_IOPORT()
+#define ds1302_set_tx()
+#define ds1302_set_rx()
+
+static inline int ds1302_hw_init(void)
+{
+       return 0;
+}
+
+static inline void ds1302_reset(void)
+{
+       set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+}
+
+static inline void ds1302_clock(void)
+{
+       set_dp(get_dp() | RTC_SCLK);    /* clock high */
+       set_dp(get_dp() & ~RTC_SCLK);   /* clock low */
+}
+
+static inline void ds1302_start(void)
+{
+       set_dp(get_dp() | RTC_RESET);
+}
+
+static inline void ds1302_stop(void)
+{
+       set_dp(get_dp() & ~RTC_RESET);
+}
+
+static inline void ds1302_txbit(int bit)
+{
+       set_dp((get_dp() & ~RTC_IODATA) | (bit ? RTC_IODATA : 0));
+}
+
+static inline int ds1302_rxbit(void)
+{
+       return !!(get_dp() & RTC_IODATA);
+}
+
 #else
 #error "Add support for your platform"
 #endif
@@ -50,11 +90,11 @@ static void ds1302_sendbits(unsigned int val)
 {
        int i;
 
+       ds1302_set_tx();
+
        for (i = 8; (i); i--, val >>= 1) {
-               set_dp((get_dp() & ~RTC_IODATA) | ((val & 0x1) ?
-                       RTC_IODATA : 0));
-               set_dp(get_dp() | RTC_SCLK);    /* clock high */
-               set_dp(get_dp() & ~RTC_SCLK);   /* clock low */
+               ds1302_txbit(val & 0x1);
+               ds1302_clock();
        }
 }
 
@@ -63,10 +103,11 @@ static unsigned int ds1302_recvbits(void)
        unsigned int val;
        int i;
 
+       ds1302_set_rx();
+
        for (i = 0, val = 0; (i < 8); i++) {
-               val |= (((get_dp() & RTC_IODATA) ? 1 : 0) << i);
-               set_dp(get_dp() | RTC_SCLK);    /* clock high */
-               set_dp(get_dp() & ~RTC_SCLK);   /* clock low */
+               val |= (ds1302_rxbit() << i);
+               ds1302_clock();
        }
 
        return val;
@@ -76,23 +117,24 @@ static unsigned int ds1302_readbyte(unsigned int addr)
 {
        unsigned int val;
 
-       set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+       ds1302_reset();
 
-       set_dp(get_dp() | RTC_RESET);
+       ds1302_start();
        ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_READ);
        val = ds1302_recvbits();
-       set_dp(get_dp() & ~RTC_RESET);
+       ds1302_stop();
 
        return val;
 }
 
 static void ds1302_writebyte(unsigned int addr, unsigned int val)
 {
-       set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
-       set_dp(get_dp() | RTC_RESET);
+       ds1302_reset();
+
+       ds1302_start();
        ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_WRITE);
        ds1302_sendbits(val);
-       set_dp(get_dp() & ~RTC_RESET);
+       ds1302_stop();
 }
 
 static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm)
@@ -167,13 +209,20 @@ static int __init ds1302_rtc_probe(struct platform_device *pdev)
 {
        struct rtc_device *rtc;
 
+       if (ds1302_hw_init()) {
+               dev_err(&pdev->dev, "Failed to init communication channel");
+               return -EINVAL;
+       }
+
        /* Reset */
-       set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+       ds1302_reset();
 
        /* Write a magic value to the DS1302 RAM, and see if it sticks. */
        ds1302_writebyte(RTC_ADDR_RAM0, 0x42);
-       if (ds1302_readbyte(RTC_ADDR_RAM0) != 0x42)
+       if (ds1302_readbyte(RTC_ADDR_RAM0) != 0x42) {
+               dev_err(&pdev->dev, "Failed to probe");
                return -ENODEV;
+       }
 
        rtc = rtc_device_register("ds1302", &pdev->dev,
                                           &ds1302_rtc_ops, THIS_MODULE);
index 054e052..468200c 100644 (file)
@@ -462,39 +462,16 @@ isl1208_sysfs_store_usr(struct device *dev,
 static DEVICE_ATTR(usr, S_IRUGO | S_IWUSR, isl1208_sysfs_show_usr,
                   isl1208_sysfs_store_usr);
 
-static int
-isl1208_sysfs_register(struct device *dev)
-{
-       int err;
-
-       err = device_create_file(dev, &dev_attr_atrim);
-       if (err)
-               return err;
-
-       err = device_create_file(dev, &dev_attr_dtrim);
-       if (err) {
-               device_remove_file(dev, &dev_attr_atrim);
-               return err;
-       }
-
-       err = device_create_file(dev, &dev_attr_usr);
-       if (err) {
-               device_remove_file(dev, &dev_attr_atrim);
-               device_remove_file(dev, &dev_attr_dtrim);
-       }
-
-       return 0;
-}
-
-static int
-isl1208_sysfs_unregister(struct device *dev)
-{
-       device_remove_file(dev, &dev_attr_dtrim);
-       device_remove_file(dev, &dev_attr_atrim);
-       device_remove_file(dev, &dev_attr_usr);
+static struct attribute *isl1208_rtc_attrs[] = {
+       &dev_attr_atrim.attr,
+       &dev_attr_dtrim.attr,
+       &dev_attr_usr.attr,
+       NULL
+};
 
-       return 0;
-}
+static const struct attribute_group isl1208_rtc_sysfs_files = {
+       .attrs  = isl1208_rtc_attrs,
+};
 
 static int
 isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
@@ -529,7 +506,7 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
                dev_warn(&client->dev, "rtc power failure detected, "
                         "please set clock.\n");
 
-       rc = isl1208_sysfs_register(&client->dev);
+       rc = sysfs_create_group(&client->dev.kobj, &isl1208_rtc_sysfs_files);
        if (rc)
                goto exit_unregister;
 
@@ -546,7 +523,7 @@ isl1208_remove(struct i2c_client *client)
 {
        struct rtc_device *rtc = i2c_get_clientdata(client);
 
-       isl1208_sysfs_unregister(&client->dev);
+       sysfs_remove_group(&client->dev.kobj, &isl1208_rtc_sysfs_files);
        rtc_device_unregister(rtc);
 
        return 0;
index d71fe61..25ec921 100644 (file)
@@ -379,7 +379,6 @@ static struct rtc_class_ops mxc_rtc_ops = {
 
 static int __init mxc_rtc_probe(struct platform_device *pdev)
 {
-       struct clk *clk;
        struct resource *res;
        struct rtc_device *rtc;
        struct rtc_plat_data *pdata = NULL;
@@ -402,14 +401,15 @@ static int __init mxc_rtc_probe(struct platform_device *pdev)
        pdata->ioaddr = devm_ioremap(&pdev->dev, res->start,
                                     resource_size(res));
 
-       clk = clk_get(&pdev->dev, "ckil");
-       if (IS_ERR(clk)) {
-               ret = PTR_ERR(clk);
+       pdata->clk = clk_get(&pdev->dev, "rtc");
+       if (IS_ERR(pdata->clk)) {
+               dev_err(&pdev->dev, "unable to get clock!\n");
+               ret = PTR_ERR(pdata->clk);
                goto exit_free_pdata;
        }
 
-       rate = clk_get_rate(clk);
-       clk_put(clk);
+       clk_enable(pdata->clk);
+       rate = clk_get_rate(pdata->clk);
 
        if (rate == 32768)
                reg = RTC_INPUT_CLK_32768HZ;
@@ -420,7 +420,7 @@ static int __init mxc_rtc_probe(struct platform_device *pdev)
        else {
                dev_err(&pdev->dev, "rtc clock is not valid (%lu)\n", rate);
                ret = -EINVAL;
-               goto exit_free_pdata;
+               goto exit_put_clk;
        }
 
        reg |= RTC_ENABLE_BIT;
@@ -428,18 +428,9 @@ static int __init mxc_rtc_probe(struct platform_device *pdev)
        if (((readw(pdata->ioaddr + RTC_RTCCTL)) & RTC_ENABLE_BIT) == 0) {
                dev_err(&pdev->dev, "hardware module can't be enabled!\n");
                ret = -EIO;
-               goto exit_free_pdata;
-       }
-
-       pdata->clk = clk_get(&pdev->dev, "rtc");
-       if (IS_ERR(pdata->clk)) {
-               dev_err(&pdev->dev, "unable to get clock!\n");
-               ret = PTR_ERR(pdata->clk);
-               goto exit_free_pdata;
+               goto exit_put_clk;
        }
 
-       clk_enable(pdata->clk);
-
        rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops,
                                  THIS_MODULE);
        if (IS_ERR(rtc)) {
index 4969b60..e5972b2 100644 (file)
 #include <asm/irq.h>
 #include <plat/regs-rtc.h>
 
+enum s3c_cpu_type {
+       TYPE_S3C2410,
+       TYPE_S3C64XX,
+};
+
 /* I have yet to find an S3C implementation with more than one
  * of these rtc blocks in */
 
@@ -37,6 +42,7 @@ static struct resource *s3c_rtc_mem;
 static void __iomem *s3c_rtc_base;
 static int s3c_rtc_alarmno = NO_IRQ;
 static int s3c_rtc_tickno  = NO_IRQ;
+static enum s3c_cpu_type s3c_rtc_cpu_type;
 
 static DEFINE_SPINLOCK(s3c_rtc_pie_lock);
 
@@ -80,12 +86,25 @@ static int s3c_rtc_setpie(struct device *dev, int enabled)
        pr_debug("%s: pie=%d\n", __func__, enabled);
 
        spin_lock_irq(&s3c_rtc_pie_lock);
-       tmp = readb(s3c_rtc_base + S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE;
 
-       if (enabled)
-               tmp |= S3C2410_TICNT_ENABLE;
+       if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
+               tmp = readb(s3c_rtc_base + S3C2410_RTCCON);
+               tmp &= ~S3C64XX_RTCCON_TICEN;
+
+               if (enabled)
+                       tmp |= S3C64XX_RTCCON_TICEN;
+
+               writeb(tmp, s3c_rtc_base + S3C2410_RTCCON);
+       } else {
+               tmp = readb(s3c_rtc_base + S3C2410_TICNT);
+               tmp &= ~S3C2410_TICNT_ENABLE;
+
+               if (enabled)
+                       tmp |= S3C2410_TICNT_ENABLE;
+
+               writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
+       }
 
-       writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
        spin_unlock_irq(&s3c_rtc_pie_lock);
 
        return 0;
@@ -93,15 +112,21 @@ static int s3c_rtc_setpie(struct device *dev, int enabled)
 
 static int s3c_rtc_setfreq(struct device *dev, int freq)
 {
-       unsigned int tmp;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
+       unsigned int tmp = 0;
 
        if (!is_power_of_2(freq))
                return -EINVAL;
 
        spin_lock_irq(&s3c_rtc_pie_lock);
 
-       tmp = readb(s3c_rtc_base + S3C2410_TICNT) & S3C2410_TICNT_ENABLE;
-       tmp |= (128 / freq)-1;
+       if (s3c_rtc_cpu_type == TYPE_S3C2410) {
+               tmp = readb(s3c_rtc_base + S3C2410_TICNT);
+               tmp &= S3C2410_TICNT_ENABLE;
+       }
+
+       tmp |= (rtc_dev->max_user_freq / freq)-1;
 
        writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
        spin_unlock_irq(&s3c_rtc_pie_lock);
@@ -283,10 +308,17 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
 
 static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
 {
-       unsigned int ticnt = readb(s3c_rtc_base + S3C2410_TICNT);
+       unsigned int ticnt;
 
-       seq_printf(seq, "periodic_IRQ\t: %s\n",
-                    (ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" );
+       if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
+               ticnt = readb(s3c_rtc_base + S3C2410_RTCCON);
+               ticnt &= S3C64XX_RTCCON_TICEN;
+       } else {
+               ticnt = readb(s3c_rtc_base + S3C2410_TICNT);
+               ticnt &= S3C2410_TICNT_ENABLE;
+       }
+
+       seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt  ? "yes" : "no");
        return 0;
 }
 
@@ -353,10 +385,16 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en)
 
        if (!en) {
                tmp = readb(base + S3C2410_RTCCON);
-               writeb(tmp & ~S3C2410_RTCCON_RTCEN, base + S3C2410_RTCCON);
-
-               tmp = readb(base + S3C2410_TICNT);
-               writeb(tmp & ~S3C2410_TICNT_ENABLE, base + S3C2410_TICNT);
+               if (s3c_rtc_cpu_type == TYPE_S3C64XX)
+                       tmp &= ~S3C64XX_RTCCON_TICEN;
+               tmp &= ~S3C2410_RTCCON_RTCEN;
+               writeb(tmp, base + S3C2410_RTCCON);
+
+               if (s3c_rtc_cpu_type == TYPE_S3C2410) {
+                       tmp = readb(base + S3C2410_TICNT);
+                       tmp &= ~S3C2410_TICNT_ENABLE;
+                       writeb(tmp, base + S3C2410_TICNT);
+               }
        } else {
                /* re-enable the device, and check it is ok */
 
@@ -472,7 +510,12 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
                goto err_nortc;
        }
 
-       rtc->max_user_freq = 128;
+       if (s3c_rtc_cpu_type == TYPE_S3C64XX)
+               rtc->max_user_freq = 32768;
+       else
+               rtc->max_user_freq = 128;
+
+       s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data;
 
        platform_set_drvdata(pdev, rtc);
        return 0;
@@ -492,20 +535,30 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
 
 /* RTC Power management control */
 
-static int ticnt_save;
+static int ticnt_save, ticnt_en_save;
 
 static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
 {
        /* save TICNT for anyone using periodic interrupts */
        ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
+       if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
+               ticnt_en_save = readb(s3c_rtc_base + S3C2410_RTCCON);
+               ticnt_en_save &= S3C64XX_RTCCON_TICEN;
+       }
        s3c_rtc_enable(pdev, 0);
        return 0;
 }
 
 static int s3c_rtc_resume(struct platform_device *pdev)
 {
+       unsigned int tmp;
+
        s3c_rtc_enable(pdev, 1);
        writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
+       if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) {
+               tmp = readb(s3c_rtc_base + S3C2410_RTCCON);
+               writeb(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON);
+       }
        return 0;
 }
 #else
@@ -513,13 +566,27 @@ static int s3c_rtc_resume(struct platform_device *pdev)
 #define s3c_rtc_resume  NULL
 #endif
 
-static struct platform_driver s3c2410_rtc_driver = {
+static struct platform_device_id s3c_rtc_driver_ids[] = {
+       {
+               .name           = "s3c2410-rtc",
+               .driver_data    = TYPE_S3C2410,
+       }, {
+               .name           = "s3c64xx-rtc",
+               .driver_data    = TYPE_S3C64XX,
+       },
+       { }
+};
+
+MODULE_DEVICE_TABLE(platform, s3c_rtc_driver_ids);
+
+static struct platform_driver s3c_rtc_driver = {
        .probe          = s3c_rtc_probe,
        .remove         = __devexit_p(s3c_rtc_remove),
        .suspend        = s3c_rtc_suspend,
        .resume         = s3c_rtc_resume,
+       .id_table       = s3c_rtc_driver_ids,
        .driver         = {
-               .name   = "s3c2410-rtc",
+               .name   = "s3c-rtc",
                .owner  = THIS_MODULE,
        },
 };
@@ -529,12 +596,12 @@ static char __initdata banner[] = "S3C24XX RTC, (c) 2004,2006 Simtec Electronics
 static int __init s3c_rtc_init(void)
 {
        printk(banner);
-       return platform_driver_register(&s3c2410_rtc_driver);
+       return platform_driver_register(&s3c_rtc_driver);
 }
 
 static void __exit s3c_rtc_exit(void)
 {
-       platform_driver_unregister(&s3c2410_rtc_driver);
+       platform_driver_unregister(&s3c_rtc_driver);
 }
 
 module_init(s3c_rtc_init);
index b16cfe5..82931dc 100644 (file)
@@ -449,17 +449,17 @@ static int wm831x_rtc_probe(struct platform_device *pdev)
                goto err;
        }
 
-       ret = wm831x_request_irq(wm831x, per_irq, wm831x_per_irq,
-                                IRQF_TRIGGER_RISING, "wm831x_rtc_per",
-                                wm831x_rtc);
+       ret = request_threaded_irq(per_irq, NULL, wm831x_per_irq,
+                                  IRQF_TRIGGER_RISING, "RTC period",
+                                  wm831x_rtc);
        if (ret != 0) {
                dev_err(&pdev->dev, "Failed to request periodic IRQ %d: %d\n",
                        per_irq, ret);
        }
 
-       ret = wm831x_request_irq(wm831x, alm_irq, wm831x_alm_irq,
-                                IRQF_TRIGGER_RISING, "wm831x_rtc_alm",
-                                wm831x_rtc);
+       ret = request_threaded_irq(alm_irq, NULL, wm831x_alm_irq,
+                                  IRQF_TRIGGER_RISING, "RTC alarm",
+                                  wm831x_rtc);
        if (ret != 0) {
                dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n",
                        alm_irq, ret);
@@ -478,8 +478,8 @@ static int __devexit wm831x_rtc_remove(struct platform_device *pdev)
        int per_irq = platform_get_irq_byname(pdev, "PER");
        int alm_irq = platform_get_irq_byname(pdev, "ALM");
 
-       wm831x_free_irq(wm831x_rtc->wm831x, alm_irq, wm831x_rtc);
-       wm831x_free_irq(wm831x_rtc->wm831x, per_irq, wm831x_rtc);
+       free_irq(alm_irq, wm831x_rtc);
+       free_irq(per_irq, wm831x_rtc);
        rtc_device_unregister(wm831x_rtc->rtc);
        kfree(wm831x_rtc);
 
index 9276121..44a0759 100644 (file)
@@ -688,7 +688,7 @@ static int fcoe_shost_config(struct fc_lport *lport, struct device *dev)
        }
 
        if (!lport->vport)
-               fc_host_max_npiv_vports(lport->host) = USHORT_MAX;
+               fc_host_max_npiv_vports(lport->host) = USHRT_MAX;
 
        snprintf(fc_host_symbolic_name(lport->host), FC_SYMBOLIC_NAME_SIZE,
                 "%s v%s over %s", FCOE_NAME, FCOE_VERSION,
index b830d61..0ec1ed3 100644 (file)
@@ -3757,7 +3757,7 @@ _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
                if (ioc->config_cmds.status & MPT2_CMD_PENDING) {
                        ioc->config_cmds.status |= MPT2_CMD_RESET;
                        mpt2sas_base_free_smid(ioc, ioc->config_cmds.smid);
-                       ioc->config_cmds.smid = USHORT_MAX;
+                       ioc->config_cmds.smid = USHRT_MAX;
                        complete(&ioc->config_cmds.done);
                }
                break;
index e762dd3..c654429 100644 (file)
@@ -258,7 +258,7 @@ mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
 #ifdef CONFIG_SCSI_MPT2SAS_LOGGING
        _config_display_some_debug(ioc, smid, "config_done", mpi_reply);
 #endif
-       ioc->config_cmds.smid = USHORT_MAX;
+       ioc->config_cmds.smid = USHRT_MAX;
        complete(&ioc->config_cmds.done);
        return 1;
 }
index 78ed24b..3046386 100644 (file)
@@ -1437,7 +1437,7 @@ int m68328_console_setup(struct console *cp, char *arg)
        for (i = 0; i < ARRAY_SIZE(baud_table); i++)
                if (baud_table[i] == n)
                        break;
-       if (i < BAUD_TABLE_SIZE) {
+       if (i < ARRAY_SIZE(baud_table)) {
                m68328_console_baud = n;
                m68328_console_cbaud = 0;
                if (i > 15) {
index 21a95ff..a090385 100644 (file)
@@ -2810,17 +2810,6 @@ void UserCfgInit(struct rt_rtmp_adapter *pAd)
 }
 
 /* IRQL = PASSIVE_LEVEL */
-u8 BtoH(char ch)
-{
-       if (ch >= '0' && ch <= '9')
-               return (ch - '0');      /* Handle numerals */
-       if (ch >= 'A' && ch <= 'F')
-               return (ch - 'A' + 0xA);        /* Handle capitol hex digits */
-       if (ch >= 'a' && ch <= 'f')
-               return (ch - 'a' + 0xA);        /* Handle small hex digits */
-       return (255);
-}
-
 /* */
 /*  FUNCTION: AtoH(char *, u8 *, int) */
 /* */
@@ -2847,8 +2836,8 @@ void AtoH(char *src, u8 *dest, int destlen)
        destTemp = (u8 *)dest;
 
        while (destlen--) {
-               *destTemp = BtoH(*srcptr++) << 4;       /* Put 1st ascii byte in upper nibble. */
-               *destTemp += BtoH(*srcptr++);   /* Add 2nd ascii byte to above. */
+               *destTemp = hex_to_bin(*srcptr++) << 4; /* Put 1st ascii byte in upper nibble. */
+               *destTemp += hex_to_bin(*srcptr++);     /* Add 2nd ascii byte to above. */
                destTemp++;
        }
 }
index ab525ee..82b6e78 100644 (file)
@@ -2356,8 +2356,6 @@ void RTMPMoveMemory(void *pDest, void *pSrc, unsigned long Length);
 
 void AtoH(char *src, u8 *dest, int destlen);
 
-u8 BtoH(char ch);
-
 void RTMPPatchMacBbpBug(struct rt_rtmp_adapter *pAd);
 
 void RTMPInitTimer(struct rt_rtmp_adapter *pAd,
index 1e9ba4b..1335456 100644 (file)
@@ -127,8 +127,6 @@ MODULE_PARM_DESC(ModemOption, "default: 0x10,0x00,0x00,0x00,0x20");
 #define ENDPOINT_ISOC_DATA     0x07
 #define ENDPOINT_FIRMWARE      0x05
 
-#define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) )
-
 struct speedtch_params {
        unsigned int altsetting;
        unsigned int BMaxDSL;
@@ -669,7 +667,8 @@ static int speedtch_atm_start(struct usbatm_data *usbatm, struct atm_dev *atm_de
        memset(atm_dev->esi, 0, sizeof(atm_dev->esi));
        if (usb_string(usb_dev, usb_dev->descriptor.iSerialNumber, mac_str, sizeof(mac_str)) == 12) {
                for (i = 0; i < 6; i++)
-                       atm_dev->esi[i] = (hex2int(mac_str[i * 2]) * 16) + (hex2int(mac_str[i * 2 + 1]));
+                       atm_dev->esi[i] = (hex_to_bin(mac_str[i * 2]) << 4) +
+                               hex_to_bin(mac_str[i * 2 + 1]);
        }
 
        /* Start modem synchronisation */
index 750effe..c6fb8e9 100644 (file)
@@ -806,7 +806,7 @@ static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq,
        count = indirect->len / sizeof desc;
        /* Buffers are chained via a 16 bit next field, so
         * we can have at most 2^16 of these. */
-       if (count > USHORT_MAX + 1) {
+       if (count > USHRT_MAX + 1) {
                vq_err(vq, "Indirect buffer length too big: %d\n",
                       indirect->len);
                return -E2BIG;
index 8d406fb..f3d7440 100644 (file)
@@ -80,7 +80,7 @@ struct arcfb_par {
        spinlock_t lock;
 };
 
-static struct fb_fix_screeninfo arcfb_fix __initdata = {
+static struct fb_fix_screeninfo arcfb_fix __devinitdata = {
        .id =           "arcfb",
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_MONO01,
@@ -90,7 +90,7 @@ static struct fb_fix_screeninfo arcfb_fix __initdata = {
        .accel =        FB_ACCEL_NONE,
 };
 
-static struct fb_var_screeninfo arcfb_var __initdata = {
+static struct fb_var_screeninfo arcfb_var __devinitdata = {
        .xres           = 128,
        .yres           = 64,
        .xres_virtual   = 128,
@@ -588,7 +588,7 @@ err:
        return retval;
 }
 
-static int arcfb_remove(struct platform_device *dev)
+static int __devexit arcfb_remove(struct platform_device *dev)
 {
        struct fb_info *info = platform_get_drvdata(dev);
 
@@ -602,7 +602,7 @@ static int arcfb_remove(struct platform_device *dev)
 
 static struct platform_driver arcfb_driver = {
        .probe  = arcfb_probe,
-       .remove = arcfb_remove,
+       .remove = __devexit_p(arcfb_remove),
        .driver = {
                .name   = "arcfb",
        },
index 29d7285..f8d69ad 100644 (file)
@@ -1820,10 +1820,6 @@ struct atyclk {
 #define ATYIO_FEATW            0x41545903      /* ATY\03 */
 #endif
 
-#ifndef FBIO_WAITFORVSYNC
-#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
-#endif
-
 static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
 {
        struct atyfb_par *par = (struct atyfb_par *) info->par;
index 2baac7c..c8e1f04 100644 (file)
 #define LCD_X_RES              320     /* Horizontal Resolution */
 #define LCD_Y_RES              240     /* Vertical Resolution */
 #define        DMA_BUS_SIZE            16
+#define U_LINE                 4       /* Blanking Lines */
 
-#define USE_RGB565_16_BIT_PPI
-
-#ifdef USE_RGB565_16_BIT_PPI
-#define LCD_BPP                16      /* Bit Per Pixel */
-#define CLOCKS_PER_PIX 1
-#define CPLD_PIPELINE_DELAY_COR 0      /* NO CPLB */
-#endif
 
 /* Interface 16/18-bit TFT over an 8-bit wide PPI using a small Programmable Logic Device (CPLD)
  * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165
  */
 
-#ifdef USE_RGB565_8_BIT_PPI
-#define LCD_BPP                16      /* Bit Per Pixel */
-#define CLOCKS_PER_PIX 2
-#define CPLD_PIPELINE_DELAY_COR 3      /* RGB565 */
-#endif
-
-#ifdef USE_RGB888_8_BIT_PPI
-#define LCD_BPP                24      /* Bit Per Pixel */
-#define CLOCKS_PER_PIX 3
-#define CPLD_PIPELINE_DELAY_COR 5      /* RGB888 */
-#endif
-
-       /*
-        * HS and VS timing parameters (all in number of PPI clk ticks)
-        */
-
-#define U_LINE         4                               /* Blanking Lines */
-
-#define H_ACTPIX       (LCD_X_RES * CLOCKS_PER_PIX)    /* active horizontal pixel */
-#define H_PERIOD       (336 * CLOCKS_PER_PIX)          /* HS period */
-#define H_PULSE                (2 * CLOCKS_PER_PIX)                            /* HS pulse width */
-#define H_START                (7 * CLOCKS_PER_PIX + CPLD_PIPELINE_DELAY_COR)  /* first valid pixel */
-
-#define        V_LINES         (LCD_Y_RES + U_LINE)            /* total vertical lines */
-#define V_PULSE                (2 * CLOCKS_PER_PIX)            /* VS pulse width (1-5 H_PERIODs) */
-#define V_PERIOD       (H_PERIOD * V_LINES)            /* VS period */
-
-#define ACTIVE_VIDEO_MEM_OFFSET                ((U_LINE / 2) * LCD_X_RES * (LCD_BPP / 8))
 
 #define BFIN_LCD_NBR_PALETTE_ENTRIES   256
 
 #define PPI_PORT_CFG_01                        0x10
 #define PPI_POLS_1                     0x8000
 
-#if (CLOCKS_PER_PIX > 1)
-#define PPI_PMODE (DLEN_8 | PACK_EN)
-#else
-#define PPI_PMODE (DLEN_16)
-#endif
-
 #define LQ035_INDEX                    0x74
 #define LQ035_DATA                     0x76
 
@@ -139,6 +99,15 @@ struct bfin_lq035q1fb_info {
        int irq;
        spinlock_t lock;        /* lock */
        u32 pseudo_pal[16];
+
+       u32 lcd_bpp;
+       u32 h_actpix;
+       u32 h_period;
+       u32 h_pulse;
+       u32 h_start;
+       u32 v_lines;
+       u32 v_pulse;
+       u32 v_period;
 };
 
 static int nocursor;
@@ -234,16 +203,69 @@ static int lq035q1_backlight(struct bfin_lq035q1fb_info *info, unsigned arg)
        return 0;
 }
 
+static int bfin_lq035q1_calc_timing(struct bfin_lq035q1fb_info *fbi)
+{
+       unsigned long clocks_per_pix, cpld_pipeline_delay_cor;
+
+       /*
+        * Interface 16/18-bit TFT over an 8-bit wide PPI using a small
+        * Programmable Logic Device (CPLD)
+        * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165
+        */
+
+       switch (fbi->disp_info->ppi_mode) {
+       case USE_RGB565_16_BIT_PPI:
+               fbi->lcd_bpp = 16;
+               clocks_per_pix = 1;
+               cpld_pipeline_delay_cor = 0;
+               break;
+       case USE_RGB565_8_BIT_PPI:
+               fbi->lcd_bpp = 16;
+               clocks_per_pix = 2;
+               cpld_pipeline_delay_cor = 3;
+               break;
+       case USE_RGB888_8_BIT_PPI:
+               fbi->lcd_bpp = 24;
+               clocks_per_pix = 3;
+               cpld_pipeline_delay_cor = 5;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /*
+        * HS and VS timing parameters (all in number of PPI clk ticks)
+        */
+
+       fbi->h_actpix = (LCD_X_RES * clocks_per_pix);   /* active horizontal pixel */
+       fbi->h_period = (336 * clocks_per_pix);         /* HS period */
+       fbi->h_pulse = (2 * clocks_per_pix);                            /* HS pulse width */
+       fbi->h_start = (7 * clocks_per_pix + cpld_pipeline_delay_cor);  /* first valid pixel */
+
+       fbi->v_lines = (LCD_Y_RES + U_LINE);            /* total vertical lines */
+       fbi->v_pulse = (2 * clocks_per_pix);            /* VS pulse width (1-5 H_PERIODs) */
+       fbi->v_period = (fbi->h_period * fbi->v_lines); /* VS period */
+
+       return 0;
+}
+
 static void bfin_lq035q1_config_ppi(struct bfin_lq035q1fb_info *fbi)
 {
-       bfin_write_PPI_DELAY(H_START);
-       bfin_write_PPI_COUNT(H_ACTPIX - 1);
-       bfin_write_PPI_FRAME(V_LINES);
+       unsigned ppi_pmode;
+
+       if (fbi->disp_info->ppi_mode == USE_RGB565_16_BIT_PPI)
+               ppi_pmode = DLEN_16;
+       else
+               ppi_pmode = (DLEN_8 | PACK_EN);
+
+       bfin_write_PPI_DELAY(fbi->h_start);
+       bfin_write_PPI_COUNT(fbi->h_actpix - 1);
+       bfin_write_PPI_FRAME(fbi->v_lines);
 
        bfin_write_PPI_CONTROL(PPI_TX_MODE |       /* output mode , PORT_DIR */
                                PPI_XFER_TYPE_11 | /* sync mode XFR_TYPE */
                                PPI_PORT_CFG_01 |  /* two frame sync PORT_CFG */
-                               PPI_PMODE |        /* 8/16 bit data length / PACK_EN? */
+                               ppi_pmode |        /* 8/16 bit data length / PACK_EN? */
                                PPI_POLS_1);       /* faling edge syncs POLS */
 }
 
@@ -272,19 +294,19 @@ static void bfin_lq035q1_stop_timers(void)
 
 }
 
-static void bfin_lq035q1_init_timers(void)
+static void bfin_lq035q1_init_timers(struct bfin_lq035q1fb_info *fbi)
 {
 
        bfin_lq035q1_stop_timers();
 
-       set_gptimer_period(TIMER_HSYNC_id, H_PERIOD);
-       set_gptimer_pwidth(TIMER_HSYNC_id, H_PULSE);
+       set_gptimer_period(TIMER_HSYNC_id, fbi->h_period);
+       set_gptimer_pwidth(TIMER_HSYNC_id, fbi->h_pulse);
        set_gptimer_config(TIMER_HSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT |
                                      TIMER_TIN_SEL | TIMER_CLK_SEL|
                                      TIMER_EMU_RUN);
 
-       set_gptimer_period(TIMER_VSYNC_id, V_PERIOD);
-       set_gptimer_pwidth(TIMER_VSYNC_id, V_PULSE);
+       set_gptimer_period(TIMER_VSYNC_id, fbi->v_period);
+       set_gptimer_pwidth(TIMER_VSYNC_id, fbi->v_pulse);
        set_gptimer_config(TIMER_VSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT |
                                      TIMER_TIN_SEL | TIMER_CLK_SEL |
                                      TIMER_EMU_RUN);
@@ -294,21 +316,21 @@ static void bfin_lq035q1_init_timers(void)
 static void bfin_lq035q1_config_dma(struct bfin_lq035q1fb_info *fbi)
 {
 
+
        set_dma_config(CH_PPI,
                       set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO,
                                           INTR_DISABLE, DIMENSION_2D,
                                           DATA_SIZE_16,
                                           DMA_NOSYNC_KEEP_DMA_BUF));
-       set_dma_x_count(CH_PPI, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE);
+       set_dma_x_count(CH_PPI, (LCD_X_RES * fbi->lcd_bpp) / DMA_BUS_SIZE);
        set_dma_x_modify(CH_PPI, DMA_BUS_SIZE / 8);
-       set_dma_y_count(CH_PPI, V_LINES);
+       set_dma_y_count(CH_PPI, fbi->v_lines);
 
        set_dma_y_modify(CH_PPI, DMA_BUS_SIZE / 8);
        set_dma_start_addr(CH_PPI, (unsigned long)fbi->fb_buffer);
 
 }
 
-#if (CLOCKS_PER_PIX == 1)
 static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
                            P_PPI0_D0, P_PPI0_D1, P_PPI0_D2,
                            P_PPI0_D3, P_PPI0_D4, P_PPI0_D5,
@@ -316,22 +338,27 @@ static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
                            P_PPI0_D9, P_PPI0_D10, P_PPI0_D11,
                            P_PPI0_D12, P_PPI0_D13, P_PPI0_D14,
                            P_PPI0_D15, 0};
-#else
-static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
+
+static const u16 ppi0_req_8[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
                            P_PPI0_D0, P_PPI0_D1, P_PPI0_D2,
                            P_PPI0_D3, P_PPI0_D4, P_PPI0_D5,
                            P_PPI0_D6, P_PPI0_D7, 0};
-#endif
 
-static inline void bfin_lq035q1_free_ports(void)
+static inline void bfin_lq035q1_free_ports(unsigned ppi16)
 {
-       peripheral_free_list(ppi0_req_16);
+       if (ppi16)
+               peripheral_free_list(ppi0_req_16);
+       else
+               peripheral_free_list(ppi0_req_8);
+
        if (ANOMALY_05000400)
                gpio_free(P_IDENT(P_PPI0_FS3));
 }
 
-static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev)
+static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev,
+                                               unsigned ppi16)
 {
+       int ret;
        /* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode:
         * Drive PPI_FS3 Low
         */
@@ -342,7 +369,12 @@ static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev)
                gpio_direction_output(P_IDENT(P_PPI0_FS3), 0);
        }
 
-       if (peripheral_request_list(ppi0_req_16, DRIVER_NAME)) {
+       if (ppi16)
+               ret = peripheral_request_list(ppi0_req_16, DRIVER_NAME);
+       else
+               ret = peripheral_request_list(ppi0_req_8, DRIVER_NAME);
+
+       if (ret) {
                dev_err(&pdev->dev, "requesting peripherals failed\n");
                return -EFAULT;
        }
@@ -364,7 +396,7 @@ static int bfin_lq035q1_fb_open(struct fb_info *info, int user)
 
                bfin_lq035q1_config_dma(fbi);
                bfin_lq035q1_config_ppi(fbi);
-               bfin_lq035q1_init_timers();
+               bfin_lq035q1_init_timers(fbi);
 
                /* start dma */
                enable_dma(CH_PPI);
@@ -402,12 +434,9 @@ static int bfin_lq035q1_fb_release(struct fb_info *info, int user)
 static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var,
                                     struct fb_info *info)
 {
-       switch (var->bits_per_pixel) {
-#if (LCD_BPP == 24)
-       case 24:/* TRUECOLOUR, 16m */
-#else
-       case 16:/* DIRECTCOLOUR, 64k */
-#endif
+       struct bfin_lq035q1fb_info *fbi = info->par;
+
+       if (var->bits_per_pixel == fbi->lcd_bpp) {
                var->red.offset = info->var.red.offset;
                var->green.offset = info->var.green.offset;
                var->blue.offset = info->var.blue.offset;
@@ -420,8 +449,7 @@ static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var,
                var->red.msb_right = 0;
                var->green.msb_right = 0;
                var->blue.msb_right = 0;
-               break;
-       default:
+       } else {
                pr_debug("%s: depth not supported: %u BPP\n", __func__,
                         var->bits_per_pixel);
                return -EINVAL;
@@ -528,6 +556,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
 {
        struct bfin_lq035q1fb_info *info;
        struct fb_info *fbinfo;
+       u32 active_video_mem_offset;
        int ret;
 
        ret = request_dma(CH_PPI, DRIVER_NAME"_CH_PPI");
@@ -550,6 +579,12 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, fbinfo);
 
+       ret = bfin_lq035q1_calc_timing(info);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed PPI Mode\n");
+               goto out3;
+       }
+
        strcpy(fbinfo->fix.id, DRIVER_NAME);
 
        fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
@@ -571,46 +606,48 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
        fbinfo->var.xres_virtual = LCD_X_RES;
        fbinfo->var.yres = LCD_Y_RES;
        fbinfo->var.yres_virtual = LCD_Y_RES;
-       fbinfo->var.bits_per_pixel = LCD_BPP;
+       fbinfo->var.bits_per_pixel = info->lcd_bpp;
 
        if (info->disp_info->mode & LQ035_BGR) {
-#if (LCD_BPP == 24)
-               fbinfo->var.red.offset = 0;
-               fbinfo->var.green.offset = 8;
-               fbinfo->var.blue.offset = 16;
-#else
-               fbinfo->var.red.offset = 0;
-               fbinfo->var.green.offset = 5;
-               fbinfo->var.blue.offset = 11;
-#endif
+               if (info->lcd_bpp == 24) {
+                       fbinfo->var.red.offset = 0;
+                       fbinfo->var.green.offset = 8;
+                       fbinfo->var.blue.offset = 16;
+               } else {
+                       fbinfo->var.red.offset = 0;
+                       fbinfo->var.green.offset = 5;
+                       fbinfo->var.blue.offset = 11;
+               }
        } else {
-#if (LCD_BPP == 24)
-               fbinfo->var.red.offset = 16;
-               fbinfo->var.green.offset = 8;
-               fbinfo->var.blue.offset = 0;
-#else
-               fbinfo->var.red.offset = 11;
-               fbinfo->var.green.offset = 5;
-               fbinfo->var.blue.offset = 0;
-#endif
+               if (info->lcd_bpp == 24) {
+                       fbinfo->var.red.offset = 16;
+                       fbinfo->var.green.offset = 8;
+                       fbinfo->var.blue.offset = 0;
+               } else {
+                       fbinfo->var.red.offset = 11;
+                       fbinfo->var.green.offset = 5;
+                       fbinfo->var.blue.offset = 0;
+               }
        }
 
        fbinfo->var.transp.offset = 0;
 
-#if (LCD_BPP == 24)
-       fbinfo->var.red.length = 8;
-       fbinfo->var.green.length = 8;
-       fbinfo->var.blue.length = 8;
-#else
-       fbinfo->var.red.length = 5;
-       fbinfo->var.green.length = 6;
-       fbinfo->var.blue.length = 5;
-#endif
+       if (info->lcd_bpp == 24) {
+               fbinfo->var.red.length = 8;
+               fbinfo->var.green.length = 8;
+               fbinfo->var.blue.length = 8;
+       } else {
+               fbinfo->var.red.length = 5;
+               fbinfo->var.green.length = 6;
+               fbinfo->var.blue.length = 5;
+       }
 
        fbinfo->var.transp.length = 0;
 
-       fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * LCD_BPP / 8
-                               + ACTIVE_VIDEO_MEM_OFFSET;
+       active_video_mem_offset = ((U_LINE / 2) * LCD_X_RES * (info->lcd_bpp / 8));
+
+       fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * info->lcd_bpp / 8
+                               + active_video_mem_offset;
 
        fbinfo->fix.line_length = fbinfo->var.xres_virtual *
            fbinfo->var.bits_per_pixel / 8;
@@ -629,8 +666,8 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
                goto out3;
        }
 
-       fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET;
-       fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET;
+       fbinfo->screen_base = (void *)info->fb_buffer + active_video_mem_offset;
+       fbinfo->fix.smem_start = (int)info->fb_buffer + active_video_mem_offset;
 
        fbinfo->fbops = &bfin_lq035q1_fb_ops;
 
@@ -643,7 +680,8 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
                goto out4;
        }
 
-       ret = bfin_lq035q1_request_ports(pdev);
+       ret = bfin_lq035q1_request_ports(pdev,
+                       info->disp_info->ppi_mode == USE_RGB565_16_BIT_PPI);
        if (ret) {
                dev_err(&pdev->dev, "couldn't request gpio port\n");
                goto out6;
@@ -693,7 +731,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
        }
 
        dev_info(&pdev->dev, "%dx%d %d-bit RGB FrameBuffer initialized\n",
-               LCD_X_RES, LCD_Y_RES, LCD_BPP);
+               LCD_X_RES, LCD_Y_RES, info->lcd_bpp);
 
        return 0;
 
@@ -705,7 +743,8 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
  out8:
        free_irq(info->irq, info);
  out7:
-       bfin_lq035q1_free_ports();
+       bfin_lq035q1_free_ports(info->disp_info->ppi_mode ==
+                               USE_RGB565_16_BIT_PPI);
  out6:
        fb_dealloc_cmap(&fbinfo->cmap);
  out4:
@@ -742,7 +781,8 @@ static int __devexit bfin_lq035q1_remove(struct platform_device *pdev)
 
        fb_dealloc_cmap(&fbinfo->cmap);
 
-       bfin_lq035q1_free_ports();
+       bfin_lq035q1_free_ports(info->disp_info->ppi_mode ==
+                               USE_RGB565_16_BIT_PPI);
 
        platform_set_drvdata(pdev, NULL);
        framebuffer_release(fbinfo);
@@ -781,7 +821,7 @@ static int bfin_lq035q1_resume(struct device *dev)
 
                bfin_lq035q1_config_dma(info);
                bfin_lq035q1_config_ppi(info);
-               bfin_lq035q1_init_timers();
+               bfin_lq035q1_init_timers(info);
 
                /* start dma */
                enable_dma(CH_PPI);
index 8d244ba..cad7d45 100644 (file)
@@ -36,7 +36,9 @@
 #define DRIVER_NAME "da8xx_lcdc"
 
 /* LCD Status Register */
+#define LCD_END_OF_FRAME1              BIT(9)
 #define LCD_END_OF_FRAME0              BIT(8)
+#define LCD_PL_LOAD_DONE               BIT(6)
 #define LCD_FIFO_UNDERFLOW             BIT(5)
 #define LCD_SYNC_LOST                  BIT(2)
 
 #define LCD_PALETTE_LOAD_MODE(x)       ((x) << 20)
 #define PALETTE_AND_DATA               0x00
 #define PALETTE_ONLY                   0x01
+#define DATA_ONLY                      0x02
 
 #define LCD_MONO_8BIT_MODE             BIT(9)
 #define LCD_RASTER_ORDER               BIT(8)
 #define LCD_TFT_MODE                   BIT(7)
 #define LCD_UNDERFLOW_INT_ENA          BIT(6)
+#define LCD_PL_ENABLE                  BIT(4)
 #define LCD_MONOCHROME_MODE            BIT(1)
 #define LCD_RASTER_ENABLE              BIT(0)
 #define LCD_TFT_ALT_ENABLE             BIT(23)
 #define  LCD_DMA_CTRL_REG                      0x40
 #define  LCD_DMA_FRM_BUF_BASE_ADDR_0_REG       0x44
 #define  LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG    0x48
+#define  LCD_DMA_FRM_BUF_BASE_ADDR_1_REG       0x4C
+#define  LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG    0x50
+
+#define LCD_NUM_BUFFERS        2
 
 #define WSI_TIMEOUT    50
 #define PALETTE_SIZE   256
@@ -111,13 +119,20 @@ static inline void lcdc_write(unsigned int val, unsigned int addr)
 struct da8xx_fb_par {
        resource_size_t p_palette_base;
        unsigned char *v_palette_base;
+       dma_addr_t              vram_phys;
+       unsigned long           vram_size;
+       void                    *vram_virt;
+       unsigned int            dma_start;
+       unsigned int            dma_end;
        struct clk *lcdc_clk;
        int irq;
        unsigned short pseudo_palette[16];
-       unsigned int databuf_sz;
        unsigned int palette_sz;
        unsigned int pxl_clk;
        int blank;
+       wait_queue_head_t       vsync_wait;
+       int                     vsync_flag;
+       int                     vsync_timeout;
 #ifdef CONFIG_CPU_FREQ
        struct notifier_block   freq_transition;
 #endif
@@ -148,9 +163,9 @@ static struct fb_fix_screeninfo da8xx_fb_fix __devinitdata = {
        .type = FB_TYPE_PACKED_PIXELS,
        .type_aux = 0,
        .visual = FB_VISUAL_PSEUDOCOLOR,
-       .xpanstep = 1,
+       .xpanstep = 0,
        .ypanstep = 1,
-       .ywrapstep = 1,
+       .ywrapstep = 0,
        .accel = FB_ACCEL_NONE
 };
 
@@ -221,22 +236,48 @@ static inline void lcd_disable_raster(void)
 
 static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
 {
-       u32 tmp = par->p_palette_base + par->databuf_sz - 4;
-       u32 reg;
+       u32 start;
+       u32 end;
+       u32 reg_ras;
+       u32 reg_dma;
+
+       /* init reg to clear PLM (loading mode) fields */
+       reg_ras = lcdc_read(LCD_RASTER_CTRL_REG);
+       reg_ras &= ~(3 << 20);
+
+       reg_dma  = lcdc_read(LCD_DMA_CTRL_REG);
+
+       if (load_mode == LOAD_DATA) {
+               start    = par->dma_start;
+               end      = par->dma_end;
+
+               reg_ras |= LCD_PALETTE_LOAD_MODE(DATA_ONLY);
+               reg_dma |= LCD_END_OF_FRAME_INT_ENA;
+               reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE;
+
+               lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
+               lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
+               lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
+               lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
+       } else if (load_mode == LOAD_PALETTE) {
+               start    = par->p_palette_base;
+               end      = start + par->palette_sz - 1;
+
+               reg_ras |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY);
+               reg_ras |= LCD_PL_ENABLE;
+
+               lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
+               lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
+       }
 
-       /* Update the databuf in the hw. */
-       lcdc_write(par->p_palette_base, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
-       lcdc_write(tmp, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
+       lcdc_write(reg_dma, LCD_DMA_CTRL_REG);
+       lcdc_write(reg_ras, LCD_RASTER_CTRL_REG);
 
-       /* Start the DMA. */
-       reg = lcdc_read(LCD_RASTER_CTRL_REG);
-       reg &= ~(3 << 20);
-       if (load_mode == LOAD_DATA)
-               reg |= LCD_PALETTE_LOAD_MODE(PALETTE_AND_DATA);
-       else if (load_mode == LOAD_PALETTE)
-               reg |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY);
-
-       lcdc_write(reg, LCD_RASTER_CTRL_REG);
+       /*
+        * The Raster enable bit must be set after all other control fields are
+        * set.
+        */
+       lcd_enable_raster();
 }
 
 /* Configure the Burst Size of DMA */
@@ -368,12 +409,8 @@ static int lcd_cfg_display(const struct lcd_ctrl_config *cfg)
 static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
                u32 bpp, u32 raster_order)
 {
-       u32 bpl, reg;
+       u32 reg;
 
-       /* Disable Dual Frame Buffer. */
-       reg = lcdc_read(LCD_DMA_CTRL_REG);
-       lcdc_write(reg & ~LCD_DUAL_FRAME_BUFFER_ENABLE,
-                                               LCD_DMA_CTRL_REG);
        /* Set the Panel Width */
        /* Pixels per line = (PPL + 1)*16 */
        /*0x3F in bits 4..9 gives max horisontal resolution = 1024 pixels*/
@@ -410,9 +447,6 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
                return -EINVAL;
        }
 
-       bpl = width * bpp / 8;
-       par->databuf_sz = height * bpl + par->palette_sz;
-
        return 0;
 }
 
@@ -421,8 +455,9 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
                              struct fb_info *info)
 {
        struct da8xx_fb_par *par = info->par;
-       unsigned short *palette = (unsigned short *)par->v_palette_base;
+       unsigned short *palette = (unsigned short *) par->v_palette_base;
        u_short pal;
+       int update_hw = 0;
 
        if (regno > 255)
                return 1;
@@ -439,8 +474,10 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
                pal |= (green & 0x00f0);
                pal |= (blue & 0x000f);
 
-               palette[regno] = pal;
-
+               if (palette[regno] != pal) {
+                       update_hw = 1;
+                       palette[regno] = pal;
+               }
        } else if ((info->var.bits_per_pixel == 16) && regno < 16) {
                red >>= (16 - info->var.red.length);
                red <<= info->var.red.offset;
@@ -453,9 +490,16 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
 
                par->pseudo_palette[regno] = red | green | blue;
 
-               palette[0] = 0x4000;
+               if (palette[0] != 0x4000) {
+                       update_hw = 1;
+                       palette[0] = 0x4000;
+               }
        }
 
+       /* Update the palette in the h/w as needed. */
+       if (update_hw)
+               lcd_blit(LOAD_PALETTE, par);
+
        return 0;
 }
 
@@ -541,15 +585,54 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
 
 static irqreturn_t lcdc_irq_handler(int irq, void *arg)
 {
+       struct da8xx_fb_par *par = arg;
        u32 stat = lcdc_read(LCD_STAT_REG);
+       u32 reg_ras;
 
        if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
                lcd_disable_raster();
                lcdc_write(stat, LCD_STAT_REG);
                lcd_enable_raster();
-       } else
+       } else if (stat & LCD_PL_LOAD_DONE) {
+               /*
+                * Must disable raster before changing state of any control bit.
+                * And also must be disabled before clearing the PL loading
+                * interrupt via the following write to the status register. If
+                * this is done after then one gets multiple PL done interrupts.
+                */
+               lcd_disable_raster();
+
                lcdc_write(stat, LCD_STAT_REG);
 
+               /* Disable PL completion inerrupt */
+               reg_ras  = lcdc_read(LCD_RASTER_CTRL_REG);
+               reg_ras &= ~LCD_PL_ENABLE;
+               lcdc_write(reg_ras, LCD_RASTER_CTRL_REG);
+
+               /* Setup and start data loading mode */
+               lcd_blit(LOAD_DATA, par);
+       } else {
+               lcdc_write(stat, LCD_STAT_REG);
+
+               if (stat & LCD_END_OF_FRAME0) {
+                       lcdc_write(par->dma_start,
+                                  LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
+                       lcdc_write(par->dma_end,
+                                  LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
+                       par->vsync_flag = 1;
+                       wake_up_interruptible(&par->vsync_wait);
+               }
+
+               if (stat & LCD_END_OF_FRAME1) {
+                       lcdc_write(par->dma_start,
+                                  LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
+                       lcdc_write(par->dma_end,
+                                  LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
+                       par->vsync_flag = 1;
+                       wake_up_interruptible(&par->vsync_wait);
+               }
+       }
+
        return IRQ_HANDLED;
 }
 
@@ -654,9 +737,10 @@ static int __devexit fb_remove(struct platform_device *dev)
 
                unregister_framebuffer(info);
                fb_dealloc_cmap(&info->cmap);
-               dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE,
-                                       info->screen_base - PAGE_SIZE,
-                                       info->fix.smem_start);
+               dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base,
+                                 par->p_palette_base);
+               dma_free_coherent(NULL, par->vram_size, par->vram_virt,
+                                 par->vram_phys);
                free_irq(par->irq, par);
                clk_disable(par->lcdc_clk);
                clk_put(par->lcdc_clk);
@@ -668,6 +752,39 @@ static int __devexit fb_remove(struct platform_device *dev)
        return 0;
 }
 
+/*
+ * Function to wait for vertical sync which for this LCD peripheral
+ * translates into waiting for the current raster frame to complete.
+ */
+static int fb_wait_for_vsync(struct fb_info *info)
+{
+       struct da8xx_fb_par *par = info->par;
+       int ret;
+
+       /*
+        * Set flag to 0 and wait for isr to set to 1. It would seem there is a
+        * race condition here where the ISR could have occured just before or
+        * just after this set. But since we are just coarsely waiting for
+        * a frame to complete then that's OK. i.e. if the frame completed
+        * just before this code executed then we have to wait another full
+        * frame time but there is no way to avoid such a situation. On the
+        * other hand if the frame completed just after then we don't need
+        * to wait long at all. Either way we are guaranteed to return to the
+        * user immediately after a frame completion which is all that is
+        * required.
+        */
+       par->vsync_flag = 0;
+       ret = wait_event_interruptible_timeout(par->vsync_wait,
+                                              par->vsync_flag != 0,
+                                              par->vsync_timeout);
+       if (ret < 0)
+               return ret;
+       if (ret == 0)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
 static int fb_ioctl(struct fb_info *info, unsigned int cmd,
                          unsigned long arg)
 {
@@ -697,6 +814,8 @@ static int fb_ioctl(struct fb_info *info, unsigned int cmd,
                                        sync_arg.pulse_width,
                                        sync_arg.front_porch);
                break;
+       case FBIO_WAITFORVSYNC:
+               return fb_wait_for_vsync(info);
        default:
                return -EINVAL;
        }
@@ -732,10 +851,47 @@ static int cfb_blank(int blank, struct fb_info *info)
        return ret;
 }
 
+/*
+ * Set new x,y offsets in the virtual display for the visible area and switch
+ * to the new mode.
+ */
+static int da8xx_pan_display(struct fb_var_screeninfo *var,
+                            struct fb_info *fbi)
+{
+       int ret = 0;
+       struct fb_var_screeninfo new_var;
+       struct da8xx_fb_par         *par = fbi->par;
+       struct fb_fix_screeninfo    *fix = &fbi->fix;
+       unsigned int end;
+       unsigned int start;
+
+       if (var->xoffset != fbi->var.xoffset ||
+                       var->yoffset != fbi->var.yoffset) {
+               memcpy(&new_var, &fbi->var, sizeof(new_var));
+               new_var.xoffset = var->xoffset;
+               new_var.yoffset = var->yoffset;
+               if (fb_check_var(&new_var, fbi))
+                       ret = -EINVAL;
+               else {
+                       memcpy(&fbi->var, &new_var, sizeof(new_var));
+
+                       start   = fix->smem_start +
+                               new_var.yoffset * fix->line_length +
+                               new_var.xoffset * var->bits_per_pixel / 8;
+                       end     = start + var->yres * fix->line_length - 1;
+                       par->dma_start  = start;
+                       par->dma_end    = end;
+               }
+       }
+
+       return ret;
+}
+
 static struct fb_ops da8xx_fb_ops = {
        .owner = THIS_MODULE,
        .fb_check_var = fb_check_var,
        .fb_setcolreg = fb_setcolreg,
+       .fb_pan_display = da8xx_pan_display,
        .fb_ioctl = fb_ioctl,
        .fb_fillrect = cfb_fillrect,
        .fb_copyarea = cfb_copyarea,
@@ -829,40 +985,53 @@ static int __init fb_probe(struct platform_device *device)
        }
 
        /* allocate frame buffer */
-       da8xx_fb_info->screen_base = dma_alloc_coherent(NULL,
-                                       par->databuf_sz + PAGE_SIZE,
-                                       (resource_size_t *)
-                                       &da8xx_fb_info->fix.smem_start,
-                                       GFP_KERNEL | GFP_DMA);
-
-       if (!da8xx_fb_info->screen_base) {
+       par->vram_size = lcdc_info->width * lcdc_info->height * lcd_cfg->bpp;
+       par->vram_size = PAGE_ALIGN(par->vram_size/8);
+       par->vram_size = par->vram_size * LCD_NUM_BUFFERS;
+
+       par->vram_virt = dma_alloc_coherent(NULL,
+                                           par->vram_size,
+                                           (resource_size_t *) &par->vram_phys,
+                                           GFP_KERNEL | GFP_DMA);
+       if (!par->vram_virt) {
                dev_err(&device->dev,
                        "GLCD: kmalloc for frame buffer failed\n");
                ret = -EINVAL;
                goto err_release_fb;
        }
 
-       /* move palette base pointer by (PAGE_SIZE - palette_sz) bytes */
-       par->v_palette_base = da8xx_fb_info->screen_base +
-                               (PAGE_SIZE - par->palette_sz);
-       par->p_palette_base = da8xx_fb_info->fix.smem_start +
-                               (PAGE_SIZE - par->palette_sz);
-
-       /* the rest of the frame buffer is pixel data */
-       da8xx_fb_info->screen_base = par->v_palette_base + par->palette_sz;
-       da8xx_fb_fix.smem_start = par->p_palette_base + par->palette_sz;
-       da8xx_fb_fix.smem_len = par->databuf_sz - par->palette_sz;
-       da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8;
+       da8xx_fb_info->screen_base = (char __iomem *) par->vram_virt;
+       da8xx_fb_fix.smem_start    = par->vram_phys;
+       da8xx_fb_fix.smem_len      = par->vram_size;
+       da8xx_fb_fix.line_length   = (lcdc_info->width * lcd_cfg->bpp) / 8;
+
+       par->dma_start = par->vram_phys;
+       par->dma_end   = par->dma_start + lcdc_info->height *
+               da8xx_fb_fix.line_length - 1;
+
+       /* allocate palette buffer */
+       par->v_palette_base = dma_alloc_coherent(NULL,
+                                              PALETTE_SIZE,
+                                              (resource_size_t *)
+                                              &par->p_palette_base,
+                                              GFP_KERNEL | GFP_DMA);
+       if (!par->v_palette_base) {
+               dev_err(&device->dev,
+                       "GLCD: kmalloc for palette buffer failed\n");
+               ret = -EINVAL;
+               goto err_release_fb_mem;
+       }
+       memset(par->v_palette_base, 0, PALETTE_SIZE);
 
        par->irq = platform_get_irq(device, 0);
        if (par->irq < 0) {
                ret = -ENOENT;
-               goto err_release_fb_mem;
+               goto err_release_pl_mem;
        }
 
        ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par);
        if (ret)
-               goto err_release_fb_mem;
+               goto err_release_pl_mem;
 
        /* Initialize par */
        da8xx_fb_info->var.bits_per_pixel = lcd_cfg->bpp;
@@ -870,8 +1039,8 @@ static int __init fb_probe(struct platform_device *device)
        da8xx_fb_var.xres = lcdc_info->width;
        da8xx_fb_var.xres_virtual = lcdc_info->width;
 
-       da8xx_fb_var.yres = lcdc_info->height;
-       da8xx_fb_var.yres_virtual = lcdc_info->height;
+       da8xx_fb_var.yres         = lcdc_info->height;
+       da8xx_fb_var.yres_virtual = lcdc_info->height * LCD_NUM_BUFFERS;
 
        da8xx_fb_var.grayscale =
            lcd_cfg->p_disp_panel->panel_shade == MONOCHROME ? 1 : 0;
@@ -892,18 +1061,18 @@ static int __init fb_probe(struct platform_device *device)
        ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0);
        if (ret)
                goto err_free_irq;
-
-       /* First palette_sz byte of the frame buffer is the palette */
        da8xx_fb_info->cmap.len = par->palette_sz;
 
-       /* Flush the buffer to the screen. */
-       lcd_blit(LOAD_DATA, par);
-
        /* initialize var_screeninfo */
        da8xx_fb_var.activate = FB_ACTIVATE_FORCE;
        fb_set_var(da8xx_fb_info, &da8xx_fb_var);
 
        dev_set_drvdata(&device->dev, da8xx_fb_info);
+
+       /* initialize the vsync wait queue */
+       init_waitqueue_head(&par->vsync_wait);
+       par->vsync_timeout = HZ / 5;
+
        /* Register the Frame Buffer  */
        if (register_framebuffer(da8xx_fb_info) < 0) {
                dev_err(&device->dev,
@@ -919,10 +1088,6 @@ static int __init fb_probe(struct platform_device *device)
                goto err_cpu_freq;
        }
 #endif
-
-       /* enable raster engine */
-       lcd_enable_raster();
-
        return 0;
 
 #ifdef CONFIG_CPU_FREQ
@@ -936,10 +1101,12 @@ err_dealloc_cmap:
 err_free_irq:
        free_irq(par->irq, par);
 
+err_release_pl_mem:
+       dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base,
+                         par->p_palette_base);
+
 err_release_fb_mem:
-       dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE,
-                               da8xx_fb_info->screen_base - PAGE_SIZE,
-                               da8xx_fb_info->fix.smem_start);
+       dma_free_coherent(NULL, par->vram_size, par->vram_virt, par->vram_phys);
 
 err_release_fb:
        framebuffer_release(da8xx_fb_info);
index 6113c47..1105a59 100644 (file)
@@ -155,25 +155,41 @@ static void fb_deferred_io_work(struct work_struct *work)
 {
        struct fb_info *info = container_of(work, struct fb_info,
                                                deferred_work.work);
-       struct list_head *node, *next;
-       struct page *cur;
        struct fb_deferred_io *fbdefio = info->fbdefio;
+       struct page *page, *tmp_page;
+       struct list_head *node, *tmp_node;
+       struct list_head non_dirty;
+
+       INIT_LIST_HEAD(&non_dirty);
 
        /* here we mkclean the pages, then do all deferred IO */
        mutex_lock(&fbdefio->lock);
-       list_for_each_entry(cur, &fbdefio->pagelist, lru) {
-               lock_page(cur);
-               page_mkclean(cur);
-               unlock_page(cur);
+       list_for_each_entry_safe(page, tmp_page, &fbdefio->pagelist, lru) {
+               lock_page(page);
+               /*
+                * The workqueue callback can be triggered after a
+                * ->page_mkwrite() call but before the PTE has been marked
+                * dirty. In this case page_mkclean() won't "rearm" the page.
+                *
+                * To avoid this, remove those "non-dirty" pages from the
+                * pagelist before calling the driver's callback, then add
+                * them back to get processed on the next work iteration.
+                * At that time, their PTEs will hopefully be dirty for real.
+                */
+               if (!page_mkclean(page))
+                       list_move_tail(&page->lru, &non_dirty);
+               unlock_page(page);
        }
 
        /* driver's callback with pagelist */
        fbdefio->deferred_io(info, &fbdefio->pagelist);
 
-       /* clear the list */
-       list_for_each_safe(node, next, &fbdefio->pagelist) {
+       /* clear the list... */
+       list_for_each_safe(node, tmp_node, &fbdefio->pagelist) {
                list_del(node);
        }
+       /* ... and add back the "non-dirty" pages to the list */
+       list_splice_tail(&non_dirty, &fbdefio->pagelist);
        mutex_unlock(&fbdefio->lock);
 }
 
@@ -202,6 +218,7 @@ EXPORT_SYMBOL_GPL(fb_deferred_io_open);
 void fb_deferred_io_cleanup(struct fb_info *info)
 {
        struct fb_deferred_io *fbdefio = info->fbdefio;
+       struct list_head *node, *tmp_node;
        struct page *page;
        int i;
 
@@ -209,6 +226,13 @@ void fb_deferred_io_cleanup(struct fb_info *info)
        cancel_delayed_work(&info->deferred_work);
        flush_scheduled_work();
 
+       /*  the list may have still some non-dirty pages at this point */
+       mutex_lock(&fbdefio->lock);
+       list_for_each_safe(node, tmp_node, &fbdefio->pagelist) {
+               list_del(node);
+       }
+       mutex_unlock(&fbdefio->lock);
+
        /* clear out the mapping that we setup */
        for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) {
                page = fb_deferred_io_page(info, i);
index 8bbf251..af8f0f2 100644 (file)
@@ -106,7 +106,7 @@ static DEFINE_SPINLOCK(hga_reg_lock);
 
 /* Framebuffer driver structures */
 
-static struct fb_var_screeninfo __initdata hga_default_var = {
+static struct fb_var_screeninfo hga_default_var __devinitdata = {
        .xres           = 720,
        .yres           = 348,
        .xres_virtual   = 720,
@@ -120,7 +120,7 @@ static struct fb_var_screeninfo __initdata hga_default_var = {
        .width          = -1,
 };
 
-static struct fb_fix_screeninfo __initdata hga_fix = {
+static struct fb_fix_screeninfo hga_fix __devinitdata = {
        .id             = "HGA",
        .type           = FB_TYPE_PACKED_PIXELS,        /* (not sure) */
        .visual         = FB_VISUAL_MONO10,
@@ -276,7 +276,7 @@ static void hga_blank(int blank_mode)
        spin_unlock_irqrestore(&hga_reg_lock, flags);
 }
 
-static int __init hga_card_detect(void)
+static int __devinit hga_card_detect(void)
 {
        int count = 0;
        void __iomem *p, *q;
@@ -596,7 +596,7 @@ static int __devinit hgafb_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int hgafb_remove(struct platform_device *pdev)
+static int __devexit hgafb_remove(struct platform_device *pdev)
 {
        struct fb_info *info = platform_get_drvdata(pdev);
 
@@ -621,7 +621,7 @@ static int hgafb_remove(struct platform_device *pdev)
 
 static struct platform_driver hgafb_driver = {
        .probe = hgafb_probe,
-       .remove = hgafb_remove,
+       .remove = __devexit_p(hgafb_remove),
        .driver = {
                .name = "hgafb",
        },
index 393f3f3..cfb8d64 100644 (file)
 
 #define        WIDTH 640
 
-static struct fb_var_screeninfo hitfb_var __initdata = {
+static struct fb_var_screeninfo hitfb_var __devinitdata = {
        .activate       = FB_ACTIVATE_NOW,
        .height         = -1,
        .width          = -1,
        .vmode          = FB_VMODE_NONINTERLACED,
 };
 
-static struct fb_fix_screeninfo hitfb_fix __initdata = {
+static struct fb_fix_screeninfo hitfb_fix __devinitdata = {
        .id             = "Hitachi HD64461",
        .type           = FB_TYPE_PACKED_PIXELS,
        .accel          = FB_ACCEL_NONE,
@@ -417,7 +417,7 @@ err_fb:
        return ret;
 }
 
-static int __exit hitfb_remove(struct platform_device *dev)
+static int __devexit hitfb_remove(struct platform_device *dev)
 {
        struct fb_info *info = platform_get_drvdata(dev);
 
@@ -462,7 +462,7 @@ static const struct dev_pm_ops hitfb_dev_pm_ops = {
 
 static struct platform_driver hitfb_driver = {
        .probe          = hitfb_probe,
-       .remove         = __exit_p(hitfb_remove),
+       .remove         = __devexit_p(hitfb_remove),
        .driver         = {
                .name   = "hitfb",
                .owner  = THIS_MODULE,
index 4098455..6b51175 100644 (file)
@@ -371,10 +371,6 @@ struct intelfb_info {
                        ((dinfo)->chipset == INTEL_965G) ||     \
                        ((dinfo)->chipset == INTEL_965GM))
 
-#ifndef FBIO_WAITFORVSYNC
-#define FBIO_WAITFORVSYNC      _IOW('F', 0x20, __u32)
-#endif
-
 /*** function prototypes ***/
 
 extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var);
index 6bf0d46..d4cde79 100644 (file)
@@ -667,7 +667,7 @@ release_irq:
 release_regs:
        iounmap(fbi->io);
 release_mem_region:
-       release_mem_region((unsigned long)fbi->mem, size);
+       release_mem_region(res->start, size);
 free_fb:
        framebuffer_release(fbinfo);
        return ret;
index 2b094de..46b4309 100644 (file)
@@ -631,7 +631,7 @@ static struct fb_ops s3c2410fb_ops = {
  *     cache.  Once this area is remapped, all virtual memory
  *     access to the video memory should occur at the new region.
  */
-static int __init s3c2410fb_map_video_memory(struct fb_info *info)
+static int __devinit s3c2410fb_map_video_memory(struct fb_info *info)
 {
        struct s3c2410fb_info *fbi = info->par;
        dma_addr_t map_dma;
@@ -814,7 +814,7 @@ static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info)
 
 static char driver_name[] = "s3c2410fb";
 
-static int __init s3c24xxfb_probe(struct platform_device *pdev,
+static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
                                  enum s3c_drv_type drv_type)
 {
        struct s3c2410fb_info *info;
@@ -1018,7 +1018,7 @@ static int __devinit s3c2412fb_probe(struct platform_device *pdev)
 /*
  *  Cleanup
  */
-static int s3c2410fb_remove(struct platform_device *pdev)
+static int __devexit s3c2410fb_remove(struct platform_device *pdev)
 {
        struct fb_info *fbinfo = platform_get_drvdata(pdev);
        struct s3c2410fb_info *info = fbinfo->par;
@@ -1096,7 +1096,7 @@ static int s3c2410fb_resume(struct platform_device *dev)
 
 static struct platform_driver s3c2410fb_driver = {
        .probe          = s3c2410fb_probe,
-       .remove         = s3c2410fb_remove,
+       .remove         = __devexit_p(s3c2410fb_remove),
        .suspend        = s3c2410fb_suspend,
        .resume         = s3c2410fb_resume,
        .driver         = {
@@ -1107,7 +1107,7 @@ static struct platform_driver s3c2410fb_driver = {
 
 static struct platform_driver s3c2412fb_driver = {
        .probe          = s3c2412fb_probe,
-       .remove         = s3c2410fb_remove,
+       .remove         = __devexit_p(s3c2410fb_remove),
        .suspend        = s3c2410fb_suspend,
        .resume         = s3c2410fb_resume,
        .driver         = {
index 7a3a5e2..53455f2 100644 (file)
@@ -47,7 +47,7 @@ static int ywrap = 0;
 
 static int flatpanel_id = -1;
 
-static struct fb_fix_screeninfo sgivwfb_fix __initdata = {
+static struct fb_fix_screeninfo sgivwfb_fix __devinitdata = {
        .id             = "SGI Vis WS FB",
        .type           = FB_TYPE_PACKED_PIXELS,
         .visual                = FB_VISUAL_PSEUDOCOLOR,
@@ -57,7 +57,7 @@ static struct fb_fix_screeninfo sgivwfb_fix __initdata = {
        .line_length    = 640,
 };
 
-static struct fb_var_screeninfo sgivwfb_var __initdata = {
+static struct fb_var_screeninfo sgivwfb_var __devinitdata = {
        /* 640x480, 8 bpp */
        .xres           = 640,
        .yres           = 480,
@@ -79,7 +79,7 @@ static struct fb_var_screeninfo sgivwfb_var __initdata = {
        .vmode          = FB_VMODE_NONINTERLACED
 };
 
-static struct fb_var_screeninfo sgivwfb_var1600sw __initdata = {
+static struct fb_var_screeninfo sgivwfb_var1600sw __devinitdata = {
        /* 1600x1024, 8 bpp */
        .xres           = 1600,
        .yres           = 1024,
@@ -825,7 +825,7 @@ fail_ioremap_regs:
        return -ENXIO;
 }
 
-static int sgivwfb_remove(struct platform_device *dev)
+static int __devexit sgivwfb_remove(struct platform_device *dev)
 {
        struct fb_info *info = platform_get_drvdata(dev);
 
@@ -845,7 +845,7 @@ static int sgivwfb_remove(struct platform_device *dev)
 
 static struct platform_driver sgivwfb_driver = {
        .probe  = sgivwfb_probe,
-       .remove = sgivwfb_remove,
+       .remove = __devexit_p(sgivwfb_remove),
        .driver = {
                .name   = "sgivwfb",
        },
index a531a0f..559bf17 100644 (file)
@@ -1845,7 +1845,7 @@ sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
 
        memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 
-       strcpy(fix->id, ivideo->myid);
+       strlcpy(fix->id, ivideo->myid, sizeof(fix->id));
 
        mutex_lock(&info->mm_lock);
        fix->smem_start  = ivideo->video_base + ivideo->video_offset;
index 9b5532b..bc67251 100644 (file)
@@ -78,7 +78,7 @@ static void rvfree(void *mem, unsigned long size)
        vfree(mem);
 }
 
-static struct fb_var_screeninfo vfb_default __initdata = {
+static struct fb_var_screeninfo vfb_default __devinitdata = {
        .xres =         640,
        .yres =         480,
        .xres_virtual = 640,
@@ -100,7 +100,7 @@ static struct fb_var_screeninfo vfb_default __initdata = {
        .vmode =        FB_VMODE_NONINTERLACED,
 };
 
-static struct fb_fix_screeninfo vfb_fix __initdata = {
+static struct fb_fix_screeninfo vfb_fix __devinitdata = {
        .id =           "Virtual FB",
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_PSEUDOCOLOR,
index 149c47a..28ccab4 100644 (file)
@@ -65,7 +65,7 @@ struct vga16fb_par {
 
 /* --------------------------------------------------------------------- */
 
-static struct fb_var_screeninfo vga16fb_defined __initdata = {
+static struct fb_var_screeninfo vga16fb_defined __devinitdata = {
        .xres           = 640,
        .yres           = 480,
        .xres_virtual   = 640,
@@ -85,7 +85,7 @@ static struct fb_var_screeninfo vga16fb_defined __initdata = {
 };
 
 /* name should not depend on EGA/VGA */
-static struct fb_fix_screeninfo vga16fb_fix __initdata = {
+static struct fb_fix_screeninfo vga16fb_fix __devinitdata = {
        .id             = "VGA16 VGA",
        .smem_start     = VGA_FB_PHYS,
        .smem_len       = VGA_FB_PHYS_LEN,
@@ -1287,7 +1287,7 @@ static struct fb_ops vga16fb_ops = {
 };
 
 #ifndef MODULE
-static int vga16fb_setup(char *options)
+static int __init vga16fb_setup(char *options)
 {
        char *this_opt;
        
@@ -1393,7 +1393,7 @@ static int __devinit vga16fb_probe(struct platform_device *dev)
        return ret;
 }
 
-static int vga16fb_remove(struct platform_device *dev)
+static int __devexit vga16fb_remove(struct platform_device *dev)
 {
        struct fb_info *info = platform_get_drvdata(dev);
 
@@ -1405,7 +1405,7 @@ static int vga16fb_remove(struct platform_device *dev)
 
 static struct platform_driver vga16fb_driver = {
        .probe = vga16fb_probe,
-       .remove = vga16fb_remove,
+       .remove = __devexit_p(vga16fb_remove),
        .driver = {
                .name = "vga16fb",
        },
index 31b0e17..e66b8b1 100644 (file)
@@ -53,7 +53,7 @@ static void w100_update_enable(void);
 static void w100_update_disable(void);
 static void calc_hsync(struct w100fb_par *par);
 static void w100_init_graphic_engine(struct w100fb_par *par);
-struct w100_pll_info *w100_get_xtal_table(unsigned int freq);
+struct w100_pll_info *w100_get_xtal_table(unsigned int freq) __devinit;
 
 /* Pseudo palette size */
 #define MAX_PALETTES      16
@@ -782,7 +782,7 @@ out:
 }
 
 
-static int w100fb_remove(struct platform_device *pdev)
+static int __devexit w100fb_remove(struct platform_device *pdev)
 {
        struct fb_info *info = platform_get_drvdata(pdev);
        struct w100fb_par *par=info->par;
@@ -1020,7 +1020,7 @@ static struct pll_entries {
        { 0 },
 };
 
-struct w100_pll_info *w100_get_xtal_table(unsigned int freq)
+struct w100_pll_info __devinit *w100_get_xtal_table(unsigned int freq)
 {
        struct pll_entries *pll_entry = w100_pll_tables;
 
@@ -1611,7 +1611,7 @@ static void w100_vsync(void)
 
 static struct platform_driver w100fb_driver = {
        .probe          = w100fb_probe,
-       .remove         = w100fb_remove,
+       .remove         = __devexit_p(w100fb_remove),
        .suspend        = w100fb_suspend,
        .resume         = w100fb_resume,
        .driver         = {
@@ -1619,7 +1619,7 @@ static struct platform_driver w100fb_driver = {
        },
 };
 
-int __devinit w100fb_init(void)
+int __init w100fb_init(void)
 {
        return platform_driver_register(&w100fb_driver);
 }
index 8943b8c..07e857b 100644 (file)
@@ -185,6 +185,7 @@ static void shutdown_handler(struct xenbus_watch *watch,
        kfree(str);
 }
 
+#ifdef CONFIG_MAGIC_SYSRQ
 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
                          unsigned int len)
 {
@@ -214,15 +215,16 @@ static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
                handle_sysrq(sysrq_key, NULL);
 }
 
-static struct xenbus_watch shutdown_watch = {
-       .node = "control/shutdown",
-       .callback = shutdown_handler
-};
-
 static struct xenbus_watch sysrq_watch = {
        .node = "control/sysrq",
        .callback = sysrq_handler
 };
+#endif
+
+static struct xenbus_watch shutdown_watch = {
+       .node = "control/shutdown",
+       .callback = shutdown_handler
+};
 
 static int setup_shutdown_watcher(void)
 {
@@ -234,11 +236,13 @@ static int setup_shutdown_watcher(void)
                return err;
        }
 
+#ifdef CONFIG_MAGIC_SYSRQ
        err = register_xenbus_watch(&sysrq_watch);
        if (err) {
                printk(KERN_ERR "Failed to set sysrq watcher\n");
                return err;
        }
+#endif
 
        return 0;
 }
index e6e94c6..9badbc0 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -242,9 +242,10 @@ static int __bprm_mm_init(struct linux_binprm *bprm)
         * use STACK_TOP because that can depend on attributes which aren't
         * configured yet.
         */
+       BUG_ON(VM_STACK_FLAGS & VM_STACK_INCOMPLETE_SETUP);
        vma->vm_end = STACK_TOP_MAX;
        vma->vm_start = vma->vm_end - PAGE_SIZE;
-       vma->vm_flags = VM_STACK_FLAGS;
+       vma->vm_flags = VM_STACK_FLAGS | VM_STACK_INCOMPLETE_SETUP;
        vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
        INIT_LIST_HEAD(&vma->anon_vma_chain);
        err = insert_vm_struct(mm, vma);
@@ -616,6 +617,7 @@ int setup_arg_pages(struct linux_binprm *bprm,
        else if (executable_stack == EXSTACK_DISABLE_X)
                vm_flags &= ~VM_EXEC;
        vm_flags |= mm->def_flags;
+       vm_flags |= VM_STACK_INCOMPLETE_SETUP;
 
        ret = mprotect_fixup(vma, &prev, vma->vm_start, vma->vm_end,
                        vm_flags);
@@ -630,6 +632,9 @@ int setup_arg_pages(struct linux_binprm *bprm,
                        goto out_unlock;
        }
 
+       /* mprotect_fixup is overkill to remove the temporary stack flags */
+       vma->vm_flags &= ~VM_STACK_INCOMPLETE_SETUP;
+
        stack_expand = 131072UL; /* randomly 32*4k (or 2*64k) pages */
        stack_size = vma->vm_end - vma->vm_start;
        /*
index 113f0a1..ae8200f 100644 (file)
@@ -242,9 +242,10 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
        while (*fclus < cluster) {
                /* prevent the infinite loop of cluster chain */
                if (*fclus > limit) {
-                       fat_fs_error(sb, "%s: detected the cluster chain loop"
-                                    " (i_pos %lld)", __func__,
-                                    MSDOS_I(inode)->i_pos);
+                       fat_fs_error_ratelimit(sb,
+                                       "%s: detected the cluster chain loop"
+                                       " (i_pos %lld)", __func__,
+                                       MSDOS_I(inode)->i_pos);
                        nr = -EIO;
                        goto out;
                }
@@ -253,9 +254,9 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
                if (nr < 0)
                        goto out;
                else if (nr == FAT_ENT_FREE) {
-                       fat_fs_error(sb, "%s: invalid cluster chain"
-                                    " (i_pos %lld)", __func__,
-                                    MSDOS_I(inode)->i_pos);
+                       fat_fs_error_ratelimit(sb, "%s: invalid cluster chain"
+                                              " (i_pos %lld)", __func__,
+                                              MSDOS_I(inode)->i_pos);
                        nr = -EIO;
                        goto out;
                } else if (nr == FAT_ENT_EOF) {
index eb821ee..53dba57 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/nls.h>
 #include <linux/fs.h>
 #include <linux/mutex.h>
+#include <linux/ratelimit.h>
 #include <linux/msdos_fs.h>
 
 /*
@@ -82,6 +83,8 @@ struct msdos_sb_info {
        struct fatent_operations *fatent_ops;
        struct inode *fat_inode;
 
+       struct ratelimit_state ratelimit;
+
        spinlock_t inode_hash_lock;
        struct hlist_head inode_hashtable[FAT_HASH_SIZE];
 };
@@ -322,8 +325,13 @@ extern int fat_fill_super(struct super_block *sb, void *data, int silent,
 extern int fat_flush_inodes(struct super_block *sb, struct inode *i1,
                            struct inode *i2);
 /* fat/misc.c */
-extern void fat_fs_error(struct super_block *s, const char *fmt, ...)
-       __attribute__ ((format (printf, 2, 3))) __cold;
+extern void
+__fat_fs_error(struct super_block *s, int report, const char *fmt, ...)
+       __attribute__ ((format (printf, 3, 4))) __cold;
+#define fat_fs_error(s, fmt, args...)          \
+       __fat_fs_error(s, 1, fmt , ## args)
+#define fat_fs_error_ratelimit(s, fmt, args...) \
+       __fat_fs_error(s, __ratelimit(&MSDOS_SB(s)->ratelimit), fmt , ## args)
 extern int fat_clusters_flush(struct super_block *sb);
 extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster);
 extern void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts,
index c611818..ed33904 100644 (file)
@@ -1250,6 +1250,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
        sb->s_op = &fat_sops;
        sb->s_export_op = &fat_export_ops;
        sbi->dir_ops = fs_dir_inode_ops;
+       ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL,
+                            DEFAULT_RATELIMIT_BURST);
 
        error = parse_options(data, isvfat, silent, &debug, &sbi->options);
        if (error)
index d3da05f..1fa23f6 100644 (file)
  * In case the file system is remounted read-only, it can be made writable
  * again by remounting it.
  */
-void fat_fs_error(struct super_block *s, const char *fmt, ...)
+void __fat_fs_error(struct super_block *s, int report, const char *fmt, ...)
 {
        struct fat_mount_options *opts = &MSDOS_SB(s)->options;
        va_list args;
 
-       printk(KERN_ERR "FAT: Filesystem error (dev %s)\n", s->s_id);
+       if (report) {
+               printk(KERN_ERR "FAT: Filesystem error (dev %s)\n", s->s_id);
 
-       printk(KERN_ERR "    ");
-       va_start(args, fmt);
-       vprintk(fmt, args);
-       va_end(args);
-       printk("\n");
+               printk(KERN_ERR "    ");
+               va_start(args, fmt);
+               vprintk(fmt, args);
+               va_end(args);
+               printk("\n");
+       }
 
        if (opts->errors == FAT_ERRORS_PANIC)
-               panic("    FAT fs panic from previous error\n");
+               panic("FAT: fs panic from previous error\n");
        else if (opts->errors == FAT_ERRORS_RO && !(s->s_flags & MS_RDONLY)) {
                s->s_flags |= MS_RDONLY;
-               printk(KERN_ERR "    File system has been set read-only\n");
+               printk(KERN_ERR "FAT: Filesystem has been set read-only\n");
        }
 }
-EXPORT_SYMBOL_GPL(fat_fs_error);
+EXPORT_SYMBOL_GPL(__fat_fs_error);
 
 /* Flushes the number of free clusters on FAT32 */
 /* XXX: Need to write one per FSINFO block.  Currently only writes 1 */
index 5c4161f..ea8592b 100644 (file)
@@ -409,11 +409,11 @@ static void inode_wait_for_writeback(struct inode *inode)
        wait_queue_head_t *wqh;
 
        wqh = bit_waitqueue(&inode->i_state, __I_SYNC);
-       do {
+        while (inode->i_state & I_SYNC) {
                spin_unlock(&inode_lock);
                __wait_on_bit(wqh, &wq, inode_wait, TASK_UNINTERRUPTIBLE);
                spin_lock(&inode_lock);
-       } while (inode->i_state & I_SYNC);
+       }
 }
 
 /*
index 2f8b115..04214fc 100644 (file)
@@ -1060,7 +1060,7 @@ static int nfs_parse_mount_options(char *raw,
                                goto out_nomem;
                        rc = strict_strtoul(string, 10, &option);
                        kfree(string);
-                       if (rc != 0 || option > USHORT_MAX)
+                       if (rc != 0 || option > USHRT_MAX)
                                goto out_invalid_value;
                        mnt->nfs_server.port = option;
                        break;
@@ -1181,7 +1181,7 @@ static int nfs_parse_mount_options(char *raw,
                                goto out_nomem;
                        rc = strict_strtoul(string, 10, &option);
                        kfree(string);
-                       if (rc != 0 || option > USHORT_MAX)
+                       if (rc != 0 || option > USHRT_MAX)
                                goto out_invalid_value;
                        mnt->mount_server.port = option;
                        break;
index bc3194e..508941c 100644 (file)
@@ -998,7 +998,7 @@ static ssize_t __write_ports_addxprt(char *buf)
        if (sscanf(buf, "%15s %4u", transport, &port) != 2)
                return -EINVAL;
 
-       if (port < 1 || port > USHORT_MAX)
+       if (port < 1 || port > USHRT_MAX)
                return -EINVAL;
 
        err = nfsd_create_serv();
@@ -1040,7 +1040,7 @@ static ssize_t __write_ports_delxprt(char *buf)
        if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2)
                return -EINVAL;
 
-       if (port < 1 || port > USHORT_MAX || nfsd_serv == NULL)
+       if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL)
                return -EINVAL;
 
        xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port);
index 8804f09..a1924a0 100644 (file)
@@ -98,9 +98,6 @@ static int ntfs_file_open(struct inode *vi, struct file *filp)
  * the page at all.  For a more detailed explanation see ntfs_truncate() in
  * fs/ntfs/inode.c.
  *
- * @cached_page and @lru_pvec are just optimizations for dealing with multiple
- * pages.
- *
  * Return 0 on success and -errno on error.  In the case that an error is
  * encountered it is possible that the initialized size will already have been
  * incremented some way towards @new_init_size but it is guaranteed that if
@@ -110,8 +107,7 @@ static int ntfs_file_open(struct inode *vi, struct file *filp)
  * Locking: i_mutex on the vfs inode corrseponsind to the ntfs inode @ni must be
  *         held by the caller.
  */
-static int ntfs_attr_extend_initialized(ntfs_inode *ni, const s64 new_init_size,
-               struct page **cached_page, struct pagevec *lru_pvec)
+static int ntfs_attr_extend_initialized(ntfs_inode *ni, const s64 new_init_size)
 {
        s64 old_init_size;
        loff_t old_i_size;
@@ -403,18 +399,13 @@ static inline void ntfs_fault_in_pages_readable_iovec(const struct iovec *iov,
  * Obtain @nr_pages locked page cache pages from the mapping @mapping and
  * starting at index @index.
  *
- * If a page is newly created, increment its refcount and add it to the
- * caller's lru-buffering pagevec @lru_pvec.
- *
- * This is the same as mm/filemap.c::__grab_cache_page(), except that @nr_pages
- * are obtained at once instead of just one page and that 0 is returned on
- * success and -errno on error.
+ * If a page is newly created, add it to lru list
  *
  * Note, the page locks are obtained in ascending page index order.
  */
 static inline int __ntfs_grab_cache_pages(struct address_space *mapping,
                pgoff_t index, const unsigned nr_pages, struct page **pages,
-               struct page **cached_page, struct pagevec *lru_pvec)
+               struct page **cached_page)
 {
        int err, nr;
 
@@ -430,7 +421,7 @@ static inline int __ntfs_grab_cache_pages(struct address_space *mapping,
                                        goto err_out;
                                }
                        }
-                       err = add_to_page_cache(*cached_page, mapping, index,
+                       err = add_to_page_cache_lru(*cached_page, mapping, index,
                                        GFP_KERNEL);
                        if (unlikely(err)) {
                                if (err == -EEXIST)
@@ -438,9 +429,6 @@ static inline int __ntfs_grab_cache_pages(struct address_space *mapping,
                                goto err_out;
                        }
                        pages[nr] = *cached_page;
-                       page_cache_get(*cached_page);
-                       if (unlikely(!pagevec_add(lru_pvec, *cached_page)))
-                               __pagevec_lru_add_file(lru_pvec);
                        *cached_page = NULL;
                }
                index++;
@@ -1800,7 +1788,6 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb,
        ssize_t status, written;
        unsigned nr_pages;
        int err;
-       struct pagevec lru_pvec;
 
        ntfs_debug("Entering for i_ino 0x%lx, attribute type 0x%x, "
                        "pos 0x%llx, count 0x%lx.",
@@ -1912,7 +1899,6 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb,
                        }
                }
        }
-       pagevec_init(&lru_pvec, 0);
        written = 0;
        /*
         * If the write starts beyond the initialized size, extend it up to the
@@ -1925,8 +1911,7 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb,
        ll = ni->initialized_size;
        read_unlock_irqrestore(&ni->size_lock, flags);
        if (pos > ll) {
-               err = ntfs_attr_extend_initialized(ni, pos, &cached_page,
-                               &lru_pvec);
+              &nb