Merge branches 'sh/ftrace' and 'sh/cachetlb'

This commit is contained in:
Paul Mundt 2009-07-06 20:19:28 +09:00
Родитель c652d780c9 0f60bb25b4
Коммит 7119888df1
23 изменённых файлов: 710 добавлений и 162 удалений

Просмотреть файл

@ -10,6 +10,7 @@ config SUPERH
select EMBEDDED
select HAVE_CLK
select HAVE_IDE
select HAVE_LMB
select HAVE_OPROFILE
select HAVE_GENERIC_DMA_COHERENT
select HAVE_IOREMAP_PROT if MMU

Просмотреть файл

@ -19,6 +19,7 @@
#include <linux/smc91x.h>
#include <linux/gpio.h>
#include <linux/input.h>
#include <linux/usb/r8a66597.h>
#include <video/sh_mobile_lcdc.h>
#include <media/sh_mobile_ceu.h>
#include <asm/io.h>
@ -302,6 +303,34 @@ static struct platform_device sh_eth_device = {
.resource = sh_eth_resources,
};
static struct r8a66597_platdata sh7724_usb0_host_data = {
};
static struct resource sh7724_usb0_host_resources[] = {
[0] = {
.start = 0xa4d80000,
.end = 0xa4d800ff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 65,
.end = 65,
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
},
};
static struct platform_device sh7724_usb0_host_device = {
.name = "r8a66597_hcd",
.id = 0,
.dev = {
.dma_mask = NULL, /* not use dma */
.coherent_dma_mask = 0xffffffff,
.platform_data = &sh7724_usb0_host_data,
},
.num_resources = ARRAY_SIZE(sh7724_usb0_host_resources),
.resource = sh7724_usb0_host_resources,
};
static struct platform_device *ms7724se_devices[] __initdata = {
&heartbeat_device,
&smc91x_eth_device,
@ -311,6 +340,7 @@ static struct platform_device *ms7724se_devices[] __initdata = {
&ceu1_device,
&keysc_device,
&sh_eth_device,
&sh7724_usb0_host_device,
};
#define EEPROM_OP 0xBA206000
@ -364,6 +394,7 @@ static void __init sh_eth_init(void)
#define SW4140 0xBA201000
#define FPGA_OUT 0xBA200400
#define PORT_HIZA 0xA4050158
#define PORT_MSELCRB 0xA4050182
#define SW41_A 0x0100
#define SW41_B 0x0200
@ -373,6 +404,7 @@ static void __init sh_eth_init(void)
#define SW41_F 0x2000
#define SW41_G 0x4000
#define SW41_H 0x8000
static int __init devices_setup(void)
{
u16 sw = ctrl_inw(SW4140); /* select camera, monitor */
@ -385,6 +417,12 @@ static int __init devices_setup(void)
(1 << 14)), /* RMII */
FPGA_OUT);
/* turn on USB clocks, use external clock */
ctrl_outw((ctrl_inw(PORT_MSELCRB) & ~0xc000) | 0x8000, PORT_MSELCRB);
/* enable USB0 port */
ctrl_outw(0x0600, 0xa40501d4);
/* enable IRQ 0,1,2 */
gpio_request(GPIO_FN_INTC_IRQ0, NULL);
gpio_request(GPIO_FN_INTC_IRQ1, NULL);

Просмотреть файл

@ -0,0 +1,61 @@
#ifndef __ASM_SH_HWBLK_H
#define __ASM_SH_HWBLK_H
#include <asm/clock.h>
#include <asm/io.h>
#define HWBLK_AREA_FLAG_PARENT (1 << 0) /* valid parent */
#define HWBLK_AREA(_flags, _parent) \
{ \
.flags = _flags, \
.parent = _parent, \
}
struct hwblk_area {
unsigned long cnt;
unsigned char parent;
unsigned char flags;
};
#define HWBLK(_mstp, _bit, _area) \
{ \
.mstp = (void __iomem *)_mstp, \
.bit = _bit, \
.area = _area, \
}
struct hwblk {
void __iomem *mstp;
unsigned char bit;
unsigned char area;
unsigned long cnt;
};
struct hwblk_info {
struct hwblk_area *areas;
int nr_areas;
struct hwblk *hwblks;
int nr_hwblks;
};
/* Should be defined by processor-specific code */
int arch_hwblk_init(void);
int arch_hwblk_sleep_mode(void);
int hwblk_register(struct hwblk_info *info);
int hwblk_init(void);
/* allow clocks to enable and disable hardware blocks */
#define SH_HWBLK_CLK(_name, _id, _parent, _hwblk, _flags) \
{ \
.name = _name, \
.id = _id, \
.parent = _parent, \
.arch_flags = _hwblk, \
.flags = _flags, \
}
int sh_hwblk_clk_register(struct clk *clks, int nr);
#endif /* __ASM_SH_HWBLK_H */

Просмотреть файл

@ -0,0 +1,6 @@
#ifndef __ASM_SH_LMB_H
#define __ASM_SH_LMB_H
#define LMB_REAL_LIMIT 0
#endif /* __ASM_SH_LMB_H */

Просмотреть файл

@ -4,4 +4,6 @@
/* SH only supports software counters through this interface. */
static inline void set_perf_counter_pending(void) {}
#define PERF_COUNTER_INDEX_OFFSET 0
#endif /* __ASM_SH_PERF_COUNTER_H */

Просмотреть файл

@ -10,6 +10,15 @@ struct swsusp_arch_regs {
struct pt_regs user_regs;
unsigned long bank1_regs[8];
};
void sh_mobile_call_standby(unsigned long mode);
#ifdef CONFIG_CPU_IDLE
void sh_mobile_setup_cpuidle(void);
#else
static inline void sh_mobile_setup_cpuidle(void) {}
#endif
#endif
/* flags passed to assembly suspend code */

Просмотреть файл

