Commit b693ffe6 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'sh/for-2.6.27' of git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6

* 'sh/for-2.6.27' of git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6:
  i2c: fix i2c-sh_mobile timing issues
  sh64: resume_kernel fix for kernel oops built with CONFIG_BKL_PREEMPT=y.
  sh: resume_kernel fix for kernel oops built with CONFIG_BKL_PREEMPT=y.
  sh: fix semtimedop syscall
  sh: update AP325RXA defconfig
  sh: update Migo-R defconfig
  sh: fix platform_resource_setup_memory() section mismatch
  sh: fix kexec entry point for crash kernels
  sh: crash kernel resource fix
  sh: fix ptrace_64.c:user_disable_single_step()
  sh64: re-add the __strnlen_user() prototype
parents 14408c4f 4eb00c9f
# #
# Automatically generated make config: don't edit # Automatically generated make config: don't edit
# Linux kernel version: 2.6.26 # Linux kernel version: 2.6.27-rc4
# Wed Jul 30 01:18:59 2008 # Tue Aug 26 14:21:17 2008
# #
CONFIG_SUPERH=y CONFIG_SUPERH=y
CONFIG_SUPERH32=y CONFIG_SUPERH32=y
...@@ -11,6 +11,7 @@ CONFIG_GENERIC_BUG=y ...@@ -11,6 +11,7 @@ CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_GENERIC_IRQ_PROBE=y CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_TIME=y CONFIG_GENERIC_TIME=y
...@@ -20,7 +21,6 @@ CONFIG_LOCKDEP_SUPPORT=y ...@@ -20,7 +21,6 @@ CONFIG_LOCKDEP_SUPPORT=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_ARCH_NO_VIRT_TO_BUS=y CONFIG_ARCH_NO_VIRT_TO_BUS=y
CONFIG_ARCH_SUPPORTS_AOUT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
# #
...@@ -58,7 +58,6 @@ CONFIG_SYSCTL=y ...@@ -58,7 +58,6 @@ CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y CONFIG_EMBEDDED=y
CONFIG_UID16=y CONFIG_UID16=y
CONFIG_SYSCTL_SYSCALL=y CONFIG_SYSCTL_SYSCALL=y
CONFIG_SYSCTL_SYSCALL_CHECK=y
# CONFIG_KALLSYMS is not set # CONFIG_KALLSYMS is not set
CONFIG_HOTPLUG=y CONFIG_HOTPLUG=y
CONFIG_PRINTK=y CONFIG_PRINTK=y
...@@ -89,6 +88,7 @@ CONFIG_HAVE_OPROFILE=y ...@@ -89,6 +88,7 @@ CONFIG_HAVE_OPROFILE=y
# CONFIG_USE_GENERIC_SMP_HELPERS is not set # CONFIG_USE_GENERIC_SMP_HELPERS is not set
CONFIG_HAVE_CLK=y CONFIG_HAVE_CLK=y
CONFIG_PROC_PAGE_MONITOR=y CONFIG_PROC_PAGE_MONITOR=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_SLABINFO=y CONFIG_SLABINFO=y
CONFIG_RT_MUTEXES=y CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set # CONFIG_TINY_SHMEM is not set
...@@ -261,9 +261,10 @@ CONFIG_HZ_250=y ...@@ -261,9 +261,10 @@ CONFIG_HZ_250=y
# CONFIG_HZ_300 is not set # CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set # CONFIG_HZ_1000 is not set
CONFIG_HZ=250 CONFIG_HZ=250
# CONFIG_SCHED_HRTICK is not set CONFIG_SCHED_HRTICK=y
# CONFIG_KEXEC is not set # CONFIG_KEXEC is not set
# CONFIG_CRASH_DUMP is not set # CONFIG_CRASH_DUMP is not set
CONFIG_SECCOMP=y
# CONFIG_PREEMPT_NONE is not set # CONFIG_PREEMPT_NONE is not set
# CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT_VOLUNTARY is not set
CONFIG_PREEMPT=y CONFIG_PREEMPT=y
...@@ -289,10 +290,6 @@ CONFIG_CMDLINE="console=tty1 console=ttySC5,38400 root=/dev/nfs ip=dhcp" ...@@ -289,10 +290,6 @@ CONFIG_CMDLINE="console=tty1 console=ttySC5,38400 root=/dev/nfs ip=dhcp"
# #
CONFIG_BINFMT_ELF=y CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set # CONFIG_BINFMT_MISC is not set
#
# Networking
#
CONFIG_NET=y CONFIG_NET=y
# #
...@@ -647,6 +644,7 @@ CONFIG_SSB_POSSIBLE=y ...@@ -647,6 +644,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_CORE is not set # CONFIG_MFD_CORE is not set
# CONFIG_MFD_SM501 is not set # CONFIG_MFD_SM501 is not set
# CONFIG_HTC_PASIC3 is not set # CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
# #
# Multimedia devices # Multimedia devices
...@@ -690,7 +688,10 @@ CONFIG_DUMMY_CONSOLE=y ...@@ -690,7 +688,10 @@ CONFIG_DUMMY_CONSOLE=y
# CONFIG_ACCESSIBILITY is not set # CONFIG_ACCESSIBILITY is not set
# CONFIG_RTC_CLASS is not set # CONFIG_RTC_CLASS is not set
# CONFIG_DMADEVICES is not set # CONFIG_DMADEVICES is not set
# CONFIG_UIO is not set CONFIG_UIO=y
# CONFIG_UIO_PDRV is not set
CONFIG_UIO_PDRV_GENIRQ=y
# CONFIG_UIO_SMX is not set
# #
# File systems # File systems
...@@ -854,6 +855,7 @@ CONFIG_FRAME_WARN=1024 ...@@ -854,6 +855,7 @@ CONFIG_FRAME_WARN=1024
# CONFIG_DEBUG_KERNEL is not set # CONFIG_DEBUG_KERNEL is not set
# CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_DEBUG_MEMORY_INIT is not set # CONFIG_DEBUG_MEMORY_INIT is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
# CONFIG_SAMPLES is not set # CONFIG_SAMPLES is not set
# CONFIG_SH_STANDARD_BIOS is not set # CONFIG_SH_STANDARD_BIOS is not set
# CONFIG_EARLY_SCIF_CONSOLE is not set # CONFIG_EARLY_SCIF_CONSOLE is not set
......
# #
# Automatically generated make config: don't edit # Automatically generated make config: don't edit
# Linux kernel version: 2.6.26 # Linux kernel version: 2.6.27-rc4
# Wed Jul 30 01:44:41 2008 # Tue Aug 26 14:18:17 2008
# #
CONFIG_SUPERH=y CONFIG_SUPERH=y
CONFIG_SUPERH32=y CONFIG_SUPERH32=y
...@@ -11,6 +11,7 @@ CONFIG_GENERIC_BUG=y ...@@ -11,6 +11,7 @@ CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_GENERIC_IRQ_PROBE=y CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_TIME=y CONFIG_GENERIC_TIME=y
...@@ -21,7 +22,6 @@ CONFIG_LOCKDEP_SUPPORT=y ...@@ -21,7 +22,6 @@ CONFIG_LOCKDEP_SUPPORT=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_ARCH_NO_VIRT_TO_BUS=y CONFIG_ARCH_NO_VIRT_TO_BUS=y
CONFIG_ARCH_SUPPORTS_AOUT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
# #
...@@ -87,6 +87,7 @@ CONFIG_HAVE_OPROFILE=y ...@@ -87,6 +87,7 @@ CONFIG_HAVE_OPROFILE=y
# CONFIG_USE_GENERIC_SMP_HELPERS is not set # CONFIG_USE_GENERIC_SMP_HELPERS is not set
CONFIG_HAVE_CLK=y CONFIG_HAVE_CLK=y
CONFIG_PROC_PAGE_MONITOR=y CONFIG_PROC_PAGE_MONITOR=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_SLABINFO=y CONFIG_SLABINFO=y
CONFIG_RT_MUTEXES=y CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set # CONFIG_TINY_SHMEM is not set
...@@ -270,6 +271,7 @@ CONFIG_HZ=250 ...@@ -270,6 +271,7 @@ CONFIG_HZ=250
# CONFIG_SCHED_HRTICK is not set # CONFIG_SCHED_HRTICK is not set
# CONFIG_KEXEC is not set # CONFIG_KEXEC is not set
# CONFIG_CRASH_DUMP is not set # CONFIG_CRASH_DUMP is not set
CONFIG_SECCOMP=y
CONFIG_PREEMPT_NONE=y CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set # CONFIG_PREEMPT is not set
...@@ -294,10 +296,6 @@ CONFIG_CMDLINE="console=ttySC0,115200 earlyprintk=serial ip=on" ...@@ -294,10 +296,6 @@ CONFIG_CMDLINE="console=ttySC0,115200 earlyprintk=serial ip=on"
# #
CONFIG_BINFMT_ELF=y CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set # CONFIG_BINFMT_MISC is not set
#
# Networking
#
CONFIG_NET=y CONFIG_NET=y
# #
...@@ -649,6 +647,7 @@ CONFIG_HW_RANDOM=y ...@@ -649,6 +647,7 @@ CONFIG_HW_RANDOM=y
CONFIG_I2C=y CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y CONFIG_I2C_BOARDINFO=y
# CONFIG_I2C_CHARDEV is not set # CONFIG_I2C_CHARDEV is not set
CONFIG_I2C_HELPER_AUTO=y
# #
# I2C Hardware Bus support # I2C Hardware Bus support
...@@ -709,6 +708,7 @@ CONFIG_SSB_POSSIBLE=y ...@@ -709,6 +708,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_CORE is not set # CONFIG_MFD_CORE is not set
# CONFIG_MFD_SM501 is not set # CONFIG_MFD_SM501 is not set
# CONFIG_HTC_PASIC3 is not set # CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
# #
# Multimedia devices # Multimedia devices
...@@ -755,6 +755,8 @@ CONFIG_USB_ARCH_HAS_HCD=y ...@@ -755,6 +755,8 @@ CONFIG_USB_ARCH_HAS_HCD=y
# CONFIG_USB is not set # CONFIG_USB is not set
# CONFIG_USB_OTG_WHITELIST is not set # CONFIG_USB_OTG_WHITELIST is not set
# CONFIG_USB_OTG_BLACKLIST_HUB is not set # CONFIG_USB_OTG_BLACKLIST_HUB is not set
# CONFIG_USB_MUSB_HDRC is not set
# CONFIG_USB_GADGET_MUSB_HDRC is not set
# #
# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
...@@ -842,7 +844,10 @@ CONFIG_RTC_DRV_RS5C372=y ...@@ -842,7 +844,10 @@ CONFIG_RTC_DRV_RS5C372=y
# #
CONFIG_RTC_DRV_SH=y CONFIG_RTC_DRV_SH=y
# CONFIG_DMADEVICES is not set # CONFIG_DMADEVICES is not set
# CONFIG_UIO is not set CONFIG_UIO=y
# CONFIG_UIO_PDRV is not set
CONFIG_UIO_PDRV_GENIRQ=y
# CONFIG_UIO_SMX is not set
# #
# File systems # File systems
......
...@@ -76,4 +76,6 @@ extern long __put_user_asm_l(void *, long); ...@@ -76,4 +76,6 @@ extern long __put_user_asm_l(void *, long);
extern long __put_user_asm_q(void *, long); extern long __put_user_asm_q(void *, long);
extern void __put_user_unknown(void); extern void __put_user_unknown(void);
extern long __strnlen_user(const char *__s, long __n);
#endif /* __ASM_SH_UACCESS_64_H */ #endif /* __ASM_SH_UACCESS_64_H */
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* arch/sh/kernel/cpu/sh5/entry.S * arch/sh/kernel/cpu/sh5/entry.S
* *
* Copyright (C) 2000, 2001 Paolo Alberelli * Copyright (C) 2000, 2001 Paolo Alberelli
* Copyright (C) 2004 - 2007 Paul Mundt * Copyright (C) 2004 - 2008 Paul Mundt
* Copyright (C) 2003, 2004 Richard Curnow * Copyright (C) 2003, 2004 Richard Curnow
* *
* This file is subject to the terms and conditions of the GNU General Public * This file is subject to the terms and conditions of the GNU General Public
...@@ -923,6 +923,8 @@ ret_from_exception: ...@@ -923,6 +923,8 @@ ret_from_exception:
blink tr0, ZERO blink tr0, ZERO
resume_kernel: resume_kernel:
CLI()
pta restore_all, tr0 pta restore_all, tr0
getcon KCR0, r6 getcon KCR0, r6
...@@ -939,19 +941,11 @@ need_resched: ...@@ -939,19 +941,11 @@ need_resched:
andi r7, 0xf0, r7 andi r7, 0xf0, r7
bne r7, ZERO, tr0 bne r7, ZERO, tr0
movi ((PREEMPT_ACTIVE >> 16) & 65535), r8 movi preempt_schedule_irq, r7
shori (PREEMPT_ACTIVE & 65535), r8
st.l r6, TI_PRE_COUNT, r8
STI()
movi schedule, r7
ori r7, 1, r7 ori r7, 1, r7
ptabs r7, tr1 ptabs r7, tr1
blink tr1, LINK blink tr1, LINK
st.l r6, TI_PRE_COUNT, ZERO
CLI()
pta need_resched, tr1 pta need_resched, tr1
blink tr1, ZERO blink tr1, ZERO
#endif #endif
......
...@@ -92,6 +92,7 @@ ENTRY(ret_from_irq) ...@@ -92,6 +92,7 @@ ENTRY(ret_from_irq)
bra resume_userspace bra resume_userspace
nop nop
ENTRY(resume_kernel) ENTRY(resume_kernel)
cli
mov.l @(TI_PRE_COUNT,r8), r0 ! current_thread_info->preempt_count mov.l @(TI_PRE_COUNT,r8), r0 ! current_thread_info->preempt_count
tst r0, r0 tst r0, r0
bf noresched bf noresched
...@@ -105,28 +106,9 @@ need_resched: ...@@ -105,28 +106,9 @@ need_resched:
and #0xf0, r0 ! interrupts off (exception path)? and #0xf0, r0 ! interrupts off (exception path)?
cmp/eq #0xf0, r0 cmp/eq #0xf0, r0
bt noresched bt noresched
mov.l 1f, r0
mov.l r0, @(TI_PRE_COUNT,r8)
#ifdef CONFIG_TRACE_IRQFLAGS
mov.l 3f, r0 mov.l 3f, r0
jsr @r0 jsr @r0 ! call preempt_schedule_irq
nop
#endif
sti
mov.l 2f, r0
jsr @r0
nop
mov #0, r0
mov.l r0, @(TI_PRE_COUNT,r8)
cli
#ifdef CONFIG_TRACE_IRQFLAGS
mov.l 4f, r0
jsr @r0
nop nop
#endif
bra need_resched bra need_resched
nop nop
...@@ -137,10 +119,7 @@ noresched: ...@@ -137,10 +119,7 @@ noresched:
.align 2 .align 2
1: .long PREEMPT_ACTIVE 1: .long PREEMPT_ACTIVE
2: .long schedule 2: .long schedule
#ifdef CONFIG_TRACE_IRQFLAGS 3: .long preempt_schedule_irq
3: .long trace_hardirqs_on
4: .long trace_hardirqs_off
#endif
#endif #endif
ENTRY(resume_userspace) ENTRY(resume_userspace)
......
...@@ -102,7 +102,7 @@ void machine_kexec(struct kimage *image) ...@@ -102,7 +102,7 @@ void machine_kexec(struct kimage *image)
/* now call it */ /* now call it */
rnk = (relocate_new_kernel_t) reboot_code_buffer; rnk = (relocate_new_kernel_t) reboot_code_buffer;
(*rnk)(page_list, reboot_code_buffer, image->start, vbr_reg); (*rnk)(page_list, reboot_code_buffer, P2SEGADDR(image->start), vbr_reg);
} }
void arch_crash_save_vmcoreinfo(void) void arch_crash_save_vmcoreinfo(void)
......
...@@ -131,6 +131,8 @@ void user_enable_single_step(struct task_struct *child) ...@@ -131,6 +131,8 @@ void user_enable_single_step(struct task_struct *child)
void user_disable_single_step(struct task_struct *child) void user_disable_single_step(struct task_struct *child)
{ {
struct pt_regs *regs = child->thread.uregs;
regs->sr &= ~SR_SSTEP; regs->sr &= ~SR_SSTEP;
} }
......
...@@ -171,6 +171,7 @@ static void __init reserve_crashkernel(void) ...@@ -171,6 +171,7 @@ static void __init reserve_crashkernel(void)
(unsigned long)(free_mem >> 20)); (unsigned long)(free_mem >> 20));
crashk_res.start = crash_base; crashk_res.start = crash_base;
crashk_res.end = crash_base + crash_size - 1; crashk_res.end = crash_base + crash_size - 1;
insert_resource(&iomem_resource, &crashk_res);
} }
} }
#else #else
...@@ -204,11 +205,6 @@ void __init __add_active_range(unsigned int nid, unsigned long start_pfn, ...@@ -204,11 +205,6 @@ void __init __add_active_range(unsigned int nid, unsigned long start_pfn,
request_resource(res, &data_resource); request_resource(res, &data_resource);
request_resource(res, &bss_resource); request_resource(res, &bss_resource);
#ifdef CONFIG_KEXEC
if (crashk_res.start != crashk_res.end)
request_resource(res, &crashk_res);
#endif
add_active_range(nid, start_pfn, end_pfn); add_active_range(nid, start_pfn, end_pfn);
} }
......
...@@ -170,7 +170,7 @@ asmlinkage int sys_ipc(uint call, int first, int second, ...@@ -170,7 +170,7 @@ asmlinkage int sys_ipc(uint call, int first, int second,
version = call >> 16; /* hack for backward compatibility */ version = call >> 16; /* hack for backward compatibility */
call &= 0xffff; call &= 0xffff;
if (call <= SEMCTL) if (call <= SEMTIMEDOP)
switch (call) { switch (call) {
case SEMOP: case SEMOP:
return sys_semtimedop(first, return sys_semtimedop(first,
......
...@@ -101,7 +101,7 @@ static int __init memchunk_setup(char *str) ...@@ -101,7 +101,7 @@ static int __init memchunk_setup(char *str)
} }
__setup("memchunk.", memchunk_setup); __setup("memchunk.", memchunk_setup);
static void memchunk_cmdline_override(char *name, unsigned long *sizep) static void __init memchunk_cmdline_override(char *name, unsigned long *sizep)
{ {
char *p = boot_command_line; char *p = boot_command_line;
int k = strlen(name); int k = strlen(name);
...@@ -118,8 +118,8 @@ static void memchunk_cmdline_override(char *name, unsigned long *sizep) ...@@ -118,8 +118,8 @@ static void memchunk_cmdline_override(char *name, unsigned long *sizep)
} }
} }
int platform_resource_setup_memory(struct platform_device *pdev, int __init platform_resource_setup_memory(struct platform_device *pdev,
char *name, unsigned long memsize) char *name, unsigned long memsize)
{ {
struct resource *r; struct resource *r;
dma_addr_t dma_handle; dma_addr_t dma_handle;
......
...@@ -31,13 +31,84 @@ ...@@ -31,13 +31,84 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/io.h> #include <linux/io.h>
/* Transmit operation: */
/* */
/* 0 byte transmit */
/* BUS: S A8 ACK P */
/* IRQ: DTE WAIT */
/* ICIC: */
/* ICCR: 0x94 0x90 */
/* ICDR: A8 */
/* */
/* 1 byte transmit */
/* BUS: S A8 ACK D8(1) ACK P */
/* IRQ: DTE WAIT WAIT */
/* ICIC: -DTE */
/* ICCR: 0x94 0x90 */
/* ICDR: A8 D8(1) */
/* */
/* 2 byte transmit */
/* BUS: S A8 ACK D8(1) ACK D8(2) ACK P */
/* IRQ: DTE WAIT WAIT WAIT */
/* ICIC: -DTE */
/* ICCR: 0x94 0x90 */
/* ICDR: A8 D8(1) D8(2) */
/* */
/* 3 bytes or more, +---------+ gets repeated */
/* */
/* */
/* Receive operation: */
/* */
/* 0 byte receive - not supported since slave may hold SDA low */
/* */
/* 1 byte receive [TX] | [RX] */
/* BUS: S A8 ACK | D8(1) ACK P */
/* IRQ: DTE WAIT | WAIT DTE */
/* ICIC: -DTE | +DTE */
/* ICCR: 0x94 0x81 | 0xc0 */
/* ICDR: A8 | D8(1) */
/* */
/* 2 byte receive [TX]| [RX] */
/* BUS: S A8 ACK | D8(1) ACK D8(2) ACK P */
/* IRQ: DTE WAIT | WAIT WAIT DTE */
/* ICIC: -DTE | +DTE */
/* ICCR: 0x94 0x81 | 0xc0 */
/* ICDR: A8 | D8(1) D8(2) */
/* */
/* 3 byte receive [TX] | [RX] */
/* BUS: S A8 ACK | D8(1) ACK D8(2) ACK D8(3) ACK P */
/* IRQ: DTE WAIT | WAIT WAIT WAIT DTE */
/* ICIC: -DTE | +DTE */
/* ICCR: 0x94 0x81 | 0xc0 */
/* ICDR: A8 | D8(1) D8(2) D8(3) */
/* */
/* 4 bytes or more, this part is repeated +---------+ */
/* */
/* */
/* Interrupt order and BUSY flag */
/* ___ _ */
/* SDA ___\___XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAAAAAAAAA___/ */
/* SCL \_/1\_/2\_/3\_/4\_/5\_/6\_/7\_/8\___/9\_____/ */
/* */
/* S D7 D6 D5 D4 D3 D2 D1 D0 P */
/* ___ */
/* WAIT IRQ ________________________________/ \___________ */
/* TACK IRQ ____________________________________/ \_______ */
/* DTE IRQ __________________________________________/ \_ */
/* AL IRQ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
/* _______________________________________________ */
/* BUSY __/ \_ */
/* */
enum sh_mobile_i2c_op { enum sh_mobile_i2c_op {
OP_START = 0, OP_START = 0,
OP_TX_ONLY, OP_TX_FIRST,
OP_TX,
OP_TX_STOP, OP_TX_STOP,
OP_TX_TO_RX, OP_TX_TO_RX,
OP_RX_ONLY, OP_RX,
OP_RX_STOP, OP_RX_STOP,
OP_RX_STOP_DATA,
}; };
struct sh_mobile_i2c_data { struct sh_mobile_i2c_data {
...@@ -127,25 +198,34 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, ...@@ -127,25 +198,34 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
spin_lock_irqsave(&pd->lock, flags); spin_lock_irqsave(&pd->lock, flags);
switch (op) { switch (op) {
case OP_START: case OP_START: /* issue start and trigger DTE interrupt */
iowrite8(0x94, ICCR(pd)); iowrite8(0x94, ICCR(pd));
break; break;
case OP_TX_ONLY: case OP_TX_FIRST: /* disable DTE interrupt and write data */
iowrite8(ICIC_WAITE | ICIC_ALE | ICIC_TACKE, ICIC(pd));
iowrite8(data, ICDR(pd)); iowrite8(data, ICDR(pd));
break; break;
case OP_TX_STOP: case OP_TX: /* write data */
iowrite8(data, ICDR(pd)); iowrite8(data, ICDR(pd));
iowrite8(0x90, ICCR(pd));
iowrite8(ICIC_ALE | ICIC_TACKE, ICIC(pd));
break; break;
case OP_TX_TO_RX: case OP_TX_STOP: /* write data and issue a stop afterwards */
iowrite8(data, ICDR(pd)); iowrite8(data, ICDR(pd));
iowrite8(0x90, ICCR(pd));
break;
case OP_TX_TO_RX: /* select read mode */
iowrite8(0x81, ICCR(pd)); iowrite8(0x81, ICCR(pd));
break; break;
case OP_RX_ONLY: case OP_RX: /* just read data */
ret = ioread8(ICDR(pd)); ret = ioread8(ICDR(pd));
break; break;
case OP_RX_STOP: case OP_RX_STOP: /* enable DTE interrupt, issue stop */
iowrite8(ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE,
ICIC(pd));
iowrite8(0xc0, ICCR(pd));
break;
case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */
iowrite8(ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE,
ICIC(pd));
ret = ioread8(ICDR(pd)); ret = ioread8(ICDR(pd));
iowrite8(0xc0, ICCR(pd)); iowrite8(0xc0, ICCR(pd));
break; break;
...@@ -157,58 +237,120 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, ...@@ -157,58 +237,120 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
return ret; return ret;
} }
static int sh_mobile_i2c_is_first_byte(struct sh_mobile_i2c_data *pd)
{
if (pd->pos == -1)
return 1;
return 0;
}
static int sh_mobile_i2c_is_last_byte(struct sh_mobile_i2c_data *pd)
{
if (pd->pos == (pd->msg->len - 1))
return 1;
return 0;
}
static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd,
unsigned char *buf)
{
switch (pd->pos) {
case -1:
*buf = (pd->msg->addr & 0x7f) << 1;
*buf |= (pd->msg->flags & I2C_M_RD) ? 1 : 0;
break;
default:
*buf = pd->msg->buf[pd->pos];
}
}
static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd)
{
unsigned char data;
if (pd->pos == pd->msg->len)
return 1;
sh_mobile_i2c_get_data(pd, &data);
if (sh_mobile_i2c_is_last_byte(pd))
i2c_op(pd, OP_TX_STOP, data);
else if (sh_mobile_i2c_is_first_byte(pd))
i2c_op(pd, OP_TX_FIRST, data);
else
i2c_op(pd, OP_TX, data);
pd->pos++;
return 0;
}
static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd)
{
unsigned char data;
int real_pos;
do {
if (pd->pos <= -1) {
sh_mobile_i2c_get_data(pd, &data);
if (sh_mobile_i2c_is_first_byte(pd))
i2c_op(pd, OP_TX_FIRST, data);
else
i2c_op(pd, OP_TX, data);
break;
}
if (pd->pos == 0) {
i2c_op(pd, OP_TX_TO_RX, 0);
break;
}
real_pos = pd->pos - 2;
if (pd->pos == pd->msg->len) {
if (real_pos < 0) {
i2c_op(pd, OP_RX_STOP, 0);
break;
}
data = i2c_op(pd, OP_RX_STOP_DATA, 0);
} else
data = i2c_op(pd, OP_RX, 0);
pd->msg->buf[real_pos] = data;
} while (0);
pd->pos++;
return pd->pos == (pd->msg->len + 2);
}
static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
{ {
struct platform_device *dev = dev_id; struct platform_device *dev = dev_id;
struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev); struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev);
struct i2c_msg *msg = pd->msg; unsigned char sr;
unsigned char data, sr; int wakeup;
int wakeup = 0;
sr = ioread8(ICSR(pd)); sr = ioread8(ICSR(pd));
pd->sr |= sr; pd->sr |= sr; /* remember state */
dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr, dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr,
(msg->flags & I2C_M_RD) ? "read" : "write", (pd->msg->flags & I2C_M_RD) ? "read" : "write",
pd->pos, msg->len); pd->pos, pd->msg->len);
if (sr & (ICSR_AL | ICSR_TACK)) { if (sr & (ICSR_AL | ICSR_TACK)) {
iowrite8(0, ICIC(pd)); /* disable interrupts */ /* don't interrupt transaction - continue to issue stop */
wakeup = 1; iowrite8(sr & ~(ICSR_AL | ICSR_TACK), ICSR(pd));
goto do_wakeup; wakeup = 0;
} } else if (pd->msg->flags & I2C_M_RD)
wakeup = sh_mobile_i2c_isr_rx(pd);
else
wakeup = sh_mobile_i2c_isr_tx(pd);
if (pd->pos == msg->len) { if (sr & ICSR_WAIT) /* TODO: add delay here to support slow acks */
i2c_op(pd, OP_RX_ONLY, 0); iowrite8(sr & ~ICSR_WAIT, ICSR(pd));
wakeup = 1;
goto do_wakeup;
}
if (pd->pos == -1) {
data = (msg->addr & 0x7f) << 1;
data |= (msg->flags & I2C_M_RD) ? 1 : 0;
} else
data = msg->buf[pd->pos];
if ((pd->pos == -1) || !(msg->flags & I2C_M_RD)) {
if (msg->flags & I2C_M_RD)
i2c_op(pd, OP_TX_TO_RX, data);
else if (pd->pos == (msg->len - 1)) {
i2c_op(pd, OP_TX_STOP, data);
wakeup = 1;
} else
i2c_op(pd, OP_TX_ONLY, data);
} else {
if (pd->pos == (msg->len - 1))
data = i2c_op(pd, OP_RX_STOP, 0);
else
data = i2c_op(pd, OP_RX_ONLY, 0);
msg->buf[pd->pos] = data;
}
pd->pos++;
do_wakeup:
if (wakeup) { if (wakeup) {
pd->sr |= SW_DONE; pd->sr |= SW_DONE;
wake_up(&pd->wait); wake_up(&pd->wait);
...@@ -219,6 +361,11 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) ...@@ -219,6 +361,11 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg) static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg)
{ {
if (usr_msg->len == 0 && (usr_msg->flags & I2C_M_RD)) {
dev_err(pd->dev, "Unsupported zero length i2c read\n");
return -EIO;
}
/* Initialize channel registers */ /* Initialize channel registers */
iowrite8(ioread8(ICCR(pd)) & ~ICCR_ICE, ICCR(pd)); iowrite8(ioread8(ICCR(pd)) & ~ICCR_ICE, ICCR(pd));
...@@ -233,9 +380,8 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg) ...@@ -233,9 +380,8 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg)
pd->pos = -1; pd->pos = -1;
pd->sr = 0; pd->sr = 0;
/* Enable all interrupts except wait */ /* Enable all interrupts to begin with */
iowrite8(ioread8(ICIC(pd)) | ICIC_ALE | ICIC_TACKE | ICIC_DTEE, iowrite8(ICIC_WAITE | ICIC_ALE | ICIC_TACKE | ICIC_DTEE, ICIC(pd));
ICIC(pd));
return 0; return 0;
} }
...@@ -268,25 +414,18 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, ...@@ -268,25 +414,18 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
if (!k) if (!k)
dev_err(pd->dev, "Transfer request timed out\n"); dev_err(pd->dev, "Transfer request timed out\n");
retry_count = 10; retry_count = 1000;
again: again:
val = ioread8(ICSR(pd)); val = ioread8(ICSR(pd));
dev_dbg(pd->dev, "val 0x%02x pd->sr 0x%02x\n", val, pd->sr); dev_dbg(pd->dev, "val 0x%02x pd->sr 0x%02x\n", val, pd->sr);
if ((val | pd->sr) & (ICSR_TACK | ICSR_AL)) {
err = -EIO;
break;
}
/* the interrupt handler may wake us up before the /* the interrupt handler may wake us up before the
* transfer is finished, so poll the hardware * transfer is finished, so poll the hardware
* until we're done. * until we're done.
*/ */
if (val & ICSR_BUSY) {
if (!(!(val & ICSR_BUSY) && (val & ICSR_SCLM) && udelay(10);
(val & ICSR_SDAM))) {
msleep(1);
if (retry_count--) if (retry_count--)
goto again; goto again;
...@@ -294,6 +433,12 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, ...@@ -294,6 +433,12 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
dev_err(pd->dev, "Polling timed out\n"); dev_err(pd->dev, "Polling timed out\n");
break; break;
} }
/* handle missing acknowledge and arbitration lost */
if ((val | pd->sr) & (ICSR_TACK | ICSR_AL)) {
err = -EIO;
break;
}
} }
deactivate_ch(pd); deactivate_ch(pd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment