]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/avr32/mach-at32ap/at32ap700x.c
Merge branch 'core/stacktrace' of git://git.kernel.org/pub/scm/linux/kernel/git/tip...
[linux-2.6-omap-h63xx.git] / arch / avr32 / mach-at32ap / at32ap700x.c
index 6302bfd585140542e6fa11b946758def8eacd1d1..07b21b121eef995726a6e8a981f3c416497e997e 100644 (file)
@@ -6,6 +6,7 @@
  * 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>
@@ -19,6 +20,7 @@
 #include <asm/arch/at32ap700x.h>
 #include <asm/arch/board.h>
 #include <asm/arch/portmux.h>
+#include <asm/arch/sram.h>
 
 #include <video/atmel_lcdc.h>
 
@@ -92,25 +94,18 @@ static struct clk devname##_##_name = {                             \
 
 static DEFINE_SPINLOCK(pm_lock);
 
-unsigned long at32ap7000_osc_rates[3] = {
-       [0] = 32768,
-       /* FIXME: these are ATSTK1002-specific */
-       [1] = 20000000,
-       [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];
+       return at32_board_osc_rates[clk->index];
 }
 
 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;
 
@@ -121,6 +116,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;
@@ -130,6 +190,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;
@@ -139,6 +234,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.
@@ -167,7 +305,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,
 };
 
@@ -535,6 +676,14 @@ static struct clk hramc_clk = {
        .users          = 1,
        .index          = 3,
 };
+static struct clk sdramc_clk = {
+       .name           = "sdramc_clk",
+       .parent         = &pbb_clk,
+       .mode           = pbb_clk_mode,
+       .get_rate       = pbb_clk_get_rate,
+       .users          = 1,
+       .index          = 14,
+};
 
 static struct resource smc0_resource[] = {
        PBMEM(0xfff03400),
@@ -606,19 +755,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
@@ -670,7 +832,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);
@@ -679,6 +842,81 @@ void __init at32_add_system_devices(void)
        platform_device_register(&pio4_device);
 }
 