@ -221,4 +221,18 @@ enum {
GPIO_FN_KEYOUT3, GPIO_FN_KEYOUT4_IN6, GPIO_FN_KEYOUT5_IN5,
};
enum {
HWBLK_UNKNOWN = 0,
HWBLK_TLB, HWBLK_IC, HWBLK_OC, HWBLK_URAM, HWBLK_XYMEM,
HWBLK_INTC, HWBLK_DMAC, HWBLK_SHYWAY, HWBLK_HUDI,
HWBLK_UBC, HWBLK_TMU, HWBLK_CMT, HWBLK_RWDT, HWBLK_FLCTL,
HWBLK_SCIF0, HWBLK_SCIF1, HWBLK_SCIF2, HWBLK_SIO,
HWBLK_SIOF0, HWBLK_SIOF1, HWBLK_IIC, HWBLK_RTC,
HWBLK_TPU, HWBLK_IRDA, HWBLK_SDHI, HWBLK_SIM, HWBLK_KEYSC,
HWBLK_TSIF, HWBLK_USBF, HWBLK_2DG, HWBLK_SIU, HWBLK_VOU,
HWBLK_JPU, HWBLK_BEU, HWBLK_CEU, HWBLK_VEU, HWBLK_VPU,
HWBLK_LCDC,
HWBLK_NR,
};
#endif /* __ASM_SH7722_H__ */

Просмотреть файл

@ -19,4 +19,4 @@ obj-$(CONFIG_UBC_WAKEUP) += ubc.o
obj-$(CONFIG_SH_ADC) += adc.o
obj-$(CONFIG_SH_CLK_CPG) += clock-cpg.o
obj-y += irq/ init.o clock.o
obj-y += irq/ init.o clock.o hwblk.o

130
arch/sh/kernel/cpu/hwblk.c Normal file
Просмотреть файл

@ -0,0 +1,130 @@
#include <linux/clk.h>
#include <linux/compiler.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/spinlock.h>
#include <asm/suspend.h>
#include <asm/hwblk.h>
#include <asm/clock.h>
static DEFINE_SPINLOCK(hwblk_lock);
static void hwblk_area_inc(struct hwblk_info *info, int area)
{
struct hwblk_area *hap = info->areas + area;
hap->cnt++;
if (hap->cnt == 1)
if (hap->flags & HWBLK_AREA_FLAG_PARENT)
hwblk_area_inc(info, hap->parent);
}
static void hwblk_area_dec(struct hwblk_info *info, int area)
{
struct hwblk_area *hap = info->areas + area;
if (hap->cnt == 1)
if (hap->flags & HWBLK_AREA_FLAG_PARENT)
hwblk_area_dec(info, hap->parent);
hap->cnt--;
}
static void hwblk_enable(struct hwblk_info *info, int hwblk)
{
struct hwblk *hp = info->hwblks + hwblk;
unsigned long tmp;
unsigned long flags;
spin_lock_irqsave(&hwblk_lock, flags);
hp->cnt++;
if (hp->cnt == 1) {
hwblk_area_inc(info, hp->area);
tmp = __raw_readl(hp->mstp);
tmp &= ~(1 << hp->bit);
__raw_writel(tmp, hp->mstp);
}
spin_unlock_irqrestore(&hwblk_lock, flags);
}
static void hwblk_disable(struct hwblk_info *info, int hwblk)
{
struct hwblk *hp = info->hwblks + hwblk;
unsigned long tmp;
unsigned long flags;
spin_lock_irqsave(&hwblk_lock, flags);
if (hp->cnt == 1) {
hwblk_area_dec(info, hp->area);
tmp = __raw_readl(hp->mstp);
tmp |= 1 << hp->bit;
__raw_writel(tmp, hp->mstp);
}
hp->cnt--;
spin_unlock_irqrestore(&hwblk_lock, flags);
}
static struct hwblk_info *hwblk_info;
int __init hwblk_register(struct hwblk_info *info)
{
hwblk_info = info;
return 0;
}
int __init __weak arch_hwblk_init(void)
{
return 0;
}
int __weak arch_hwblk_sleep_mode(void)
{
return SUSP_SH_SLEEP;
}
int __init hwblk_init(void)
{
return arch_hwblk_init();
}
/* allow clocks to enable and disable hardware blocks */
static int sh_hwblk_clk_enable(struct clk *clk)
{
if (!hwblk_info)
return -ENOENT;
hwblk_enable(hwblk_info, clk->arch_flags);
return 0;
}
static void sh_hwblk_clk_disable(struct clk *clk)
{
if (hwblk_info)
hwblk_disable(hwblk_info, clk->arch_flags);
}
static struct clk_ops sh_hwblk_clk_ops = {
.enable = sh_hwblk_clk_enable,
.disable = sh_hwblk_clk_disable,
.recalc = followparent_recalc,
};
int __init sh_hwblk_clk_register(struct clk *clks, int nr)
{
struct clk *clkp;
int ret = 0;
int k;
for (k = 0; !ret && (k < nr); k++) {
clkp = clks + k;
clkp->ops = &sh_hwblk_clk_ops;
ret |= clk_register(clkp);
}
return ret;
}

Просмотреть файл

@ -25,7 +25,7 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o
clock-$(CONFIG_CPU_SUBTYPE_SH7785) := clock-sh7785.o
clock-$(CONFIG_CPU_SUBTYPE_SH7786) := clock-sh7786.o
clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o
clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o
clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o hwblk-sh7722.o
clock-$(CONFIG_CPU_SUBTYPE_SH7723) := clock-sh7723.o
clock-$(CONFIG_CPU_SUBTYPE_SH7724) := clock-sh7724.o
clock-$(CONFIG_CPU_SUBTYPE_SH7366) := clock-sh7366.o

Просмотреть файл

