]> pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'sh/stable-updates'
authorPaul Mundt <lethal@linux-sh.org>
Thu, 12 Feb 2009 08:27:56 +0000 (17:27 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Thu, 12 Feb 2009 08:27:56 +0000 (17:27 +0900)
24 files changed:
arch/sh/Kconfig
arch/sh/boards/Kconfig
arch/sh/boards/mach-highlander/Kconfig
arch/sh/boards/mach-rsk/Kconfig
arch/sh/include/asm/atomic-irq.h
arch/sh/include/asm/bitops-llsc.h
arch/sh/include/asm/cmpxchg-llsc.h
arch/sh/include/asm/gpio.h
arch/sh/include/asm/kprobes.h
arch/sh/include/asm/processor_32.h
arch/sh/include/asm/processor_64.h
arch/sh/include/asm/timer.h
arch/sh/kernel/cpu/sh4a/setup-sh7343.c
arch/sh/kernel/cpu/sh4a/setup-sh7366.c
arch/sh/kernel/cpu/sh4a/setup-sh7722.c
arch/sh/kernel/cpu/sh4a/setup-sh7723.c
arch/sh/kernel/gpio.c
arch/sh/kernel/time_32.c
arch/sh/kernel/timers/timer-mtu2.c
arch/sh/kernel/timers/timer-tmu.c
drivers/clocksource/Makefile
drivers/clocksource/sh_cmt.c [new file with mode: 0644]
drivers/serial/sh-sci.h
include/linux/sh_cmt.h [new file with mode: 0644]

index ebabe518e729dcdb95fa551b21a4e404bca9ba93..78a01d7d37efaee90241ff9524b07520b8186fec 100644 (file)
@@ -107,6 +107,9 @@ config SYS_SUPPORTS_NUMA
 config SYS_SUPPORTS_PCI
        bool
 
+config SYS_SUPPORTS_CMT
+       bool
+
 config STACKTRACE_SUPPORT
        def_bool y
 
@@ -188,6 +191,7 @@ choice
 config CPU_SUBTYPE_SH7619
        bool "Support SH7619 processor"
        select CPU_SH2
+       select SYS_SUPPORTS_CMT
 
 # SH-2A Processor Support
 
@@ -200,15 +204,18 @@ config CPU_SUBTYPE_SH7203
        bool "Support SH7203 processor"
        select CPU_SH2A
        select CPU_HAS_FPU
+       select SYS_SUPPORTS_CMT
 
 config CPU_SUBTYPE_SH7206
        bool "Support SH7206 processor"
        select CPU_SH2A
+       select SYS_SUPPORTS_CMT
 
 config CPU_SUBTYPE_SH7263
        bool "Support SH7263 processor"
        select CPU_SH2A
        select CPU_HAS_FPU
+       select SYS_SUPPORTS_CMT
 
 config CPU_SUBTYPE_MXG
        bool "Support MX-G processor"
@@ -324,6 +331,7 @@ config CPU_SUBTYPE_SH7723
        select CPU_SH4A
        select CPU_SHX2
        select ARCH_SPARSEMEM_ENABLE
+       select SYS_SUPPORTS_CMT
        help
          Select SH7723 if you have an SH-MobileR2 CPU.
 
@@ -362,6 +370,7 @@ config CPU_SUBTYPE_SHX3
 config CPU_SUBTYPE_SH7343
        bool "Support SH7343 processor"
        select CPU_SH4AL_DSP
+       select SYS_SUPPORTS_CMT
 
 config CPU_SUBTYPE_SH7722
        bool "Support SH7722 processor"
@@ -369,6 +378,7 @@ config CPU_SUBTYPE_SH7722
        select CPU_SHX2
        select ARCH_SPARSEMEM_ENABLE
        select SYS_SUPPORTS_NUMA
+       select SYS_SUPPORTS_CMT
 
 config CPU_SUBTYPE_SH7366
        bool "Support SH7366 processor"
@@ -376,6 +386,7 @@ config CPU_SUBTYPE_SH7366
        select CPU_SHX2
        select ARCH_SPARSEMEM_ENABLE
        select SYS_SUPPORTS_NUMA
+       select SYS_SUPPORTS_CMT
 
 # SH-5 Processor Support
 
@@ -398,25 +409,34 @@ source "arch/sh/boards/Kconfig"
 menu "Timer and clock configuration"
 
 config SH_TMU
-       def_bool y
-       prompt "TMU timer support"
+       bool "TMU timer support"
        depends on CPU_SH3 || CPU_SH4
+       default y
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
        help
          This enables the use of the TMU as the system timer.
 
 config SH_CMT
-       def_bool y
-       prompt "CMT timer support"
-       depends on CPU_SH2 && !CPU_SUBTYPE_MXG
+       bool "CMT timer support"
+       depends on SYS_SUPPORTS_CMT && CPU_SH2
+       default y
        help
          This enables the use of the CMT as the system timer.
 
+#
+# Support for the new-style CMT driver. This will replace SH_CMT
+# once its other dependencies are merged.
+#
+config SH_TIMER_CMT
+       bool "CMT clockevents driver"
+       depends on SYS_SUPPORTS_CMT && !SH_CMT
+       select GENERIC_CLOCKEVENTS
+
 config SH_MTU2
-       def_bool n
-       prompt "MTU2 timer support"
+       bool "MTU2 timer support"
        depends on CPU_SH2A
+       default y
        help
          This enables the use of the MTU2 as the system timer.
 
@@ -426,7 +446,8 @@ config SH_TIMER_IRQ
                        CPU_SUBTYPE_SH7763
        default "86" if CPU_SUBTYPE_SH7619
        default "140" if CPU_SUBTYPE_SH7206
-       default "142" if CPU_SUBTYPE_SH7203
+       default "142" if CPU_SUBTYPE_SH7203 && SH_CMT
+       default "153" if CPU_SUBTYPE_SH7203 && SH_MTU2
        default "238" if CPU_SUBTYPE_MXG
        default "16"
 
index 861914747e4ecf4d2ea2ab2ad81e5c0c4a690d9c..c9da37088d2eacb4810a15a1465a5f5bec658934 100644 (file)
@@ -165,7 +165,7 @@ config SH_SH7785LCR_29BIT_PHYSMAPS
 config SH_MIGOR
        bool "Migo-R"
        depends on CPU_SUBTYPE_SH7722
-       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
        help
          Select Migo-R if configuring for the SH7722 Migo-R platform
           by Renesas System Solutions Asia Pte. Ltd.
@@ -173,7 +173,7 @@ config SH_MIGOR
 config SH_AP325RXA
        bool "AP-325RXA"
        depends on CPU_SUBTYPE_SH7723
-       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
        help
          Renesas "AP-325RXA" support.
          Compatible with ALGO SYSTEM CO.,LTD. "AP-320A"
@@ -240,7 +240,7 @@ config SH_X3PROTO
 config SH_MAGIC_PANEL_R2
        bool "Magic Panel R2"
        depends on CPU_SUBTYPE_SH7720
-       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
        help
          Select Magic Panel R2 if configuring for Magic Panel R2.
 
index 08057f62687b7bcc3e3687dabf4b53554500d080..def49cc0a7b9266b3d1f75a074017a2f49b670ac 100644 (file)
@@ -18,7 +18,7 @@ config SH_R7780MP
 config SH_R7785RP
        bool "R7785RP board support"
        depends on CPU_SUBTYPE_SH7785
-       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
 
 endchoice
 
index bff095dffc02bbb41525c9c81a3042a00d5b4433..aeff3b04220590f70a28de6d4ff960326a78b034 100644 (file)
@@ -10,7 +10,7 @@ config SH_RSK7201
 
 config SH_RSK7203
        bool "RSK7203"
-       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
        depends on CPU_SUBTYPE_SH7203
 
 endchoice
index 74f7943cff6f3a80b6c084c86d9b360945e05892..a0b348068cae66f4407760abde7013d0e7034f7a 100644 (file)
@@ -11,7 +11,7 @@ static inline void atomic_add(int i, atomic_t *v)
        unsigned long flags;
 
        local_irq_save(flags);
-       *(long *)v += i;
+       v->counter += i;
        local_irq_restore(flags);
 }
 
@@ -20,7 +20,7 @@ static inline void atomic_sub(int i, atomic_t *v)
        unsigned long flags;
 
        local_irq_save(flags);
-       *(long *)v -= i;
+       v->counter -= i;
        local_irq_restore(flags);
 }
 
@@ -29,9 +29,9 @@ static inline int atomic_add_return(int i, atomic_t *v)
        unsigned long temp, flags;
 
        local_irq_save(flags);
-       temp = *(long *)v;
+       temp = v->counter;
        temp += i;
-       *(long *)v = temp;
+       v->counter = temp;
        local_irq_restore(flags);
 
        return temp;
@@ -42,9 +42,9 @@ static inline int atomic_sub_return(int i, atomic_t *v)
        unsigned long temp, flags;
 
        local_irq_save(flags);
-       temp = *(long *)v;
+       temp = v->counter;
        temp -= i;
-       *(long *)v = temp;
+       v->counter = temp;
        local_irq_restore(flags);
 
        return temp;
@@ -55,7 +55,7 @@ static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
        unsigned long flags;
 
        local_irq_save(flags);
-       *(long *)v &= ~mask;
+       v->counter &= ~mask;
        local_irq_restore(flags);
 }
 
@@ -64,7 +64,7 @@ static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
        unsigned long flags;
 
        local_irq_save(flags);
-       *(long *)v |= mask;
+       v->counter |= mask;
        local_irq_restore(flags);
 }
 
index 1d2fc0b010adf1a608375d3a59c6cce57e42002a..d8328be0619113d254de7a9f2deec3648feee404 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __ASM_SH_BITOPS_LLSC_H
 #define __ASM_SH_BITOPS_LLSC_H
 
