Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * MediaTek AHCI SATA driver
  4 *
  5 * Copyright (c) 2017 MediaTek Inc.
  6 * Author: Ryder Lee <ryder.lee@mediatek.com>
  7 */
  8
  9#include <linux/ahci_platform.h>
 10#include <linux/kernel.h>
 11#include <linux/libata.h>
 12#include <linux/mfd/syscon.h>
 13#include <linux/module.h>
 14#include <linux/platform_device.h>
 15#include <linux/pm.h>
 16#include <linux/regmap.h>
 17#include <linux/reset.h>
 18#include "ahci.h"
 19
 20#define DRV_NAME		"ahci-mtk"
 21
 22#define SYS_CFG			0x14
 23#define SYS_CFG_SATA_MSK	GENMASK(31, 30)
 24#define SYS_CFG_SATA_EN		BIT(31)
 25
 26struct mtk_ahci_plat {
 27	struct regmap *mode;
 28	struct reset_control *axi_rst;
 29	struct reset_control *sw_rst;
 30	struct reset_control *reg_rst;
 31};
 32
 33static const struct ata_port_info ahci_port_info = {
 34	.flags		= AHCI_FLAG_COMMON,
 35	.pio_mask	= ATA_PIO4,
 36	.udma_mask	= ATA_UDMA6,
 37	.port_ops	= &ahci_platform_ops,
 38};
 39
 40static struct scsi_host_template ahci_platform_sht = {
 41	AHCI_SHT(DRV_NAME),
 42};
 43
 44static int mtk_ahci_platform_resets(struct ahci_host_priv *hpriv,
 45				    struct device *dev)
 46{
 47	struct mtk_ahci_plat *plat = hpriv->plat_data;
 48	int err;
 49
 50	/* reset AXI bus and PHY part */
 51	plat->axi_rst = devm_reset_control_get_optional_exclusive(dev, "axi");
 52	if (PTR_ERR(plat->axi_rst) == -EPROBE_DEFER)
 53		return PTR_ERR(plat->axi_rst);
 54
 55	plat->sw_rst = devm_reset_control_get_optional_exclusive(dev, "sw");
 56	if (PTR_ERR(plat->sw_rst) == -EPROBE_DEFER)
 57		return PTR_ERR(plat->sw_rst);
 58
 59	plat->reg_rst = devm_reset_control_get_optional_exclusive(dev, "reg");
 60	if (PTR_ERR(plat->reg_rst) == -EPROBE_DEFER)
 61		return PTR_ERR(plat->reg_rst);
 62
 63	err = reset_control_assert(plat->axi_rst);
 64	if (err) {
 65		dev_err(dev, "failed to assert AXI bus\n");
 66		return err;
 67	}
 68
 69	err = reset_control_assert(plat->sw_rst);
 70	if (err) {
 71		dev_err(dev, "failed to assert PHY digital part\n");
 72		return err;
 73	}
 74
 75	err = reset_control_assert(plat->reg_rst);
 76	if (err) {
 77		dev_err(dev, "failed to assert PHY register part\n");
 78		return err;
 79	}
 80
 81	err = reset_control_deassert(plat->reg_rst);
 82	if (err) {
 83		dev_err(dev, "failed to deassert PHY register part\n");
 84		return err;
 85	}
 86
 87	err = reset_control_deassert(plat->sw_rst);
 88	if (err) {
 89		dev_err(dev, "failed to deassert PHY digital part\n");
 90		return err;
 91	}
 92
 93	err = reset_control_deassert(plat->axi_rst);
 94	if (err) {
 95		dev_err(dev, "failed to deassert AXI bus\n");
 96		return err;
 97	}
 98
 99	return 0;
100}
101
102static int mtk_ahci_parse_property(struct ahci_host_priv *hpriv,
103				   struct device *dev)
104{
105	struct mtk_ahci_plat *plat = hpriv->plat_data;
106	struct device_node *np = dev->of_node;
107
108	/* enable SATA function if needed */
109	if (of_find_property(np, "mediatek,phy-mode", NULL)) {
110		plat->mode = syscon_regmap_lookup_by_phandle(
111					np, "mediatek,phy-mode");
112		if (IS_ERR(plat->mode)) {
113			dev_err(dev, "missing phy-mode phandle\n");
114			return PTR_ERR(plat->mode);
115		}
116
117		regmap_update_bits(plat->mode, SYS_CFG, SYS_CFG_SATA_MSK,
118				   SYS_CFG_SATA_EN);
119	}
120
121	return 0;
122}
123
124static int mtk_ahci_probe(struct platform_device *pdev)
125{
126	struct device *dev = &pdev->dev;
127	struct mtk_ahci_plat *plat;
128	struct ahci_host_priv *hpriv;
129	int err;
130
131	plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL);
132	if (!plat)
133		return -ENOMEM;
134
135	hpriv = ahci_platform_get_resources(pdev, 0);
136	if (IS_ERR(hpriv))
137		return PTR_ERR(hpriv);
138
139	hpriv->plat_data = plat;
140
141	err = mtk_ahci_parse_property(hpriv, dev);
142	if (err)
143		return err;
144
145	err = mtk_ahci_platform_resets(hpriv, dev);
146	if (err)
147		return err;
148
149	err = ahci_platform_enable_resources(hpriv);
150	if (err)
151		return err;
152
153	err = ahci_platform_init_host(pdev, hpriv, &ahci_port_info,
154				      &ahci_platform_sht);
155	if (err)
156		goto disable_resources;
157
158	return 0;
159
160disable_resources:
161	ahci_platform_disable_resources(hpriv);
162	return err;
163}
164
165static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
166			 ahci_platform_resume);
167
168static const struct of_device_id ahci_of_match[] = {
169	{ .compatible = "mediatek,mtk-ahci", },
170	{ /* sentinel */ }
171};
172MODULE_DEVICE_TABLE(of, ahci_of_match);
173
174static struct platform_driver mtk_ahci_driver = {
175	.probe = mtk_ahci_probe,
176	.remove = ata_platform_remove_one,
177	.driver = {
178		.name = DRV_NAME,
179		.of_match_table = ahci_of_match,
180		.pm = &ahci_pm_ops,
181	},
182};
183module_platform_driver(mtk_ahci_driver);
184
185MODULE_DESCRIPTION("MediaTek SATA AHCI Driver");
186MODULE_LICENSE("GPL v2");