+/* --------------------------------------------------------------------
+ *  PSIF
+ * -------------------------------------------------------------------- */
+static struct resource atmel_psif0_resource[] __initdata = {
+       {
+               .start  = 0xffe03c00,
+               .end    = 0xffe03cff,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(18),
+};
+static struct clk atmel_psif0_pclk = {
+       .name           = "pclk",
+       .parent         = &pba_clk,
+       .mode           = pba_clk_mode,
+       .get_rate       = pba_clk_get_rate,
+       .index          = 15,
+};
+
+static struct resource atmel_psif1_resource[] __initdata = {
+       {
+               .start  = 0xffe03d00,
+               .end    = 0xffe03dff,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(18),
+};
+static struct clk atmel_psif1_pclk = {
+       .name           = "pclk",
+       .parent         = &pba_clk,
+       .mode           = pba_clk_mode,
+       .get_rate       = pba_clk_get_rate,
+       .index          = 15,
+};
+
+struct platform_device *__init at32_add_device_psif(unsigned int id)
+{
+       struct platform_device *pdev;
+
+       if (!(id == 0 || id == 1))
+               return NULL;
+
+       pdev = platform_device_alloc("atmel_psif", id);
+       if (!pdev)
+               return NULL;
+
+       switch (id) {
+       case 0:
+               if (platform_device_add_resources(pdev, atmel_psif0_resource,
+                                       ARRAY_SIZE(atmel_psif0_resource)))
+                       goto err_add_resources;
+               atmel_psif0_pclk.dev = &pdev->dev;
+               select_peripheral(PA(8), PERIPH_A, 0); /* CLOCK */
+               select_peripheral(PA(9), PERIPH_A, 0); /* DATA  */
+               break;
+       case 1:
+               if (platform_device_add_resources(pdev, atmel_psif1_resource,
+                                       ARRAY_SIZE(atmel_psif1_resource)))
+                       goto err_add_resources;
+               atmel_psif1_pclk.dev = &pdev->dev;
+               select_peripheral(PB(11), PERIPH_A, 0); /* CLOCK */
+               select_peripheral(PB(12), PERIPH_A, 0); /* DATA  */
+               break;
+       default:
+               return NULL;
+       }
+
+       platform_device_add(pdev);
+       return pdev;
+
+err_add_resources:
+       platform_device_put(pdev);
+       return NULL;
+}
+
 /* --------------------------------------------------------------------
  *  USART
  * -------------------------------------------------------------------- */
@@ -952,7 +1190,8 @@ at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
        switch (id) {
        case 0:
                pdev = &atmel_spi0_device;
-               select_peripheral(PA(0),  PERIPH_A, 0); /* MISO  */
+               /* pullup MISO so a level is always defined */
+               select_peripheral(PA(0),  PERIPH_A, AT32_GPIOF_PULLUP);
                select_peripheral(PA(1),  PERIPH_A, 0); /* MOSI  */
                select_peripheral(PA(2),  PERIPH_A, 0); /* SCK   */
                at32_spi_setup_slaves(0, b, n, spi0_pins);
@@ -960,7 +1199,8 @@ at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
 
        case 1:
                pdev = &atmel_spi1_device;
-               select_peripheral(PB(0),  PERIPH_B, 0); /* MISO  */
+               /* pullup MISO so a level is always defined */
+               select_peripheral(PB(0),  PERIPH_B, AT32_GPIOF_PULLUP);
                select_peripheral(PB(1),  PERIPH_B, 0); /* MOSI  */
                select_peripheral(PB(5),  PERIPH_B, 0); /* SCK   */
                at32_spi_setup_slaves(1, b, n, spi1_pins);
@@ -1103,7 +1343,8 @@ static struct clk atmel_lcdfb0_pixclk = {
 
 struct platform_device *__init
 at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
-                    unsigned long fbmem_start, unsigned long fbmem_len)
+                    unsigned long fbmem_start, unsigned long fbmem_len,
+                    unsigned int pin_config)
 {
        struct platform_device *pdev;
        struct atmel_lcdfb_info *info;
@@ -1130,37 +1371,77 @@ at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
        switch (id) {
        case 0:
                pdev = &atmel_lcdfb0_device;
-               select_peripheral(PC(19), PERIPH_A, 0); /* CC     */
-               select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
-               select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
-               select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC  */
-               select_peripheral(PC(23), PERIPH_A, 0); /* DVAL   */
-               select_peripheral(PC(24), PERIPH_A, 0); /* MODE   */
-               select_peripheral(PC(25), PERIPH_A, 0); /* PWR    */
-               select_peripheral(PC(26), PERIPH_A, 0); /* DATA0  */
-               select_peripheral(PC(27), PERIPH_A, 0); /* DATA1  */
-               select_peripheral(PC(28), PERIPH_A, 0); /* DATA2  */
-               select_peripheral(PC(29), PERIPH_A, 0); /* DATA3  */
-               select_peripheral(PC(30), PERIPH_A, 0); /* DATA4  */
-               select_peripheral(PC(31), PERIPH_A, 0); /* DATA5  */
-               select_peripheral(PD(0),  PERIPH_A, 0); /* DATA6  */
-               select_peripheral(PD(1),  PERIPH_A, 0); /* DATA7  */
-               select_peripheral(PD(2),  PERIPH_A, 0); /* DATA8  */
-               select_peripheral(PD(3),  PERIPH_A, 0); /* DATA9  */
-               select_peripheral(PD(4),  PERIPH_A, 0); /* DATA10 */
-               select_peripheral(PD(5),  PERIPH_A, 0); /* DATA11 */
-               select_peripheral(PD(6),  PERIPH_A, 0); /* DATA12 */
-               select_peripheral(PD(7),  PERIPH_A, 0); /* DATA13 */
-               select_peripheral(PD(8),  PERIPH_A, 0); /* DATA14 */
-               select_peripheral(PD(9),  PERIPH_A, 0); /* DATA15 */
-               select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
-               select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
-               select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
-               select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
-               select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
-               select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
-               select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
-               select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
+
+               switch (pin_config) {
+               case 0:
+                       select_peripheral(PC(19), PERIPH_A, 0); /* CC     */
+                       select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
+                       select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
+                       select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC  */
+                       select_peripheral(PC(23), PERIPH_A, 0); /* DVAL   */
+                       select_peripheral(PC(24), PERIPH_A, 0); /* MODE   */
+                       select_peripheral(PC(25), PERIPH_A, 0); /* PWR    */
+                       select_peripheral(PC(26), PERIPH_A, 0); /* DATA0  */
+                       select_peripheral(PC(27), PERIPH_A, 0); /* DATA1  */
+                       select_peripheral(PC(28), PERIPH_A, 0); /* DATA2  */
+                       select_peripheral(PC(29), PERIPH_A, 0); /* DATA3  */
+                       select_peripheral(PC(30), PERIPH_A, 0); /* DATA4  */
+                       select_peripheral(PC(31), PERIPH_A, 0); /* DATA5  */
+                       select_peripheral(PD(0),  PERIPH_A, 0); /* DATA6  */
+                       select_peripheral(PD(1),  PERIPH_A, 0); /* DATA7  */
+                       select_peripheral(PD(2),  PERIPH_A, 0); /* DATA8  */
+                       select_peripheral(PD(3),  PERIPH_A, 0); /* DATA9  */
+                       select_peripheral(PD(4),  PERIPH_A, 0); /* DATA10 */
+                       select_peripheral(PD(5),  PERIPH_A, 0); /* DATA11 */
+                       select_peripheral(PD(6),  PERIPH_A, 0); /* DATA12 */
+                       select_peripheral(PD(7),  PERIPH_A, 0); /* DATA13 */
+                       select_peripheral(PD(8),  PERIPH_A, 0); /* DATA14 */
+                       select_peripheral(PD(9),  PERIPH_A, 0); /* DATA15 */
+                       select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
+                       select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
+                       select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
+                       select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
+                       select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
+                       select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
+                       select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
+                       select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
+                       break;
+               case 1:
+                       select_peripheral(PE(0),  PERIPH_B, 0); /* CC     */
+                       select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
+                       select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
+                       select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC  */
+                       select_peripheral(PE(1),  PERIPH_B, 0); /* DVAL   */
+                       select_peripheral(PE(2),  PERIPH_B, 0); /* MODE   */
+                       select_peripheral(PC(25), PERIPH_A, 0); /* PWR    */
+                       select_peripheral(PE(3),  PERIPH_B, 0); /* DATA0  */
+                       select_peripheral(PE(4),  PERIPH_B, 0); /* DATA1  */
+                       select_peripheral(PE(5),  PERIPH_B, 0); /* DATA2  */
+                       select_peripheral(PE(6),  PERIPH_B, 0); /* DATA3  */
+                       select_peripheral(PE(7),  PERIPH_B, 0); /* DATA4  */
+                       select_peripheral(PC(31), PERIPH_A, 0); /* DATA5  */
+                       select_peripheral(PD(0),  PERIPH_A, 0); /* DATA6  */
+                       select_peripheral(PD(1),  PERIPH_A, 0); /* DATA7  */
+                       select_peripheral(PE(8),  PERIPH_B, 0); /* DATA8  */
+                       select_peripheral(PE(9),  PERIPH_B, 0); /* DATA9  */
+                       select_peripheral(PE(10), PERIPH_B, 0); /* DATA10 */
+                       select_peripheral(PE(11), PERIPH_B, 0); /* DATA11 */
+                       select_peripheral(PE(12), PERIPH_B, 0); /* DATA12 */
+                       select_peripheral(PD(7),  PERIPH_A, 0); /* DATA13 */
+                       select_peripheral(PD(8),  PERIPH_A, 0); /* DATA14 */
+                       select_peripheral(PD(9),  PERIPH_A, 0); /* DATA15 */
+                       select_peripheral(PE(13), PERIPH_B, 0); /* DATA16 */
+                       select_peripheral(PE(14), PERIPH_B, 0); /* DATA17 */
+                       select_peripheral(PE(15), PERIPH_B, 0); /* DATA18 */
+                       select_peripheral(PE(16), PERIPH_B, 0); /* DATA19 */
+                       select_peripheral(PE(17), PERIPH_B, 0); /* DATA20 */
+                       select_peripheral(PE(18), PERIPH_B, 0); /* DATA21 */
+                       select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
+                       select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
+                       break;
+               default:
+                       goto err_invalid_id;
+               }
 
                clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
                clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
@@ -1199,7 +1480,7 @@ static struct resource atmel_pwm0_resource[] __initdata = {
        IRQ(24),
 };
 static struct clk atmel_pwm0_mck = {
-       .name           = "mck",
+       .name           = "pwm_clk",
        .parent         = &pbb_clk,
        .mode           = pbb_clk_mode,
        .get_rate       = pbb_clk_get_rate,
@@ -1726,6 +2007,7 @@ struct clk *at32_clock_list[] = {
        &hmatrix_clk,
        &ebi_clk,
        &hramc_clk,
+       &sdramc_clk,
        &smc0_pclk,
        &smc0_mck,
        &pdc_hclk,
@@ -1737,7 +2019,10 @@ struct clk *at32_clock_list[] = {
        &pio2_mck,
        &pio3_mck,
        &pio4_mck,
-       &at32_systc0_pclk,
+       &at32_tcb0_t0_clk,
+       &at32_tcb1_t0_clk,
+       &atmel_psif0_pclk,
+       &atmel_psif1_pclk,
        &atmel_usart0_usart,
        &atmel_usart1_usart,
        &atmel_usart2_usart,
@@ -1773,16 +2058,7 @@ struct clk *at32_clock_list[] = {
 };
 unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
 
-void __init at32_portmux_init(void)
-{
-       at32_init_pio(&pio0_device);
-       at32_init_pio(&pio1_device);
-       at32_init_pio(&pio2_device);
-       at32_init_pio(&pio3_device);
-       at32_init_pio(&pio4_device);
-}
-
-void __init at32_clock_init(void)
+void __init setup_platform(void)
 {
        u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
        int i;
@@ -1837,4 +2113,36 @@ void __init at32_clock_init(void)
        pm_writel(HSB_MASK, hsb_mask);
        pm_writel(PBA_MASK, pba_mask);
        pm_writel(PBB_MASK, pbb_mask);
+
+       /* Initialize the port muxes */
+       at32_init_pio(&pio0_device);
+       at32_init_pio(&pio1_device);
+       at32_init_pio(&pio2_device);
+       at32_init_pio(&pio3_device);
+       at32_init_pio(&pio4_device);
+}
+
+struct gen_pool *sram_pool;
+
+static int __init sram_init(void)
+{
+       struct gen_pool *pool;
+
+       /* 1KiB granularity */
+       pool = gen_pool_create(10, -1);
+       if (!pool)
+               goto fail;
+
+       if (gen_pool_add(pool, 0x24000000, 0x8000, -1))
+               goto err_pool_add;
+
+       sram_pool = pool;
+       return 0;
+
+err_pool_add:
+       gen_pool_destroy(pool);
+fail:
+       pr_err("Failed to create SRAM pool\n");
+       return -ENOMEM;
 }
+core_initcall(sram_init);