brintos

brintos / linux-shallow public Read only

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