cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dwc3-exynos.c (6076B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * dwc3-exynos.c - Samsung Exynos DWC3 Specific Glue layer
      4 *
      5 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
      6 *		http://www.samsung.com
      7 *
      8 * Author: Anton Tikhomirov <av.tikhomirov@samsung.com>
      9 */
     10
     11#include <linux/module.h>
     12#include <linux/kernel.h>
     13#include <linux/slab.h>
     14#include <linux/platform_device.h>
     15#include <linux/clk.h>
     16#include <linux/of.h>
     17#include <linux/of_platform.h>
     18#include <linux/regulator/consumer.h>
     19
     20#define DWC3_EXYNOS_MAX_CLOCKS	4
     21
     22struct dwc3_exynos_driverdata {
     23	const char		*clk_names[DWC3_EXYNOS_MAX_CLOCKS];
     24	int			num_clks;
     25	int			suspend_clk_idx;
     26};
     27
     28struct dwc3_exynos {
     29	struct device		*dev;
     30
     31	const char		**clk_names;
     32	struct clk		*clks[DWC3_EXYNOS_MAX_CLOCKS];
     33	int			num_clks;
     34	int			suspend_clk_idx;
     35
     36	struct regulator	*vdd33;
     37	struct regulator	*vdd10;
     38};
     39
     40static int dwc3_exynos_remove_child(struct device *dev, void *unused)
     41{
     42	struct platform_device *pdev = to_platform_device(dev);
     43
     44	platform_device_unregister(pdev);
     45
     46	return 0;
     47}
     48
     49static int dwc3_exynos_probe(struct platform_device *pdev)
     50{
     51	struct dwc3_exynos	*exynos;
     52	struct device		*dev = &pdev->dev;
     53	struct device_node	*node = dev->of_node;
     54	const struct dwc3_exynos_driverdata *driver_data;
     55	int			i, ret;
     56
     57	exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL);
     58	if (!exynos)
     59		return -ENOMEM;
     60
     61	driver_data = of_device_get_match_data(dev);
     62	exynos->dev = dev;
     63	exynos->num_clks = driver_data->num_clks;
     64	exynos->clk_names = (const char **)driver_data->clk_names;
     65	exynos->suspend_clk_idx = driver_data->suspend_clk_idx;
     66
     67	platform_set_drvdata(pdev, exynos);
     68
     69	for (i = 0; i < exynos->num_clks; i++) {
     70		exynos->clks[i] = devm_clk_get(dev, exynos->clk_names[i]);
     71		if (IS_ERR(exynos->clks[i])) {
     72			dev_err(dev, "failed to get clock: %s\n",
     73				exynos->clk_names[i]);
     74			return PTR_ERR(exynos->clks[i]);
     75		}
     76	}
     77
     78	for (i = 0; i < exynos->num_clks; i++) {
     79		ret = clk_prepare_enable(exynos->clks[i]);
     80		if (ret) {
     81			while (i-- > 0)
     82				clk_disable_unprepare(exynos->clks[i]);
     83			return ret;
     84		}
     85	}
     86
     87	if (exynos->suspend_clk_idx >= 0)
     88		clk_prepare_enable(exynos->clks[exynos->suspend_clk_idx]);
     89
     90	exynos->vdd33 = devm_regulator_get(dev, "vdd33");
     91	if (IS_ERR(exynos->vdd33)) {
     92		ret = PTR_ERR(exynos->vdd33);
     93		goto vdd33_err;
     94	}
     95	ret = regulator_enable(exynos->vdd33);
     96	if (ret) {
     97		dev_err(dev, "Failed to enable VDD33 supply\n");
     98		goto vdd33_err;
     99	}
    100
    101	exynos->vdd10 = devm_regulator_get(dev, "vdd10");
    102	if (IS_ERR(exynos->vdd10)) {
    103		ret = PTR_ERR(exynos->vdd10);
    104		goto vdd10_err;
    105	}
    106	ret = regulator_enable(exynos->vdd10);
    107	if (ret) {
    108		dev_err(dev, "Failed to enable VDD10 supply\n");
    109		goto vdd10_err;
    110	}
    111
    112	if (node) {
    113		ret = of_platform_populate(node, NULL, NULL, dev);
    114		if (ret) {
    115			dev_err(dev, "failed to add dwc3 core\n");
    116			goto populate_err;
    117		}
    118	} else {
    119		dev_err(dev, "no device node, failed to add dwc3 core\n");
    120		ret = -ENODEV;
    121		goto populate_err;
    122	}
    123
    124	return 0;
    125
    126populate_err:
    127	regulator_disable(exynos->vdd10);
    128vdd10_err:
    129	regulator_disable(exynos->vdd33);
    130vdd33_err:
    131	for (i = exynos->num_clks - 1; i >= 0; i--)
    132		clk_disable_unprepare(exynos->clks[i]);
    133
    134	if (exynos->suspend_clk_idx >= 0)
    135		clk_disable_unprepare(exynos->clks[exynos->suspend_clk_idx]);
    136
    137	return ret;
    138}
    139
    140static int dwc3_exynos_remove(struct platform_device *pdev)
    141{
    142	struct dwc3_exynos	*exynos = platform_get_drvdata(pdev);
    143	int i;
    144
    145	device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child);
    146
    147	for (i = exynos->num_clks - 1; i >= 0; i--)
    148		clk_disable_unprepare(exynos->clks[i]);
    149
    150	if (exynos->suspend_clk_idx >= 0)
    151		clk_disable_unprepare(exynos->clks[exynos->suspend_clk_idx]);
    152
    153	regulator_disable(exynos->vdd33);
    154	regulator_disable(exynos->vdd10);
    155
    156	return 0;
    157}
    158
    159static const struct dwc3_exynos_driverdata exynos5250_drvdata = {
    160	.clk_names = { "usbdrd30" },
    161	.num_clks = 1,
    162	.suspend_clk_idx = -1,
    163};
    164
    165static const struct dwc3_exynos_driverdata exynos5433_drvdata = {
    166	.clk_names = { "aclk", "susp_clk", "pipe_pclk", "phyclk" },
    167	.num_clks = 4,
    168	.suspend_clk_idx = 1,
    169};
    170
    171static const struct dwc3_exynos_driverdata exynos7_drvdata = {
    172	.clk_names = { "usbdrd30", "usbdrd30_susp_clk", "usbdrd30_axius_clk" },
    173	.num_clks = 3,
    174	.suspend_clk_idx = 1,
    175};
    176
    177static const struct of_device_id exynos_dwc3_match[] = {
    178	{
    179		.compatible = "samsung,exynos5250-dwusb3",
    180		.data = &exynos5250_drvdata,
    181	}, {
    182		.compatible = "samsung,exynos5433-dwusb3",
    183		.data = &exynos5433_drvdata,
    184	}, {
    185		.compatible = "samsung,exynos7-dwusb3",
    186		.data = &exynos7_drvdata,
    187	}, {
    188	}
    189};
    190MODULE_DEVICE_TABLE(of, exynos_dwc3_match);
    191
    192#ifdef CONFIG_PM_SLEEP
    193static int dwc3_exynos_suspend(struct device *dev)
    194{
    195	struct dwc3_exynos *exynos = dev_get_drvdata(dev);
    196	int i;
    197
    198	for (i = exynos->num_clks - 1; i >= 0; i--)
    199		clk_disable_unprepare(exynos->clks[i]);
    200
    201	regulator_disable(exynos->vdd33);
    202	regulator_disable(exynos->vdd10);
    203
    204	return 0;
    205}
    206
    207static int dwc3_exynos_resume(struct device *dev)
    208{
    209	struct dwc3_exynos *exynos = dev_get_drvdata(dev);
    210	int i, ret;
    211
    212	ret = regulator_enable(exynos->vdd33);
    213	if (ret) {
    214		dev_err(dev, "Failed to enable VDD33 supply\n");
    215		return ret;
    216	}
    217	ret = regulator_enable(exynos->vdd10);
    218	if (ret) {
    219		dev_err(dev, "Failed to enable VDD10 supply\n");
    220		return ret;
    221	}
    222
    223	for (i = 0; i < exynos->num_clks; i++) {
    224		ret = clk_prepare_enable(exynos->clks[i]);
    225		if (ret) {
    226			while (i-- > 0)
    227				clk_disable_unprepare(exynos->clks[i]);
    228			return ret;
    229		}
    230	}
    231
    232	return 0;
    233}
    234
    235static const struct dev_pm_ops dwc3_exynos_dev_pm_ops = {
    236	SET_SYSTEM_SLEEP_PM_OPS(dwc3_exynos_suspend, dwc3_exynos_resume)
    237};
    238
    239#define DEV_PM_OPS	(&dwc3_exynos_dev_pm_ops)
    240#else
    241#define DEV_PM_OPS	NULL
    242#endif /* CONFIG_PM_SLEEP */
    243
    244static struct platform_driver dwc3_exynos_driver = {
    245	.probe		= dwc3_exynos_probe,
    246	.remove		= dwc3_exynos_remove,
    247	.driver		= {
    248		.name	= "exynos-dwc3",
    249		.of_match_table = exynos_dwc3_match,
    250		.pm	= DEV_PM_OPS,
    251	},
    252};
    253
    254module_platform_driver(dwc3_exynos_driver);
    255
    256MODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>");
    257MODULE_LICENSE("GPL v2");
    258MODULE_DESCRIPTION("DesignWare USB3 Exynos Glue Layer");