Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7a5b8059 authored by Haavard Skinnemoen's avatar Haavard Skinnemoen
Browse files

[AVR32] Split SM device into PM, RTC, WDT and EIC



Split the SM platform device into separate platform devices for PM,
RTC, WDT and EIC. This is more correct according to the documentation
and allows us to simplify the code a little.

Also turn the EIC driver into a real platform driver.

Signed-off-by: default avatarHaavard Skinnemoen <hskinnemoen@atmel.com>
Acked-by: default avatarHans-Christian Egtvedt <hcegtvedt@atmel.com>
parent c6083cd6
Loading
Loading
Loading
Loading
+0 −31
Original line number Diff line number Diff line
@@ -11,41 +11,10 @@
#include <linux/init.h>
#include <linux/platform_device.h>

#include <asm/io.h>

#include <asm/arch/init.h>
#include <asm/arch/sm.h>

struct at32_sm system_manager;

static int __init at32_sm_init(void)
{
	struct resource *regs;
	struct at32_sm *sm = &system_manager;
	int ret = -ENXIO;

	regs = platform_get_resource(&at32_sm_device, IORESOURCE_MEM, 0);
	if (!regs)
		goto fail;

	spin_lock_init(&sm->lock);
	sm->pdev = &at32_sm_device;

	ret = -ENOMEM;
	sm->regs = ioremap(regs->start, regs->end - regs->start + 1);
	if (!sm->regs)
		goto fail;

	return 0;

fail:
	printk(KERN_ERR "Failed to initialize System Manager: %d\n", ret);
	return ret;
}

void __init setup_platform(void)
{
	at32_sm_init();
	at32_clock_init();
	at32_portmux_init();
}
+124 −89
Original line number Diff line number Diff line
@@ -17,14 +17,20 @@
#include <asm/arch/at32ap7000.h>
#include <asm/arch/board.h>
#include <asm/arch/portmux.h>
#include <asm/arch/sm.h>

#include <video/atmel_lcdc.h>

#include "clock.h"
#include "hmatrix.h"
#include "pio.h"
#include "sm.h"
#include "pm.h"

/*
 * We can reduce the code size a bit by using a constant here. Since
 * this file is completely chip-specific, it's safe to not use
 * ioremap. Generic drivers should of course never do this.
 */
#define AT32_PM_BASE	0xfff00000

#define PBMEM(base)					\
	{						\
@@ -88,6 +94,8 @@ static struct clk devname##_##_name = { \
	.index		= _index,				\
}

static DEFINE_SPINLOCK(pm_lock);