-static inline void set_bit(int nr, volatile void * addr)
+static inline void set_bit(int nr, volatile void *addr)
 {
        int     mask;
        volatile unsigned int *a = addr;
@@ -13,16 +13,16 @@ static inline void set_bit(int nr, volatile void * addr)
        __asm__ __volatile__ (
                "1:                                             \n\t"
                "movli.l        @%1, %0 ! set_bit               \n\t"
-               "or             %3, %0                          \n\t"
+               "or             %2, %0                          \n\t"
                "movco.l        %0, @%1                         \n\t"
                "bf             1b                              \n\t"
-               : "=&z" (tmp), "=r" (a)
-               : "1" (a), "r" (mask)
+               : "=&z" (tmp)
+               : "r" (a), "r" (mask)
                : "t", "memory"
        );
 }
 
-static inline void clear_bit(int nr, volatile void * addr)
+static inline void clear_bit(int nr, volatile void *addr)
 {
        int     mask;
        volatile unsigned int *a = addr;
@@ -34,16 +34,16 @@ static inline void clear_bit(int nr, volatile void * addr)
        __asm__ __volatile__ (
                "1:                                             \n\t"
                "movli.l        @%1, %0 ! clear_bit             \n\t"
-               "and            %3, %0                          \n\t"
+               "and            %2, %0                          \n\t"
                "movco.l        %0, @%1                         \n\t"
                "bf             1b                              \n\t"
-               : "=&z" (tmp), "=r" (a)
-               : "1" (a), "r" (~mask)
+               : "=&z" (tmp)
+               : "r" (a), "r" (~mask)
                : "t", "memory"
        );
 }
 
-static inline void change_bit(int nr, volatile void * addr)
+static inline void change_bit(int nr, volatile void *addr)
 {
        int     mask;
        volatile unsigned int *a = addr;
@@ -55,16 +55,16 @@ static inline void change_bit(int nr, volatile void * addr)
        __asm__ __volatile__ (
                "1:                                             \n\t"
                "movli.l        @%1, %0 ! change_bit            \n\t"
-               "xor            %3, %0                          \n\t"
+               "xor            %2, %0                          \n\t"
                "movco.l        %0, @%1                         \n\t"
                "bf             1b                              \n\t"
-               : "=&z" (tmp), "=r" (a)
-               : "1" (a), "r" (mask)
+               : "=&z" (tmp)
+               : "r" (a), "r" (mask)
                : "t", "memory"
        );
 }
 
-static inline int test_and_set_bit(int nr, volatile void * addr)
+static inline int test_and_set_bit(int nr, volatile void *addr)
 {
        int     mask, retval;
        volatile unsigned int *a = addr;
@@ -75,21 +75,21 @@ static inline int test_and_set_bit(int nr, volatile void * addr)
 
        __asm__ __volatile__ (
                "1:                                             \n\t"
-               "movli.l        @%1, %0 ! test_and_set_bit      \n\t"
-               "mov            %0, %2                          \n\t"
-               "or             %4, %0                          \n\t"
-               "movco.l        %0, @%1                         \n\t"
+               "movli.l        @%2, %0 ! test_and_set_bit      \n\t"
+               "mov            %0, %1                          \n\t"
+               "or             %3, %0                          \n\t"
+               "movco.l        %0, @%2                         \n\t"
                "bf             1b                              \n\t"
-               "and            %4, %2                          \n\t"
-               : "=&z" (tmp), "=r" (a), "=&r" (retval)
-               : "1" (a), "r" (mask)
+               "and            %3, %1                          \n\t"
+               : "=&z" (tmp), "=&r" (retval)
+               : "r" (a), "r" (mask)
                : "t", "memory"
        );
 
        return retval != 0;
 }
 
-static inline int test_and_clear_bit(int nr, volatile void * addr)
+static inline int test_and_clear_bit(int nr, volatile void *addr)
 {
        int     mask, retval;
        volatile unsigned int *a = addr;
@@ -100,22 +100,22 @@ static inline int test_and_clear_bit(int nr, volatile void * addr)
 
        __asm__ __volatile__ (
                "1:                                             \n\t"
-               "movli.l        @%1, %0 ! test_and_clear_bit    \n\t"
-               "mov            %0, %2                          \n\t"
-               "and            %5, %0                          \n\t"
-               "movco.l        %0, @%1                         \n\t"
+               "movli.l        @%2, %0 ! test_and_clear_bit    \n\t"
+               "mov            %0, %1                          \n\t"
+               "and            %4, %0                          \n\t"
+               "movco.l        %0, @%2                         \n\t"
                "bf             1b                              \n\t"
-               "and            %4, %2                          \n\t"
+               "and            %3, %1                          \n\t"
                "synco                                          \n\t"
-               : "=&z" (tmp), "=r" (a), "=&r" (retval)
-               : "1" (a), "r" (mask), "r" (~mask)
+               : "=&z" (tmp), "=&r" (retval)
+               : "r" (a), "r" (mask), "r" (~mask)
                : "t", "memory"
        );
 
        return retval != 0;
 }
 
-static inline int test_and_change_bit(int nr, volatile void * addr)
+static inline int test_and_change_bit(int nr, volatile void *addr)
 {
        int     mask, retval;
        volatile unsigned int *a = addr;
@@ -126,15 +126,15 @@ static inline int test_and_change_bit(int nr, volatile void * addr)
 
        __asm__ __volatile__ (
                "1:                                             \n\t"
-               "movli.l        @%1, %0 ! test_and_change_bit   \n\t"
-               "mov            %0, %2                          \n\t"
-               "xor            %4, %0                          \n\t"
-               "movco.l        %0, @%1                         \n\t"
+               "movli.l        @%2, %0 ! test_and_change_bit   \n\t"
+               "mov            %0, %1                          \n\t"
+               "xor            %3, %0                          \n\t"
+               "movco.l        %0, @%2                         \n\t"
                "bf             1b                              \n\t"
-               "and            %4, %2                          \n\t"
+               "and            %3, %1                          \n\t"
                "synco                                          \n\t"
-               : "=&z" (tmp), "=r" (a), "=&r" (retval)
-               : "1" (a), "r" (mask)
+               : "=&z" (tmp), "=&r" (retval)
+               : "r" (a), "r" (mask)
                : "t", "memory"
        );
 
index aee3bf2865818131a5d4700d970f080ca84a6ce0..0fac3da536ca025797385130a9972296c578276c 100644 (file)
@@ -8,14 +8,14 @@ static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val)
 
        __asm__ __volatile__ (
                "1:                                     \n\t"
-               "movli.l        @%1, %0 ! xchg_u32      \n\t"
-               "mov            %0, %2                  \n\t"
-               "mov            %4, %0                  \n\t"
-               "movco.l        %0, @%1                 \n\t"
+               "movli.l        @%2, %0 ! xchg_u32      \n\t"
+               "mov            %0, %1                  \n\t"
+               "mov            %3, %0                  \n\t"
+               "movco.l        %0, @%2                 \n\t"
                "bf             1b                      \n\t"
                "synco                                  \n\t"
-               : "=&z"(tmp), "=r" (m), "=&r" (retval)
-               : "1" (m), "r" (val)
+               : "=&z"(tmp), "=&r" (retval)
+               : "r" (m), "r" (val)
                : "t", "memory"
        );
 
@@ -29,14 +29,14 @@ static inline unsigned long xchg_u8(volatile u8 *m, unsigned long val)
 
        __asm__ __volatile__ (
                "1:                                     \n\t"
-               "movli.l        @%1, %0 ! xchg_u8       \n\t"
-               "mov            %0, %2                  \n\t"
-               "mov            %4, %0                  \n\t"
-               "movco.l        %0, @%1                 \n\t"
+               "movli.l        @%2, %0 ! xchg_u8       \n\t"
+               "mov            %0, %1                  \n\t"
+               "mov            %3, %0                  \n\t"
+               "movco.l        %0, @%2                 \n\t"
                "bf             1b                      \n\t"
                "synco                                  \n\t"
-               : "=&z"(tmp), "=r" (m), "=&r" (retval)
-               : "1" (m), "r" (val & 0xff)
+               : "=&z"(tmp), "=&r" (retval)
+               : "r" (m), "r" (val & 0xff)
                : "t", "memory"
        );
 
@@ -51,17 +51,17 @@ __cmpxchg_u32(volatile int *m, unsigned long old, unsigned long new)
 
        __asm__ __volatile__ (
                "1:                                             \n\t"
-               "movli.l        @%1, %0 ! __cmpxchg_u32         \n\t"
-               "mov            %0, %2                          \n\t"
-               "cmp/eq         %2, %4                          \n\t"
+               "movli.l        @%2, %0 ! __cmpxchg_u32         \n\t"
+               "mov            %0, %1                          \n\t"
+               "cmp/eq         %1, %3                          \n\t"
                "bf             2f                              \n\t"
-               "mov            %5, %0                          \n\t"
+               "mov            %3, %0                          \n\t"
                "2:                                             \n\t"
-               "movco.l        %0, @%1                         \n\t"
+               "movco.l        %0, @%2                         \n\t"
                "bf             1b                              \n\t"
                "synco                                          \n\t"
-               : "=&z" (tmp), "=r" (m), "=&r" (retval)
-               : "1" (m), "r" (old), "r" (new)
+               : "=&z" (tmp), "=&r" (retval)
+               : "r" (m), "r" (old), "r" (new)
                : "t", "memory"
        );
 
index 90673658eb14c19e5506ebcda7c3024084fbd036..61f93da2c62e3dc41de14a4b05eccabf3df84f36 100644 (file)
 #include <cpu/gpio.h>
 #endif
 