@ -22,6 +22,8 @@
#include <linux/kernel.h>
#include <linux/io.h>
#include <asm/clock.h>
#include <asm/hwblk.h>
#include <cpu/sh7722.h>
/* SH7722 registers */
#define FRQCR 0xa4150000
@ -140,35 +142,37 @@ struct clk div6_clks[] = {
SH_CLK_DIV6("video_clk", &pll_clk, VCLKCR, 0),
};
#define MSTP(_str, _parent, _reg, _bit, _flags) \
SH_CLK_MSTP32(_str, -1, _parent, _reg, _bit, _flags)
#define R_CLK &r_clk
#define P_CLK &div4_clks[DIV4_P]
#define B_CLK &div4_clks[DIV4_B]
#define U_CLK &div4_clks[DIV4_U]
static struct clk mstp_clks[] = {
MSTP("uram0", &div4_clks[DIV4_U], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
MSTP("xymem0", &div4_clks[DIV4_B], MSTPCR0, 26, CLK_ENABLE_ON_INIT),
MSTP("tmu0", &div4_clks[DIV4_P], MSTPCR0, 15, 0),
MSTP("cmt0", &r_clk, MSTPCR0, 14, 0),
MSTP("rwdt0", &r_clk, MSTPCR0, 13, 0),
MSTP("flctl0", &div4_clks[DIV4_P], MSTPCR0, 10, 0),
MSTP("scif0", &div4_clks[DIV4_P], MSTPCR0, 7, 0),
MSTP("scif1", &div4_clks[DIV4_P], MSTPCR0, 6, 0),
MSTP("scif2", &div4_clks[DIV4_P], MSTPCR0, 5, 0),
SH_HWBLK_CLK("uram0", -1, U_CLK, HWBLK_URAM, CLK_ENABLE_ON_INIT),
SH_HWBLK_CLK("xymem0", -1, B_CLK, HWBLK_XYMEM, CLK_ENABLE_ON_INIT),
SH_HWBLK_CLK("tmu0", -1, P_CLK, HWBLK_TMU, 0),
SH_HWBLK_CLK("cmt0", -1, R_CLK, HWBLK_CMT, 0),
SH_HWBLK_CLK("rwdt0", -1, R_CLK, HWBLK_RWDT, 0),
SH_HWBLK_CLK("flctl0", -1, P_CLK, HWBLK_FLCTL, 0),
SH_HWBLK_CLK("scif0", -1, P_CLK, HWBLK_SCIF0, 0),
SH_HWBLK_CLK("scif1", -1, P_CLK, HWBLK_SCIF1, 0),
SH_HWBLK_CLK("scif2", -1, P_CLK, HWBLK_SCIF2, 0),
MSTP("i2c0", &div4_clks[DIV4_P], MSTPCR1, 9, 0),
MSTP("rtc0", &r_clk, MSTPCR1, 8, 0),
SH_HWBLK_CLK("i2c0", -1, P_CLK, HWBLK_IIC, 0),
SH_HWBLK_CLK("rtc0", -1, R_CLK, HWBLK_RTC, 0),
MSTP("sdhi0", &div4_clks[DIV4_P], MSTPCR2, 18, 0),
MSTP("keysc0", &r_clk, MSTPCR2, 14, 0),
MSTP("usbf0", &div4_clks[DIV4_P], MSTPCR2, 11, 0),
MSTP("2dg0", &div4_clks[DIV4_B], MSTPCR2, 9, 0),
MSTP("siu0", &div4_clks[DIV4_B], MSTPCR2, 8, 0),
MSTP("vou0", &div4_clks[DIV4_B], MSTPCR2, 5, 0),
MSTP("jpu0", &div4_clks[DIV4_B], MSTPCR2, 6, CLK_ENABLE_ON_INIT),
MSTP("beu0", &div4_clks[DIV4_B], MSTPCR2, 4, 0),
MSTP("ceu0", &div4_clks[DIV4_B], MSTPCR2, 3, 0),
MSTP("veu0", &div4_clks[DIV4_B], MSTPCR2, 2, CLK_ENABLE_ON_INIT),
MSTP("vpu0", &div4_clks[DIV4_B], MSTPCR2, 1, CLK_ENABLE_ON_INIT),
MSTP("lcdc0", &div4_clks[DIV4_B], MSTPCR2, 0, 0),
SH_HWBLK_CLK("sdhi0", -1, P_CLK, HWBLK_SDHI, 0),
SH_HWBLK_CLK("keysc0", -1, R_CLK, HWBLK_KEYSC, 0),
SH_HWBLK_CLK("usbf0", -1, P_CLK, HWBLK_USBF, 0),
SH_HWBLK_CLK("2dg0", -1, B_CLK, HWBLK_2DG, 0),
SH_HWBLK_CLK("siu0", -1, B_CLK, HWBLK_SIU, 0),
SH_HWBLK_CLK("vou0", -1, B_CLK, HWBLK_VOU, 0),
SH_HWBLK_CLK("jpu0", -1, B_CLK, HWBLK_JPU, CLK_ENABLE_ON_INIT),
SH_HWBLK_CLK("beu0", -1, B_CLK, HWBLK_BEU, 0),
SH_HWBLK_CLK("ceu0", -1, B_CLK, HWBLK_CEU, 0),
SH_HWBLK_CLK("veu0", -1, B_CLK, HWBLK_VEU, CLK_ENABLE_ON_INIT),
SH_HWBLK_CLK("vpu0", -1, B_CLK, HWBLK_VPU, CLK_ENABLE_ON_INIT),
SH_HWBLK_CLK("lcdc0", -1, P_CLK, HWBLK_LCDC, 0),
};
int __init arch_clk_init(void)
@ -191,7 +195,7 @@ int __init arch_clk_init(void)
ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks));
if (!ret)
ret = sh_clk_mstp32_register(mstp_clks, ARRAY_SIZE(mstp_clks));
ret = sh_hwblk_clk_register(mstp_clks, ARRAY_SIZE(mstp_clks));
return ret;
}

Просмотреть файл

