root/drivers/usb/dwc3/dwc3-exynos.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dwc3_exynos_remove_child
  2. dwc3_exynos_probe
  3. dwc3_exynos_remove
  4. dwc3_exynos_suspend
  5. dwc3_exynos_resume

   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 
  22 struct dwc3_exynos_driverdata {
  23         const char              *clk_names[DWC3_EXYNOS_MAX_CLOCKS];
  24         int                     num_clks;
  25         int                     suspend_clk_idx;
  26 };
  27 
  28 struct 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 
  40 static 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 
  49 static 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 
 126 populate_err:
 127         regulator_disable(exynos->vdd10);
 128 vdd10_err:
 129         regulator_disable(exynos->vdd33);
 130 vdd33_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 
 140 static 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 
 159 static const struct dwc3_exynos_driverdata exynos5250_drvdata = {
 160         .clk_names = { "usbdrd30" },
 161         .num_clks = 1,
 162         .suspend_clk_idx = -1,
 163 };
 164 
 165 static 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 
 171 static 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 
 177 static 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 };
 190 MODULE_DEVICE_TABLE(of, exynos_dwc3_match);
 191 
 192 #ifdef CONFIG_PM_SLEEP
 193 static 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 
 207 static 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 
 235 static 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 
 244 static 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 
 254 module_platform_driver(dwc3_exynos_driver);
 255 
 256 MODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>");
 257 MODULE_LICENSE("GPL v2");
 258 MODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer");

/* [<][>][^][v][top][bottom][index][help] */