1 /* 2 * DaVinci DA850 AHCI SATA platform driver 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2, or (at your option) 7 * any later version. 8 */ 9 10 #include <linux/kernel.h> 11 #include <linux/module.h> 12 #include <linux/pm.h> 13 #include <linux/device.h> 14 #include <linux/platform_device.h> 15 #include <linux/libata.h> 16 #include <linux/ahci_platform.h> 17 #include "ahci.h" 18 19 /* SATA PHY Control Register offset from AHCI base */ 20 #define SATA_P0PHYCR_REG 0x178 21 22 #define SATA_PHY_MPY(x) ((x) << 0) 23 #define SATA_PHY_LOS(x) ((x) << 6) 24 #define SATA_PHY_RXCDR(x) ((x) << 10) 25 #define SATA_PHY_RXEQ(x) ((x) << 13) 26 #define SATA_PHY_TXSWING(x) ((x) << 19) 27 #define SATA_PHY_ENPLL(x) ((x) << 31) 28 29 /* 30 * The multiplier needed for 1.5GHz PLL output. 31 * 32 * NOTE: This is currently hardcoded to be suitable for 100MHz crystal 33 * frequency (which is used by DA850 EVM board) and may need to be changed 34 * if you would like to use this driver on some other board. 35 */ 36 #define DA850_SATA_CLK_MULTIPLIER 7 37 38 static void da850_sata_init(struct device *dev, void __iomem *pwrdn_reg, 39 void __iomem *ahci_base) 40 { 41 unsigned int val; 42 43 /* Enable SATA clock receiver */ 44 val = readl(pwrdn_reg); 45 val &= ~BIT(0); 46 writel(val, pwrdn_reg); 47 48 val = SATA_PHY_MPY(DA850_SATA_CLK_MULTIPLIER + 1) | SATA_PHY_LOS(1) | 49 SATA_PHY_RXCDR(4) | SATA_PHY_RXEQ(1) | SATA_PHY_TXSWING(3) | 50 SATA_PHY_ENPLL(1); 51 52 writel(val, ahci_base + SATA_P0PHYCR_REG); 53 } 54 55 static const struct ata_port_info ahci_da850_port_info = { 56 .flags = AHCI_FLAG_COMMON, 57 .pio_mask = ATA_PIO4, 58 .udma_mask = ATA_UDMA6, 59 .port_ops = &ahci_platform_ops, 60 }; 61 62 static int ahci_da850_probe(struct platform_device *pdev) 63 { 64 struct device *dev = &pdev->dev; 65 struct ahci_host_priv *hpriv; 66 struct resource *res; 67 void __iomem *pwrdn_reg; 68 int rc; 69 70 hpriv = ahci_platform_get_resources(pdev); 71 if (IS_ERR(hpriv)) 72 return PTR_ERR(hpriv); 73 74 rc = ahci_platform_enable_resources(hpriv); 75 if (rc) 76 return rc; 77 78 res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 79 if (!res) 80 goto disable_resources; 81 82 pwrdn_reg = devm_ioremap(dev, res->start, resource_size(res)); 83 if (!pwrdn_reg) 84 goto disable_resources; 85 86 da850_sata_init(dev, pwrdn_reg, hpriv->mmio); 87 88 rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info, 89 0, 0, 0); 90 if (rc) 91 goto disable_resources; 92 93 return 0; 94 disable_resources: 95 ahci_platform_disable_resources(hpriv); 96 return rc; 97 } 98 99 static SIMPLE_DEV_PM_OPS(ahci_da850_pm_ops, ahci_platform_suspend, 100 ahci_platform_resume); 101 102 static struct platform_driver ahci_da850_driver = { 103 .probe = ahci_da850_probe, 104 .remove = ata_platform_remove_one, 105 .driver = { 106 .name = "ahci_da850", 107 .owner = THIS_MODULE, 108 .pm = &ahci_da850_pm_ops, 109 }, 110 }; 111 module_platform_driver(ahci_da850_driver); 112 113 MODULE_DESCRIPTION("DaVinci DA850 AHCI SATA platform driver"); 114 MODULE_AUTHOR("Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>"); 115 MODULE_LICENSE("GPL"); 116