@ -0,0 +1,106 @@
/*
* arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c
*
* SH7722 hardware block support
*
* Copyright (C) 2009 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/kernel.h>
#include <linux/io.h>
#include <asm/suspend.h>
#include <asm/hwblk.h>
#include <cpu/sh7722.h>
/* SH7722 registers */
#define MSTPCR0 0xa4150030
#define MSTPCR1 0xa4150034
#define MSTPCR2 0xa4150038
/* SH7722 Power Domains */
enum { CORE_AREA, SUB_AREA, CORE_AREA_BM };
static struct hwblk_area sh7722_hwblk_area[] = {
[CORE_AREA] = HWBLK_AREA(0, 0),
[CORE_AREA_BM] = HWBLK_AREA(HWBLK_AREA_FLAG_PARENT, CORE_AREA),
[SUB_AREA] = HWBLK_AREA(0, 0),
};
/* Table mapping HWBLK to Module Stop Bit and Power Domain */
static struct hwblk sh7722_hwblk[HWBLK_NR] = {
[HWBLK_TLB] = HWBLK(MSTPCR0, 31, CORE_AREA),
[HWBLK_IC] = HWBLK(MSTPCR0, 30, CORE_AREA),
[HWBLK_OC] = HWBLK(MSTPCR0, 29, CORE_AREA),
[HWBLK_URAM] = HWBLK(MSTPCR0, 28, CORE_AREA),
[HWBLK_XYMEM] = HWBLK(MSTPCR0, 26, CORE_AREA),
[HWBLK_INTC] = HWBLK(MSTPCR0, 22, CORE_AREA),
[HWBLK_DMAC] = HWBLK(MSTPCR0, 21, CORE_AREA_BM),
[HWBLK_SHYWAY] = HWBLK(MSTPCR0, 20, CORE_AREA),
[HWBLK_HUDI] = HWBLK(MSTPCR0, 19, CORE_AREA),
[HWBLK_UBC] = HWBLK(MSTPCR0, 17, CORE_AREA),
[HWBLK_TMU] = HWBLK(MSTPCR0, 15, CORE_AREA),
[HWBLK_CMT] = HWBLK(MSTPCR0, 14, SUB_AREA),
[HWBLK_RWDT] = HWBLK(MSTPCR0, 13, SUB_AREA),
[HWBLK_FLCTL] = HWBLK(MSTPCR0, 10, CORE_AREA),
[HWBLK_SCIF0] = HWBLK(MSTPCR0, 7, CORE_AREA),
[HWBLK_SCIF1] = HWBLK(MSTPCR0, 6, CORE_AREA),
[HWBLK_SCIF2] = HWBLK(MSTPCR0, 5, CORE_AREA),
[HWBLK_SIO] = HWBLK(MSTPCR0, 3, CORE_AREA),
[HWBLK_SIOF0] = HWBLK(MSTPCR0, 2, CORE_AREA),
[HWBLK_SIOF1] = HWBLK(MSTPCR0, 1, CORE_AREA),
[HWBLK_IIC] = HWBLK(MSTPCR1, 9, CORE_AREA),
[HWBLK_RTC] = HWBLK(MSTPCR1, 8, SUB_AREA),
[HWBLK_TPU] = HWBLK(MSTPCR2, 25, CORE_AREA),
[HWBLK_IRDA] = HWBLK(MSTPCR2, 24, CORE_AREA),
[HWBLK_SDHI] = HWBLK(MSTPCR2, 18, CORE_AREA),
[HWBLK_SIM] = HWBLK(MSTPCR2, 16, CORE_AREA),
[HWBLK_KEYSC] = HWBLK(MSTPCR2, 14, SUB_AREA),
[HWBLK_TSIF] = HWBLK(MSTPCR2, 13, SUB_AREA),
[HWBLK_USBF] = HWBLK(MSTPCR2, 11, CORE_AREA),
[HWBLK_2DG] = HWBLK(MSTPCR2, 9, CORE_AREA_BM),
[HWBLK_SIU] = HWBLK(MSTPCR2, 8, CORE_AREA),
[HWBLK_JPU] = HWBLK(MSTPCR2, 6, CORE_AREA_BM),
[HWBLK_VOU] = HWBLK(MSTPCR2, 5, CORE_AREA_BM),
[HWBLK_BEU] = HWBLK(MSTPCR2, 4, CORE_AREA_BM),
[HWBLK_CEU] = HWBLK(MSTPCR2, 3, CORE_AREA_BM),
[HWBLK_VEU] = HWBLK(MSTPCR2, 2, CORE_AREA_BM),
[HWBLK_VPU] = HWBLK(MSTPCR2, 1, CORE_AREA_BM),
[HWBLK_LCDC] = HWBLK(MSTPCR2, 0, CORE_AREA_BM),
};
static struct hwblk_info sh7722_hwblk_info = {
.areas = sh7722_hwblk_area,
.nr_areas = ARRAY_SIZE(sh7722_hwblk_area),
.hwblks = sh7722_hwblk,
.nr_hwblks = ARRAY_SIZE(sh7722_hwblk),
};
int arch_hwblk_sleep_mode(void)
{
if (!sh7722_hwblk_area[CORE_AREA].cnt)
return SUSP_SH_STANDBY | SUSP_SH_SF;
if (!sh7722_hwblk_area[CORE_AREA_BM].cnt)
return SUSP_SH_SLEEP | SUSP_SH_SF;
return SUSP_SH_SLEEP;
}
int __init arch_hwblk_init(void)
{
return hwblk_register(&sh7722_hwblk_info);
}

Просмотреть файл

@ -4,3 +4,4 @@
# Power Management & Sleep mode
obj-$(CONFIG_PM) += pm.o sleep.o
obj-$(CONFIG_CPU_IDLE) += cpuidle.o

Просмотреть файл

