Merge branches 'regmap-linus' and 'regmap-interface' into regmap-next
[pandora-kernel.git] / arch / arm / mach-davinci / devices-da8xx.c
index fc4e98e..2f7e719 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/serial_8250.h>
+#include <linux/ahci_platform.h>
+#include <linux/clk.h>
 
 #include <mach/cputype.h>
 #include <mach/common.h>
@@ -33,6 +35,7 @@
 #define DA8XX_SPI0_BASE                        0x01c41000
 #define DA830_SPI1_BASE                        0x01e12000
 #define DA8XX_LCD_CNTRL_BASE           0x01e13000
+#define DA850_SATA_BASE                        0x01e18000
 #define DA850_MMCSD1_BASE              0x01e1b000
 #define DA8XX_EMAC_CPPI_PORT_BASE      0x01e20000
 #define DA8XX_EMAC_CPGMACSS_BASE       0x01e22000
@@ -842,3 +845,126 @@ int __init da8xx_register_spi(int instance, struct spi_board_info *info,
 
        return platform_device_register(&da8xx_spi_device[instance]);
 }
+
+#ifdef CONFIG_ARCH_DAVINCI_DA850
+
+static struct resource da850_sata_resources[] = {
+       {
+               .start  = DA850_SATA_BASE,
+               .end    = DA850_SATA_BASE + 0x1fff,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = IRQ_DA850_SATAINT,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+/* SATA PHY Control Register offset from AHCI base */
+#define SATA_P0PHYCR_REG       0x178
+
+#define SATA_PHY_MPY(x)                ((x) << 0)
+#define SATA_PHY_LOS(x)                ((x) << 6)
+#define SATA_PHY_RXCDR(x)      ((x) << 10)
+#define SATA_PHY_RXEQ(x)       ((x) << 13)
+#define SATA_PHY_TXSWING(x)    ((x) << 19)
+#define SATA_PHY_ENPLL(x)      ((x) << 31)
+
+static struct clk *da850_sata_clk;
+static unsigned long da850_sata_refclkpn;
+
+/* Supported DA850 SATA crystal frequencies */
+#define KHZ_TO_HZ(freq) ((freq) * 1000)
+static unsigned long da850_sata_xtal[] = {
+       KHZ_TO_HZ(300000),
+       KHZ_TO_HZ(250000),
+       0,                      /* Reserved */
+       KHZ_TO_HZ(187500),
+       KHZ_TO_HZ(150000),
+       KHZ_TO_HZ(125000),
+       KHZ_TO_HZ(120000),
+       KHZ_TO_HZ(100000),
+       KHZ_TO_HZ(75000),
+       KHZ_TO_HZ(60000),
+};
+
+static int da850_sata_init(struct device *dev, void __iomem *addr)
+{
+       int i, ret;
+       unsigned int val;
+
+       da850_sata_clk = clk_get(dev, NULL);
+       if (IS_ERR(da850_sata_clk))
+               return PTR_ERR(da850_sata_clk);
+
+       ret = clk_enable(da850_sata_clk);
+       if (ret)
+               goto err0;
+
+       /* Enable SATA clock receiver */
+       val = __raw_readl(DA8XX_SYSCFG1_VIRT(DA8XX_PWRDN_REG));
+       val &= ~BIT(0);
+       __raw_writel(val, DA8XX_SYSCFG1_VIRT(DA8XX_PWRDN_REG));
+
+       /* Get the multiplier needed for 1.5GHz PLL output */
+       for (i = 0; i < ARRAY_SIZE(da850_sata_xtal); i++)
+               if (da850_sata_xtal[i] == da850_sata_refclkpn)
+                       break;
+
+       if (i == ARRAY_SIZE(da850_sata_xtal)) {
+               ret = -EINVAL;
+               goto err1;
+       }
+
+       val = SATA_PHY_MPY(i + 1) |
+               SATA_PHY_LOS(1) |
+               SATA_PHY_RXCDR(4) |
+               SATA_PHY_RXEQ(1) |
+               SATA_PHY_TXSWING(3) |
+               SATA_PHY_ENPLL(1);
+
+       __raw_writel(val, addr + SATA_P0PHYCR_REG);
+
+       return 0;
+
+err1:
+       clk_disable(da850_sata_clk);
+err0:
+       clk_put(da850_sata_clk);
+       return ret;
+}
+
+static void da850_sata_exit(struct device *dev)
+{
+       clk_disable(da850_sata_clk);
+       clk_put(da850_sata_clk);
+}
+
+static struct ahci_platform_data da850_sata_pdata = {
+       .init   = da850_sata_init,
+       .exit   = da850_sata_exit,
+};
+
+static u64 da850_sata_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device da850_sata_device = {
+       .name   = "ahci",
+       .id     = -1,
+       .dev    = {
+               .platform_data          = &da850_sata_pdata,
+               .dma_mask               = &da850_sata_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+       .num_resources  = ARRAY_SIZE(da850_sata_resources),
+       .resource       = da850_sata_resources,
+};
+
+int __init da850_register_sata(unsigned long refclkpn)
+{
+       da850_sata_refclkpn = refclkpn;
+       if (!da850_sata_refclkpn)
+               return -EINVAL;
+
+       return platform_device_register(&da850_sata_device);
+}
+#endif