+#define ARCH_NR_GPIOS 512
+#include <asm-generic/gpio.h>
+
+#ifdef CONFIG_GPIOLIB
+
+static inline int gpio_get_value(unsigned gpio)
+{
+       return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+       __gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned gpio)
+{
+       return __gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+       WARN_ON(1);
+       return -ENOSYS;
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+       WARN_ON(1);
+       return -EINVAL;
+}
+
+#endif /* CONFIG_GPIOLIB */
+
 typedef unsigned short pinmux_enum_t;
-typedef unsigned char pinmux_flag_t;
+typedef unsigned short pinmux_flag_t;
 
 #define PINMUX_TYPE_NONE            0
 #define PINMUX_TYPE_FUNCTION        1
@@ -34,6 +68,11 @@ typedef unsigned char pinmux_flag_t;
 #define PINMUX_FLAG_WANT_PULLUP     (1 << 3)
 #define PINMUX_FLAG_WANT_PULLDOWN   (1 << 4)
 
+#define PINMUX_FLAG_DBIT_SHIFT      5
+#define PINMUX_FLAG_DBIT            (0x1f << PINMUX_FLAG_DBIT_SHIFT)
+#define PINMUX_FLAG_DREG_SHIFT      10
+#define PINMUX_FLAG_DREG            (0x3f << PINMUX_FLAG_DREG_SHIFT)
+
 struct pinmux_gpio {
        pinmux_enum_t enum_id;
        pinmux_flag_t flags;
@@ -54,7 +93,7 @@ struct pinmux_cfg_reg {
        .enum_ids = (pinmux_enum_t [(r_width / f_width) * (1 << f_width)]) \
 
 struct pinmux_data_reg {
-       unsigned long reg, reg_width;
+       unsigned long reg, reg_width, reg_shadow;
        pinmux_enum_t *enum_ids;
 };
 
@@ -89,34 +128,9 @@ struct pinmux_info {
        unsigned int gpio_data_size;
 
        unsigned long *gpio_in_use;
+       struct gpio_chip chip;
 };
 
 int register_pinmux(struct pinmux_info *pip);
 
-int __gpio_request(unsigned gpio);
-static inline int gpio_request(unsigned gpio, const char *label)
-{
-       return __gpio_request(gpio);
-}
-void gpio_free(unsigned gpio);
-int gpio_direction_input(unsigned gpio);
-int gpio_direction_output(unsigned gpio, int value);
-int gpio_get_value(unsigned gpio);
-void gpio_set_value(unsigned gpio, int value);
-
-/* IRQ modes are unspported */
-static inline int gpio_to_irq(unsigned gpio)
-{
-       WARN_ON(1);
-       return -EINVAL;
-}
-
-static inline int irq_to_gpio(unsigned irq)
-{
-       WARN_ON(1);
-       return -EINVAL;
-}
-
-#include <asm-generic/gpio.h>
-
 #endif /* __ASM_SH_GPIO_H */
index 6078d8e551d4960e66c0cf7da92fc266470d717a..613644a758e8e82b54a975d17376bd63bdd63768 100644 (file)
@@ -16,7 +16,7 @@ typedef u16 kprobe_opcode_t;
        ? (MAX_STACK_SIZE) \
        : (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR)))
 
-#define regs_return_value(regs)                ((regs)->regs[0])
+#define regs_return_value(_regs)               ((_regs)->regs[0])
 #define flush_insn_slot(p)             do { } while (0)
 #define kretprobe_blacklist_size       0
 
index d79063c5eb9c1ebb531425dda142c031115cfca2..dcaed24c71fc6a2590d43671b34e99946a7e7e3a 100644 (file)
@@ -108,12 +108,12 @@ extern int ubc_usercnt;
 /*
  * Do necessary setup to start up a newly executed thread.
  */
-#define start_thread(regs, new_pc, new_sp)      \
+#define start_thread(_regs, new_pc, new_sp)     \
        set_fs(USER_DS);                         \
-       regs->pr = 0;                            \
-       regs->sr = SR_FD;       /* User mode. */ \
-       regs->pc = new_pc;                       \
-       regs->regs[15] = new_sp
+       _regs->pr = 0;                           \
+       _regs->sr = SR_FD;      /* User mode. */ \
+       _regs->pc = new_pc;                      \
+       _regs->regs[15] = new_sp
 
 /* Forward declaration, a strange C thing */
 struct task_struct;
@@ -189,7 +189,7 @@ extern unsigned long get_wchan(struct task_struct *p);
 #define KSTK_EIP(tsk)  (task_pt_regs(tsk)->pc)
 #define KSTK_ESP(tsk)  (task_pt_regs(tsk)->regs[15])
 
-#define user_stack_pointer(regs)       ((regs)->regs[15])
+#define user_stack_pointer(_regs)      ((_regs)->regs[15])
 
 #if defined(CONFIG_CPU_SH2A) || defined(CONFIG_CPU_SH3) || \
     defined(CONFIG_CPU_SH4)