@ -0,0 +1,102 @@
/*
* arch/sh/kernel/cpu/shmobile/cpuidle.c
*
* Cpuidle support code for SuperH Mobile
*
* Copyright (C) 2009 Magnus Damm
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/suspend.h>
#include <linux/cpuidle.h>
#include <asm/suspend.h>
#include <asm/uaccess.h>
#include <asm/hwblk.h>
static unsigned long cpuidle_mode[] = {
SUSP_SH_SLEEP, /* regular sleep mode */
SUSP_SH_SLEEP | SUSP_SH_SF, /* sleep mode + self refresh */
};
static int cpuidle_sleep_enter(struct cpuidle_device *dev,
struct cpuidle_state *state)
{
unsigned long allowed_mode = arch_hwblk_sleep_mode();
ktime_t before, after;
int requested_state = state - &dev->states[0];
int allowed_state;
int k;
/* convert allowed mode to allowed state */
for (k = ARRAY_SIZE(cpuidle_mode) - 1; k > 0; k--)
if (cpuidle_mode[k] == allowed_mode)
break;
allowed_state = k;
/* take the following into account for sleep mode selection:
* - allowed_state: best mode allowed by hardware (clock deps)
* - requested_state: best mode allowed by software (latencies)
*/
k = min_t(int, allowed_state, requested_state);
dev->last_state = &dev->states[k];
before = ktime_get();
sh_mobile_call_standby(cpuidle_mode[k]);
after = ktime_get();
return ktime_to_ns(ktime_sub(after, before)) >> 10;
}
static struct cpuidle_device cpuidle_dev;
static struct cpuidle_driver cpuidle_driver = {
.name = "sh_idle",
.owner = THIS_MODULE,
};
void sh_mobile_setup_cpuidle(void)
{
struct cpuidle_device *dev = &cpuidle_dev;
struct cpuidle_state *state;
int i;
cpuidle_register_driver(&cpuidle_driver);
for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
dev->states[i].name[0] = '\0';
dev->states[i].desc[0] = '\0';
}
i = CPUIDLE_DRIVER_STATE_START;
state = &dev->states[i++];
snprintf(state->name, CPUIDLE_NAME_LEN, "C0");
strncpy(state->desc, "SuperH Sleep Mode", CPUIDLE_DESC_LEN);
state->exit_latency = 1;
state->target_residency = 1 * 2;
state->power_usage = 3;
state->flags = 0;
state->flags |= CPUIDLE_FLAG_SHALLOW;
state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = cpuidle_sleep_enter;
dev->safe_state = state;
state = &dev->states[i++];
snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
strncpy(state->desc, "SuperH Sleep Mode [SF]", CPUIDLE_DESC_LEN);
state->exit_latency = 100;
state->target_residency = 1 * 2;
state->power_usage = 1;
state->flags = 0;
state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = cpuidle_sleep_enter;
dev->state_count = i;
cpuidle_register_device(dev);
}

Просмотреть файл

