summaryrefslogtreecommitdiff
path: root/arch/avr32/mach-at32ap/at32ap7000.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/avr32/mach-at32ap/at32ap7000.c')
-rw-r--r--arch/avr32/mach-at32ap/at32ap7000.c144
1 files changed, 111 insertions, 33 deletions
diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c
index c1e477ec7576..bc235507c5c7 100644
--- a/arch/avr32/mach-at32ap/at32ap7000.c
+++ b/arch/avr32/mach-at32ap/at32ap7000.c
@@ -8,6 +8,7 @@
#include <linux/clk.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
#include <asm/io.h>
@@ -310,8 +311,6 @@ static void genclk_mode(struct clk *clk, int enabled)
{
u32 control;
- BUG_ON(clk->index > 7);
-
control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
if (enabled)
control |= SM_BIT(CEN);
@@ -325,11 +324,6 @@ static unsigned long genclk_get_rate(struct clk *clk)
u32 control;
unsigned long div = 1;
- BUG_ON(clk->index > 7);
-
- if (!clk->parent)
- return 0;
-
control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
if (control & SM_BIT(DIVEN))
div = 2 * (SM_BFEXT(DIV, control) + 1);
@@ -342,11 +336,6 @@ static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply)
u32 control;
unsigned long parent_rate, actual_rate, div;
- BUG_ON(clk->index > 7);
-
- if (!clk->parent)
- return 0;
-
parent_rate = clk->parent->get_rate(clk->parent);
control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
@@ -373,11 +362,8 @@ int genclk_set_parent(struct clk *clk, struct clk *parent)
{
u32 control;
- BUG_ON(clk->index > 7);
-
printk("clk %s: new parent %s (was %s)\n",
- clk->name, parent->name,
- clk->parent ? clk->parent->name : "(null)");
+ clk->name, parent->name, clk->parent->name);
control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
@@ -399,6 +385,22 @@ int genclk_set_parent(struct clk *clk, struct clk *parent)
return 0;
}
+static void __init genclk_init_parent(struct clk *clk)
+{
+ u32 control;
+ struct clk *parent;
+
+ 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;
+ else
+ parent = (control & SM_BIT(PLLSEL)) ? &pll0 : &osc0;
+
+ clk->parent = parent;
+}
+
/* --------------------------------------------------------------------
* System peripherals
* -------------------------------------------------------------------- */
@@ -750,8 +752,41 @@ static struct resource atmel_spi1_resource[] = {
DEFINE_DEV(atmel_spi, 1);
DEV_CLK(spi_clk, atmel_spi1, pba, 1);
-struct platform_device *__init at32_add_device_spi(unsigned int id)
+static void
+at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b,
+ unsigned int n, const u8 *pins)
+{
+ unsigned int pin, mode;
+
+ for (; n; n--, b++) {
+ b->bus_num = bus_num;
+ if (b->chip_select >= 4)
+ continue;
+ pin = (unsigned)b->controller_data;
+ if (!pin) {
+ pin = pins[b->chip_select];
+ b->controller_data = (void *)pin;
+ }
+ mode = AT32_GPIOF_OUTPUT;
+ if (!(b->mode & SPI_CS_HIGH))
+ mode |= AT32_GPIOF_HIGH;
+ at32_select_gpio(pin, mode);
+ }
+}
+
+struct platform_device *__init
+at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
{
+ /*
+ * Manage the chipselects as GPIOs, normally using the same pins
+ * the SPI controller expects; but boards can use other pins.
+ */
+ static u8 __initdata spi0_pins[] =
+ { GPIO_PIN_PA(3), GPIO_PIN_PA(4),
+ GPIO_PIN_PA(5), GPIO_PIN_PA(20), };
+ static u8 __initdata spi1_pins[] =
+ { GPIO_PIN_PB(2), GPIO_PIN_PB(3),
+ GPIO_PIN_PB(4), GPIO_PIN_PA(27), };
struct platform_device *pdev;
switch (id) {
@@ -760,14 +795,7 @@ struct platform_device *__init at32_add_device_spi(unsigned int id)
select_peripheral(PA(0), PERIPH_A, 0); /* MISO */
select_peripheral(PA(1), PERIPH_A, 0); /* MOSI */
select_peripheral(PA(2), PERIPH_A, 0); /* SCK */
-
- /* NPCS[2:0] */
- at32_select_gpio(GPIO_PIN_PA(3),
- AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
- at32_select_gpio(GPIO_PIN_PA(4),
- AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
- at32_select_gpio(GPIO_PIN_PA(5),
- AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
+ at32_spi_setup_slaves(0, b, n, spi0_pins);
break;
case 1:
@@ -775,20 +803,14 @@ struct platform_device *__init at32_add_device_spi(unsigned int id)
select_peripheral(PB(0), PERIPH_B, 0); /* MISO */
select_peripheral(PB(1), PERIPH_B, 0); /* MOSI */
select_peripheral(PB(5), PERIPH_B, 0); /* SCK */
-
- /* NPCS[2:0] */
- at32_select_gpio(GPIO_PIN_PB(2),
- AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
- at32_select_gpio(GPIO_PIN_PB(3),
- AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
- at32_select_gpio(GPIO_PIN_PB(4),
- AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
+ at32_spi_setup_slaves(1, b, n, spi1_pins);
break;
default:
return NULL;
}
+ spi_register_board_info(b, n);
platform_device_register(pdev);
return pdev;
}
@@ -872,6 +894,50 @@ at32_add_device_lcdc(unsigned int id, struct lcdc_platform_data *data)
return pdev;
}
+/* --------------------------------------------------------------------
+ * GCLK
+ * -------------------------------------------------------------------- */
+static struct clk gclk0 = {
+ .name = "gclk0",
+ .mode = genclk_mode,
+ .get_rate = genclk_get_rate,
+ .set_rate = genclk_set_rate,
+ .set_parent = genclk_set_parent,
+ .index = 0,
+};
+static struct clk gclk1 = {
+ .name = "gclk1",
+ .mode = genclk_mode,
+ .get_rate = genclk_get_rate,
+ .set_rate = genclk_set_rate,
+ .set_parent = genclk_set_parent,
+ .index = 1,
+};
+static struct clk gclk2 = {
+ .name = "gclk2",
+ .mode = genclk_mode,
+ .get_rate = genclk_get_rate,
+ .set_rate = genclk_set_rate,
+ .set_parent = genclk_set_parent,
+ .index = 2,
+};
+static struct clk gclk3 = {
+ .name = "gclk3",
+ .mode = genclk_mode,
+ .get_rate = genclk_get_rate,
+ .set_rate = genclk_set_rate,
+ .set_parent = genclk_set_parent,
+ .index = 3,
+};
+static struct clk gclk4 = {
+ .name = "gclk4",
+ .mode = genclk_mode,
+ .get_rate = genclk_get_rate,
+ .set_rate = genclk_set_rate,
+ .set_parent = genclk_set_parent,
+ .index = 4,
+};
+
struct clk *at32_clock_list[] = {
&osc32k,
&osc0,
@@ -908,6 +974,11 @@ struct clk *at32_clock_list[] = {
&atmel_spi1_spi_clk,
&lcdc0_hclk,
&lcdc0_pixclk,
+ &gclk0,
+ &gclk1,
+ &gclk2,
+ &gclk3,
+ &gclk4,
};
unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
@@ -936,6 +1007,13 @@ void __init at32_clock_init(void)
if (sm_readl(sm, PM_PLL1) & SM_BIT(PLLOSC))
pll1.parent = &osc1;
+ genclk_init_parent(&gclk0);
+ genclk_init_parent(&gclk1);
+ genclk_init_parent(&gclk2);
+ genclk_init_parent(&gclk3);
+ genclk_init_parent(&gclk4);
+ genclk_init_parent(&lcdc0_pixclk);
+
/*
* Turn on all clocks that have at least one user already, and
* turn off everything else. We only do this for module