Home | History | Annotate | Download | only in host
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Copyright (C) 2015 Alexey Brodkin <abrodkin (at) synopsys.com>
      4  */
      5 
      6 #include <common.h>
      7 #include <clk.h>
      8 #include <dm.h>
      9 #include <dm/ofnode.h>
     10 #include <generic-phy.h>
     11 #include <reset.h>
     12 #include "ohci.h"
     13 
     14 #if !defined(CONFIG_USB_OHCI_NEW)
     15 # error "Generic OHCI driver requires CONFIG_USB_OHCI_NEW"
     16 #endif
     17 
     18 struct generic_ohci {
     19 	ohci_t ohci;
     20 	struct clk *clocks;	/* clock list */
     21 	struct reset_ctl *resets; /* reset list */
     22 	struct phy phy;
     23 	int clock_count;	/* number of clock in clock list */
     24 	int reset_count;	/* number of reset in reset list */
     25 };
     26 
     27 static int ohci_setup_phy(struct udevice *dev, int index)
     28 {
     29 	struct generic_ohci *priv = dev_get_priv(dev);
     30 	int ret;
     31 
     32 	ret = generic_phy_get_by_index(dev, index, &priv->phy);
     33 	if (ret) {
     34 		if (ret != -ENOENT) {
     35 			dev_err(dev, "failed to get usb phy\n");
     36 			return ret;
     37 		}
     38 	} else {
     39 		ret = generic_phy_init(&priv->phy);
     40 		if (ret) {
     41 			dev_err(dev, "failed to init usb phy\n");
     42 			return ret;
     43 		}
     44 
     45 		ret = generic_phy_power_on(&priv->phy);
     46 		if (ret) {
     47 			dev_err(dev, "failed to power on usb phy\n");
     48 			return generic_phy_exit(&priv->phy);
     49 		}
     50 	}
     51 
     52 	return 0;
     53 }
     54 
     55 static int ohci_shutdown_phy(struct udevice *dev)
     56 {
     57 	struct generic_ohci *priv = dev_get_priv(dev);
     58 	int ret = 0;
     59 
     60 	if (generic_phy_valid(&priv->phy)) {
     61 		ret = generic_phy_power_off(&priv->phy);
     62 		if (ret) {
     63 			dev_err(dev, "failed to power off usb phy\n");
     64 			return ret;
     65 		}
     66 
     67 		ret = generic_phy_exit(&priv->phy);
     68 		if (ret) {
     69 			dev_err(dev, "failed to power off usb phy\n");
     70 			return ret;
     71 		}
     72 	}
     73 
     74 	return 0;
     75 }
     76 
     77 static int ohci_usb_probe(struct udevice *dev)
     78 {
     79 	struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev);
     80 	struct generic_ohci *priv = dev_get_priv(dev);
     81 	int i, err, ret, clock_nb, reset_nb;
     82 
     83 	err = 0;
     84 	priv->clock_count = 0;
     85 	clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells");
     86 	if (clock_nb > 0) {
     87 		priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
     88 					    GFP_KERNEL);
     89 		if (!priv->clocks)
     90 			return -ENOMEM;
     91 
     92 		for (i = 0; i < clock_nb; i++) {
     93 			err = clk_get_by_index(dev, i, &priv->clocks[i]);
     94 			if (err < 0)
     95 				break;
     96 
     97 			err = clk_enable(&priv->clocks[i]);
     98 			if (err) {
     99 				dev_err(dev, "failed to enable clock %d\n", i);
    100 				clk_free(&priv->clocks[i]);
    101 				goto clk_err;
    102 			}
    103 			priv->clock_count++;
    104 		}
    105 	} else if (clock_nb != -ENOENT) {
    106 		dev_err(dev, "failed to get clock phandle(%d)\n", clock_nb);
    107 		return clock_nb;
    108 	}
    109 
    110 	priv->reset_count = 0;
    111 	reset_nb = dev_count_phandle_with_args(dev, "resets", "#reset-cells");
    112 	if (reset_nb > 0) {
    113 		priv->resets = devm_kcalloc(dev, reset_nb,
    114 					    sizeof(struct reset_ctl),
    115 					    GFP_KERNEL);
    116 		if (!priv->resets)
    117 			return -ENOMEM;
    118 
    119 		for (i = 0; i < reset_nb; i++) {
    120 			err = reset_get_by_index(dev, i, &priv->resets[i]);
    121 			if (err < 0)
    122 				break;
    123 
    124 			err = reset_deassert(&priv->resets[i]);
    125 			if (err) {
    126 				dev_err(dev, "failed to deassert reset %d\n", i);
    127 				reset_free(&priv->resets[i]);
    128 				goto reset_err;
    129 			}
    130 			priv->reset_count++;
    131 		}
    132 	} else if (reset_nb != -ENOENT) {
    133 		dev_err(dev, "failed to get reset phandle(%d)\n", reset_nb);
    134 		goto clk_err;
    135 	}
    136 
    137 	err = ohci_setup_phy(dev, 0);
    138 	if (err)
    139 		goto reset_err;
    140 
    141 	err = ohci_register(dev, regs);
    142 	if (err)
    143 		goto phy_err;
    144 
    145 	return 0;
    146 
    147 phy_err:
    148 	ret = ohci_shutdown_phy(dev);
    149 	if (ret)
    150 		dev_err(dev, "failed to shutdown usb phy\n");
    151 
    152 reset_err:
    153 	ret = reset_release_all(priv->resets, priv->reset_count);
    154 	if (ret)
    155 		dev_err(dev, "failed to assert all resets\n");
    156 clk_err:
    157 	ret = clk_release_all(priv->clocks, priv->clock_count);
    158 	if (ret)
    159 		dev_err(dev, "failed to disable all clocks\n");
    160 
    161 	return err;
    162 }
    163 
    164 static int ohci_usb_remove(struct udevice *dev)
    165 {
    166 	struct generic_ohci *priv = dev_get_priv(dev);
    167 	int ret;
    168 
    169 	ret = ohci_deregister(dev);
    170 	if (ret)
    171 		return ret;
    172 
    173 	ret = ohci_shutdown_phy(dev);
    174 	if (ret)
    175 		return ret;
    176 
    177 	ret = reset_release_all(priv->resets, priv->reset_count);
    178 	if (ret)
    179 		return ret;
    180 
    181 	return clk_release_all(priv->clocks, priv->clock_count);
    182 }
    183 
    184 static const struct udevice_id ohci_usb_ids[] = {
    185 	{ .compatible = "generic-ohci" },
    186 	{ }
    187 };
    188 
    189 U_BOOT_DRIVER(ohci_generic) = {
    190 	.name	= "ohci_generic",
    191 	.id	= UCLASS_USB,
    192 	.of_match = ohci_usb_ids,
    193 	.probe = ohci_usb_probe,
    194 	.remove = ohci_usb_remove,
    195 	.ops	= &ohci_usb_ops,
    196 	.priv_auto_alloc_size = sizeof(struct generic_ohci),
    197 	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
    198 };
    199