@ -1,5 +1,5 @@
/*
* arch/sh/kernel/cpu/sh4a/pm-sh_mobile.c
* arch/sh/kernel/cpu/shmobile/pm.c
*
* Power management support code for SuperH Mobile
*
@ -32,20 +32,17 @@
*
* R-standby mode is unsupported, but will be added in the future
* U-standby mode is low priority since it needs bootloader hacks
*
* All modes should be tied in with cpuidle. But before that can
* happen we need to keep track of enabled hardware blocks so we
* can avoid entering sleep modes that stop clocks to hardware
* blocks that are in use even though the cpu core is idle.
*/
#define ILRAM_BASE 0xe5200000
extern const unsigned char sh_mobile_standby[];
extern const unsigned int sh_mobile_standby_size;
static void sh_mobile_call_standby(unsigned long mode)
void sh_mobile_call_standby(unsigned long mode)
{
extern void *vbr_base;
void *onchip_mem = (void *)0xe5200000; /* ILRAM */
void *onchip_mem = (void *)ILRAM_BASE;
void (*standby_onchip_mem)(unsigned long) = onchip_mem;
/* Note: Wake up from sleep may generate exceptions!
@ -55,11 +52,6 @@ static void sh_mobile_call_standby(unsigned long mode)
if (mode & SUSP_SH_SF)
asm volatile("ldc %0, vbr" : : "r" (onchip_mem) : "memory");
/* Copy the assembly snippet to the otherwise ununsed ILRAM */
memcpy(onchip_mem, sh_mobile_standby, sh_mobile_standby_size);
wmb();
ctrl_barrier();
/* Let assembly snippet in on-chip memory handle the rest */
standby_onchip_mem(mode);
@ -85,7 +77,15 @@ static struct platform_suspend_ops sh_pm_ops = {
static int __init sh_pm_init(void)
{
void *onchip_mem = (void *)ILRAM_BASE;
/* Copy the assembly snippet to the otherwise ununsed ILRAM */
memcpy(onchip_mem, sh_mobile_standby, sh_mobile_standby_size);
wmb();
ctrl_barrier();
suspend_set_ops(&sh_pm_ops);
sh_mobile_setup_cpuidle();
return 0;
}

Просмотреть файл

@ -30,6 +30,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/lmb.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/page.h>
@ -233,39 +234,45 @@ void __init __add_active_range(unsigned int nid, unsigned long start_pfn,
void __init setup_bootmem_allocator(unsigned long free_pfn)
{
unsigned long bootmap_size;
unsigned long bootmap_pages, bootmem_paddr;
u64 total_pages = (lmb_end_of_DRAM() - __MEMORY_START) >> PAGE_SHIFT;
int i;
bootmap_pages = bootmem_bootmap_pages(total_pages);
bootmem_paddr = lmb_alloc(bootmap_pages << PAGE_SHIFT, PAGE_SIZE);
/*
* Find a proper area for the bootmem bitmap. After this
* bootstrap step all allocations (until the page allocator
* is intact) must be done via bootmem_alloc().
*/
bootmap_size = init_bootmem_node(NODE_DATA(0), free_pfn,
bootmap_size = init_bootmem_node(NODE_DATA(0),
bootmem_paddr >> PAGE_SHIFT,
min_low_pfn, max_low_pfn);
__add_active_range(0, min_low_pfn, max_low_pfn);
/* Add active regions with valid PFNs. */
for (i = 0; i < lmb.memory.cnt; i++) {
unsigned long start_pfn, end_pfn;
start_pfn = lmb.memory.region[i].base >> PAGE_SHIFT;
end_pfn = start_pfn + lmb_size_pages(&lmb.memory, i);
__add_active_range(0, start_pfn, end_pfn);
}
/*
* Add all physical memory to the bootmem map and mark each
* area as present.
*/
register_bootmem_low_pages();
node_set_online(0);
/*
* Reserve the kernel text and
* Reserve the bootmem bitmap. We do this in two steps (first step
* was init_bootmem()), because this catches the (definitely buggy)
* case of us accidentally initializing the bootmem allocator with
* an invalid RAM area.
*/
reserve_bootmem(__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET,
(PFN_PHYS(free_pfn) + bootmap_size + PAGE_SIZE - 1) -
(__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET),
BOOTMEM_DEFAULT);
/*
* Reserve physical pages below CONFIG_ZERO_PAGE_OFFSET.
*/
if (CONFIG_ZERO_PAGE_OFFSET != 0)
reserve_bootmem(__MEMORY_START, CONFIG_ZERO_PAGE_OFFSET,
/* Reserve the sections we're already using. */
for (i = 0; i < lmb.reserved.cnt; i++)
reserve_bootmem(lmb.reserved.region[i].base,
lmb_size_bytes(&lmb.reserved, i),
BOOTMEM_DEFAULT);
node_set_online(0);
sparse_memory_present_with_active_regions(0);
#ifdef CONFIG_BLK_DEV_INITRD
@ -296,12 +303,37 @@ void __init setup_bootmem_allocator(unsigned long free_pfn)
static void __init setup_memory(void)
{
unsigned long start_pfn;
u64 base = min_low_pfn << PAGE_SHIFT;
u64 size = (max_low_pfn << PAGE_SHIFT) - base;
/*
* Partially used pages are not usable - thus
* we are rounding upwards:
*/
start_pfn = PFN_UP(__pa(_end));
lmb_add(base, size);
/*
* Reserve the kernel text and
* Reserve the bootmem bitmap. We do this in two steps (first step
* was init_bootmem()), because this catches the (definitely buggy)
* case of us accidentally initializing the bootmem allocator with
* an invalid RAM area.
*/
lmb_reserve(__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET,
(PFN_PHYS(start_pfn) + PAGE_SIZE - 1) -
(__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET));
/*
* Reserve physical pages below CONFIG_ZERO_PAGE_OFFSET.
*/
if (CONFIG_ZERO_PAGE_OFFSET != 0)
lmb_reserve(__MEMORY_START, CONFIG_ZERO_PAGE_OFFSET);
lmb_analyze();
lmb_dump_all();
setup_bootmem_allocator(start_pfn);
}
#else
@ -402,6 +434,7 @@ void __init setup_arch(char **cmdline_p)
nodes_clear(node_online_map);
/* Setup bootmem with available RAM */
lmb_init();
setup_memory();
sparse_init();

Просмотреть файл

@ -21,6 +21,7 @@
#include <linux/smp.h>
#include <linux/rtc.h>
#include <asm/clock.h>
#include <asm/hwblk.h>
#include <asm/rtc.h>
/* Dummy RTC ops */
@ -96,6 +97,7 @@ void __init time_init(void)
if (board_time_init)
board_time_init();
hwblk_init();
clk_init();
rtc_sh_get_time(&xtime);

Просмотреть файл

@ -2,7 +2,7 @@
* Page fault handler for SH with an MMU.
*
* Copyright (C) 1999 Niibe Yutaka
* Copyright (C) 2003 - 2008 Paul Mundt
* Copyright (C) 2003 - 2009 Paul Mundt
*
* Based on linux/arch/i386/mm/fault.c:
* Copyright (C) 1995 Linus Torvalds
@ -25,18 +25,84 @@ static inline int notify_page_fault(struct pt_regs *regs, int trap)
{
int ret = 0;
#ifdef CONFIG_KPROBES
if (!user_mode(regs)) {
if (kprobes_built_in() && !user_mode(regs)) {
preempt_disable();
if (kprobe_running() && kprobe_fault_handler(regs, trap))
ret = 1;
preempt_enable();
}
#endif
return ret;
}
static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
{
unsigned index = pgd_index(address);
pgd_t *pgd_k;
pud_t *pud, *pud_k;
pmd_t *pmd, *pmd_k;
pgd += index;
pgd_k = init_mm.pgd + index;
if (!pgd_present(*pgd_k))
return NULL;
pud = pud_offset(pgd, address);
pud_k = pud_offset(pgd_k, address);
if (!pud_present(*pud_k))
return NULL;
pmd = pmd_offset(pud, address);
pmd_k = pmd_offset(pud_k, address);
if (!pmd_present(*pmd_k))
return NULL;
if (!pmd_present(*pmd))
set_pmd(pmd, *pmd_k);
else
BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k));
return pmd_k;
}
/*
* Handle a fault on the vmalloc or module mapping area
*/
static noinline int vmalloc_fault(unsigned long address)
{
pgd_t *pgd_k;
pmd_t *pmd_k;
pte_t *pte_k;
/* Make sure we are in vmalloc area: */
if (!(address >= VMALLOC_START && address < VMALLOC_END))
return -1;
/*
* Synchronize this task's top level page-table
* with the 'reference' page table.
*
* Do _not_ use "current" here. We might be inside
* an interrupt in the middle of a task switch..
*/
pgd_k = get_TTB();
pmd_k = vmalloc_sync_one(__va((unsigned long)pgd_k), address);
if (!pmd_k)
return -1;
pte_k = pte_offset_kernel(pmd_k, address);
if (!pte_present(*pte_k))
return -1;
return 0;
}
static int fault_in_kernel_space(unsigned long address)
{
return address >= TASK_SIZE;
}
/*
* This routine handles page faults. It determines the address,
* and the problem, and then passes it off to one of the appropriate
@ -46,6 +112,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
unsigned long writeaccess,
unsigned long address)
{
unsigned long vec;
struct task_struct *tsk;
struct mm_struct *mm;
struct vm_area_struct * vma;
@ -53,59 +120,30 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
int fault;
siginfo_t info;
/*
* We don't bother with any notifier callbacks here, as they are
* all handled through the __do_page_fault() fast-path.
*/
tsk = current;
mm = tsk->mm;
si_code = SEGV_MAPERR;
vec = lookup_exception_vector();
if (unlikely(address >= TASK_SIZE)) {
/*
* Synchronize this task's top level page-table
* with the 'reference' page table.
*
* Do _not_ use "tsk" here. We might be inside
* an interrupt in the middle of a task switch..
*/
int offset = pgd_index(address);
pgd_t *pgd, *pgd_k;
pud_t *pud, *pud_k;
pmd_t *pmd, *pmd_k;
pgd = get_TTB() + offset;
pgd_k = swapper_pg_dir + offset;
if (!pgd_present(*pgd)) {
if (!pgd_present(*pgd_k))
goto bad_area_nosemaphore;
set_pgd(pgd, *pgd_k);
/*
* We fault-in kernel-space virtual memory on-demand. The
* 'reference' page table is init_mm.pgd.
*
* NOTE! We MUST NOT take any locks for this case. We may
* be in an interrupt or a critical region, and should
* only copy the information from the master page table,
* nothing more.
*/
if (unlikely(fault_in_kernel_space(address))) {
if (vmalloc_fault(address) >= 0)
return;
}
pud = pud_offset(pgd, address);
pud_k = pud_offset(pgd_k, address);
if (!pud_present(*pud)) {
if (!pud_present(*pud_k))
goto bad_area_nosemaphore;
set_pud(pud, *pud_k);
if (notify_page_fault(regs, vec))
return;
}
pmd = pmd_offset(pud, address);
pmd_k = pmd_offset(pud_k, address);
if (pmd_present(*pmd) || !pmd_present(*pmd_k))
goto bad_area_nosemaphore;
set_pmd(pmd, *pmd_k);
return;
goto bad_area_nosemaphore;
}
mm = tsk->mm;
if (unlikely(notify_page_fault(regs, lookup_exception_vector())))
if (unlikely(notify_page_fault(regs, vec)))
return;
/* Only enable interrupts if they were on before the fault */
@ -115,8 +153,8 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
/*
* If we're in an interrupt or have no user
* context, we must not take the fault..
* If we're in an interrupt, have no user context or are running
* in an atomic region then we must not take the fault:
*/
if (in_atomic() || !mm)
goto no_context;
@ -132,10 +170,11 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
goto bad_area;
if (expand_stack(vma, address))
goto bad_area;
/*
* Ok, we have a good vm_area for this memory access, so
* we can handle it..
*/
/*
* Ok, we have a good vm_area for this memory access, so
* we can handle it..
*/
good_area:
si_code = SEGV_ACCERR;
if (writeaccess) {
@ -173,10 +212,10 @@ survive:
up_read(&mm->mmap_sem);
return;
/*
* Something tried to access memory that isn't in our memory map..
* Fix it, but check if it's kernel or user first..
*/
/*
* Something tried to access memory that isn't in our memory map..
* Fix it, but check if it's kernel or user first..
*/
bad_area:
up_read(&mm->mmap_sem);

Просмотреть файл

@ -9,6 +9,7 @@
*/
#include <linux/module.h>
#include <linux/bootmem.h>
#include <linux/lmb.h>
#include <linux/mm.h>
#include <linux/numa.h>
#include <linux/pfn.h>
@ -26,6 +27,15 @@ EXPORT_SYMBOL_GPL(node_data);
void __init setup_memory(void)
{
unsigned long free_pfn = PFN_UP(__pa(_end));
u64 base = min_low_pfn << PAGE_SHIFT;
u64 size = (max_low_pfn << PAGE_SHIFT) - min_low_pfn;
lmb_add(base, size);
/* Reserve the LMB regions used by the kernel, initrd, etc.. */
lmb_reserve(__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET,
(PFN_PHYS(free_pfn) + PAGE_SIZE - 1) -
(__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET));
/*
* Node 0 sets up its pgdat at the first available pfn,
@ -45,24 +55,23 @@ void __init setup_memory(void)
void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end)
{
unsigned long bootmap_pages, bootmap_start, bootmap_size;
unsigned long start_pfn, free_pfn, end_pfn;
unsigned long bootmap_pages;
unsigned long start_pfn, end_pfn;
unsigned long bootmem_paddr;
/* Don't allow bogus node assignment */
BUG_ON(nid > MAX_NUMNODES || nid == 0);
/*
* The free pfn starts at the beginning of the range, and is
* advanced as necessary for pgdat and node map allocations.
*/
free_pfn = start_pfn = start >> PAGE_SHIFT;
start_pfn = start >> PAGE_SHIFT;
end_pfn = end >> PAGE_SHIFT;
lmb_add(start, end - start);
__add_active_range(nid, start_pfn, end_pfn);
/* Node-local pgdat */
NODE_DATA(nid) = pfn_to_kaddr(free_pfn);
free_pfn += PFN_UP(sizeof(struct pglist_data));
NODE_DATA(nid) = __va(lmb_alloc_base(sizeof(struct pglist_data),
SMP_CACHE_BYTES, end_pfn));
memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));
NODE_DATA(nid)->bdata = &bootmem_node_data[nid];
@ -71,16 +80,17 @@ void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end)
/* Node-local bootmap */
bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
bootmap_start = (unsigned long)pfn_to_kaddr(free_pfn);
bootmap_size = init_bootmem_node(NODE_DATA(nid), free_pfn, start_pfn,
end_pfn);
bootmem_paddr = lmb_alloc_base(bootmap_pages << PAGE_SHIFT,
PAGE_SIZE, end_pfn);
init_bootmem_node(NODE_DATA(nid), bootmem_paddr >> PAGE_SHIFT,
start_pfn, end_pfn);
free_bootmem_with_active_regions(nid, end_pfn);
/* Reserve the pgdat and bootmap space with the bootmem allocator */
reserve_bootmem_node(NODE_DATA(nid), start_pfn << PAGE_SHIFT,
sizeof(struct pglist_data), BOOTMEM_DEFAULT);
reserve_bootmem_node(NODE_DATA(nid), free_pfn << PAGE_SHIFT,
reserve_bootmem_node(NODE_DATA(nid), bootmem_paddr,
bootmap_pages << PAGE_SHIFT, BOOTMEM_DEFAULT);
/* It's up */

Просмотреть файл

@ -707,12 +707,13 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr)
static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
{
unsigned short ssr_status, scr_status;
unsigned short ssr_status, scr_status, err_enabled;
struct uart_port *port = ptr;
irqreturn_t ret = IRQ_NONE;
ssr_status = sci_in(port, SCxSR);
scr_status = sci_in(port, SCSCR);
err_enabled = scr_status & (SCI_CTRL_FLAGS_REIE | SCI_CTRL_FLAGS_RIE);
/* Tx Interrupt */
if ((ssr_status & 0x0020) && (scr_status & SCI_CTRL_FLAGS_TIE))
@ -721,10 +722,10 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
if ((ssr_status & 0x0002) && (scr_status & SCI_CTRL_FLAGS_RIE))
ret = sci_rx_interrupt(irq, ptr);
/* Error Interrupt */
if ((ssr_status & 0x0080) && (scr_status & SCI_CTRL_FLAGS_REIE))
if ((ssr_status & 0x0080) && err_enabled)
ret = sci_er_interrupt(irq, ptr);
/* Break Interrupt */
if ((ssr_status & 0x0010) && (scr_status & SCI_CTRL_FLAGS_REIE))
if ((ssr_status & 0x0010) && err_enabled)
ret = sci_br_interrupt(irq, ptr);
return ret;

Просмотреть файл

@ -37,7 +37,7 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yoshihiro Shimoda");
MODULE_ALIAS("platform:m66592_udc");
#define DRIVER_VERSION "18 Oct 2007"
#define DRIVER_VERSION "26 Jun 2009"
/* module parameters */
#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
@ -276,24 +276,27 @@ static int pipe_buffer_setting(struct m66592 *m66592,
buf_bsize = 0;
break;
case M66592_BULK:
bufnum = m66592->bi_bufnum +
(info->pipe - M66592_BASE_PIPENUM_BULK) * 16;
m66592->bi_bufnum += 16;
/* isochronous pipes may be used as bulk pipes */
if (info->pipe > M66592_BASE_PIPENUM_BULK)
bufnum = info->pipe - M66592_BASE_PIPENUM_BULK;
else
bufnum = info->pipe - M66592_BASE_PIPENUM_ISOC;
bufnum = M66592_BASE_BUFNUM + (bufnum * 16);
buf_bsize = 7;
pipecfg |= M66592_DBLB;
if (!info->dir_in)
pipecfg |= M66592_SHTNAK;
break;
case M66592_ISO:
bufnum = m66592->bi_bufnum +
bufnum = M66592_BASE_BUFNUM +
(info->pipe - M66592_BASE_PIPENUM_ISOC) * 16;
m66592->bi_bufnum += 16;
buf_bsize = 7;
break;
}
if (m66592->bi_bufnum > M66592_MAX_BUFNUM) {
pr_err("m66592 pipe memory is insufficient(%d)\n",
m66592->bi_bufnum);
if (buf_bsize && ((bufnum + 16) >= M66592_MAX_BUFNUM)) {
pr_err("m66592 pipe memory is insufficient\n");
return -ENOMEM;
}
@ -313,17 +316,6 @@ static void pipe_buffer_release(struct m66592 *m66592,
if (info->pipe == 0)
return;
switch (info->type) {
case M66592_BULK:
if (is_bulk_pipe(info->pipe))
m66592->bi_bufnum -= 16;
break;
case M66592_ISO:
if (is_isoc_pipe(info->pipe))
m66592->bi_bufnum -= 16;
break;
}
if (is_bulk_pipe(info->pipe)) {
m66592->bulk--;
} else if (is_interrupt_pipe(info->pipe))
@ -1603,8 +1595,6 @@ static int __init m66592_probe(struct platform_device *pdev)
m66592->timer.data = (unsigned long)m66592;
m66592->reg = reg;
m66592->bi_bufnum = M66592_BASE_BUFNUM;
ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED,
udc_name, m66592);
if (ret < 0) {

Просмотреть файл

@ -506,7 +506,6 @@ struct m66592 {
int interrupt;
int isochronous;
int num_dma;
int bi_bufnum; /* bulk and isochronous's bufnum */
};
#define gadget_to_m66592(_gadget) container_of(_gadget, struct m66592, gadget)

Просмотреть файл

@ -337,10 +337,10 @@ config USB_R8A66597_HCD
config SUPERH_ON_CHIP_R8A66597
boolean "Enable SuperH on-chip R8A66597 USB"
depends on USB_R8A66597_HCD && (CPU_SUBTYPE_SH7366 || CPU_SUBTYPE_SH7723)
depends on USB_R8A66597_HCD && (CPU_SUBTYPE_SH7366 || CPU_SUBTYPE_SH7723 || CPU_SUBTYPE_SH7724)
help
This driver enables support for the on-chip R8A66597 in the
SH7366 and SH7723 processors.
SH7366, SH7723 and SH7724 processors.
config USB_WHCI_HCD
tristate "Wireless USB Host Controller Interface (WHCI) driver (EXPERIMENTAL)"