unsigned long at32ap7000_osc_rates[3] = {
	[0] = 32768,
	/* FIXME: these are ATSTK1002-specific */
@@ -104,11 +112,11 @@ static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
{
	unsigned long div, mul, rate;

	if (!(control & SM_BIT(PLLEN)))
	if (!(control & PM_BIT(PLLEN)))
		return 0;

	div = SM_BFEXT(PLLDIV, control) + 1;
	mul = SM_BFEXT(PLLMUL, control) + 1;
	div = PM_BFEXT(PLLDIV, control) + 1;
	mul = PM_BFEXT(PLLMUL, control) + 1;

	rate = clk->parent->get_rate(clk->parent);
	rate = (rate + div / 2) / div;
@@ -121,7 +129,7 @@ static unsigned long pll0_get_rate(struct clk *clk)
{
	u32 control;

	control = sm_readl(&system_manager, PM_PLL0);
	control = pm_readl(PLL0);

	return pll_get_rate(clk, control);
}
@@ -130,7 +138,7 @@ static unsigned long pll1_get_rate(struct clk *clk)
{
	u32 control;

	control = sm_readl(&system_manager, PM_PLL1);
	control = pm_readl(PLL1);

	return pll_get_rate(clk, control);
}
@@ -187,108 +195,104 @@ static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift)

static void cpu_clk_mode(struct clk *clk, int enabled)
{
	struct at32_sm *sm = &system_manager;
	unsigned long flags;
	u32 mask;

	spin_lock_irqsave(&sm->lock, flags);
	mask = sm_readl(sm, PM_CPU_MASK);
	spin_lock_irqsave(&pm_lock, flags);
	mask = pm_readl(CPU_MASK);
	if (enabled)
		mask |= 1 << clk->index;
	else
		mask &= ~(1 << clk->index);
	sm_writel(sm, PM_CPU_MASK, mask);
	spin_unlock_irqrestore(&sm->lock, flags);
	pm_writel(CPU_MASK, mask);
	spin_unlock_irqrestore(&pm_lock, flags);
}

static unsigned long cpu_clk_get_rate(struct clk *clk)
{
	unsigned long cksel, shift = 0;

	cksel = sm_readl(&system_manager, PM_CKSEL);
	if (cksel & SM_BIT(CPUDIV))
		shift = SM_BFEXT(CPUSEL, cksel) + 1;
	cksel = pm_readl(CKSEL);
	if (cksel & PM_BIT(CPUDIV))
		shift = PM_BFEXT(CPUSEL, cksel) + 1;

	return bus_clk_get_rate(clk, shift);
}

static void hsb_clk_mode(struct clk *clk, int enabled)
{
	struct at32_sm *sm = &system_manager;
	unsigned long flags;
	u32 mask;

	spin_lock_irqsave(&sm->lock, flags);
	mask = sm_readl(sm, PM_HSB_MASK);
	spin_lock_irqsave(&pm_lock, flags);
	mask = pm_readl(HSB_MASK);
	if (enabled)
		mask |= 1 << clk->index;
	else
		mask &= ~(1 << clk->index);
	sm_writel(sm, PM_HSB_MASK, mask);
	spin_unlock_irqrestore(&sm->lock, flags);
	pm_writel(HSB_MASK, mask);
	spin_unlock_irqrestore(&pm_lock, flags);
}

static unsigned long hsb_clk_get_rate(struct clk *clk)
{
	unsigned long cksel, shift = 0;

	cksel = sm_readl(&system_manager, PM_CKSEL);
	if (cksel & SM_BIT(HSBDIV))
		shift = SM_BFEXT(HSBSEL, cksel) + 1;
	cksel = pm_readl(CKSEL);
	if (cksel & PM_BIT(HSBDIV))
		shift = PM_BFEXT(HSBSEL, cksel) + 1;

	return bus_clk_get_rate(clk, shift);
}

static void pba_clk_mode(struct clk *clk, int enabled)
{
	struct at32_sm *sm = &system_manager;
	unsigned long flags;
	u32 mask;

	spin_lock_irqsave(&sm->lock, flags);
	mask = sm_readl(sm, PM_PBA_MASK);
	spin_lock_irqsave(&pm_lock, flags);
	mask = pm_readl(PBA_MASK);
	if (enabled)
		mask |= 1 << clk->index;
	else
		mask &= ~(1 << clk->index);
	sm_writel(sm, PM_PBA_MASK, mask);
	spin_unlock_irqrestore(&sm->lock, flags);
	pm_writel(PBA_MASK, mask);
	spin_unlock_irqrestore(&pm_lock, flags);
}

static unsigned long pba_clk_get_rate(struct clk *clk)
{
	unsigned long cksel, shift = 0;

	cksel = sm_readl(&system_manager, PM_CKSEL);
	if (cksel & SM_BIT(PBADIV))
		shift = SM_BFEXT(PBASEL, cksel) + 1;
	cksel = pm_readl(CKSEL);
	if (cksel & PM_BIT(PBADIV))
		shift = PM_BFEXT(PBASEL, cksel) + 1;

	return bus_clk_get_rate(clk, shift);
}

static void pbb_clk_mode(struct clk *clk, int enabled)
{
	struct at32_sm *sm = &system_manager;
	unsigned long flags;
	u32 mask;

	spin_lock_irqsave(&sm->lock, flags);
	mask = sm_readl(sm, PM_PBB_MASK);
	spin_lock_irqsave(&pm_lock, flags);
	mask = pm_readl(PBB_MASK);
	if (enabled)
		mask |= 1 << clk->index;
	else
		mask &= ~(1 << clk->index);
	sm_writel(sm, PM_PBB_MASK, mask);
	spin_unlock_irqrestore(&sm->lock, flags);
	pm_writel(PBB_MASK, mask);
	spin_unlock_irqrestore(&pm_lock, flags);
}

static unsigned long pbb_clk_get_rate(struct clk *clk)
{
	unsigned long cksel, shift = 0;

	cksel = sm_readl(&system_manager, PM_CKSEL);
	if (cksel & SM_BIT(PBBDIV))
		shift = SM_BFEXT(PBBSEL, cksel) + 1;
	cksel = pm_readl(CKSEL);
	if (cksel & PM_BIT(PBBDIV))
		shift = PM_BFEXT(PBBSEL, cksel) + 1;

	return bus_clk_get_rate(clk, shift);
}
@@ -327,12 +331,12 @@ static void genclk_mode(struct clk *clk, int enabled)
{
	u32 control;

	control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
	control = pm_readl(GCCTRL(clk->index));
	if (enabled)
		control |= SM_BIT(CEN);
		control |= PM_BIT(CEN);
	else
		control &= ~SM_BIT(CEN);
	sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index, control);
		control &= ~PM_BIT(CEN);
	pm_writel(GCCTRL(clk->index), control);
}

