Merge branch 'drm-patches' of master.kernel.org:/pub/scm/linux/kernel/git/airlied...
[linux-drm-fsl-dcu.git] / arch / avr32 / mach-at32ap / at32ap7000.c
index c1e477ec7576850887591f9cc14c7d42128fa0b0..56db45b99a0f1f68d4f859a7ab00646348b5290e 100644 (file)
@@ -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>
 
@@ -17,6 +18,7 @@
 #include <asm/arch/sm.h>
 
 #include "clock.h"
+#include "hmatrix.h"
 #include "pio.h"
 #include "sm.h"
 
@@ -310,8 +312,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 +325,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 +337,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 +363,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 +386,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
  * -------------------------------------------------------------------- */
@@ -414,7 +417,15 @@ struct platform_device at32_sm_device = {
        .resource       = sm_resource,
        .num_resources  = ARRAY_SIZE(sm_resource),
 };
-DEV_CLK(pclk, at32_sm, pbb, 0);
+static struct clk at32_sm_pclk = {
+       .name           = "pclk",
+       .dev            = &at32_sm_device.dev,
+       .parent         = &pbb_clk,
+       .mode           = pbb_clk_mode,
+       .get_rate       = pbb_clk_get_rate,
+       .users          = 1,
+       .index          = 0,
+};
 
 static struct resource intc0_resource[] = {
        PBMEM(0xfff00400),
@@ -440,6 +451,7 @@ static struct clk hramc_clk = {
        .mode           = hsb_clk_mode,
        .get_rate       = hsb_clk_get_rate,
        .users          = 1,
+       .index          = 3,
 };
 
 static struct resource smc0_resource[] = {
@@ -464,6 +476,57 @@ static struct clk pico_clk = {
        .users          = 1,
 };
 
+/* --------------------------------------------------------------------
+ * HMATRIX
+ * -------------------------------------------------------------------- */
+
+static struct clk hmatrix_clk = {
+       .name           = "hmatrix_clk",
+       .parent         = &pbb_clk,
+       .mode           = pbb_clk_mode,
+       .get_rate       = pbb_clk_get_rate,
+       .index          = 2,
+       .users          = 1,
+};
+#define HMATRIX_BASE   ((void __iomem *)0xfff00800)
+
+#define hmatrix_readl(reg)                                     \
+       __raw_readl((HMATRIX_BASE) + HMATRIX_##reg)
+#define hmatrix_writel(reg,value)                              \
+       __raw_writel((value), (HMATRIX_BASE) + HMATRIX_##reg)
+
+/*
+ * Set bits in the HMATRIX Special Function Register (SFR) used by the
+ * External Bus Interface (EBI). This can be used to enable special
+ * features like CompactFlash support, NAND Flash support, etc. on
+ * certain chipselects.
+ */
+static inline void set_ebi_sfr_bits(u32 mask)
+{
+       u32 sfr;
+
+       clk_enable(&hmatrix_clk);
+       sfr = hmatrix_readl(SFR4);
+       sfr |= mask;
+       hmatrix_writel(SFR4, sfr);
+       clk_disable(&hmatrix_clk);
+}
+
+/* --------------------------------------------------------------------
+ *  System Timer/Counter (TC)
+ * -------------------------------------------------------------------- */
+static struct resource at32_systc0_resource[] = {
+       PBMEM(0xfff00c00),
+       IRQ(22),
+};
+struct platform_device at32_systc0_device = {
+       .name           = "systc",
+       .id             = 0,
+       .resource       = at32_systc0_resource,
+       .num_resources  = ARRAY_SIZE(at32_systc0_resource),
+};
+DEV_CLK(pclk, at32_systc0, pbb, 3);
+
 /* --------------------------------------------------------------------
  *  PIO
  * -------------------------------------------------------------------- */
@@ -512,6 +575,8 @@ void __init at32_add_system_devices(void)
        platform_device_register(&smc0_device);
        platform_device_register(&pdc_device);
 
+       platform_device_register(&at32_systc0_device);
+
        platform_device_register(&pio0_device);
        platform_device_register(&pio1_device);
        platform_device_register(&pio2_device);
@@ -750,8 +815,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 __init
+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 +858,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 +866,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 +957,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,
@@ -884,6 +1013,7 @@ struct clk *at32_clock_list[] = {
        &pbb_clk,
        &at32_sm_pclk,
        &at32_intc0_pclk,
+       &hmatrix_clk,
        &ebi_clk,
        &hramc_clk,
        &smc0_pclk,
@@ -896,6 +1026,7 @@ struct clk *at32_clock_list[] = {
        &pio2_mck,
        &pio3_mck,
        &pio4_mck,
+       &at32_systc0_pclk,
        &atmel_usart0_usart,
        &atmel_usart1_usart,
        &atmel_usart2_usart,
@@ -908,6 +1039,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 +1072,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
@@ -946,6 +1089,9 @@ void __init at32_clock_init(void)
        for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
                struct clk *clk = at32_clock_list[i];
 
+               if (clk->users == 0)
+                       continue;
+
                if (clk->mode == &cpu_clk_mode)
                        cpu_mask |= 1 << clk->index;
                else if (clk->mode == &hsb_clk_mode)