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

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemoen/avr32-2.6: (25 commits)
  avr32: Add hardware power-down function call
  avr32: add include/asm-avr32/serial.h
  avr32: don't offer PARPORT_PC
  avr32: don't offer CONFIG_GEN_RTC
  avr32: don't offer CONFIG_RTC
  add include/asm-avr32/xor.h
  avr32: Remove two unused #defines from mm/init.c
  avr32: Implement set_rate(), set_parent() and mode() for pll1
  avr32: Generic clockevents support
  avr32: Move sleep code into mach-at32ap
  avr32: Use constants from sysreg.h in asm.h
  avr32: Delete mostly unused header asm/intc.h
  avr32: start clocksource cleanup
  avr32: pass i2c board info through at32_add_device_twi
  avr32: cleanup - use _AC macro to define PAGE_SIZE
  Generate raw keyboard codes for AVR32 architecture
  atmel_usba_udc: Add support for AT91CAP9 UDPHS
  atmel_usba_udc: Add missing kfree() in usba_udc_remove()
  atmel_usba_udc: move endpoint declarations into platform data.
  atmel_usba_udc: Kill GPIO_PIN_NONE
  ...
This commit is contained in:
Linus Torvalds
2008-04-21 15:44:57 -07:00
33 changed files with 1346 additions and 789 deletions
+5
View File
@@ -47,6 +47,9 @@ config RWSEM_GENERIC_SPINLOCK
config GENERIC_TIME
def_bool y
config GENERIC_CLOCKEVENTS
def_bool y
config RWSEM_XCHGADD_ALGORITHM
def_bool n
@@ -70,6 +73,8 @@ source "init/Kconfig"
menu "System Type and features"
source "kernel/time/Kconfig"
config SUBARCH_AVR32B
bool
config MMU
-20
View File
@@ -741,26 +741,6 @@ irq_level\level:
.section .irq.text,"ax",@progbits
.global cpu_idle_sleep
cpu_idle_sleep:
mask_interrupts
get_thread_info r8
ld.w r9, r8[TI_flags]
bld r9, TIF_NEED_RESCHED
brcs cpu_idle_enable_int_and_exit
sbr r9, TIF_CPU_GOING_TO_SLEEP
st.w r8[TI_flags], r9
unmask_interrupts
sleep 0
cpu_idle_skip_sleep:
mask_interrupts
ld.w r9, r8[TI_flags]
cbr r9, TIF_CPU_GOING_TO_SLEEP
st.w r8[TI_flags], r9
cpu_idle_enable_int_and_exit:
unmask_interrupts
retal r12
.global irq_level0
.global irq_level1
.global irq_level2
+4 -2
View File
@@ -18,11 +18,11 @@
#include <asm/sysreg.h>
#include <asm/ocd.h>
#include <asm/arch/pm.h>
void (*pm_power_off)(void) = NULL;
EXPORT_SYMBOL(pm_power_off);
extern void cpu_idle_sleep(void);
/*
* This file handles the architecture-dependent parts of process handling..
*/
@@ -54,6 +54,8 @@ void machine_halt(void)
void machine_power_off(void)
{
if (pm_power_off)
pm_power_off();
}
void machine_restart(char *cmd)
+102 -180
View File
@@ -1,16 +1,12 @@
/*
* Copyright (C) 2004-2007 Atmel Corporation
*
* Based on MIPS implementation arch/mips/kernel/time.c
* Copyright 2001 MontaVista Software Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/time.h>
#include <linux/module.h>
#include <linux/interrupt.h>
@@ -27,207 +23,133 @@
#include <asm/io.h>
#include <asm/sections.h>
/* how many counter cycles in a jiffy? */
static u32 cycles_per_jiffy;
#include <asm/arch/pm.h>
/* the count value for the next timer interrupt */
static u32 expirelo;
cycle_t __weak read_cycle_count(void)
static cycle_t read_cycle_count(void)
{
return (cycle_t)sysreg_read(COUNT);
}
struct clocksource __weak clocksource_avr32 = {
.name = "avr32",
.rating = 350,
/*
* The architectural cycle count registers are a fine clocksource unless
* the system idle loop use sleep states like "idle": the CPU cycles
* measured by COUNT (and COMPARE) don't happen during sleep states.
* Their duration also changes if cpufreq changes the CPU clock rate.
* So we rate the clocksource using COUNT as very low quality.
*/
static struct clocksource counter = {
.name = "avr32_counter",
.rating = 50,
.read = read_cycle_count,
.mask = CLOCKSOURCE_MASK(32),
.shift = 16,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
irqreturn_t __weak timer_interrupt(int irq, void *dev_id);
struct irqaction timer_irqaction = {
.handler = timer_interrupt,
.flags = IRQF_DISABLED,
.name = "timer",
};
/*
* By default we provide the null RTC ops
*/
static unsigned long null_rtc_get_time(void)
static irqreturn_t timer_interrupt(int irq, void *dev_id)
{
return mktime(2007, 1, 1, 0, 0, 0);
}
static int null_rtc_set_time(unsigned long sec)
{
return 0;
}
static unsigned long (*rtc_get_time)(void) = null_rtc_get_time;
static int (*rtc_set_time)(unsigned long) = null_rtc_set_time;
static void avr32_timer_ack(void)
{
u32 count;
/* Ack this timer interrupt and set the next one */
expirelo += cycles_per_jiffy;
/* setting COMPARE to 0 stops the COUNT-COMPARE */
if (expirelo == 0) {
sysreg_write(COMPARE, expirelo + 1);
} else {
sysreg_write(COMPARE, expirelo);
}
/* Check to see if we have missed any timer interrupts */
count = sysreg_read(COUNT);
if ((count - expirelo) < 0x7fffffff) {
expirelo = count + cycles_per_jiffy;
sysreg_write(COMPARE, expirelo);
}
}
int __weak avr32_hpt_init(void)
{
int ret;
unsigned long mult, shift, count_hz;
count_hz = clk_get_rate(boot_cpu_data.clk);
shift = clocksource_avr32.shift;
mult = clocksource_hz2mult(count_hz, shift);
clocksource_avr32.mult = mult;
{
u64 tmp;
tmp = TICK_NSEC;
tmp <<= shift;
tmp += mult / 2;
do_div(tmp, mult);
cycles_per_jiffy = tmp;
}
ret = setup_irq(0, &timer_irqaction);
if (ret) {
pr_debug("timer: could not request IRQ 0: %d\n", ret);
return -ENODEV;
}
printk(KERN_INFO "timer: AT32AP COUNT-COMPARE at irq 0, "
"%lu.%03lu MHz\n",
((count_hz + 500) / 1000) / 1000,
((count_hz + 500) / 1000) % 1000);
return 0;
}
/*
* Taken from MIPS c0_hpt_timer_init().
*
* The reason COUNT is written twice is probably to make sure we don't get any
* timer interrupts while we are messing with the counter.
*/
int __weak avr32_hpt_start(void)
{
u32 count = sysreg_read(COUNT);
expirelo = (count / cycles_per_jiffy + 1) * cycles_per_jiffy;
sysreg_write(COUNT, expirelo - cycles_per_jiffy);
sysreg_write(COMPARE, expirelo);
sysreg_write(COUNT, count);
return 0;
}
/*
* local_timer_interrupt() does profiling and process accounting on a
* per-CPU basis.
*
* In UP mode, it is invoked from the (global) timer_interrupt.
*/
void local_timer_interrupt(int irq, void *dev_id)
{
if (current->pid)
profile_tick(CPU_PROFILING);
update_process_times(user_mode(get_irq_regs()));
}
irqreturn_t __weak timer_interrupt(int irq, void *dev_id)
{
/* ack timer interrupt and try to set next interrupt */
avr32_timer_ack();
struct clock_event_device *evdev = dev_id;
/*
* Call the generic timer interrupt handler
*/
write_seqlock(&xtime_lock);
do_timer(1);
write_sequnlock(&xtime_lock);
/*
* In UP mode, we call local_timer_interrupt() to do profiling
* and process accounting.
*
* SMP is not supported yet.
*/
local_timer_interrupt(irq, dev_id);
return IRQ_HANDLED;
}
void __init time_init(void)
{
int ret;
/*
* Make sure we don't get any COMPARE interrupts before we can
* handle them.
* Disable the interrupt until the clockevent subsystem
* reprograms it.
*/
sysreg_write(COMPARE, 0);
xtime.tv_sec = rtc_get_time();
evdev->event_handler(evdev);
return IRQ_HANDLED;
}
static struct irqaction timer_irqaction = {
.handler = timer_interrupt,
.flags = IRQF_TIMER | IRQF_DISABLED,
.name = "avr32_comparator",
};
static int comparator_next_event(unsigned long delta,
struct clock_event_device *evdev)
{
unsigned long flags;
raw_local_irq_save(flags);
/* The time to read COUNT then update COMPARE must be less
* than the min_delta_ns value for this clockevent source.
*/
sysreg_write(COMPARE, (sysreg_read(COUNT) + delta) ? : 1);
raw_local_irq_restore(flags);
return 0;
}
static void comparator_mode(enum clock_event_mode mode,
struct clock_event_device *evdev)
{
switch (mode) {
case CLOCK_EVT_MODE_ONESHOT:
pr_debug("%s: start\n", evdev->name);
/* FALLTHROUGH */
case CLOCK_EVT_MODE_RESUME:
cpu_disable_idle_sleep();
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
sysreg_write(COMPARE, 0);
pr_debug("%s: stop\n", evdev->name);
cpu_enable_idle_sleep();
break;
default:
BUG();
}
}
static struct clock_event_device comparator = {
.name = "avr32_comparator",
.features = CLOCK_EVT_FEAT_ONESHOT,
.shift = 16,
.rating = 50,
.cpumask = CPU_MASK_CPU0,
.set_next_event = comparator_next_event,
.set_mode = comparator_mode,
};
void __init time_init(void)
{
unsigned long counter_hz;
int ret;
xtime.tv_sec = mktime(2007, 1, 1, 0, 0, 0);
xtime.tv_nsec = 0;
set_normalized_timespec(&wall_to_monotonic,
-xtime.tv_sec, -xtime.tv_nsec);
ret = avr32_hpt_init();
if (ret) {
pr_debug("timer: failed setup: %d\n", ret);
return;
}
/* figure rate for counter */
counter_hz = clk_get_rate(boot_cpu_data.clk);
counter.mult = clocksource_hz2mult(counter_hz, counter.shift);
ret = clocksource_register(&clocksource_avr32);
ret = clocksource_register(&counter);
if (ret)
pr_debug("timer: could not register clocksource: %d\n", ret);
ret = avr32_hpt_start();
if (ret) {
pr_debug("timer: failed starting: %d\n", ret);
return;
/* setup COMPARE clockevent */
comparator.mult = div_sc(counter_hz, NSEC_PER_SEC, comparator.shift);
comparator.max_delta_ns = clockevent_delta2ns((u32)~0, &comparator);
comparator.min_delta_ns = clockevent_delta2ns(50, &comparator) + 1;
sysreg_write(COMPARE, 0);
timer_irqaction.dev_id = &comparator;
ret = setup_irq(0, &timer_irqaction);
if (ret)
pr_debug("timer: could not request IRQ 0: %d\n", ret);
else {
clockevents_register_device(&comparator);
pr_info("%s: irq 0, %lu.%03lu MHz\n", comparator.name,
((counter_hz + 500) / 1000) / 1000,
((counter_hz + 500) / 1000) % 1000);
}
}
static struct sysdev_class timer_class = {
.name = "timer",
};
static struct sys_device timer_device = {
.id = 0,
.cls = &timer_class,
};
static int __init init_timer_sysfs(void)
{
int err = sysdev_class_register(&timer_class);
if (!err)
err = sysdev_register(&timer_device);
return err;
}
device_initcall(init_timer_sysfs);
+1 -2
View File
@@ -1,4 +1,3 @@
obj-y += at32ap.o clock.o intc.o extint.o pio.o hsmc.o
obj-$(CONFIG_CPU_AT32AP700X) += at32ap700x.o
obj-$(CONFIG_CPU_AT32AP700X) += time-tc.o
obj-$(CONFIG_CPU_AT32AP700X) += at32ap700x.o pm-at32ap700x.o
obj-$(CONFIG_CPU_FREQ_AT32AP) += cpufreq.o
+224 -19
View File
@@ -6,11 +6,13 @@
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/spi/spi.h>
#include <linux/usb/atmel_usba_udc.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -98,6 +100,9 @@ unsigned long at32ap7000_osc_rates[3] = {
[2] = 12000000,
};
static struct clk osc0;
static struct clk osc1;
static unsigned long osc_get_rate(struct clk *clk)
{
return at32ap7000_osc_rates[clk->index];
@@ -107,9 +112,6 @@ static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
{
unsigned long div, mul, rate;
if (!(control & PM_BIT(PLLEN)))
return 0;
div = PM_BFEXT(PLLDIV, control) + 1;
mul = PM_BFEXT(PLLMUL, control) + 1;
@@ -120,6 +122,71 @@ static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
return rate;
}
static long pll_set_rate(struct clk *clk, unsigned long rate,
u32 *pll_ctrl)
{
unsigned long mul;
unsigned long mul_best_fit = 0;
unsigned long div;
unsigned long div_min;
unsigned long div_max;
unsigned long div_best_fit = 0;
unsigned long base;
unsigned long pll_in;
unsigned long actual = 0;
unsigned long rate_error;
unsigned long rate_error_prev = ~0UL;
u32 ctrl;
/* Rate must be between 80 MHz and 200 Mhz. */
if (rate < 80000000UL || rate > 200000000UL)
return -EINVAL;
ctrl = PM_BF(PLLOPT, 4);
base = clk->parent->get_rate(clk->parent);
/* PLL input frequency must be between 6 MHz and 32 MHz. */
div_min = DIV_ROUND_UP(base, 32000000UL);
div_max = base / 6000000UL;
if (div_max < div_min)
return -EINVAL;
for (div = div_min; div <= div_max; div++) {
pll_in = (base + div / 2) / div;
mul = (rate + pll_in / 2) / pll_in;
if (mul == 0)
continue;
actual = pll_in * mul;
rate_error = abs(actual - rate);
if (rate_error < rate_error_prev) {
mul_best_fit = mul;
div_best_fit = div;
rate_error_prev = rate_error;
}
if (rate_error == 0)
break;
}
if (div_best_fit == 0)
return -EINVAL;
ctrl |= PM_BF(PLLMUL, mul_best_fit - 1);
ctrl |= PM_BF(PLLDIV, div_best_fit - 1);
ctrl |= PM_BF(PLLCOUNT, 16);
if (clk->parent == &osc1)
ctrl |= PM_BIT(PLLOSC);
*pll_ctrl = ctrl;
return actual;
}
static unsigned long pll0_get_rate(struct clk *clk)
{
u32 control;
@@ -129,6 +196,41 @@ static unsigned long pll0_get_rate(struct clk *clk)
return pll_get_rate(clk, control);
}
static void pll1_mode(struct clk *clk, int enabled)
{
unsigned long timeout;
u32 status;
u32 ctrl;
ctrl = pm_readl(PLL1);
if (enabled) {
if (!PM_BFEXT(PLLMUL, ctrl) && !PM_BFEXT(PLLDIV, ctrl)) {
pr_debug("clk %s: failed to enable, rate not set\n",
clk->name);
return;
}
ctrl |= PM_BIT(PLLEN);
pm_writel(PLL1, ctrl);
/* Wait for PLL lock. */
for (timeout = 10000; timeout; timeout--) {
status = pm_readl(ISR);
if (status & PM_BIT(LOCK1))
break;
udelay(10);
}
if (!(status & PM_BIT(LOCK1)))
printk(KERN_ERR "clk %s: timeout waiting for lock\n",
clk->name);
} else {
ctrl &= ~PM_BIT(PLLEN);
pm_writel(PLL1, ctrl);
}
}
static unsigned long pll1_get_rate(struct clk *clk)
{
u32 control;
@@ -138,6 +240,49 @@ static unsigned long pll1_get_rate(struct clk *clk)
return pll_get_rate(clk, control);
}
static long pll1_set_rate(struct clk *clk, unsigned long rate, int apply)
{
u32 ctrl = 0;
unsigned long actual_rate;
actual_rate = pll_set_rate(clk, rate, &ctrl);
if (apply) {
if (actual_rate != rate)
return -EINVAL;
if (clk->users > 0)
return -EBUSY;
pr_debug(KERN_INFO "clk %s: new rate %lu (actual rate %lu)\n",
clk->name, rate, actual_rate);
pm_writel(PLL1, ctrl);
}
return actual_rate;
}
static int pll1_set_parent(struct clk *clk, struct clk *parent)
{
u32 ctrl;
if (clk->users > 0)
return -EBUSY;
ctrl = pm_readl(PLL1);
WARN_ON(ctrl & PM_BIT(PLLEN));
if (parent == &osc0)
ctrl &= ~PM_BIT(PLLOSC);
else if (parent == &osc1)
ctrl |= PM_BIT(PLLOSC);
else
return -EINVAL;
pm_writel(PLL1, ctrl);
clk->parent = parent;
return 0;
}
/*
* The AT32AP7000 has five primary clock sources: One 32kHz
* oscillator, two crystal oscillators and two PLLs.
@@ -166,7 +311,10 @@ static struct clk pll0 = {
};
static struct clk pll1 = {
.name = "pll1",
.mode = pll1_mode,
.get_rate = pll1_get_rate,
.set_rate = pll1_set_rate,
.set_parent = pll1_set_parent,
.parent = &osc0,
};
@@ -605,19 +753,32 @@ static inline void set_ebi_sfr_bits(u32 mask)
}
/* --------------------------------------------------------------------
* System Timer/Counter (TC)
* Timer/Counter (TC)
* -------------------------------------------------------------------- */
static struct resource at32_systc0_resource[] = {
static struct resource at32_tcb0_resource[] = {
PBMEM(0xfff00c00),
IRQ(22),
};
struct platform_device at32_systc0_device = {
.name = "systc",
static struct platform_device at32_tcb0_device = {
.name = "atmel_tcb",
.id = 0,
.resource = at32_systc0_resource,
.num_resources = ARRAY_SIZE(at32_systc0_resource),
.resource = at32_tcb0_resource,
.num_resources = ARRAY_SIZE(at32_tcb0_resource),
};
DEV_CLK(pclk, at32_systc0, pbb, 3);
DEV_CLK(t0_clk, at32_tcb0, pbb, 3);
static struct resource at32_tcb1_resource[] = {
PBMEM(0xfff01000),
IRQ(23),
};
static struct platform_device at32_tcb1_device = {
.name = "atmel_tcb",
.id = 1,
.resource = at32_tcb1_resource,
.num_resources = ARRAY_SIZE(at32_tcb1_resource),
};
DEV_CLK(t0_clk, at32_tcb1, pbb, 4);
/* --------------------------------------------------------------------
* PIO
@@ -669,7 +830,8 @@ void __init at32_add_system_devices(void)
platform_device_register(&pdc_device);
platform_device_register(&dmaca0_device);
platform_device_register(&at32_systc0_device);
platform_device_register(&at32_tcb0_device);
platform_device_register(&at32_tcb1_device);
platform_device_register(&pio0_device);
platform_device_register(&pio1_device);
@@ -989,7 +1151,9 @@ static struct clk atmel_twi0_pclk = {
.index = 2,
};
struct platform_device *__init at32_add_device_twi(unsigned int id)
struct platform_device *__init at32_add_device_twi(unsigned int id,
struct i2c_board_info *b,
unsigned int n)
{
struct platform_device *pdev;
@@ -1009,6 +1173,9 @@ struct platform_device *__init at32_add_device_twi(unsigned int id)
atmel_twi0_pclk.dev = &pdev->dev;
if (b)
i2c_register_board_info(id, b, n);
platform_device_add(pdev);
return pdev;
@@ -1351,9 +1518,39 @@ static struct clk usba0_hclk = {
.index = 6,
};
#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \
[idx] = { \
.name = nam, \
.index = idx, \
.fifo_size = maxpkt, \
.nr_banks = maxbk, \
.can_dma = dma, \
.can_isoc = isoc, \
}
static struct usba_ep_data at32_usba_ep[] __initdata = {
EP("ep0", 0, 64, 1, 0, 0),
EP("ep1", 1, 512, 2, 1, 1),
EP("ep2", 2, 512, 2, 1, 1),
EP("ep3-int", 3, 64, 3, 1, 0),
EP("ep4-int", 4, 64, 3, 1, 0),
EP("ep5", 5, 1024, 3, 1, 1),
EP("ep6", 6, 1024, 3, 1, 1),
};
#undef EP
struct platform_device *__init
at32_add_device_usba(unsigned int id, struct usba_platform_data *data)
{
/*
* pdata doesn't have room for any endpoints, so we need to
* append room for the ones we need right after it.
*/
struct {
struct usba_platform_data pdata;
struct usba_ep_data ep[7];
} usba_data;
struct platform_device *pdev;
if (id != 0)
@@ -1367,13 +1564,20 @@ at32_add_device_usba(unsigned int id, struct usba_platform_data *data)
ARRAY_SIZE(usba0_resource)))
goto out_free_pdev;
if (data) {
if (platform_device_add_data(pdev, data, sizeof(*data)))
goto out_free_pdev;
if (data)
usba_data.pdata.vbus_pin = data->vbus_pin;
else
usba_data.pdata.vbus_pin = -EINVAL;
if (data->vbus_pin != GPIO_PIN_NONE)
at32_select_gpio(data->vbus_pin, 0);
}
data = &usba_data.pdata;
data->num_ep = ARRAY_SIZE(at32_usba_ep);
memcpy(data->ep, at32_usba_ep, sizeof(at32_usba_ep));
if (platform_device_add_data(pdev, data, sizeof(usba_data)))
goto out_free_pdev;
if (data->vbus_pin >= 0)
at32_select_gpio(data->vbus_pin, 0);
usba0_pclk.dev = &pdev->dev;
usba0_hclk.dev = &pdev->dev;
@@ -1694,7 +1898,8 @@ struct clk *at32_clock_list[] = {
&pio2_mck,
&pio3_mck,
&pio4_mck,
&at32_systc0_pclk,
&at32_tcb0_t0_clk,
&at32_tcb1_t0_clk,
&atmel_usart0_usart,
&atmel_usart1_usart,
&atmel_usart2_usart,
-1
View File
@@ -13,7 +13,6 @@
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <asm/intc.h>
#include <asm/io.h>
#include "intc.h"
+66
View File
@@ -0,0 +1,66 @@
/*
* Low-level Power Management code.
*
* Copyright (C) 2008 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <asm/asm.h>
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
#include <asm/arch/pm.h>
.section .bss, "wa", @nobits
.global disable_idle_sleep
.type disable_idle_sleep, @object
disable_idle_sleep:
.int 4
.size disable_idle_sleep, . - disable_idle_sleep
/* Keep this close to the irq handlers */
.section .irq.text, "ax", @progbits
/*
* void cpu_enter_idle(void)
*
* Put the CPU into "idle" mode, in which it will consume
* significantly less power.
*
* If an interrupt comes along in the window between
* unmask_interrupts and the sleep instruction below, the
* interrupt code will adjust the return address so that we
* never execute the sleep instruction. This is required
* because the AP7000 doesn't unmask interrupts when entering
* sleep modes; later CPUs may not need this workaround.
*/
.global cpu_enter_idle
.type cpu_enter_idle, @function
cpu_enter_idle:
mask_interrupts
get_thread_info r8
ld.w r9, r8[TI_flags]
bld r9, TIF_NEED_RESCHED
brcs .Lret_from_sleep
sbr r9, TIF_CPU_GOING_TO_SLEEP
st.w r8[TI_flags], r9
unmask_interrupts
sleep CPU_SLEEP_IDLE
.size cpu_idle_sleep, . - cpu_idle_sleep
/*
* Common return path for PM functions that don't run from
* SRAM.
*/
.global cpu_idle_skip_sleep
.type cpu_idle_skip_sleep, @function
cpu_idle_skip_sleep:
mask_interrupts
ld.w r9, r8[TI_flags]
cbr r9, TIF_CPU_GOING_TO_SLEEP
st.w r8[TI_flags], r9
.Lret_from_sleep:
unmask_interrupts
retal r12
.size cpu_idle_skip_sleep, . - cpu_idle_skip_sleep
-218
View File
@@ -1,218 +0,0 @@
/*
* Copyright (C) 2004-2007 Atmel Corporation
*
* Based on MIPS implementation arch/mips/kernel/time.c
* Copyright 2001 MontaVista Software Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/clocksource.h>
#include <linux/time.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel_stat.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/profile.h>
#include <linux/sysdev.h>
#include <linux/err.h>
#include <asm/div64.h>
#include <asm/sysreg.h>
#include <asm/io.h>
#include <asm/sections.h>
#include <asm/arch/time.h>
/* how many counter cycles in a jiffy? */
static u32 cycles_per_jiffy;
/* the count value for the next timer interrupt */
static u32 expirelo;
/* the I/O registers of the TC module */
static void __iomem *ioregs;
cycle_t read_cycle_count(void)
{
return (cycle_t)timer_read(ioregs, 0, CV);
}
struct clocksource clocksource_avr32 = {
.name = "avr32",
.rating = 342,
.read = read_cycle_count,
.mask = CLOCKSOURCE_MASK(16),
.shift = 16,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static void avr32_timer_ack(void)
{
u16 count = expirelo;
/* Ack this timer interrupt and set the next one, use a u16
* variable so it will wrap around correctly */
count += cycles_per_jiffy;
expirelo = count;
timer_write(ioregs, 0, RC, expirelo);
/* Check to see if we have missed any timer interrupts */
count = timer_read(ioregs, 0, CV);
if ((count - expirelo) < 0x7fff) {
expirelo = count + cycles_per_jiffy;
timer_write(ioregs, 0, RC, expirelo);
}
}
u32 avr32_hpt_read(void)
{
return timer_read(ioregs, 0, CV);
}
static int avr32_timer_calc_div_and_set_jiffies(struct clk *pclk)
{
unsigned int cycles_max = (clocksource_avr32.mask + 1) / 2;
unsigned int divs[] = { 4, 8, 16, 32 };
int divs_size = ARRAY_SIZE(divs);
int i = 0;
unsigned long count_hz;
unsigned long shift;
unsigned long mult;
int clock_div = -1;
u64 tmp;
shift = clocksource_avr32.shift;
do {
count_hz = clk_get_rate(pclk) / divs[i];
mult = clocksource_hz2mult(count_hz, shift);
clocksource_avr32.mult = mult;
tmp = TICK_NSEC;
tmp <<= shift;
tmp += mult / 2;
do_div(tmp, mult);
cycles_per_jiffy = tmp;
} while (cycles_per_jiffy > cycles_max && ++i < divs_size);
clock_div = i + 1;
if (clock_div > divs_size) {
pr_debug("timer: could not calculate clock divider\n");
return -EFAULT;
}
/* Set the clock divider */
timer_write(ioregs, 0, CMR, TIMER_BF(CMR_TCCLKS, clock_div));
return 0;
}
int avr32_hpt_init(unsigned int count)
{
struct resource *regs;
struct clk *pclk;
int irq = -1;
int ret = 0;
ret = -ENXIO;
irq = platform_get_irq(&at32_systc0_device, 0);
if (irq < 0) {
pr_debug("timer: could not get irq\n");
goto out_error;
}
pclk = clk_get(&at32_systc0_device.dev, "pclk");
if (IS_ERR(pclk)) {
pr_debug("timer: could not get clk: %ld\n", PTR_ERR(pclk));
goto out_error;
}
clk_enable(pclk);
regs = platform_get_resource(&at32_systc0_device, IORESOURCE_MEM, 0);
if (!regs) {
pr_debug("timer: could not get resource\n");
goto out_error_clk;
}
ioregs = ioremap(regs->start, regs->end - regs->start + 1);
if (!ioregs) {
pr_debug("timer: could not get ioregs\n");
goto out_error_clk;
}
ret = avr32_timer_calc_div_and_set_jiffies(pclk);
if (ret)
goto out_error_io;
ret = setup_irq(irq, &timer_irqaction);
if (ret) {
pr_debug("timer: could not request irq %d: %d\n",
irq, ret);
goto out_error_io;
}
expirelo = (timer_read(ioregs, 0, CV) / cycles_per_jiffy + 1)
* cycles_per_jiffy;
/* Enable clock and interrupts on RC compare */
timer_write(ioregs, 0, CCR, TIMER_BIT(CCR_CLKEN));
timer_write(ioregs, 0, IER, TIMER_BIT(IER_CPCS));
/* Set cycles to first interrupt */
timer_write(ioregs, 0, RC, expirelo);
printk(KERN_INFO "timer: AT32AP system timer/counter at 0x%p irq %d\n",
ioregs, irq);
return 0;
out_error_io:
iounmap(ioregs);
out_error_clk:
clk_put(pclk);
out_error:
return ret;
}
int avr32_hpt_start(void)
{
timer_write(ioregs, 0, CCR, TIMER_BIT(CCR_SWTRG));
return 0;
}
irqreturn_t timer_interrupt(int irq, void *dev_id)
{
unsigned int sr = timer_read(ioregs, 0, SR);
if (sr & TIMER_BIT(SR_CPCS)) {
/* ack timer interrupt and try to set next interrupt */
avr32_timer_ack();
/*
* Call the generic timer interrupt handler
*/
write_seqlock(&xtime_lock);
do_timer(1);
write_sequnlock(&xtime_lock);
/*
* In UP mode, we call local_timer_interrupt() to do profiling
* and process accounting.
*
* SMP is not supported yet.
*/
local_timer_interrupt(irq, dev_id);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
-3
View File
@@ -34,9 +34,6 @@ struct page *empty_zero_page;
*/
unsigned long mmu_context_cache = NO_CONTEXT;
#define START_PFN (NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT)
#define MAX_LOW_PFN (NODE_DATA(0)->bdata->node_low_pfn)
void show_mem(void)
{
int total = 0, reserved = 0, cached = 0;
-1
View File
@@ -16,7 +16,6 @@
#include <linux/sched.h>
#include <linux/types.h>
#include <asm/intc.h>
#include <asm/sysreg.h>
#include <asm/system.h>
+2 -2
View File
@@ -706,7 +706,7 @@ config NVRAM
config RTC
tristate "Enhanced Real Time Clock Support"
depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390
depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390 && !AVR32
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -776,7 +776,7 @@ config SGI_IP27_RTC
config GEN_RTC
tristate "Generic /dev/rtc emulation"
depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH
depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH && !AVR32
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
+2 -1
View File
@@ -1033,7 +1033,8 @@ DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\
defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
(defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC))
(defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) ||\
defined(CONFIG_AVR32)
#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
+1
View File
@@ -1,3 +1,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
+302
View File
@@ -0,0 +1,302 @@
#include <linux/init.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/atmel_tc.h>
/*
* We're configured to use a specific TC block, one that's not hooked
* up to external hardware, to provide a time solution:
*
* - Two channels combine to create a free-running 32 bit counter
* with a base rate of 5+ MHz, packaged as a clocksource (with
* resolution better than 200 nsec).
*
* - The third channel may be used to provide a 16-bit clockevent
* source, used in either periodic or oneshot mode. This runs
* at 32 KiHZ, and can handle delays of up to two seconds.
*
* A boot clocksource and clockevent source are also currently needed,
* unless the relevant platforms (ARM/AT91, AVR32/AT32) are changed so
* this code can be used when init_timers() is called, well before most
* devices are set up. (Some low end AT91 parts, which can run uClinux,
* have only the timers in one TC block... they currently don't support
* the tclib code, because of that initialization issue.)
*
* REVISIT behavior during system suspend states... we should disable
* all clocks and save the power. Easily done for clockevent devices,
* but clocksources won't necessarily get the needed notifications.
* For deeper system sleep states, this will be mandatory...
*/
static void __iomem *tcaddr;
static cycle_t tc_get_cycles(void)
{
unsigned long flags;
u32 lower, upper;
raw_local_irq_save(flags);
do {
upper = __raw_readl(tcaddr + ATMEL_TC_REG(1, CV));
lower = __raw_readl(tcaddr + ATMEL_TC_REG(0, CV));
} while (upper != __raw_readl(tcaddr + ATMEL_TC_REG(1, CV)));
raw_local_irq_restore(flags);
return (upper << 16) | lower;
}
static struct clocksource clksrc = {
.name = "tcb_clksrc",
.rating = 200,
.read = tc_get_cycles,
.mask = CLOCKSOURCE_MASK(32),
.shift = 18,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
#ifdef CONFIG_GENERIC_CLOCKEVENTS
struct tc_clkevt_device {
struct clock_event_device clkevt;
struct clk *clk;
void __iomem *regs;
};
static struct tc_clkevt_device *to_tc_clkevt(struct clock_event_device *clkevt)
{
return container_of(clkevt, struct tc_clkevt_device, clkevt);
}
/* For now, we always use the 32K clock ... this optimizes for NO_HZ,
* because using one of the divided clocks would usually mean the
* tick rate can never be less than several dozen Hz (vs 0.5 Hz).
*
* A divided clock could be good for high resolution timers, since
* 30.5 usec resolution can seem "low".
*/
static u32 timer_clock;
static void tc_mode(enum clock_event_mode m, struct clock_event_device *d)
{
struct tc_clkevt_device *tcd = to_tc_clkevt(d);
void __iomem *regs = tcd->regs;
if (tcd->clkevt.mode == CLOCK_EVT_MODE_PERIODIC
|| tcd->clkevt.mode == CLOCK_EVT_MODE_ONESHOT) {
__raw_writel(0xff, regs + ATMEL_TC_REG(2, IDR));
__raw_writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR));
clk_disable(tcd->clk);
}
switch (m) {
/* By not making the gentime core emulate periodic mode on top
* of oneshot, we get lower overhead and improved accuracy.
*/
case CLOCK_EVT_MODE_PERIODIC:
clk_enable(tcd->clk);
/* slow clock, count up to RC, then irq and restart */
__raw_writel(timer_clock
| ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO,
regs + ATMEL_TC_REG(2, CMR));
__raw_writel((32768 + HZ/2) / HZ, tcaddr + ATMEL_TC_REG(2, RC));
/* Enable clock and interrupts on RC compare */
__raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
/* go go gadget! */
__raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG,
regs + ATMEL_TC_REG(2, CCR));
break;
case CLOCK_EVT_MODE_ONESHOT:
clk_enable(tcd->clk);
/* slow clock, count up to RC, then irq and stop */
__raw_writel(timer_clock | ATMEL_TC_CPCSTOP
| ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO,
regs + ATMEL_TC_REG(2, CMR));
__raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
/* set_next_event() configures and starts the timer */
break;
default:
break;
}
}
static int tc_next_event(unsigned long delta, struct clock_event_device *d)
{
__raw_writel(delta, tcaddr + ATMEL_TC_REG(2, RC));
/* go go gadget! */
__raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG,
tcaddr + ATMEL_TC_REG(2, CCR));
return 0;
}
static struct tc_clkevt_device clkevt = {
.clkevt = {
.name = "tc_clkevt",
.features = CLOCK_EVT_FEAT_PERIODIC
| CLOCK_EVT_FEAT_ONESHOT,
.shift = 32,
/* Should be lower than at91rm9200's system timer */
.rating = 125,
.cpumask = CPU_MASK_CPU0,
.set_next_event = tc_next_event,
.set_mode = tc_mode,
},
};
static irqreturn_t ch2_irq(int irq, void *handle)
{
struct tc_clkevt_device *dev = handle;
unsigned int sr;
sr = __raw_readl(dev->regs + ATMEL_TC_REG(2, SR));
if (sr & ATMEL_TC_CPCS) {
dev->clkevt.event_handler(&dev->clkevt);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
static struct irqaction tc_irqaction = {
.name = "tc_clkevt",
.flags = IRQF_TIMER | IRQF_DISABLED,
.handler = ch2_irq,
};
static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
{
struct clk *t2_clk = tc->clk[2];
int irq = tc->irq[2];
clkevt.regs = tc->regs;
clkevt.clk = t2_clk;
tc_irqaction.dev_id = &clkevt;
timer_clock = clk32k_divisor_idx;
clkevt.clkevt.mult = div_sc(32768, NSEC_PER_SEC, clkevt.clkevt.shift);
clkevt.clkevt.max_delta_ns
= clockevent_delta2ns(0xffff, &clkevt.clkevt);
clkevt.clkevt.min_delta_ns = clockevent_delta2ns(1, &clkevt.clkevt) + 1;
setup_irq(irq, &tc_irqaction);
clockevents_register_device(&clkevt.clkevt);
}
#else /* !CONFIG_GENERIC_CLOCKEVENTS */
static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
{
/* NOTHING */
}
#endif
static int __init tcb_clksrc_init(void)
{
static char bootinfo[] __initdata
= KERN_DEBUG "%s: tc%d at %d.%03d MHz\n";
struct platform_device *pdev;
struct atmel_tc *tc;
struct clk *t0_clk;
u32 rate, divided_rate = 0;
int best_divisor_idx = -1;
int clk32k_divisor_idx = -1;
int i;
tc = atmel_tc_alloc(CONFIG_ATMEL_TCB_CLKSRC_BLOCK, clksrc.name);
if (!tc) {
pr_debug("can't alloc TC for clocksource\n");
return -ENODEV;
}
tcaddr = tc->regs;
pdev = tc->pdev;
t0_clk = tc->clk[0];
clk_enable(t0_clk);
/* How fast will we be counting? Pick something over 5 MHz. */
rate = (u32) clk_get_rate(t0_clk);
for (i = 0; i < 5; i++) {
unsigned divisor = atmel_tc_divisors[i];
unsigned tmp;
/* remember 32 KiHz clock for later */
if (!divisor) {
clk32k_divisor_idx = i;
continue;
}
tmp = rate / divisor;
pr_debug("TC: %u / %-3u [%d] --> %u\n", rate, divisor, i, tmp);
if (best_divisor_idx > 0) {
if (tmp < 5 * 1000 * 1000)
continue;
}
divided_rate = tmp;
best_divisor_idx = i;
}
clksrc.mult = clocksource_hz2mult(divided_rate, clksrc.shift);
printk(bootinfo, clksrc.name, CONFIG_ATMEL_TCB_CLKSRC_BLOCK,
divided_rate / 1000000,
((divided_rate + 500000) % 1000000) / 1000);
/* tclib will give us three clocks no matter what the
* underlying platform supports.
*/
clk_enable(tc->clk[1]);
/* channel 0: waveform mode, input mclk/8, clock TIOA0 on overflow */
__raw_writel(best_divisor_idx /* likely divide-by-8 */
| ATMEL_TC_WAVE
| ATMEL_TC_WAVESEL_UP /* free-run */
| ATMEL_TC_ACPA_SET /* TIOA0 rises at 0 */
| ATMEL_TC_ACPC_CLEAR, /* (duty cycle 50%) */
tcaddr + ATMEL_TC_REG(0, CMR));
__raw_writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA));
__raw_writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC));
__raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR)); /* no irqs */
__raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
/* channel 1: waveform mode, input TIOA0 */
__raw_writel(ATMEL_TC_XC1 /* input: TIOA0 */
| ATMEL_TC_WAVE
| ATMEL_TC_WAVESEL_UP, /* free-run */
tcaddr + ATMEL_TC_REG(1, CMR));
__raw_writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR)); /* no irqs */
__raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR));
/* chain channel 0 to channel 1, then reset all the timers */
__raw_writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR);
__raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
/* and away we go! */
clocksource_register(&clksrc);
/* channel 2: periodic and oneshot timer support */
setup_clkevents(tc, clk32k_divisor_idx);
return 0;
}
arch_initcall(tcb_clksrc_init);
+33
View File
@@ -22,6 +22,39 @@ config ATMEL_PWM
purposes including software controlled power-efficent backlights
on LCD displays, motor control, and waveform generation.
config ATMEL_TCLIB
bool "Atmel AT32/AT91 Timer/Counter Library"
depends on (AVR32 || ARCH_AT91)
help
Select this if you want a library to allocate the Timer/Counter
blocks found on many Atmel processors. This facilitates using
these blocks by different drivers despite processor differences.
config ATMEL_TCB_CLKSRC
bool "TC Block Clocksource"
depends on ATMEL_TCLIB && GENERIC_TIME
default y
help
Select this to get a high precision clocksource based on a
TC block with a 5+ MHz base clock rate. Two timer channels
are combined to make a single 32-bit timer.
When GENERIC_CLOCKEVENTS is defined, the third timer channel
may be used as a clock event device supporting oneshot mode
(delays of up to two seconds) based on the 32 KiHz clock.
config ATMEL_TCB_CLKSRC_BLOCK
int
depends on ATMEL_TCB_CLKSRC
prompt "TC Block" if ARCH_AT91RM9200 || ARCH_AT91SAM9260 || CPU_AT32AP700X
default 0
range 0 1
help
Some chips provide more than one TC block, so you have the
choice of which one to use for the clock framework. The other
TC can be used for other purposes, such as PWM generation and
interval timing.
config IBM_ASM
tristate "Device driver for IBM RSA service processor"
depends on X86 && PCI && INPUT && EXPERIMENTAL
+1
View File
@@ -10,6 +10,7 @@ obj-$(CONFIG_ACER_WMI) += acer-wmi.o
obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o
obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
obj-$(CONFIG_LKDTM) += lkdtm.o
obj-$(CONFIG_TIFM_CORE) += tifm_core.o
+161
View File
@@ -0,0 +1,161 @@
#include <linux/atmel_tc.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
/* Number of bytes to reserve for the iomem resource */
#define ATMEL_TC_IOMEM_SIZE 256
/*
* This is a thin library to solve the problem of how to portably allocate
* one of the TC blocks. For simplicity, it doesn't currently expect to
* share individual timers between different drivers.
*/
#if defined(CONFIG_AVR32)
/* AVR32 has these divide PBB */
const u8 atmel_tc_divisors[5] = { 0, 4, 8, 16, 32, };
EXPORT_SYMBOL(atmel_tc_divisors);
#elif defined(CONFIG_ARCH_AT91)
/* AT91 has these divide MCK */
const u8 atmel_tc_divisors[5] = { 2, 8, 32, 128, 0, };
EXPORT_SYMBOL(atmel_tc_divisors);
#endif
static DEFINE_SPINLOCK(tc_list_lock);
static LIST_HEAD(tc_list);
/**
* atmel_tc_alloc - allocate a specified TC block
* @block: which block to allocate
* @name: name to be associated with the iomem resource
*
* Caller allocates a block. If it is available, a pointer to a
* pre-initialized struct atmel_tc is returned. The caller can access
* the registers directly through the "regs" field.
*/
struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name)
{
struct atmel_tc *tc;
struct platform_device *pdev = NULL;
struct resource *r;
spin_lock(&tc_list_lock);
list_for_each_entry(tc, &tc_list, node) {
if (tc->pdev->id == block) {
pdev = tc->pdev;
break;
}
}
if (!pdev || tc->iomem)
goto fail;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
r = request_mem_region(r->start, ATMEL_TC_IOMEM_SIZE, name);
if (!r)
goto fail;
tc->regs = ioremap(r->start, ATMEL_TC_IOMEM_SIZE);
if (!tc->regs)
goto fail_ioremap;
tc->iomem = r;
out:
spin_unlock(&tc_list_lock);
return tc;
fail_ioremap:
release_resource(r);
fail:
tc = NULL;
goto out;
}
EXPORT_SYMBOL_GPL(atmel_tc_alloc);
/**
* atmel_tc_free - release a specified TC block
* @tc: Timer/counter block that was returned by atmel_tc_alloc()
*
* This reverses the effect of atmel_tc_alloc(), unmapping the I/O
* registers, invalidating the resource returned by that routine and
* making the TC available to other drivers.
*/
void atmel_tc_free(struct atmel_tc *tc)
{
spin_lock(&tc_list_lock);
if (tc->regs) {
iounmap(tc->regs);
release_resource(tc->iomem);
tc->regs = NULL;
tc->iomem = NULL;
}
spin_unlock(&tc_list_lock);
}
EXPORT_SYMBOL_GPL(atmel_tc_free);
static int __init tc_probe(struct platform_device *pdev)
{
struct atmel_tc *tc;
struct clk *clk;
int irq;
if (!platform_get_resource(pdev, IORESOURCE_MEM, 0))
return -EINVAL;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return -EINVAL;
tc = kzalloc(sizeof(struct atmel_tc), GFP_KERNEL);
if (!tc)
return -ENOMEM;
tc->pdev = pdev;
clk = clk_get(&pdev->dev, "t0_clk");
if (IS_ERR(clk)) {
kfree(tc);
return -EINVAL;
}
tc->clk[0] = clk;
tc->clk[1] = clk_get(&pdev->dev, "t1_clk");
if (IS_ERR(tc->clk[1]))
tc->clk[1] = clk;
tc->clk[2] = clk_get(&pdev->dev, "t2_clk");
if (IS_ERR(tc->clk[2]))
tc->clk[2] = clk;
tc->irq[0] = irq;
tc->irq[1] = platform_get_irq(pdev, 1);
if (tc->irq[1] < 0)
tc->irq[1] = irq;
tc->irq[2] = platform_get_irq(pdev, 2);
if (tc->irq[2] < 0)
tc->irq[2] = irq;
spin_lock(&tc_list_lock);
list_add_tail(&tc->node, &tc_list);
spin_unlock(&tc_list_lock);
return 0;
}
static struct platform_driver tc_driver = {
.driver.name = "atmel_tcb",
};
static int __init tc_init(void)
{
return platform_driver_probe(&tc_driver, tc_probe);
}
arch_initcall(tc_init);
+1 -1
View File
@@ -36,7 +36,7 @@ if PARPORT
config PARPORT_PC
tristate "PC-style hardware"
depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && \
(!M68K || ISA) && !MN10300
(!M68K || ISA) && !MN10300 && !AVR32
---help---
You should say Y here if you have a PC-style parallel port. All
IBM PC compatible computers and some Alphas have PC-style
+2 -2
View File
@@ -118,10 +118,10 @@ config USB_AMD5536UDC
config USB_GADGET_ATMEL_USBA
boolean "Atmel USBA"
select USB_GADGET_DUALSPEED
depends on AVR32
depends on AVR32 || ARCH_AT91CAP9
help
USBA is the integrated high-speed USB Device controller on
the AT32AP700x processors from Atmel.
the AT32AP700x and AT91CAP9 processors from Atmel.
config USB_ATMEL_USBA
tristate

Some files were not shown because too many files have changed in this diff Show More