static unsigned long genclk_get_rate(struct clk *clk)
@@ -340,9 +344,9 @@ static unsigned long genclk_get_rate(struct clk *clk)
	u32 control;
	unsigned long div = 1;

	control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
	if (control & SM_BIT(DIVEN))
		div = 2 * (SM_BFEXT(DIV, control) + 1);
	control = pm_readl(GCCTRL(clk->index));
	if (control & PM_BIT(DIVEN))
		div = 2 * (PM_BFEXT(DIV, control) + 1);

	return clk->parent->get_rate(clk->parent) / div;
}
@@ -353,23 +357,22 @@ static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply)
	unsigned long parent_rate, actual_rate, div;

	parent_rate = clk->parent->get_rate(clk->parent);
	control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
	control = pm_readl(GCCTRL(clk->index));

	if (rate > 3 * parent_rate / 4) {
		actual_rate = parent_rate;
		control &= ~SM_BIT(DIVEN);
		control &= ~PM_BIT(DIVEN);
	} else {
		div = (parent_rate + rate) / (2 * rate) - 1;
		control = SM_BFINS(DIV, div, control) | SM_BIT(DIVEN);
		control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN);
		actual_rate = parent_rate / (2 * (div + 1));
	}

	printk("clk %s: new rate %lu (actual rate %lu)\n",
	dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n",
		clk->name, rate, actual_rate);

	if (apply)
		sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index,
			  control);
		pm_writel(GCCTRL(clk->index), control);

	return actual_rate;
}
@@ -378,24 +381,24 @@ int genclk_set_parent(struct clk *clk, struct clk *parent)
{
	u32 control;

	printk("clk %s: new parent %s (was %s)\n",
	dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n",
		clk->name, parent->name, clk->parent->name);

	control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
	control = pm_readl(GCCTRL(clk->index));

	if (parent == &osc1 || parent == &pll1)
		control |= SM_BIT(OSCSEL);
		control |= PM_BIT(OSCSEL);
	else if (parent == &osc0 || parent == &pll0)
		control &= ~SM_BIT(OSCSEL);
		control &= ~PM_BIT(OSCSEL);
	else
		return -EINVAL;

	if (parent == &pll0 || parent == &pll1)
		control |= SM_BIT(PLLSEL);
		control |= PM_BIT(PLLSEL);
	else
		control &= ~SM_BIT(PLLSEL);
		control &= ~PM_BIT(PLLSEL);

	sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index, control);
	pm_writel(GCCTRL(clk->index), control);
	clk->parent = parent;

	return 0;
