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