Commit fb8c7fb2 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86:
  xen: fix UP setup of shared_info
  xen: fix RMW when unmasking events
  x86, documentation: nmi_watchdog=2 works on x86_64
  x86: stricter check in follow_huge_addr()
  rdc321x: GPIO routines bugfixes
  x86: ptrace.c: fix defined-but-unused warnings
  x86: fix prefetch workaround
parents 074fcab5 2e8fe719
...@@ -23,8 +23,7 @@ kernel debugging options, such as Kernel Stack Meter or Kernel Tracer, ...@@ -23,8 +23,7 @@ kernel debugging options, such as Kernel Stack Meter or Kernel Tracer,
may implicitly disable the NMI watchdog.] may implicitly disable the NMI watchdog.]
For x86-64, the needed APIC is always compiled in, and the NMI watchdog is For x86-64, the needed APIC is always compiled in, and the NMI watchdog is
always enabled with I/O-APIC mode (nmi_watchdog=1). Currently, local APIC always enabled with I/O-APIC mode (nmi_watchdog=1).
mode (nmi_watchdog=2) does not work on x86-64.
Using local APIC (nmi_watchdog=2) needs the first performance register, so Using local APIC (nmi_watchdog=2) needs the first performance register, so
you can't use it for other purposes (such as high precision performance you can't use it for other purposes (such as high precision performance
......
...@@ -600,21 +600,6 @@ static int ptrace_bts_read_record(struct task_struct *child, ...@@ -600,21 +600,6 @@ static int ptrace_bts_read_record(struct task_struct *child,
return sizeof(ret); return sizeof(ret);
} }
static int ptrace_bts_write_record(struct task_struct *child,
const struct bts_struct *in)
{
int retval;
if (!child->thread.ds_area_msr)
return -ENXIO;
retval = ds_write_bts((void *)child->thread.ds_area_msr, in);
if (retval)
return retval;
return sizeof(*in);
}
static int ptrace_bts_clear(struct task_struct *child) static int ptrace_bts_clear(struct task_struct *child)
{ {
if (!child->thread.ds_area_msr) if (!child->thread.ds_area_msr)
...@@ -657,75 +642,6 @@ static int ptrace_bts_drain(struct task_struct *child, ...@@ -657,75 +642,6 @@ static int ptrace_bts_drain(struct task_struct *child,
return end; return end;
} }
static int ptrace_bts_realloc(struct task_struct *child,
int size, int reduce_size)
{
unsigned long rlim, vm;
int ret, old_size;
if (size < 0)
return -EINVAL;
old_size = ds_get_bts_size((void *)child->thread.ds_area_msr);
if (old_size < 0)
return old_size;
ret = ds_free((void **)&child->thread.ds_area_msr);
if (ret < 0)
goto out;
size >>= PAGE_SHIFT;
old_size >>= PAGE_SHIFT;
current->mm->total_vm -= old_size;
current->mm->locked_vm -= old_size;
if (size == 0)
goto out;
rlim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT;
vm = current->mm->total_vm + size;
if (rlim < vm) {
ret = -ENOMEM;
if (!reduce_size)
goto out;
size = rlim - current->mm->total_vm;
if (size <= 0)
goto out;
}
rlim = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
vm = current->mm->locked_vm + size;
if (rlim < vm) {
ret = -ENOMEM;
if (!reduce_size)
goto out;
size = rlim - current->mm->locked_vm;
if (size <= 0)
goto out;
}
ret = ds_allocate((void **)&child->thread.ds_area_msr,
size << PAGE_SHIFT);
if (ret < 0)
goto out;
current->mm->total_vm += size;
current->mm->locked_vm += size;
out:
if (child->thread.ds_area_msr)
set_tsk_thread_flag(child, TIF_DS_AREA_MSR);
else
clear_tsk_thread_flag(child, TIF_DS_AREA_MSR);
return ret;
}
static int ptrace_bts_config(struct task_struct *child, static int ptrace_bts_config(struct task_struct *child,
long cfg_size, long cfg_size,
const struct ptrace_bts_config __user *ucfg) const struct ptrace_bts_config __user *ucfg)
...@@ -828,6 +744,91 @@ static int ptrace_bts_status(struct task_struct *child, ...@@ -828,6 +744,91 @@ static int ptrace_bts_status(struct task_struct *child,
return sizeof(cfg); return sizeof(cfg);
} }
static int ptrace_bts_write_record(struct task_struct *child,
const struct bts_struct *in)
{
int retval;
if (!child->thread.ds_area_msr)
return -ENXIO;
retval = ds_write_bts((void *)child->thread.ds_area_msr, in);
if (retval)
return retval;
return sizeof(*in);
}
static int ptrace_bts_realloc(struct task_struct *child,
int size, int reduce_size)
{
unsigned long rlim, vm;
int ret, old_size;
if (size < 0)
return -EINVAL;
old_size = ds_get_bts_size((void *)child->thread.ds_area_msr);
if (old_size < 0)
return old_size;
ret = ds_free((void **)&child->thread.ds_area_msr);
if (ret < 0)
goto out;
size >>= PAGE_SHIFT;
old_size >>= PAGE_SHIFT;
current->mm->total_vm -= old_size;
current->mm->locked_vm -= old_size;
if (size == 0)
goto out;
rlim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT;
vm = current->mm->total_vm + size;
if (rlim < vm) {
ret = -ENOMEM;
if (!reduce_size)
goto out;
size = rlim - current->mm->total_vm;
if (size <= 0)
goto out;
}
rlim = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
vm = current->mm->locked_vm + size;
if (rlim < vm) {
ret = -ENOMEM;
if (!reduce_size)
goto out;
size = rlim - current->mm->locked_vm;
if (size <= 0)
goto out;
}
ret = ds_allocate((void **)&child->thread.ds_area_msr,
size << PAGE_SHIFT);
if (ret < 0)
goto out;
current->mm->total_vm += size;
current->mm->locked_vm += size;
out:
if (child->thread.ds_area_msr)
set_tsk_thread_flag(child, TIF_DS_AREA_MSR);
else
clear_tsk_thread_flag(child, TIF_DS_AREA_MSR);
return ret;
}
void ptrace_bts_take_timestamp(struct task_struct *tsk, void ptrace_bts_take_timestamp(struct task_struct *tsk,
enum bts_qualifier qualifier) enum bts_qualifier qualifier)
{ {
......
/* /*
* Copyright (C) 2007, OpenWrt.org, Florian Fainelli <florian@openwrt.org> * GPIO support for RDC SoC R3210/R8610
* RDC321x architecture specific GPIO support *
* Copyright (C) 2007, Florian Fainelli <florian@openwrt.org>
* Copyright (C) 2008, Volker Weiss <dev@tintuc.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/ */
#include <linux/autoconf.h>
#include <linux/init.h> #include <linux/spinlock.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/delay.h>
#include <asm/gpio.h>
#include <asm/mach-rdc321x/rdc321x_defs.h> #include <asm/mach-rdc321x/rdc321x_defs.h>
static inline int rdc_gpio_is_valid(unsigned gpio)
/* spin lock to protect our private copy of GPIO data register plus
the access to PCI conf registers. */
static DEFINE_SPINLOCK(gpio_lock);
/* copy of GPIO data registers */
static u32 gpio_data_reg1;
static u32 gpio_data_reg2;
static u32 gpio_request_data[2];
static inline void rdc321x_conf_write(unsigned addr, u32 value)
{ {
return (gpio <= RDC_MAX_GPIO); outl((1 << 31) | (7 << 11) | addr, RDC3210_CFGREG_ADDR);
outl(value, RDC3210_CFGREG_DATA);
} }
static unsigned int rdc_gpio_read(unsigned gpio) static inline void rdc321x_conf_or(unsigned addr, u32 value)
{ {
unsigned int val; outl((1 << 31) | (7 << 11) | addr, RDC3210_CFGREG_ADDR);
value |= inl(RDC3210_CFGREG_DATA);
val = 0x80000000 | (7 << 11) | ((gpio&0x20?0x84:0x48)); outl(value, RDC3210_CFGREG_DATA);
outl(val, RDC3210_CFGREG_ADDR);
udelay(10);
val = inl(RDC3210_CFGREG_DATA);
val |= (0x1 << (gpio & 0x1F));
outl(val, RDC3210_CFGREG_DATA);
udelay(10);
val = 0x80000000 | (7 << 11) | ((gpio&0x20?0x88:0x4C));
outl(val, RDC3210_CFGREG_ADDR);
udelay(10);
val = inl(RDC3210_CFGREG_DATA);
return val;
} }
static void rdc_gpio_write(unsigned int val) static inline u32 rdc321x_conf_read(unsigned addr)
{ {
if (val) { outl((1 << 31) | (7 << 11) | addr, RDC3210_CFGREG_ADDR);
outl(val, RDC3210_CFGREG_DATA);
udelay(10); return inl(RDC3210_CFGREG_DATA);
}
} }
int rdc_gpio_get_value(unsigned gpio) /* configure pin as GPIO */
static void rdc321x_configure_gpio(unsigned gpio)
{ {
if (rdc_gpio_is_valid(gpio)) unsigned long flags;
return (int)rdc_gpio_read(gpio);
else spin_lock_irqsave(&gpio_lock, flags);
rdc321x_conf_or(gpio < 32
? RDC321X_GPIO_CTRL_REG1 : RDC321X_GPIO_CTRL_REG2,
1 << (gpio & 0x1f));
spin_unlock_irqrestore(&gpio_lock, flags);
}
/* initially setup the 2 copies of the gpio data registers.
This function must be called by the platform setup code. */
void __init rdc321x_gpio_setup()
{
/* this might not be, what others (BIOS, bootloader, etc.)
wrote to these registers before, but it's a good guess. Still
better than just using 0xffffffff. */
gpio_data_reg1 = rdc321x_conf_read(RDC321X_GPIO_DATA_REG1);
gpio_data_reg2 = rdc321x_conf_read(RDC321X_GPIO_DATA_REG2);
}
/* determine, if gpio number is valid */
static inline int rdc321x_is_gpio(unsigned gpio)
{
return gpio <= RDC321X_MAX_GPIO;
}
/* request GPIO */
int rdc_gpio_request(unsigned gpio, const char *label)
{
unsigned long flags;
if (!rdc321x_is_gpio(gpio))
return -EINVAL;
spin_lock_irqsave(&gpio_lock, flags);
if (gpio_request_data[(gpio & 0x20) ? 1 : 0] & (1 << (gpio & 0x1f)))
goto inuse;
gpio_request_data[(gpio & 0x20) ? 1 : 0] |= (1 << (gpio & 0x1f));
spin_unlock_irqrestore(&gpio_lock, flags);
return 0;
inuse:
spin_unlock_irqrestore(&gpio_lock, flags);
return -EINVAL; return -EINVAL;
} }
EXPORT_SYMBOL(rdc_gpio_get_value); EXPORT_SYMBOL(rdc_gpio_request);
void rdc_gpio_set_value(unsigned gpio, int value) /* release previously-claimed GPIO */
void rdc_gpio_free(unsigned gpio)
{ {
unsigned int val; unsigned long flags;
if (!rdc_gpio_is_valid(gpio)) if (!rdc321x_is_gpio(gpio))
return; return;
val = rdc_gpio_read(gpio); spin_lock_irqsave(&gpio_lock, flags);
gpio_request_data[(gpio & 0x20) ? 1 : 0] &= ~(1 << (gpio & 0x1f));
spin_unlock_irqrestore(&gpio_lock, flags);
}
EXPORT_SYMBOL(rdc_gpio_free);
/* read GPIO pin */
int rdc_gpio_get_value(unsigned gpio)
{
u32 reg;
unsigned long flags;
spin_lock_irqsave(&gpio_lock, flags);
reg = rdc321x_conf_read(gpio < 32
? RDC321X_GPIO_DATA_REG1 : RDC321X_GPIO_DATA_REG2);
spin_unlock_irqrestore(&gpio_lock, flags);
return (1 << (gpio & 0x1f)) & reg ? 1 : 0;
}
EXPORT_SYMBOL(rdc_gpio_get_value);
/* set GPIO pin to value */
void rdc_gpio_set_value(unsigned gpio, int value)
{
unsigned long flags;
u32 reg;
reg = 1 << (gpio & 0x1f);
if (gpio < 32) {
spin_lock_irqsave(&gpio_lock, flags);
if (value) if (value)
val &= ~(0x1 << (gpio & 0x1F)); gpio_data_reg1 |= reg;
else else
val |= (0x1 << (gpio & 0x1F)); gpio_data_reg1 &= ~reg;
rdc321x_conf_write(RDC321X_GPIO_DATA_REG1, gpio_data_reg1);
rdc_gpio_write(val); spin_unlock_irqrestore(&gpio_lock, flags);
} else {
spin_lock_irqsave(&gpio_lock, flags);
if (value)
gpio_data_reg2 |= reg;
else
gpio_data_reg2 &= ~reg;
rdc321x_conf_write(RDC321X_GPIO_DATA_REG2, gpio_data_reg2);
spin_unlock_irqrestore(&gpio_lock, flags);
}
} }
EXPORT_SYMBOL(rdc_gpio_set_value); EXPORT_SYMBOL(rdc_gpio_set_value);
/* configure GPIO pin as input */
int rdc_gpio_direction_input(unsigned gpio) int rdc_gpio_direction_input(unsigned gpio)
{ {
if (!rdc321x_is_gpio(gpio))
return -EINVAL;
rdc321x_configure_gpio(gpio);
return 0; return 0;
} }
EXPORT_SYMBOL(rdc_gpio_direction_input); EXPORT_SYMBOL(rdc_gpio_direction_input);
/* configure GPIO pin as output and set value */
int rdc_gpio_direction_output(unsigned gpio, int value) int rdc_gpio_direction_output(unsigned gpio, int value)
{ {
if (!rdc321x_is_gpio(gpio))
return -EINVAL;
gpio_set_value(gpio, value);
rdc321x_configure_gpio(gpio);
return 0; return 0;
} }
EXPORT_SYMBOL(rdc_gpio_direction_output); EXPORT_SYMBOL(rdc_gpio_direction_output);
...@@ -62,6 +62,8 @@ static struct platform_device *rdc321x_devs[] = { ...@@ -62,6 +62,8 @@ static struct platform_device *rdc321x_devs[] = {
static int __init rdc_board_setup(void) static int __init rdc_board_setup(void)
{ {
rdc321x_gpio_setup();
return platform_add_devices(rdc321x_devs, ARRAY_SIZE(rdc321x_devs)); return platform_add_devices(rdc321x_devs, ARRAY_SIZE(rdc321x_devs));
} }
......
...@@ -92,7 +92,8 @@ static int is_prefetch(struct pt_regs *regs, unsigned long addr, ...@@ -92,7 +92,8 @@ static int is_prefetch(struct pt_regs *regs, unsigned long addr,
unsigned char *max_instr; unsigned char *max_instr;
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
if (!(__supported_pte_mask & _PAGE_NX)) /* Catch an obscure case of prefetch inside an NX page: */
if ((__supported_pte_mask & _PAGE_NX) && (error_code & 16))
return 0; return 0;
#endif #endif
......
...@@ -178,7 +178,7 @@ follow_huge_addr(struct mm_struct *mm, unsigned long address, int write) ...@@ -178,7 +178,7 @@ follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
page = &pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)]; page = &pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)];
WARN_ON(!PageCompound(page)); WARN_ON(!PageHead(page));
return page; return page;
} }
......
...@@ -95,7 +95,7 @@ struct shared_info *HYPERVISOR_shared_info = (void *)&dummy_shared_info; ...@@ -95,7 +95,7 @@ struct shared_info *HYPERVISOR_shared_info = (void *)&dummy_shared_info;
* *
* 0: not available, 1: available * 0: not available, 1: available
*/ */
static int have_vcpu_info_placement = 0; static int have_vcpu_info_placement = 1;
static void __init xen_vcpu_setup(int cpu) static void __init xen_vcpu_setup(int cpu)
{ {
...@@ -103,6 +103,7 @@ static void __init xen_vcpu_setup(int cpu) ...@@ -103,6 +103,7 @@ static void __init xen_vcpu_setup(int cpu)
int err; int err;
struct vcpu_info *vcpup; struct vcpu_info *vcpup;
BUG_ON(HYPERVISOR_shared_info == &dummy_shared_info);
per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
if (!have_vcpu_info_placement) if (!have_vcpu_info_placement)
...@@ -805,33 +806,43 @@ static __init void xen_pagetable_setup_start(pgd_t *base) ...@@ -805,33 +806,43 @@ static __init void xen_pagetable_setup_start(pgd_t *base)
PFN_DOWN(__pa(xen_start_info->pt_base))); PFN_DOWN(__pa(xen_start_info->pt_base)));
} }
static __init void xen_pagetable_setup_done(pgd_t *base) static __init void setup_shared_info(void)
{ {
/* This will work as long as patching hasn't happened yet
(which it hasn't) */
pv_mmu_ops.alloc_pt = xen_alloc_pt;
pv_mmu_ops.alloc_pd = xen_alloc_pd;
pv_mmu_ops.release_pt = xen_release_pt;
pv_mmu_ops.release_pd = xen_release_pt;
pv_mmu_ops.set_pte = xen_set_pte;
if (!xen_feature(XENFEAT_auto_translated_physmap)) { if (!xen_feature(XENFEAT_auto_translated_physmap)) {
unsigned long addr = fix_to_virt(FIX_PARAVIRT_BOOTMAP);
/* /*
* Create a mapping for the shared info page. * Create a mapping for the shared info page.
* Should be set_fixmap(), but shared_info is a machine * Should be set_fixmap(), but shared_info is a machine
* address with no corresponding pseudo-phys address. * address with no corresponding pseudo-phys address.
*/ */
set_pte_mfn(fix_to_virt(FIX_PARAVIRT_BOOTMAP), set_pte_mfn(addr,
PFN_DOWN(xen_start_info->shared_info), PFN_DOWN(xen_start_info->shared_info),
PAGE_KERNEL); PAGE_KERNEL);
HYPERVISOR_shared_info = HYPERVISOR_shared_info = (struct shared_info *)addr;
(struct shared_info *)fix_to_virt(FIX_PARAVIRT_BOOTMAP);
} else } else
HYPERVISOR_shared_info = HYPERVISOR_shared_info =
(struct shared_info *)__va(xen_start_info->shared_info); (struct shared_info *)__va(xen_start_info->shared_info);
#ifndef CONFIG_SMP
/* In UP this is as good a place as any to set up shared info */
xen_setup_vcpu_info_placement();
#endif
}
static __init void xen_pagetable_setup_done(pgd_t *base)
{
/* This will work as long as patching hasn't happened yet
(which it hasn't) */
pv_mmu_ops.alloc_pt = xen_alloc_pt;
pv_mmu_ops.alloc_pd = xen_alloc_pd;
pv_mmu_ops.release_pt = xen_release_pt;
pv_mmu_ops.release_pd = xen_release_pt;
pv_mmu_ops.set_pte = xen_set_pte;
setup_shared_info();
/* Actually pin the pagetable down, but we can't set PG_pinned /* Actually pin the pagetable down, but we can't set PG_pinned
yet because the page structures don't exist yet. */ yet because the page structures don't exist yet. */
{ {
...@@ -1182,15 +1193,9 @@ asmlinkage void __init xen_start_kernel(void) ...@@ -1182,15 +1193,9 @@ asmlinkage void __init xen_start_kernel(void)
x86_write_percpu(xen_cr3, __pa(pgd)); x86_write_percpu(xen_cr3, __pa(pgd));
x86_write_percpu(xen_current_cr3, __pa(pgd)); x86_write_percpu(xen_current_cr3, __pa(pgd));
#ifdef CONFIG_SMP
/* Don't do the full vcpu_info placement stuff until we have a /* Don't do the full vcpu_info placement stuff until we have a
possible map. */ possible map and a non-dummy shared_info. */
per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0]; per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0];
#else
/* May as well do it now, since there's no good time to call
it later on UP. */
xen_setup_vcpu_info_placement();
#endif
pv_info.kernel_rpl = 1; pv_info.kernel_rpl = 1;
if (xen_feature(XENFEAT_supervisor_mode_kernel)) if (xen_feature(XENFEAT_supervisor_mode_kernel))
......
...@@ -33,12 +33,17 @@ ...@@ -33,12 +33,17 @@
events, then enter the hypervisor to get them handled. events, then enter the hypervisor to get them handled.
*/ */
ENTRY(xen_irq_enable_direct) ENTRY(xen_irq_enable_direct)
/* Clear mask and test pending */ /* Unmask events */
andw $0x00ff, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_pending movb $0, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_mask
/* Preempt here doesn't matter because that will deal with /* Preempt here doesn't matter because that will deal with
any pending interrupts. The pending check may end up being any pending interrupts. The pending check may end up being
run on the wrong CPU, but that doesn't hurt. */ run on the wrong CPU, but that doesn't hurt. */
/* Test for pending */
testb $0xff, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_pending
jz 1f jz 1f
2: call check_events 2: call check_events
1: 1:
ENDPATCH(xen_irq_enable_direct) ENDPATCH(xen_irq_enable_direct)
......
...@@ -5,19 +5,20 @@ extern int rdc_gpio_get_value(unsigned gpio); ...@@ -5,19 +5,20 @@ extern int rdc_gpio_get_value(unsigned gpio);
extern void rdc_gpio_set_value(unsigned gpio, int value); extern void rdc_gpio_set_value(unsigned gpio, int value);
extern int rdc_gpio_direction_input(unsigned gpio); extern int rdc_gpio_direction_input(unsigned gpio);
extern int rdc_gpio_direction_output(unsigned gpio, int value); extern int rdc_gpio_direction_output(unsigned gpio, int value);
extern int rdc_gpio_request(unsigned gpio, const char *label);
extern void rdc_gpio_free(unsigned gpio);
extern void __init rdc321x_gpio_setup(void);
/* Wrappers for the arch-neutral GPIO API */ /* Wrappers for the arch-neutral GPIO API */
static inline int gpio_request(unsigned gpio, const char *label) static inline int gpio_request(unsigned gpio, const char *label)
{ {
/* Not yet implemented */ return rdc_gpio_request(gpio, label);
return 0;
} }
static inline void gpio_free(unsigned gpio) static inline void gpio_free(unsigned gpio)
{ {
/* Not yet implemented */ rdc_gpio_free(gpio);
} }
static inline int gpio_direction_input(unsigned gpio) static inline int gpio_direction_input(unsigned gpio)
......
...@@ -3,4 +3,10 @@ ...@@ -3,4 +3,10 @@
/* General purpose configuration and data registers */ /* General purpose configuration and data registers */
#define RDC3210_CFGREG_ADDR 0x0CF8 #define RDC3210_CFGREG_ADDR 0x0CF8
#define RDC3210_CFGREG_DATA 0x0CFC #define RDC3210_CFGREG_DATA 0x0CFC
#define RDC_MAX_GPIO 0x3A
#define RDC321X_GPIO_CTRL_REG1 0x48
#define RDC321X_GPIO_CTRL_REG2 0x84
#define RDC321X_GPIO_DATA_REG1 0x4c
#define RDC321X_GPIO_DATA_REG2 0x88
#define RDC321X_MAX_GPIO 58
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