index 803177fcf0868b1e5f3a84462a6d3fe514f101c8..5727d31b0ccfd89f6e80c5f610b36bd5f48c0dc5 100644 (file)
@@ -145,13 +145,13 @@ struct thread_struct {
  */
 #define SR_USER (SR_MMU | SR_FD)
 
-#define start_thread(regs, new_pc, new_sp)                     \
+#define start_thread(_regs, new_pc, new_sp)                    \
        set_fs(USER_DS);                                        \
-       regs->sr = SR_USER;     /* User mode. */                \
-       regs->pc = new_pc - 4;  /* Compensate syscall exit */   \
-       regs->pc |= 1;          /* Set SHmedia ! */             \
-       regs->regs[18] = 0;                                     \
-       regs->regs[15] = new_sp
+       _regs->sr = SR_USER;    /* User mode. */                \
+       _regs->pc = new_pc - 4; /* Compensate syscall exit */   \
+       _regs->pc |= 1;         /* Set SHmedia ! */             \
+       _regs->regs[18] = 0;                                    \
+       _regs->regs[15] = new_sp
 
 /* Forward declaration, a strange C thing */
 struct task_struct;
@@ -226,7 +226,7 @@ extern unsigned long get_wchan(struct task_struct *p);
 #define KSTK_EIP(tsk)  ((tsk)->thread.pc)
 #define KSTK_ESP(tsk)  ((tsk)->thread.sp)
 
-#define user_stack_pointer(regs)       ((regs)->regs[15])
+#define user_stack_pointer(_regs)      ((_regs)->regs[15])
 
 #endif /* __ASSEMBLY__ */
 #endif /* __ASM_SH_PROCESSOR_64_H */
index a7ca3a195bb589609e1d0eac2c4709f2251b46a4..4c3b66e30af23fccb48b2392b54ae5cbb581827c 100644 (file)
@@ -9,7 +9,6 @@ struct sys_timer_ops {
        int (*init)(void);
        int (*start)(void);
        int (*stop)(void);
-       cycle_t (*read)(void);
 #ifndef CONFIG_GENERIC_TIME
        unsigned long (*get_offset)(void);
 #endif
@@ -39,6 +38,7 @@ struct sys_timer *get_sys_timer(void);
 
 /* arch/sh/kernel/time.c */
 void handle_timer_tick(void);
-extern unsigned long sh_hpt_frequency;
+
+extern struct clocksource clocksource_sh;
 
 #endif /* __ASM_SH_TIMER_H */
index 4ff4dc64520c1ed68dedd3f9b0de33a1cff8ece5..c1549382c87c01070b0467ea5771bfa25205a7ba 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/uio_driver.h>
+#include <linux/sh_cmt.h>
 #include <asm/clock.h>
 
 static struct resource iic0_resources[] = {
@@ -140,6 +141,38 @@ static struct platform_device jpu_device = {
        .num_resources  = ARRAY_SIZE(jpu_resources),
 };
 
+static struct sh_cmt_config cmt_platform_data = {
+       .name = "CMT",
+       .channel_offset = 0x60,
+       .timer_bit = 5,
+       .clk = "cmt0",
+       .clockevent_rating = 125,
+       .clocksource_rating = 200,
+};
+
+static struct resource cmt_resources[] = {
+       [0] = {
+               .name   = "CMT",
+               .start  = 0x044a0060,
+               .end    = 0x044a006b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 104,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt_device = {
+       .name           = "sh_cmt",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &cmt_platform_data,
+       },
+       .resource       = cmt_resources,
+       .num_resources  = ARRAY_SIZE(cmt_resources),
+};
+
 static struct plat_sci_port sci_platform_data[] = {
        {
                .mapbase        = 0xffe00000,
@@ -175,6 +208,7 @@ static struct platform_device sci_device = {
 };
 
 static struct platform_device *sh7343_devices[] __initdata = {
+       &cmt_device,
        &iic0_device,
        &iic1_device,
        &sci_device,
index 839ae97a7fd2de8e708bd7fa82f484d012edae42..93ecf8ed5c6c346a60c166624c9278a134de46ac 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/uio_driver.h>
+#include <linux/sh_cmt.h>
 #include <asm/clock.h>
 
 static struct resource iic_resources[] = {
@@ -147,6 +148,38 @@ static struct platform_device veu1_device = {
        .num_resources  = ARRAY_SIZE(veu1_resources),
 };
 
+static struct sh_cmt_config cmt_platform_data = {
+       .name = "CMT",
+       .channel_offset = 0x60,
+       .timer_bit = 5,
+       .clk = "cmt0",
+       .clockevent_rating = 125,
+       .clocksource_rating = 200,
+};
+
+static struct resource cmt_resources[] = {
+       [0] = {
+               .name   = "CMT",
+               .start  = 0x044a0060,
+               .end    = 0x044a006b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 104,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt_device = {
+       .name           = "sh_cmt",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &cmt_platform_data,
+       },
+       .resource       = cmt_resources,
+       .num_resources  = ARRAY_SIZE(cmt_resources),
+};
+
 static struct plat_sci_port sci_platform_data[] = {
        {
                .mapbase        = 0xffe00000,
@@ -167,6 +200,7 @@ static struct platform_device sci_device = {
 };
 
 static struct platform_device *sh7366_devices[] __initdata = {
+       &cmt_device,
        &iic_device,
        &sci_device,
        &usb_host_device,
index 5146afc156e0d3d6185c7ed9c63e4cd2430e8c92..0e5d204bc79287bf4fc00197a7b3e38593ddab1e 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/serial_sci.h>
 #include <linux/mm.h>
 #include <linux/uio_driver.h>
+#include <linux/sh_cmt.h>
 #include <asm/clock.h>
 #include <asm/mmzone.h>
 
@@ -176,6 +177,38 @@ static struct platform_device jpu_device = {
        .num_resources  = ARRAY_SIZE(jpu_resources),
 };
 
+static struct sh_cmt_config cmt_platform_data = {
+       .name = "CMT",
+       .channel_offset = 0x60,
+       .timer_bit = 5,
+       .clk = "cmt0",
+       .clockevent_rating = 125,
+       .clocksource_rating = 200,
+};
+
+static struct resource cmt_resources[] = {
+       [0] = {
+               .name   = "CMT",
+               .start  = 0x044a0060,
+               .end    = 0x044a006b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 104,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt_device = {
+       .name           = "sh_cmt",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &cmt_platform_data,
+       },
+       .resource       = cmt_resources,
+       .num_resources  = ARRAY_SIZE(cmt_resources),
+};
+
 static struct plat_sci_port sci_platform_data[] = {
        {
                .mapbase        = 0xffe00000,
@@ -209,6 +242,7 @@ static struct platform_device sci_device = {
 };
 
 static struct platform_device *sh7722_devices[] __initdata = {
+       &cmt_device,
        &rtc_device,
        &usbf_device,
        &iic_device,
index 849770d780aed9e5b2de0479b32887c80f374ebf..5338dacbcfba7c00481cf5fe6424192cb07d8b9e 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/mm.h>
 #include <linux/serial_sci.h>
 #include <linux/uio_driver.h>
+#include <linux/sh_cmt.h>
 #include <asm/clock.h>
 #include <asm/mmzone.h>
 
@@ -100,6 +101,38 @@ static struct platform_device veu1_device = {
        .num_resources  = ARRAY_SIZE(veu1_resources),
 };
 
+static struct sh_cmt_config cmt_platform_data = {
+       .name = "CMT",
+       .channel_offset = 0x60,
+       .timer_bit = 5,
+       .clk = "cmt0",
+       .clockevent_rating = 125,
+       .clocksource_rating = 200,
+};
+
+static struct resource cmt_resources[] = {
+       [0] = {
+               .name   = "CMT",
+               .start  = 0x044a0060,
+               .end    = 0x044a006b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 104,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt_device = {
+       .name           = "sh_cmt",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &cmt_platform_data,
+       },
+       .resource       = cmt_resources,
+       .num_resources  = ARRAY_SIZE(cmt_resources),
+};
+
 static struct plat_sci_port sci_platform_data[] = {
        {
                .mapbase        = 0xffe00000,
@@ -221,6 +254,7 @@ static struct platform_device iic_device = {
 };
 
 static struct platform_device *sh7723_devices[] __initdata = {
+       &cmt_device,
        &sci_device,
        &rtc_device,
        &iic_device,
index d371653610348313dc4b6481764b9b0ea4a08988..d22e5af699f9839233a78065356ae174ab9d837b 100644 (file)
 #include <linux/bitops.h>
 #include <linux/gpio.h>
 
-static struct pinmux_info *registered_gpio;
+static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
+{
+       if (enum_id < r->begin)
+               return 0;
 
-static struct pinmux_info *gpio_controller(unsigned gpio)
+       if (enum_id > r->end)
+               return 0;
+
+       return 1;
+}
+
+static unsigned long gpio_read_raw_reg(unsigned long reg,
+                                      unsigned long reg_width)
 {
-       if (!registered_gpio)
-               return NULL;
+       switch (reg_width) {
+       case 8:
+               return ctrl_inb(reg);
+       case 16:
+               return ctrl_inw(reg);
+       case 32:
+               return ctrl_inl(reg);
+       }
 
-       if (gpio < registered_gpio->first_gpio)
-               return NULL;
+       BUG();
+       return 0;
+}
 
-       if (gpio > registered_gpio->last_gpio)
-               return NULL;
+static void gpio_write_raw_reg(unsigned long reg,
+                              unsigned long reg_width,
+                              unsigned long data)
+{
+       switch (reg_width) {
+       case 8:
+               ctrl_outb(data, reg);
+               return;
+       case 16:
+               ctrl_outw(data, reg);
+               return;
+       case 32:
+               ctrl_outl(data, reg);
+               return;
+       }
 
-       return registered_gpio;
+       BUG();
 }
 
-static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
+static void gpio_write_bit(struct pinmux_data_reg *dr,
+                          unsigned long in_pos, unsigned long value)
 {
-       if (enum_id < r->begin)
-               return 0;
+       unsigned long pos;
 
-       if (enum_id > r->end)
-               return 0;
+       pos = dr->reg_width - (in_pos + 1);
 
-       return 1;
+#ifdef DEBUG
+       pr_info("write_bit addr = %lx, value = %ld, pos = %ld, "
+               "r_width = %ld\n",
+               dr->reg, !!value, pos, dr->reg_width);
+#endif
+
+       if (value)
+               set_bit(pos, &dr->reg_shadow);
+       else
+               clear_bit(pos, &dr->reg_shadow);
+
+       gpio_write_raw_reg(dr->reg, dr->reg_width, dr->reg_shadow);
 }
 
-static int read_write_reg(unsigned long reg, unsigned long reg_width,
-                         unsigned long field_width, unsigned long in_pos,
-                         unsigned long value, int do_write)
+static int gpio_read_reg(unsigned long reg, unsigned long reg_width,
+                        unsigned long field_width, unsigned long in_pos)
 {
        unsigned long data, mask, pos;
 
@@ -57,52 +96,53 @@ static int read_write_reg(unsigned long reg, unsigned long reg_width,
        pos = reg_width - ((in_pos + 1) * field_width);
 
 #ifdef DEBUG
-       pr_info("%s, addr = %lx, value = %ld, pos = %ld, "
+       pr_info("read_reg: addr = %lx, pos = %ld, "
                "r_width = %ld, f_width = %ld\n",
-               do_write ? "write" : "read", reg, value, pos,
-               reg_width, field_width);
+               reg, pos, reg_width, field_width);
 #endif
 
-       switch (reg_width) {
-       case 8:
-               data = ctrl_inb(reg);
-               break;
-       case 16:
-               data = ctrl_inw(reg);
-               break;
-       case 32:
-               data = ctrl_inl(reg);
-               break;
-       }
+       data = gpio_read_raw_reg(reg, reg_width);
+       return (data >> pos) & mask;
+}
 
-       if (!do_write)
-               return (data >> pos) & mask;
+static void gpio_write_reg(unsigned long reg, unsigned long reg_width,
+                          unsigned long field_width, unsigned long in_pos,
+                          unsigned long value)
+{
+       unsigned long mask, pos;
 
-       data &= ~(mask << pos);
-       data |= value << pos;
+       mask = (1 << field_width) - 1;
+       pos = reg_width - ((in_pos + 1) * field_width);
+
+#ifdef DEBUG
+       pr_info("write_reg addr = %lx, value = %ld, pos = %ld, "
+               "r_width = %ld, f_width = %ld\n",
+               reg, value, pos, reg_width, field_width);
+#endif
+
+       mask = ~(mask << pos);
+       value = value << pos;
 
        switch (reg_width) {
        case 8:
-               ctrl_outb(data, reg);
+               ctrl_outb((ctrl_inb(reg) & mask) | value, reg);
                break;
        case 16:
-               ctrl_outw(data, reg);
+               ctrl_outw((ctrl_inw(reg) & mask) | value, reg);
                break;
        case 32:
-               ctrl_outl(data, reg);
+               ctrl_outl((ctrl_inl(reg) & mask) | value, reg);
                break;
        }
-       return 0;
 }
 
-static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio,
-                       struct pinmux_data_reg **drp, int *bitp)
+static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio)
 {
-       pinmux_enum_t enum_id = gpioc->gpios[gpio].enum_id;
+       struct pinmux_gpio *gpiop = &gpioc->gpios[gpio];
        struct pinmux_data_reg *data_reg;
        int k, n;
 
-       if (!enum_in_range(enum_id, &gpioc->data))
+       if (!enum_in_range(gpiop->enum_id, &gpioc->data))
                return -1;
 
        k = 0;
@@ -113,19 +153,58 @@ static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio,
                        break;
 
                for (n = 0; n < data_reg->reg_width; n++) {
-                       if (data_reg->enum_ids[n] == enum_id) {
-                               *drp = data_reg;
-                               *bitp = n;
+                       if (data_reg->enum_ids[n] == gpiop->enum_id) {
+                               gpiop->flags &= ~PINMUX_FLAG_DREG;
+                               gpiop->flags |= (k << PINMUX_FLAG_DREG_SHIFT);
+                               gpiop->flags &= ~PINMUX_FLAG_DBIT;
+                               gpiop->flags |= (n << PINMUX_FLAG_DBIT_SHIFT);
                                return 0;
-
                        }
                }
                k++;
        }
 
+       BUG();
+
        return -1;
 }
 
+static void setup_data_regs(struct pinmux_info *gpioc)
+{
+       struct pinmux_data_reg *drp;
+       int k;
+
+       for (k = gpioc->first_gpio; k <= gpioc->last_gpio; k++)
+               setup_data_reg(gpioc, k);
+
+       k = 0;
+       while (1) {
+               drp = gpioc->data_regs + k;
+
+               if (!drp->reg_width)
+                       break;
+
+               drp->reg_shadow = gpio_read_raw_reg(drp->reg, drp->reg_width);
+               k++;
+       }
+}
+
+static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio,
+                       struct pinmux_data_reg **drp, int *bitp)
+{
+       struct pinmux_gpio *gpiop = &gpioc->gpios[gpio];
+       int k, n;
+
+       if (!enum_in_range(gpiop->enum_id, &gpioc->data))
+               return -1;
+
+       k = (gpiop->flags & PINMUX_FLAG_DREG) >> PINMUX_FLAG_DREG_SHIFT;
+       n = (gpiop->flags & PINMUX_FLAG_DBIT) >> PINMUX_FLAG_DBIT_SHIFT;
+       *drp = gpioc->data_regs + k;
+       *bitp = n;
+       return 0;
+}
+
 static int get_config_reg(struct pinmux_info *gpioc, pinmux_enum_t enum_id,
                          struct pinmux_cfg_reg **crp, int *indexp,
                          unsigned long **cntp)
@@ -187,9 +266,9 @@ static int get_gpio_enum_id(struct pinmux_info *gpioc, unsigned gpio,
        return -1;
 }
 
-static int write_config_reg(struct pinmux_info *gpioc,
-                           struct pinmux_cfg_reg *crp,
-                           int index)
+static void write_config_reg(struct pinmux_info *gpioc,
+                            struct pinmux_cfg_reg *crp,
+                            int index)
 {
        unsigned long ncomb, pos, value;
 
@@ -197,8 +276,7 @@ static int write_config_reg(struct pinmux_info *gpioc,
        pos = index / ncomb;
        value = index % ncomb;
 
-       return read_write_reg(crp->reg, crp->reg_width,
-                             crp->field_width, pos, value, 1);
+       gpio_write_reg(crp->reg, crp->reg_width, crp->field_width, pos, value);
 }
 
 static int check_config_reg(struct pinmux_info *gpioc,
@@ -211,8 +289,8 @@ static int check_config_reg(struct pinmux_info *gpioc,
        pos = index / ncomb;
        value = index % ncomb;
 
-       if (read_write_reg(crp->reg, crp->reg_width,
-                          crp->field_width, pos, 0, 0) == value)
+       if (gpio_read_reg(crp->reg, crp->reg_width,
+                         crp->field_width, pos) == value)
                return 0;
 
        return -1;
@@ -220,8 +298,8 @@ static int check_config_reg(struct pinmux_info *gpioc,
 
 enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE };
 
-int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
-                      int pinmux_type, int cfg_mode)
+static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
+                             int pinmux_type, int cfg_mode)
 {
        struct pinmux_cfg_reg *cr = NULL;
        pinmux_enum_t enum_id;
@@ -287,8 +365,7 @@ int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
                        break;
 
                case GPIO_CFG_REQ:
-                       if (write_config_reg(gpioc, cr, index) != 0)
-                               goto out_err;
+                       write_config_reg(gpioc, cr, index);
                        *cntp = *cntp + 1;
                        break;
 
@@ -305,9 +382,14 @@ int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
 
 static DEFINE_SPINLOCK(gpio_lock);
 
-int __gpio_request(unsigned gpio)
+static struct pinmux_info *chip_to_pinmux(struct gpio_chip *chip)
 {
-       struct pinmux_info *gpioc = gpio_controller(gpio);
+       return container_of(chip, struct pinmux_info, chip);
+}
+
+static int sh_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       struct pinmux_info *gpioc = chip_to_pinmux(chip);
        struct pinmux_data_reg *dummy;
        unsigned long flags;
        int i, ret, pinmux_type;
@@ -319,29 +401,30 @@ int __gpio_request(unsigned gpio)
 
        spin_lock_irqsave(&gpio_lock, flags);
 
-       if ((gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE) != PINMUX_TYPE_NONE)
+       if ((gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE) != PINMUX_TYPE_NONE)
                goto err_unlock;
 
        /* setup pin function here if no data is associated with pin */
 
-       if (get_data_reg(gpioc, gpio, &dummy, &i) != 0)
+       if (get_data_reg(gpioc, offset, &dummy, &i) != 0)
                pinmux_type = PINMUX_TYPE_FUNCTION;
        else
                pinmux_type = PINMUX_TYPE_GPIO;
 
        if (pinmux_type == PINMUX_TYPE_FUNCTION) {
-               if (pinmux_config_gpio(gpioc, gpio,
+               if (pinmux_config_gpio(gpioc, offset,
                                       pinmux_type,
                                       GPIO_CFG_DRYRUN) != 0)
                        goto err_unlock;
 
-               if (pinmux_config_gpio(gpioc, gpio,
+               if (pinmux_config_gpio(gpioc, offset,
                                       pinmux_type,
                                       GPIO_CFG_REQ) != 0)
                        BUG();
        }
 
-       gpioc->gpios[gpio].flags = pinmux_type;
+       gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
+       gpioc->gpios[offset].flags |= pinmux_type;
 
        ret = 0;
  err_unlock:
@@ -349,11 +432,10 @@ int __gpio_request(unsigned gpio)
  err_out:
        return ret;
 }
-EXPORT_SYMBOL(__gpio_request);
 
-void gpio_free(unsigned gpio)
+static void sh_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
-       struct pinmux_info *gpioc = gpio_controller(gpio);
+       struct pinmux_info *gpioc = chip_to_pinmux(chip);
        unsigned long flags;
        int pinmux_type;
 
@@ -362,20 +444,23 @@ void gpio_free(unsigned gpio)
 
        spin_lock_irqsave(&gpio_lock, flags);
 
-       pinmux_type = gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE;
-       pinmux_config_gpio(gpioc, gpio, pinmux_type, GPIO_CFG_FREE);
-       gpioc->gpios[gpio].flags = PINMUX_TYPE_NONE;
+       pinmux_type = gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE;
+       pinmux_config_gpio(gpioc, offset, pinmux_type, GPIO_CFG_FREE);
+       gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
+       gpioc->gpios[offset].flags |= PINMUX_TYPE_NONE;
 
        spin_unlock_irqrestore(&gpio_lock, flags);
 }
-EXPORT_SYMBOL(gpio_free);
 
 static int pinmux_direction(struct pinmux_info *gpioc,
                            unsigned gpio, int new_pinmux_type)
 {
-       int ret, pinmux_type;
+       int pinmux_type;
+       int ret = -EINVAL;
+
+       if (!gpioc)
+               goto err_out;
 
-       ret = -EINVAL;
        pinmux_type = gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE;
 
        switch (pinmux_type) {
@@ -401,102 +486,99 @@ static int pinmux_direction(struct pinmux_info *gpioc,
                               GPIO_CFG_REQ) != 0)
                BUG();
 
-       gpioc->gpios[gpio].flags = new_pinmux_type;
+       gpioc->gpios[gpio].flags &= ~PINMUX_FLAG_TYPE;
+       gpioc->gpios[gpio].flags |= new_pinmux_type;
 
        ret = 0;
  err_out:
        return ret;
 }
 
-int gpio_direction_input(unsigned gpio)
+static int sh_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-       struct pinmux_info *gpioc = gpio_controller(gpio);
+       struct pinmux_info *gpioc = chip_to_pinmux(chip);
        unsigned long flags;
-       int ret = -EINVAL;
-
-       if (!gpioc)
-               goto err_out;
+       int ret;
 
        spin_lock_irqsave(&gpio_lock, flags);
-       ret = pinmux_direction(gpioc, gpio, PINMUX_TYPE_INPUT);
+       ret = pinmux_direction(gpioc, offset, PINMUX_TYPE_INPUT);
        spin_unlock_irqrestore(&gpio_lock, flags);
- err_out:
+
        return ret;
 }
-EXPORT_SYMBOL(gpio_direction_input);
 
-static int __gpio_get_set_value(struct pinmux_info *gpioc,
-                               unsigned gpio, int value,
-                               int do_write)
+static void sh_gpio_set_value(struct pinmux_info *gpioc,
+                            unsigned gpio, int value)
 {
        struct pinmux_data_reg *dr = NULL;
        int bit = 0;
 
-       if (get_data_reg(gpioc, gpio, &dr, &bit) != 0)
+       if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0)
                BUG();
        else
-               value = read_write_reg(dr->reg, dr->reg_width,
-                                      1, bit, !!value, do_write);
-
-       return value;
+               gpio_write_bit(dr, bit, value);
 }
 
-int gpio_direction_output(unsigned gpio, int value)
+static int sh_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+                                   int value)
 {
-       struct pinmux_info *gpioc = gpio_controller(gpio);
+       struct pinmux_info *gpioc = chip_to_pinmux(chip);
        unsigned long flags;
-       int ret = -EINVAL;
-
-       if (!gpioc)
-               goto err_out;
+       int ret;
 
+       sh_gpio_set_value(gpioc, offset, value);
        spin_lock_irqsave(&gpio_lock, flags);
-       __gpio_get_set_value(gpioc, gpio, value, 1);
-       ret = pinmux_direction(gpioc, gpio, PINMUX_TYPE_OUTPUT);
+       ret = pinmux_direction(gpioc, offset, PINMUX_TYPE_OUTPUT);
        spin_unlock_irqrestore(&gpio_lock, flags);
- err_out:
+
        return ret;
 }
-EXPORT_SYMBOL(gpio_direction_output);
 
-int gpio_get_value(unsigned gpio)
+static int sh_gpio_get_value(struct pinmux_info *gpioc, unsigned gpio)
 {
-       struct pinmux_info *gpioc = gpio_controller(gpio);
-       unsigned long flags;
-       int value = 0;
+       struct pinmux_data_reg *dr = NULL;
+       int bit = 0;
 
-       if (!gpioc)
+       if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) {
                BUG();
-       else {
-               spin_lock_irqsave(&gpio_lock, flags);
-               value = __gpio_get_set_value(gpioc, gpio, 0, 0);
-               spin_unlock_irqrestore(&gpio_lock, flags);
+               return 0;
        }
 
-       return value;
+       return gpio_read_reg(dr->reg, dr->reg_width, 1, bit);
 }
-EXPORT_SYMBOL(gpio_get_value);
 
-void gpio_set_value(unsigned gpio, int value)
+static int sh_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-       struct pinmux_info *gpioc = gpio_controller(gpio);
-       unsigned long flags;
+       return sh_gpio_get_value(chip_to_pinmux(chip), offset);
+}
 
-       if (!gpioc)
-               BUG();
-       else {
-               spin_lock_irqsave(&gpio_lock, flags);
-               __gpio_get_set_value(gpioc, gpio, value, 1);
-               spin_unlock_irqrestore(&gpio_lock, flags);
-       }
+static void sh_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       sh_gpio_set_value(chip_to_pinmux(chip), offset, value);
 }
-EXPORT_SYMBOL(gpio_set_value);
 
 int register_pinmux(struct pinmux_info *pip)
 {
-       registered_gpio = pip;
-       pr_info("pinmux: %s handling gpio %d -> %d\n",
+       struct gpio_chip *chip = &pip->chip;
+
+       pr_info("sh pinmux: %s handling gpio %d -> %d\n",
                pip->name, pip->first_gpio, pip->last_gpio);
 
-       return 0;
+       setup_data_regs(pip);
+
+       chip->request = sh_gpio_request;
+       chip->free = sh_gpio_free;
+       chip->direction_input = sh_gpio_direction_input;
+       chip->get = sh_gpio_get;
+       chip->direction_output = sh_gpio_direction_output;
+       chip->set = sh_gpio_set;
+
+       WARN_ON(pip->first_gpio != 0); /* needs testing */
+
+       chip->label = pip->name;
+       chip->owner = THIS_MODULE;
+       chip->base = pip->first_gpio;
+       chip->ngpio = (pip->last_gpio - pip->first_gpio) + 1;
+
+       return gpiochip_add(chip);
 }
index 8457f83242c536a35cc47fb6086a64e01bdb0a80..c34e1e0f9b025072e8fb056d727a61e652656193 100644 (file)
@@ -41,14 +41,6 @@ static int null_rtc_set_time(const time_t secs)
        return 0;
 }
 
-/*
- * Null high precision timer functions for systems lacking one.
- */
-static cycle_t null_hpt_read(void)
-{
-       return 0;
-}
-
 void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
 int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
 
@@ -112,7 +104,6 @@ int do_settimeofday(struct timespec *tv)
 EXPORT_SYMBOL(do_settimeofday);
 #endif /* !CONFIG_GENERIC_TIME */
 
-#ifndef CONFIG_GENERIC_CLOCKEVENTS
 /* last time the RTC clock got updated */
 static long last_rtc_update;
 
@@ -156,7 +147,6 @@ void handle_timer_tick(void)
        update_process_times(user_mode(get_irq_regs()));
 #endif
 }
-#endif /* !CONFIG_GENERIC_CLOCKEVENTS */
 
 #ifdef CONFIG_PM
 int timer_suspend(struct sys_device *dev, pm_message_t state)
@@ -189,7 +179,12 @@ static struct sysdev_class timer_sysclass = {
 
 static int __init timer_init_sysfs(void)
 {
-       int ret = sysdev_class_register(&timer_sysclass);
+       int ret;
+
+       if (!sys_timer)
+               return 0;
+
+       ret = sysdev_class_register(&timer_sysclass);
        if (ret != 0)
                return ret;
 
@@ -200,42 +195,21 @@ device_initcall(timer_init_sysfs);
 
 void (*board_time_init)(void);
 
-/*
- * Shamelessly based on the MIPS and Sparc64 work.
- */
-static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
-unsigned long sh_hpt_frequency = 0;
-
-#define NSEC_PER_CYC_SHIFT     10
-
-static struct clocksource clocksource_sh = {
+struct clocksource clocksource_sh = {
        .name           = "SuperH",
-       .rating         = 200,
-       .mask           = CLOCKSOURCE_MASK(32),
-       .read           = null_hpt_read,
-       .shift          = 16,
-       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-static void __init init_sh_clocksource(void)
-{
-       if (!sh_hpt_frequency || clocksource_sh.read == null_hpt_read)
-               return;
-
-       clocksource_sh.mult = clocksource_hz2mult(sh_hpt_frequency,
-                                                 clocksource_sh.shift);
-
-       timer_ticks_per_nsec_quotient =
-               clocksource_hz2mult(sh_hpt_frequency, NSEC_PER_CYC_SHIFT);
-
-       clocksource_register(&clocksource_sh);
-}
-
 #ifdef CONFIG_GENERIC_TIME
 unsigned long long sched_clock(void)
 {
-       unsigned long long ticks = clocksource_sh.read();
-       return (ticks * timer_ticks_per_nsec_quotient) >> NSEC_PER_CYC_SHIFT;
+       unsigned long long cycles;
+
+       /* jiffies based sched_clock if no clocksource is installed */
+       if (!clocksource_sh.rating)
+               return (unsigned long long)jiffies * (NSEC_PER_SEC / HZ);
+
+       cycles = clocksource_sh.read();
+       return cyc2ns(&clocksource_sh, cycles);
 }
 #endif
 
@@ -259,17 +233,8 @@ void __init time_init(void)
         * initialized for us.
         */
        sys_timer = get_sys_timer();
-       printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);
-
-
-       if (sys_timer->ops->read)
-               clocksource_sh.read = sys_timer->ops->read;
-
-       init_sh_clocksource();
-
-       if (sh_hpt_frequency)
-               printk("Using %lu.%03lu MHz high precision timer.\n",
-                      ((sh_hpt_frequency + 500) / 1000) / 1000,
-                      ((sh_hpt_frequency + 500) / 1000) % 1000);
+       if (unlikely(!sys_timer))
+               panic("System timer missing.\n");
 
+       printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);
 }
index c3d237e1d566e4c91704284b07a8ced28ce2ba1d..9a77ae86b403132a0483c964d2bf83af53794f72 100644 (file)
@@ -35,7 +35,8 @@
 #define MTU2_TSR_1     0xfffe4385
 #define MTU2_TCNT_1    0xfffe4386      /* 16-bit counter */
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7201)
+#if defined(CONFIG_CPU_SUBTYPE_SH7201) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7203)
 #define MTU2_TGRA_1    0xfffe4388
 #else
 #define MTU2_TGRA_1    0xfffe438a
index 0db3f95103368fa4c236e4666b38c828d25ac3a2..2b62f9cff22bb1de9fb476aa9b4be4851909b37f 100644 (file)
@@ -146,7 +146,14 @@ static irqreturn_t tmu_timer_interrupt(int irq, void *dummy)
        _tmu_clear_status(TMU0);
        _tmu_set_irq(TMU0,tmu0_clockevent.mode != CLOCK_EVT_MODE_ONESHOT);
 
-       evt->event_handler(evt);
+       switch (tmu0_clockevent.mode) {
+       case CLOCK_EVT_MODE_ONESHOT:
+       case CLOCK_EVT_MODE_PERIODIC:
+               evt->event_handler(evt);
+               break;
+       default:
+               break;
+       }
 
        return IRQ_HANDLED;
 }
@@ -254,7 +261,14 @@ static int tmu_timer_init(void)
 
        _tmu_start(TMU1);
 
-       sh_hpt_frequency = clk_get_rate(&tmu1_clk);
+       clocksource_sh.rating = 200;
+       clocksource_sh.mask = CLOCKSOURCE_MASK(32);
+       clocksource_sh.read = tmu_timer_read;
+       clocksource_sh.shift = 10;
+       clocksource_sh.mult = clocksource_hz2mult(clk_get_rate(&tmu1_clk),
+                                                 clocksource_sh.shift);
+       clocksource_sh.flags = CLOCK_SOURCE_IS_CONTINUOUS;
+       clocksource_register(&clocksource_sh);
 
        tmu0_clockevent.mult = div_sc(frequency, NSEC_PER_SEC,
                                      tmu0_clockevent.shift);
@@ -264,6 +278,7 @@ static int tmu_timer_init(void)
                        clockevent_delta2ns(1, &tmu0_clockevent);
 
        tmu0_clockevent.cpumask = cpumask_of(0);
+       tmu0_clockevent.rating = 100;
 
        clockevents_register_device(&tmu0_clockevent);
 
@@ -274,7 +289,6 @@ static struct sys_timer_ops tmu_timer_ops = {
        .init           = tmu_timer_init,
        .start          = tmu_timer_start,
        .stop           = tmu_timer_stop,
-       .read           = tmu_timer_read,
 };
 
 struct sys_timer tmu_timer = {
index 1525882190fdac24d6ce01eb50e3a31d3b5dbca3..1efb2879a94f48b30b3f100608328cd3a46b8bd9 100644 (file)
@@ -2,3 +2,4 @@ obj-$(CONFIG_ATMEL_TCB_CLKSRC)  += tcb_clksrc.o
 obj-$(CONFIG_X86_CYCLONE_TIMER)        += cyclone.o
 obj-$(CONFIG_X86_PM_TIMER)     += acpi_pm.o
 obj-$(CONFIG_SCx200HR_TIMER)   += scx200_hrt.o
+obj-$(CONFIG_SH_TIMER_CMT)     += sh_cmt.o
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
new file mode 100644 (file)
index 0000000..7783b42
--- /dev/null
@@ -0,0 +1,615 @@
+/*
+ * SuperH Timer Support - CMT
+ *
+ *  Copyright (C) 2008 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/sh_cmt.h>
+
+struct sh_cmt_priv {
+       void __iomem *mapbase;
+       struct clk *clk;
+       unsigned long width; /* 16 or 32 bit version of hardware block */
+       unsigned long overflow_bit;
+       unsigned long clear_bits;
+       struct irqaction irqaction;
+       struct platform_device *pdev;
+
+       unsigned long flags;
+       unsigned long match_value;
+       unsigned long next_match_value;
+       unsigned long max_match_value;
+       unsigned long rate;
+       spinlock_t lock;
+       struct clock_event_device ced;
+       unsigned long total_cycles;
+};
+
+static DEFINE_SPINLOCK(sh_cmt_lock);
+
+#define CMSTR -1 /* shared register */
+#define CMCSR 0 /* channel register */
+#define CMCNT 1 /* channel register */
+#define CMCOR 2 /* channel register */
+
+static inline unsigned long sh_cmt_read(struct sh_cmt_priv *p, int reg_nr)
+{
+       struct sh_cmt_config *cfg = p->pdev->dev.platform_data;
+       void __iomem *base = p->mapbase;
+       unsigned long offs;
+
+       if (reg_nr == CMSTR) {
+               offs = 0;
+               base -= cfg->channel_offset;
+       } else
+               offs = reg_nr;
+
+       if (p->width == 16)
+               offs <<= 1;
+       else {
+               offs <<= 2;
+               if ((reg_nr == CMCNT) || (reg_nr == CMCOR))
+                       return ioread32(base + offs);
+       }
+
+       return ioread16(base + offs);
+}
+
+static inline void sh_cmt_write(struct sh_cmt_priv *p, int reg_nr,
+                               unsigned long value)
+{
+       struct sh_cmt_config *cfg = p->pdev->dev.platform_data;
+       void __iomem *base = p->mapbase;
+       unsigned long offs;
+
+       if (reg_nr == CMSTR) {
+               offs = 0;
+               base -= cfg->channel_offset;
+       } else
+               offs = reg_nr;
+
+       if (p->width == 16)
+               offs <<= 1;
+       else {
+               offs <<= 2;
+               if ((reg_nr == CMCNT) || (reg_nr == CMCOR)) {
+                       iowrite32(value, base + offs);
+                       return;
+               }
+       }
+
+       iowrite16(value, base + offs);
+}
+
+static unsigned long sh_cmt_get_counter(struct sh_cmt_priv *p,
+                                       int *has_wrapped)
+{
+       unsigned long v1, v2, v3;
+
+       /* Make sure the timer value is stable. Stolen from acpi_pm.c */
+       do {
+               v1 = sh_cmt_read(p, CMCNT);
+               v2 = sh_cmt_read(p, CMCNT);
+               v3 = sh_cmt_read(p, CMCNT);
+       } while (unlikely((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
+                         || (v3 > v1 && v3 < v2)));
+
+       *has_wrapped = sh_cmt_read(p, CMCSR) & p->overflow_bit;
+       return v2;
+}
+
+
+static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start)
+{
+       struct sh_cmt_config *cfg = p->pdev->dev.platform_data;
+       unsigned long flags, value;
+
+       /* start stop register shared by multiple timer channels */
+       spin_lock_irqsave(&sh_cmt_lock, flags);
+       value = sh_cmt_read(p, CMSTR);
+
+       if (start)
+               value |= 1 << cfg->timer_bit;
+       else
+               value &= ~(1 << cfg->timer_bit);
+
+       sh_cmt_write(p, CMSTR, value);
+       spin_unlock_irqrestore(&sh_cmt_lock, flags);
+}
+
+static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
+{
+       struct sh_cmt_config *cfg = p->pdev->dev.platform_data;
+       int ret;
+
+       /* enable clock */
+       ret = clk_enable(p->clk);
+       if (ret) {
+               pr_err("sh_cmt: cannot enable clock \"%s\"\n", cfg->clk);
+               return ret;
+       }
+       *rate = clk_get_rate(p->clk) / 8;
+
+       /* make sure channel is disabled */
+       sh_cmt_start_stop_ch(p, 0);
+
+       /* configure channel, periodic mode and maximum timeout */
+       if (p->width == 16)
+               sh_cmt_write(p, CMCSR, 0);
+       else
+               sh_cmt_write(p, CMCSR, 0x01a4);
+
+       sh_cmt_write(p, CMCOR, 0xffffffff);
+       sh_cmt_write(p, CMCNT, 0);
+
+       /* enable channel */
+       sh_cmt_start_stop_ch(p, 1);
+       return 0;
+}
+
+static void sh_cmt_disable(struct sh_cmt_priv *p)
+{
+       /* disable channel */
+       sh_cmt_start_stop_ch(p, 0);
+
+       /* stop clock */
+       clk_disable(p->clk);
+}
+
+/* private flags */
+#define FLAG_CLOCKEVENT (1 << 0)
+#define FLAG_CLOCKSOURCE (1 << 1)
+#define FLAG_REPROGRAM (1 << 2)
+#define FLAG_SKIPEVENT (1 << 3)
+#define FLAG_IRQCONTEXT (1 << 4)
+
+static void sh_cmt_clock_event_program_verify(struct sh_cmt_priv *p,
+                                             int absolute)
+{
+       unsigned long new_match;
+       unsigned long value = p->next_match_value;
+       unsigned long delay = 0;
+       unsigned long now = 0;
+       int has_wrapped;
+
+       now = sh_cmt_get_counter(p, &has_wrapped);
+       p->flags |= FLAG_REPROGRAM; /* force reprogram */
+
+       if (has_wrapped) {
+               /* we're competing with the interrupt handler.
+                *  -> let the interrupt handler reprogram the timer.
+                *  -> interrupt number two handles the event.
+                */
+               p->flags |= FLAG_SKIPEVENT;
+               return;
+       }
+
+       if (absolute)
+               now = 0;
+
+       do {
+               /* reprogram the timer hardware,
+                * but don't save the new match value yet.
+                */
+               new_match = now + value + delay;
+               if (new_match > p->max_match_value)
+                       new_match = p->max_match_value;
+
+               sh_cmt_write(p, CMCOR, new_match);
+
+               now = sh_cmt_get_counter(p, &has_wrapped);
+               if (has_wrapped && (new_match > p->match_value)) {
+                       /* we are changing to a greater match value,
+                        * so this wrap must be caused by the counter
+                        * matching the old value.
+                        * -> first interrupt reprograms the timer.
+                        * -> interrupt number two handles the event.
+                        */
+                       p->flags |= FLAG_SKIPEVENT;
+                       break;
+               }
+
+               if (has_wrapped) {
+                       /* we are changing to a smaller match value,
+                        * so the wrap must be caused by the counter
+                        * matching the new value.
+                        * -> save programmed match value.
+                        * -> let isr handle the event.
+                        */
+                       p->match_value = new_match;
+                       break;
+               }
+
+               /* be safe: verify hardware settings */
+               if (now < new_match) {
+                       /* timer value is below match value, all good.
+                        * this makes sure we won't miss any match events.
+                        * -> save programmed match value.
+                        * -> let isr handle the event.
+                        */
+                       p->match_value = new_match;
+                       break;
+               }
+
+               /* the counter has reached a value greater
+                * than our new match value. and since the
+                * has_wrapped flag isn't set we must have
+                * programmed a too close event.
+                * -> increase delay and retry.
+                */
+               if (delay)
+                       delay <<= 1;
+               else
+                       delay = 1;
+
+               if (!delay)
+                       pr_warning("sh_cmt: too long delay\n");
+
+       } while (delay);
+}
+
+static void sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta)
+{
+       unsigned long flags;
+
+       if (delta > p->max_match_value)
+               pr_warning("sh_cmt: delta out of range\n");
+
+       spin_lock_irqsave(&p->lock, flags);
+       p->next_match_value = delta;
+       sh_cmt_clock_event_program_verify(p, 0);
+       spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id)
+{
+       struct sh_cmt_priv *p = dev_id;
+
+       /* clear flags */
+       sh_cmt_write(p, CMCSR, sh_cmt_read(p, CMCSR) & p->clear_bits);
+
+       /* update clock source counter to begin with if enabled
+        * the wrap flag should be cleared by the timer specific
+        * isr before we end up here.
+        */
+       if (p->flags & FLAG_CLOCKSOURCE)
+               p->total_cycles += p->match_value;
+
+       if (!(p->flags & FLAG_REPROGRAM))
+               p->next_match_value = p->max_match_value;
+
+       p->flags |= FLAG_IRQCONTEXT;
+
+       if (p->flags & FLAG_CLOCKEVENT) {
+               if (!(p->flags & FLAG_SKIPEVENT)) {
+                       if (p->ced.mode == CLOCK_EVT_MODE_ONESHOT) {
+                               p->next_match_value = p->max_match_value;
+                               p->flags |= FLAG_REPROGRAM;
+                       }
+
+                       p->ced.event_handler(&p->ced);
+               }
+       }
+
+       p->flags &= ~FLAG_SKIPEVENT;
+
+       if (p->flags & FLAG_REPROGRAM) {
+               p->flags &= ~FLAG_REPROGRAM;
+               sh_cmt_clock_event_program_verify(p, 1);
+
+               if (p->flags & FLAG_CLOCKEVENT)
+                       if ((p->ced.mode == CLOCK_EVT_MODE_SHUTDOWN)
+                           || (p->match_value == p->next_match_value))
+                               p->flags &= ~FLAG_REPROGRAM;
+       }
+
+       p->flags &= ~FLAG_IRQCONTEXT;
+
+       return IRQ_HANDLED;
+}
+
+static int sh_cmt_start(struct sh_cmt_priv *p, unsigned long flag)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&p->lock, flags);
+
+       if (!(p->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
+               ret = sh_cmt_enable(p, &p->rate);
+
+       if (ret)
+               goto out;
+       p->flags |= flag;
+
+       /* setup timeout if no clockevent */
+       if ((flag == FLAG_CLOCKSOURCE) && (!(p->flags & FLAG_CLOCKEVENT)))
+               sh_cmt_set_next(p, p->max_match_value);
+ out:
+       spin_unlock_irqrestore(&p->lock, flags);
+
+       return ret;
+}
+
+static void sh_cmt_stop(struct sh_cmt_priv *p, unsigned long flag)
+{
+       unsigned long flags;
+       unsigned long f;
+
+       spin_lock_irqsave(&p->lock, flags);
+
+       f = p->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE);
+       p->flags &= ~flag;
+
+       if (f && !(p->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
+               sh_cmt_disable(p);
+
+       /* adjust the timeout to maximum if only clocksource left */
+       if ((flag == FLAG_CLOCKEVENT) && (p->flags & FLAG_CLOCKSOURCE))
+               sh_cmt_set_next(p, p->max_match_value);
+
+       spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static struct sh_cmt_priv *ced_to_sh_cmt(struct clock_event_device *ced)
+{
+       return container_of(ced, struct sh_cmt_priv, ced);
+}
+
+static void sh_cmt_clock_event_start(struct sh_cmt_priv *p, int periodic)
+{
+       struct clock_event_device *ced = &p->ced;
+
+       sh_cmt_start(p, FLAG_CLOCKEVENT);
+
+       /* TODO: calculate good shift from rate and counter bit width */
+
+       ced->shift = 32;
+       ced->mult = div_sc(p->rate, NSEC_PER_SEC, ced->shift);
+       ced->max_delta_ns = clockevent_delta2ns(p->max_match_value, ced);
+       ced->min_delta_ns = clockevent_delta2ns(0x1f, ced);
+
+       if (periodic)
+               sh_cmt_set_next(p, (p->rate + HZ/2) / HZ);
+       else
+               sh_cmt_set_next(p, p->max_match_value);
+}
+
+static void sh_cmt_clock_event_mode(enum clock_event_mode mode,
+                                   struct clock_event_device *ced)
+{
+       struct sh_cmt_priv *p = ced_to_sh_cmt(ced);
+
+       /* deal with old setting first */
+       switch (ced->mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+       case CLOCK_EVT_MODE_ONESHOT:
+               sh_cmt_stop(p, FLAG_CLOCKEVENT);
+               break;
+       default:
+               break;
+       }
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               pr_info("sh_cmt: %s used for periodic clock events\n",
+                       ced->name);
+               sh_cmt_clock_event_start(p, 1);
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+               pr_info("sh_cmt: %s used for oneshot clock events\n",
+                       ced->name);
+               sh_cmt_clock_event_start(p, 0);
+               break;
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       case CLOCK_EVT_MODE_UNUSED:
+               sh_cmt_stop(p, FLAG_CLOCKEVENT);
+               break;
+       default:
+               break;
+       }
+}
+
+static int sh_cmt_clock_event_next(unsigned long delta,
+                                  struct clock_event_device *ced)
+{
+       struct sh_cmt_priv *p = ced_to_sh_cmt(ced);
+
+       BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT);
+       if (likely(p->flags & FLAG_IRQCONTEXT))
+               p->next_match_value = delta;
+       else
+               sh_cmt_set_next(p, delta);
+
+       return 0;
+}
+
+static void sh_cmt_register_clockevent(struct sh_cmt_priv *p,
+                                      char *name, unsigned long rating)
+{
+       struct clock_event_device *ced = &p->ced;
+
+       memset(ced, 0, sizeof(*ced));
+
+       ced->name = name;
+       ced->features = CLOCK_EVT_FEAT_PERIODIC;
+       ced->features |= CLOCK_EVT_FEAT_ONESHOT;
+       ced->rating = rating;
+       ced->cpumask = cpumask_of(0);
+       ced->set_next_event = sh_cmt_clock_event_next;
+       ced->set_mode = sh_cmt_clock_event_mode;
+
+       pr_info("sh_cmt: %s used for clock events\n", ced->name);
+       ced->mult = 1; /* work around misplaced WARN_ON() in clockevents.c */
+       clockevents_register_device(ced);
+}
+
+int sh_cmt_register(struct sh_cmt_priv *p, char *name,
+                   unsigned long clockevent_rating,
+                   unsigned long clocksource_rating)
+{
+       if (p->width == (sizeof(p->max_match_value) * 8))
+               p->max_match_value = ~0;
+       else
+               p->max_match_value = (1 << p->width) - 1;
+
+       p->match_value = p->max_match_value;
+       spin_lock_init(&p->lock);
+
+       if (clockevent_rating)
+               sh_cmt_register_clockevent(p, name, clockevent_rating);
+
+       return 0;
+}
+
+static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
+{
+       struct sh_cmt_config *cfg = pdev->dev.platform_data;
+       struct resource *res;
+       int irq, ret;
+       ret = -ENXIO;
+
+       memset(p, 0, sizeof(*p));
+       p->pdev = pdev;
+
+       if (!cfg) {
+               dev_err(&p->pdev->dev, "missing platform data\n");
+               goto err0;
+       }
+
+       platform_set_drvdata(pdev, p);
+
+       res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&p->pdev->dev, "failed to get I/O memory\n");
+               goto err0;
+       }
+
+       irq = platform_get_irq(p->pdev, 0);
+       if (irq < 0) {
+               dev_err(&p->pdev->dev, "failed to get irq\n");
+               goto err0;
+       }
+
+       /* map memory, let mapbase point to our channel */
+       p->mapbase = ioremap_nocache(res->start, resource_size(res));
+       if (p->mapbase == NULL) {
+               pr_err("sh_cmt: failed to remap I/O memory\n");
+               goto err0;
+       }
+
+       /* request irq using setup_irq() (too early for request_irq()) */
+       p->irqaction.name = cfg->name;
+       p->irqaction.handler = sh_cmt_interrupt;
+       p->irqaction.dev_id = p;
+       p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL;
+       p->irqaction.mask = CPU_MASK_NONE;
+       ret = setup_irq(irq, &p->irqaction);
+       if (ret) {
+               pr_err("sh_cmt: failed to request irq %d\n", irq);
+               goto err1;
+       }
+
+       /* get hold of clock */
+       p->clk = clk_get(&p->pdev->dev, cfg->clk);
+       if (IS_ERR(p->clk)) {
+               pr_err("sh_cmt: cannot get clock \"%s\"\n", cfg->clk);
+               ret = PTR_ERR(p->clk);
+               goto err2;
+       }
+
+       if (resource_size(res) == 6) {
+               p->width = 16;
+               p->overflow_bit = 0x80;
+               p->clear_bits = ~0xc0;
+       } else {
+               p->width = 32;
+               p->overflow_bit = 0x8000;
+               p->clear_bits = ~0xc000;
+       }
+
+       return sh_cmt_register(p, cfg->name,
+                              cfg->clockevent_rating,
+                              cfg->clocksource_rating);
+ err2:
+       free_irq(irq, p);
+ err1:
+       iounmap(p->mapbase);
+ err0:
+       return ret;
+}
+
+static int __devinit sh_cmt_probe(struct platform_device *pdev)
+{
+       struct sh_cmt_priv *p = platform_get_drvdata(pdev);
+       int ret;
+
+       p = kmalloc(sizeof(*p), GFP_KERNEL);
+       if (p == NULL) {
+               dev_err(&pdev->dev, "failed to allocate driver data\n");
+               return -ENOMEM;
+       }
+
+       ret = sh_cmt_setup(p, pdev);
+       if (ret) {
+               kfree(p);
+
+               platform_set_drvdata(pdev, NULL);
+       }
+       return ret;
+}
+
+static int __devexit sh_cmt_remove(struct platform_device *pdev)
+{
+       return -EBUSY; /* cannot unregister clockevent and clocksource */
+}
+
+static struct platform_driver sh_cmt_device_driver = {
+       .probe          = sh_cmt_probe,
+       .remove         = __devexit_p(sh_cmt_remove),
+       .driver         = {
+               .name   = "sh_cmt",
+       }
+};
+
+static int __init sh_cmt_init(void)
+{
+       return platform_driver_register(&sh_cmt_device_driver);
+}
+
+static void __exit sh_cmt_exit(void)
+{
+       platform_driver_unregister(&sh_cmt_device_driver);
+}
+
+module_init(sh_cmt_init);
+module_exit(sh_cmt_exit);
+
+MODULE_AUTHOR("Magnus Damm");
+MODULE_DESCRIPTION("SuperH CMT Timer Driver");
+MODULE_LICENSE("GPL v2");
index 022e89ffec1da4bc8da86bf6ba8471634f4fdaad..bb9fe122488034e0258c7c42e5111fb321b0ce49 100644 (file)
@@ -1,6 +1,6 @@
 #include <linux/serial_core.h>
 #include <asm/io.h>
-#include <asm/gpio.h>
+#include <linux/gpio.h>
 
 #if defined(CONFIG_H83007) || defined(CONFIG_H83068)
 #include <asm/regs306x.h>
diff --git a/include/linux/sh_cmt.h b/include/linux/sh_cmt.h
new file mode 100644 (file)
index 0000000..68cacde
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __SH_CMT_H__
+#define __SH_CMT_H__
+
+struct sh_cmt_config {
+       char *name;
+       unsigned long channel_offset;
+       int timer_bit;
+       char *clk;
+       unsigned long clockevent_rating;
+       unsigned long clocksource_rating;
+};
+
+#endif /* __SH_CMT_H__ */