brintos

brintos / linux-shallow public Read only

0
0
Text · 5.7 KiB · 79a8b0a Raw
249 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2012 STMicroelectronics Limited4 *5 * Authors: Francesco Virlinzi <francesco.virlinzi@st.com>6 *	    Alexandre Torgue <alexandre.torgue@st.com>7 */8 9#include <linux/init.h>10#include <linux/module.h>11#include <linux/export.h>12#include <linux/platform_device.h>13#include <linux/clk.h>14#include <linux/of.h>15#include <linux/ahci_platform.h>16#include <linux/libata.h>17#include <linux/reset.h>18#include <linux/io.h>19#include <linux/dma-mapping.h>20 21#include "ahci.h"22 23#define DRV_NAME  "st_ahci"24 25#define ST_AHCI_OOBR			0xbc26#define ST_AHCI_OOBR_WE			BIT(31)27#define ST_AHCI_OOBR_CWMIN_SHIFT	2428#define ST_AHCI_OOBR_CWMAX_SHIFT	1629#define ST_AHCI_OOBR_CIMIN_SHIFT	830#define ST_AHCI_OOBR_CIMAX_SHIFT	031 32struct st_ahci_drv_data {33	struct reset_control *pwr;34	struct reset_control *sw_rst;35	struct reset_control *pwr_rst;36};37 38static void st_ahci_configure_oob(void __iomem *mmio)39{40	unsigned long old_val, new_val;41 42	new_val = (0x02 << ST_AHCI_OOBR_CWMIN_SHIFT) |43		  (0x04 << ST_AHCI_OOBR_CWMAX_SHIFT) |44		  (0x08 << ST_AHCI_OOBR_CIMIN_SHIFT) |45		  (0x0C << ST_AHCI_OOBR_CIMAX_SHIFT);46 47	old_val = readl(mmio + ST_AHCI_OOBR);48	writel(old_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR);49	writel(new_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR);50	writel(new_val, mmio + ST_AHCI_OOBR);51}52 53static int st_ahci_deassert_resets(struct ahci_host_priv *hpriv,54				struct device *dev)55{56	struct st_ahci_drv_data *drv_data = hpriv->plat_data;57	int err;58 59	if (drv_data->pwr) {60		err = reset_control_deassert(drv_data->pwr);61		if (err) {62			dev_err(dev, "unable to bring out of pwrdwn\n");63			return err;64		}65	}66 67	if (drv_data->sw_rst) {68		err = reset_control_deassert(drv_data->sw_rst);69		if (err) {70			dev_err(dev, "unable to bring out of sw-rst\n");71			return err;72		}73	}74 75	if (drv_data->pwr_rst) {76		err = reset_control_deassert(drv_data->pwr_rst);77		if (err) {78			dev_err(dev, "unable to bring out of pwr-rst\n");79			return err;80		}81	}82 83	return 0;84}85 86static void st_ahci_host_stop(struct ata_host *host)87{88	struct ahci_host_priv *hpriv = host->private_data;89	struct st_ahci_drv_data *drv_data = hpriv->plat_data;90	struct device *dev = host->dev;91	int err;92 93	if (drv_data->pwr) {94		err = reset_control_assert(drv_data->pwr);95		if (err)96			dev_err(dev, "unable to pwrdwn\n");97	}98 99	ahci_platform_disable_resources(hpriv);100}101 102static int st_ahci_probe_resets(struct ahci_host_priv *hpriv,103				struct device *dev)104{105	struct st_ahci_drv_data *drv_data = hpriv->plat_data;106 107	drv_data->pwr = devm_reset_control_get(dev, "pwr-dwn");108	if (IS_ERR(drv_data->pwr)) {109		dev_info(dev, "power reset control not defined\n");110		drv_data->pwr = NULL;111	}112 113	drv_data->sw_rst = devm_reset_control_get(dev, "sw-rst");114	if (IS_ERR(drv_data->sw_rst)) {115		dev_info(dev, "soft reset control not defined\n");116		drv_data->sw_rst = NULL;117	}118 119	drv_data->pwr_rst = devm_reset_control_get(dev, "pwr-rst");120	if (IS_ERR(drv_data->pwr_rst)) {121		dev_dbg(dev, "power soft reset control not defined\n");122		drv_data->pwr_rst = NULL;123	}124 125	return st_ahci_deassert_resets(hpriv, dev);126}127 128static struct ata_port_operations st_ahci_port_ops = {129	.inherits	= &ahci_platform_ops,130	.host_stop	= st_ahci_host_stop,131};132 133static const struct ata_port_info st_ahci_port_info = {134	.flags          = AHCI_FLAG_COMMON,135	.pio_mask       = ATA_PIO4,136	.udma_mask      = ATA_UDMA6,137	.port_ops       = &st_ahci_port_ops,138};139 140static const struct scsi_host_template ahci_platform_sht = {141	AHCI_SHT(DRV_NAME),142};143 144static int st_ahci_probe(struct platform_device *pdev)145{146	struct st_ahci_drv_data *drv_data;147	struct ahci_host_priv *hpriv;148	int err;149 150	drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL);151	if (!drv_data)152		return -ENOMEM;153 154	hpriv = ahci_platform_get_resources(pdev, 0);155	if (IS_ERR(hpriv))156		return PTR_ERR(hpriv);157	hpriv->plat_data = drv_data;158 159	err = st_ahci_probe_resets(hpriv, &pdev->dev);160	if (err)161		return err;162 163	err = ahci_platform_enable_resources(hpriv);164	if (err)165		return err;166 167	st_ahci_configure_oob(hpriv->mmio);168 169	err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info,170				      &ahci_platform_sht);171	if (err) {172		ahci_platform_disable_resources(hpriv);173		return err;174	}175 176	return 0;177}178 179#ifdef CONFIG_PM_SLEEP180static int st_ahci_suspend(struct device *dev)181{182	struct ata_host *host = dev_get_drvdata(dev);183	struct ahci_host_priv *hpriv = host->private_data;184	struct st_ahci_drv_data *drv_data = hpriv->plat_data;185	int err;186 187	err = ahci_platform_suspend_host(dev);188	if (err)189		return err;190 191	if (drv_data->pwr) {192		err = reset_control_assert(drv_data->pwr);193		if (err) {194			dev_err(dev, "unable to pwrdwn");195			return err;196		}197	}198 199	ahci_platform_disable_resources(hpriv);200 201	return 0;202}203 204static int st_ahci_resume(struct device *dev)205{206	struct ata_host *host = dev_get_drvdata(dev);207	struct ahci_host_priv *hpriv = host->private_data;208	int err;209 210	err = ahci_platform_enable_resources(hpriv);211	if (err)212		return err;213 214	err = st_ahci_deassert_resets(hpriv, dev);215	if (err) {216		ahci_platform_disable_resources(hpriv);217		return err;218	}219 220	st_ahci_configure_oob(hpriv->mmio);221 222	return ahci_platform_resume_host(dev);223}224#endif225 226static SIMPLE_DEV_PM_OPS(st_ahci_pm_ops, st_ahci_suspend, st_ahci_resume);227 228static const struct of_device_id st_ahci_match[] = {229	{ .compatible = "st,ahci", },230	{ /* sentinel */ }231};232MODULE_DEVICE_TABLE(of, st_ahci_match);233 234static struct platform_driver st_ahci_driver = {235	.driver = {236		.name = DRV_NAME,237		.pm = &st_ahci_pm_ops,238		.of_match_table = st_ahci_match,239	},240	.probe = st_ahci_probe,241	.remove_new = ata_platform_remove_one,242};243module_platform_driver(st_ahci_driver);244 245MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@st.com>");246MODULE_AUTHOR("Francesco Virlinzi <francesco.virlinzi@st.com>");247MODULE_DESCRIPTION("STMicroelectronics SATA AHCI Driver");248MODULE_LICENSE("GPL v2");249