@@ -408,11 +411,11 @@ static void __init genclk_init_parent(struct clk *clk)

	BUG_ON(clk->index > 7);

	control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
	if (control & SM_BIT(OSCSEL))
		parent = (control & SM_BIT(PLLSEL)) ? &pll1 : &osc1;
	control = pm_readl(GCCTRL(clk->index));
	if (control & PM_BIT(OSCSEL))
		parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1;
	else
		parent = (control & SM_BIT(PLLSEL)) ? &pll0 : &osc0;
		parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0;

	clk->parent = parent;
}
@@ -420,21 +423,53 @@ static void __init genclk_init_parent(struct clk *clk)
/* --------------------------------------------------------------------
 *  System peripherals
 * -------------------------------------------------------------------- */
static struct resource sm_resource[] = {
	PBMEM(0xfff00000),
	NAMED_IRQ(19, "eim"),
	NAMED_IRQ(20, "pm"),
	NAMED_IRQ(21, "rtc"),
static struct resource at32_pm0_resource[] = {
	{
		.start	= 0xfff00000,
		.end	= 0xfff0007f,
		.flags	= IORESOURCE_MEM,
	},
	IRQ(20),
};
struct platform_device at32_sm_device = {
	.name		= "sm",
	.id		= 0,
	.resource	= sm_resource,
	.num_resources	= ARRAY_SIZE(sm_resource),

static struct resource at32ap700x_rtc0_resource[] = {
	{
		.start	= 0xfff00080,
		.end	= 0xfff000af,
		.flags	= IORESOURCE_MEM,
	},
	IRQ(21),
};
static struct clk at32_sm_pclk = {

static struct resource at32_wdt0_resource[] = {
	{
		.start	= 0xfff000b0,
		.end	= 0xfff000bf,
		.flags	= IORESOURCE_MEM,
	},
};

static struct resource at32_eic0_resource[] = {
	{
		.start	= 0xfff00100,
		.end	= 0xfff0013f,
		.flags	= IORESOURCE_MEM,
	},
	IRQ(19),
};

DEFINE_DEV(at32_pm, 0);
DEFINE_DEV(at32ap700x_rtc, 0);
DEFINE_DEV(at32_wdt, 0);
DEFINE_DEV(at32_eic, 0);

/*
 * Peripheral clock for PM, RTC, WDT and EIC. PM will ensure that this
 * is always running.
 */
static struct clk at32_pm_pclk = {
	.name		= "pclk",
	.dev		= &at32_sm_device.dev,
	.dev		= &at32_pm0_device.dev,
	.parent		= &pbb_clk,
	.mode		= pbb_clk_mode,
	.get_rate	= pbb_clk_get_rate,
@@ -583,10 +618,11 @@ DEV_CLK(mck, pio4, pba, 14);

void __init at32_add_system_devices(void)
{
	system_manager.eim_first_irq = EIM_IRQ_BASE;

	platform_device_register(&at32_sm_device);
	platform_device_register(&at32_pm0_device);
	platform_device_register(&at32_intc0_device);
	platform_device_register(&at32ap700x_rtc0_device);
	platform_device_register(&at32_wdt0_device);
	platform_device_register(&at32_eic0_device);
	platform_device_register(&smc0_device);
	platform_device_register(&pdc_device);

@@ -1066,7 +1102,7 @@ struct clk *at32_clock_list[] = {
	&hsb_clk,
	&pba_clk,
	&pbb_clk,
	&at32_sm_pclk,
	&at32_pm_pclk,
	&at32_intc0_pclk,
	&hmatrix_clk,
	&ebi_clk,
@@ -1113,18 +1149,17 @@ void __init at32_portmux_init(void)

void __init at32_clock_init(void)
{
	struct at32_sm *sm = &system_manager;
	u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
	int i;

	if (sm_readl(sm, PM_MCCTRL) & SM_BIT(PLLSEL))
	if (pm_readl(MCCTRL) & PM_BIT(PLLSEL))
		main_clock = &pll0;
	else
		main_clock = &osc0;

	if (sm_readl(sm, PM_PLL0) & SM_BIT(PLLOSC))
	if (pm_readl(PLL0) & PM_BIT(PLLOSC))
		pll0.parent = &osc1;
	if (sm_readl(sm, PM_PLL1) & SM_BIT(PLLOSC))
	if (pm_readl(PLL1) & PM_BIT(PLLOSC))
		pll1.parent = &osc1;

	genclk_init_parent(&gclk0);
@@ -1157,8 +1192,8 @@ void __init at32_clock_init(void)
			pbb_mask |= 1 << clk->index;
	}

	sm_writel(sm, PM_CPU_MASK, cpu_mask);
	sm_writel(sm, PM_HSB_MASK, hsb_mask);
	sm_writel(sm, PM_PBA_MASK, pba_mask);
	sm_writel(sm, PM_PBB_MASK, pbb_mask);
	pm_writel(CPU_MASK, cpu_mask);
	pm_writel(HSB_MASK, hsb_mask);
	pm_writel(PBA_MASK, pba_mask);
	pm_writel(PBB_MASK, pbb_mask);
}
+136 −64
Original line number Diff line number Diff line
@@ -17,42 +17,83 @@

#include <asm/io.h>

#include <asm/arch/sm.h>

#include "sm.h"
/* EIC register offsets */
#define EIC_IER					0x0000
#define EIC_IDR					0x0004
#define EIC_IMR					0x0008
#define EIC_ISR					0x000c
#define EIC_ICR					0x0010
#define EIC_MODE				0x0014
#define EIC_EDGE				0x0018
#define EIC_LEVEL				0x001c
#define EIC_TEST				0x0020
#define EIC_NMIC				0x0024

/* Bitfields in TEST */
#define EIC_TESTEN_OFFSET			31
#define EIC_TESTEN_SIZE				1

/* Bitfields in NMIC */
#define EIC_EN_OFFSET				0
#define EIC_EN_SIZE				1

/* Bit manipulation macros */
#define EIC_BIT(name)					\
	(1 << EIC_##name##_OFFSET)
#define EIC_BF(name,value)				\
	(((value) & ((1 << EIC_##name##_SIZE) - 1))	\
	 << EIC_##name##_OFFSET)
#define EIC_BFEXT(name,value)				\
	(((value) >> EIC_##name##_OFFSET)		\
	 & ((1 << EIC_##name##_SIZE) - 1))
#define EIC_BFINS(name,value,old)			\
	(((old) & ~(((1 << EIC_##name##_SIZE) - 1)	\
		    << EIC_##name##_OFFSET))		\
	 | EIC_BF(name,value))

/* Register access macros */
#define eic_readl(port,reg)				\
	__raw_readl((port)->regs + EIC_##reg)
#define eic_writel(port,reg,value)			\
	__raw_writel((value), (port)->regs + EIC_##reg)

struct eic {
	void __iomem *regs;
	struct irq_chip *chip;
	unsigned int first_irq;
};

static void eim_ack_irq(unsigned int irq)
static void eic_ack_irq(unsigned int irq)
{
	struct at32_sm *sm = get_irq_chip_data(irq);
	sm_writel(sm, EIM_ICR, 1 << (irq - sm->eim_first_irq));
	struct eic *eic = get_irq_chip_data(irq);
	eic_writel(eic, ICR, 1 << (irq - eic->first_irq));
}

static void eim_mask_irq(unsigned int irq)
static void eic_mask_irq(unsigned int irq)
{
	struct at32_sm *sm = get_irq_chip_data(irq);
	sm_writel(sm, EIM_IDR, 1 << (irq - sm->eim_first_irq));
	struct eic *eic = get_irq_chip_data(irq);
	eic_writel(eic, IDR, 1 << (irq - eic->first_irq));
}

static void eim_mask_ack_irq(unsigned int irq)
static void eic_mask_ack_irq(unsigned int irq)
{
	struct at32_sm *sm = get_irq_chip_data(irq);
	sm_writel(sm, EIM_ICR, 1 << (irq - sm->eim_first_irq));
	sm_writel(sm, EIM_IDR, 1 << (irq - sm->eim_first_irq));
	struct eic *eic = get_irq_chip_data(irq);
	eic_writel(eic, ICR, 1 << (irq - eic->first_irq));
	eic_writel(eic, IDR, 1 << (irq - eic->first_irq));
}

static void eim_unmask_irq(unsigned int irq)
static void eic_unmask_irq(unsigned int irq)
{
	struct at32_sm *sm = get_irq_chip_data(irq);
	sm_writel(sm, EIM_IER, 1 << (irq - sm->eim_first_irq));
	struct eic *eic = get_irq_chip_data(irq);
	eic_writel(eic, IER, 1 << (irq - eic->first_irq));
}

static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
static int eic_set_irq_type(unsigned int irq, unsigned int flow_type)
{
	struct at32_sm *sm = get_irq_chip_data(irq);
	struct eic *eic = get_irq_chip_data(irq);
	struct irq_desc *desc;
	unsigned int i = irq - sm->eim_first_irq;
	unsigned int i = irq - eic->first_irq;
	u32 mode, edge, level;
	unsigned long flags;
	int ret = 0;

	flow_type &= IRQ_TYPE_SENSE_MASK;
@@ -60,11 +101,10 @@ static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
		flow_type = IRQ_TYPE_LEVEL_LOW;

	desc = &irq_desc[irq];
	spin_lock_irqsave(&sm->lock, flags);

	mode = sm_readl(sm, EIM_MODE);
	edge = sm_readl(sm, EIM_EDGE);
	level = sm_readl(sm, EIM_LEVEL);
	mode = eic_readl(eic, MODE);
	edge = eic_readl(eic, EDGE);
	level = eic_readl(eic, LEVEL);

	switch (flow_type) {
	case IRQ_TYPE_LEVEL_LOW:
@@ -89,9 +129,9 @@ static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
	}

	if (ret == 0) {
		sm_writel(sm, EIM_MODE, mode);
		sm_writel(sm, EIM_EDGE, edge);
		sm_writel(sm, EIM_LEVEL, level);
		eic_writel(eic, MODE, mode);
		eic_writel(eic, EDGE, edge);
		eic_writel(eic, LEVEL, level);

		if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
			flow_type |= IRQ_LEVEL;
@@ -99,35 +139,33 @@ static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
		desc->status |= flow_type;
	}

	spin_unlock_irqrestore(&sm->lock, flags);

	return ret;
}

struct irq_chip eim_chip = {
	.name		= "eim",
	.ack		= eim_ack_irq,
	.mask		= eim_mask_irq,
	.mask_ack	= eim_mask_ack_irq,
	.unmask		= eim_unmask_irq,
	.set_type	= eim_set_irq_type,
struct irq_chip eic_chip = {
	.name		= "eic",
	.ack		= eic_ack_irq,
	.mask		= eic_mask_irq,
	.mask_ack	= eic_mask_ack_irq,
	.unmask		= eic_unmask_irq,
	.set_type	= eic_set_irq_type,
};

static void demux_eim_irq(unsigned int irq, struct irq_desc *desc)
static void demux_eic_irq(unsigned int irq, struct irq_desc *desc)
{
	struct at32_sm *sm = desc->handler_data;
	struct eic *eic = desc->handler_data;
	struct irq_desc *ext_desc;
	unsigned long status, pending;
	unsigned int i, ext_irq;

	status = sm_readl(sm, EIM_ISR);
	pending = status & sm_readl(sm, EIM_IMR);
	status = eic_readl(eic, ISR);
	pending = status & eic_readl(eic, IMR);

	while (pending) {
		i = fls(pending) - 1;
		pending &= ~(1 << i);

		ext_irq = i + sm->eim_first_irq;
		ext_irq = i + eic->first_irq;
		ext_desc = irq_desc + ext_irq;
		if (ext_desc->status & IRQ_LEVEL)
			handle_level_irq(ext_irq, ext_desc);
@@ -136,51 +174,85 @@ static void demux_eim_irq(unsigned int irq, struct irq_desc *desc)
	}
}

static int __init eim_init(void)
static int __init eic_probe(struct platform_device *pdev)
{
	struct at32_sm *sm = &system_manager;
	struct eic *eic;
	struct resource *regs;
	unsigned int i;
	unsigned int nr_irqs;
	unsigned int int_irq;
	int ret;
	u32 pattern;

	/*
	 * The EIM is really the same module as SM, so register
	 * mapping, etc. has been taken care of already.
	 */
	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	int_irq = platform_get_irq(pdev, 0);
	if (!regs || !int_irq) {
		dev_dbg(&pdev->dev, "missing regs and/or irq resource\n");
		return -ENXIO;
	}

	ret = -ENOMEM;
	eic = kzalloc(sizeof(struct eic), GFP_KERNEL);
	if (!eic) {
		dev_dbg(&pdev->dev, "no memory for eic structure\n");
		goto err_kzalloc;
	}

	eic->first_irq = EIM_IRQ_BASE + 32 * pdev->id;
	eic->regs = ioremap(regs->start, regs->end - regs->start + 1);
	if (!eic->regs) {
		dev_dbg(&pdev->dev, "failed to map regs\n");
		goto err_ioremap;
	}

	/*
	 * Find out how many interrupt lines that are actually
	 * implemented in hardware.
	 */
	sm_writel(sm, EIM_IDR, ~0UL);
	sm_writel(sm, EIM_MODE, ~0UL);
	pattern = sm_readl(sm, EIM_MODE);
	eic_writel(eic, IDR, ~0UL);
	eic_writel(eic, MODE, ~0UL);
	pattern = eic_readl(eic, MODE);
	nr_irqs = fls(pattern);

	/* Trigger on falling edge unless overridden by driver */
	sm_writel(sm, EIM_MODE, 0UL);
	sm_writel(sm, EIM_EDGE, 0UL);
	eic_writel(eic, MODE, 0UL);
	eic_writel(eic, EDGE, 0UL);

	sm->eim_chip = &eim_chip;
	eic->chip = &eic_chip;

	for (i = 0; i < nr_irqs; i++) {
		/* NOTE the handler we set here is ignored by the demux */
		set_irq_chip_and_handler(sm->eim_first_irq + i, &eim_chip,
		set_irq_chip_and_handler(eic->first_irq + i, &eic_chip,
					 handle_level_irq);
		set_irq_chip_data(sm->eim_first_irq + i, sm);
		set_irq_chip_data(eic->first_irq + i, eic);
	}

	int_irq = platform_get_irq_byname(sm->pdev, "eim");

	set_irq_chained_handler(int_irq, demux_eim_irq);
	set_irq_data(int_irq, sm);
	set_irq_chained_handler(int_irq, demux_eic_irq);
	set_irq_data(int_irq, eic);

	printk("EIM: External Interrupt Module at 0x%p, IRQ %u\n",
	       sm->regs, int_irq);
	printk("EIM: Handling %u external IRQs, starting with IRQ %u\n",
	       nr_irqs, sm->eim_first_irq);
	dev_info(&pdev->dev,
		 "External Interrupt Controller at 0x%p, IRQ %u\n",
		 eic->regs, int_irq);
	dev_info(&pdev->dev,
		 "Handling %u external IRQs, starting with IRQ %u\n",
		 nr_irqs, eic->first_irq);

	return 0;

err_ioremap:
	kfree(eic);
err_kzalloc:
	return ret;
}

static struct platform_driver eic_driver = {
	.driver = {
		.name = "at32_eic",
	},
};

static int __init eic_init(void)
{
	return platform_driver_probe(&eic_driver, eic_probe);
}
arch_initcall(eim_init);
arch_initcall(eic_init);
+112 −0
Original line number Diff line number Diff line
/*
 * Register definitions for the Power Manager (PM)
 */
#ifndef __ARCH_AVR32_MACH_AT32AP_PM_H__
#define __ARCH_AVR32_MACH_AT32AP_PM_H__

/* PM register offsets */
#define PM_MCCTRL				0x0000
#define PM_CKSEL				0x0004
#define PM_CPU_MASK				0x0008
#define PM_HSB_MASK				0x000c
#define PM_PBA_MASK				0x0010
#define PM_PBB_MASK				0x0014
#define PM_PLL0					0x0020
#define PM_PLL1					0x0024
#define PM_IER					0x0040
#define PM_IDR					0x0044
#define PM_IMR					0x0048
#define PM_ISR					0x004c
#define PM_ICR					0x0050
#define PM_GCCTRL(x)				(0x0060 + 4 * (x))
#define PM_RCAUSE				0x00c0

/* Bitfields in CKSEL */
#define PM_CPUSEL_OFFSET			0
#define PM_CPUSEL_SIZE				3
#define PM_CPUDIV_OFFSET			7
#define PM_CPUDIV_SIZE				1
#define PM_HSBSEL_OFFSET			8
#define PM_HSBSEL_SIZE				3
#define PM_HSBDIV_OFFSET			15
#define PM_HSBDIV_SIZE				1
#define PM_PBASEL_OFFSET			16
#define PM_PBASEL_SIZE				3
#define PM_PBADIV_OFFSET			23
#define PM_PBADIV_SIZE				1
#define PM_PBBSEL_OFFSET			24
#define PM_PBBSEL_SIZE				3
#define PM_PBBDIV_OFFSET			31
#define PM_PBBDIV_SIZE				1

/* Bitfields in PLL0 */
#define PM_PLLEN_OFFSET				0
#define PM_PLLEN_SIZE				1
#define PM_PLLOSC_OFFSET			1
#define PM_PLLOSC_SIZE				1
#define PM_PLLOPT_OFFSET			2
#define PM_PLLOPT_SIZE				3
#define PM_PLLDIV_OFFSET			8
#define PM_PLLDIV_SIZE				8
#define PM_PLLMUL_OFFSET			16
#define PM_PLLMUL_SIZE				8
#define PM_PLLCOUNT_OFFSET			24
#define PM_PLLCOUNT_SIZE			6
#define PM_PLLTEST_OFFSET			31
#define PM_PLLTEST_SIZE				1

/* Bitfields in ICR */
#define PM_LOCK0_OFFSET				0
#define PM_LOCK0_SIZE				1
#define PM_LOCK1_OFFSET				1
#define PM_LOCK1_SIZE				1
#define PM_WAKE_OFFSET				2
#define PM_WAKE_SIZE				1
#define PM_CKRDY_OFFSET				5
#define PM_CKRDY_SIZE				1
#define PM_MSKRDY_OFFSET			6
#define PM_MSKRDY_SIZE				1

/* Bitfields in GCCTRL0 */
#define PM_OSCSEL_OFFSET			0
#define PM_OSCSEL_SIZE				1
#define PM_PLLSEL_OFFSET			1
#define PM_PLLSEL_SIZE				1
#define PM_CEN_OFFSET				2
#define PM_CEN_SIZE				1
#define PM_DIVEN_OFFSET				4
#define PM_DIVEN_SIZE				1
#define PM_DIV_OFFSET				8
#define PM_DIV_SIZE				8

/* Bitfields in RCAUSE */
#define PM_POR_OFFSET				0
#define PM_POR_SIZE				1
#define PM_EXT_OFFSET				2
#define PM_EXT_SIZE				1
#define PM_WDT_OFFSET				3
#define PM_WDT_SIZE				1
#define PM_NTAE_OFFSET				4
#define PM_NTAE_SIZE				1

/* Bit manipulation macros */
#define PM_BIT(name)					\
	(1 << PM_##name##_OFFSET)
#define PM_BF(name,value)				\
	(((value) & ((1 << PM_##name##_SIZE) - 1))	\
	 << PM_##name##_OFFSET)
#define PM_BFEXT(name,value)				\
	(((value) >> PM_##name##_OFFSET)		\
	 & ((1 << PM_##name##_SIZE) - 1))
#define PM_BFINS(name,value,old)\
	(((old) & ~(((1 << PM_##name##_SIZE) - 1)	\
		    << PM_##name##_OFFSET))		\
	 | PM_BF(name,value))

/* Register access macros */
#define pm_readl(reg)							\
	__raw_readl((void __iomem *)AT32_PM_BASE + PM_##reg)
#define pm_writel(reg,value)						\
	__raw_writel((value), (void __iomem *)AT32_PM_BASE + PM_##reg)

#endif /* __ARCH_AVR32_MACH_AT32AP_PM_H__ */

arch/avr32/mach-at32ap/sm.h

deleted100644 → 0
+0 −242

File deleted.

Preview size limit exceeded, changes collapsed.

Loading