^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * phy-brcm-usb.c - Broadcom USB Phy Driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2015-2017 Broadcom
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/phy/phy.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/soc/brcmstb/brcmstb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <dt-bindings/phy/phy.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/mfd/syscon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/suspend.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "phy-brcm-usb-init.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) static DEFINE_MUTEX(sysfs_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) enum brcm_usb_phy_id {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) BRCM_USB_PHY_2_0 = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) BRCM_USB_PHY_3_0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) BRCM_USB_PHY_ID_MAX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct value_to_name_map {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) int value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct match_chip_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) void *init_func;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) u8 required_regs[BRCM_REGS_MAX + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) u8 optional_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static const struct value_to_name_map brcm_dr_mode_to_name[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) { USB_CTLR_MODE_HOST, "host" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) { USB_CTLR_MODE_DEVICE, "peripheral" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) { USB_CTLR_MODE_DRD, "drd" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) { USB_CTLR_MODE_TYPEC_PD, "typec-pd" }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) static const struct value_to_name_map brcm_dual_mode_to_name[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) { 0, "host" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) { 1, "device" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) { 2, "auto" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct brcm_usb_phy {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct phy *phy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) unsigned int id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) bool inited;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct brcm_usb_phy_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct brcm_usb_init_params ini;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) bool has_eohci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) bool has_xhci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) struct clk *usb_20_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) struct clk *usb_30_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct clk *suspend_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) struct mutex mutex; /* serialize phy init */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) int init_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) int wake_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct brcm_usb_phy phys[BRCM_USB_PHY_ID_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct notifier_block pm_notifier;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) bool pm_active;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static s8 *node_reg_names[BRCM_REGS_MAX] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) "crtl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio", "bdc_ec"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static int brcm_pm_notifier(struct notifier_block *notifier,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) unsigned long pm_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) void *unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) struct brcm_usb_phy_data *priv =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) container_of(notifier, struct brcm_usb_phy_data, pm_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) switch (pm_event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) case PM_HIBERNATION_PREPARE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) case PM_SUSPEND_PREPARE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) priv->pm_active = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) case PM_POST_RESTORE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) case PM_POST_HIBERNATION:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) case PM_POST_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) priv->pm_active = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static irqreturn_t brcm_usb_phy_wake_isr(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) struct phy *gphy = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) pm_wakeup_event(&gphy->dev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static int brcm_usb_phy_init(struct phy *gphy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) struct brcm_usb_phy *phy = phy_get_drvdata(gphy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct brcm_usb_phy_data *priv =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) container_of(phy, struct brcm_usb_phy_data, phys[phy->id]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (priv->pm_active)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * Use a lock to make sure a second caller waits until
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * the base phy is inited before using it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) mutex_lock(&priv->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (priv->init_count++ == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) clk_prepare_enable(priv->usb_20_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) clk_prepare_enable(priv->usb_30_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) clk_prepare_enable(priv->suspend_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) brcm_usb_init_common(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) mutex_unlock(&priv->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (phy->id == BRCM_USB_PHY_2_0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) brcm_usb_init_eohci(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) else if (phy->id == BRCM_USB_PHY_3_0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) brcm_usb_init_xhci(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) phy->inited = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) dev_dbg(&gphy->dev, "INIT, id: %d, total: %d\n", phy->id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) priv->init_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) static int brcm_usb_phy_exit(struct phy *gphy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) struct brcm_usb_phy *phy = phy_get_drvdata(gphy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) struct brcm_usb_phy_data *priv =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) container_of(phy, struct brcm_usb_phy_data, phys[phy->id]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (priv->pm_active)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) dev_dbg(&gphy->dev, "EXIT\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (phy->id == BRCM_USB_PHY_2_0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) brcm_usb_uninit_eohci(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (phy->id == BRCM_USB_PHY_3_0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) brcm_usb_uninit_xhci(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) /* If both xhci and eohci are gone, reset everything else */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) mutex_lock(&priv->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (--priv->init_count == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) brcm_usb_uninit_common(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) clk_disable_unprepare(priv->usb_20_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) clk_disable_unprepare(priv->usb_30_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) clk_disable_unprepare(priv->suspend_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) mutex_unlock(&priv->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) phy->inited = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) static const struct phy_ops brcm_usb_phy_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) .init = brcm_usb_phy_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) .exit = brcm_usb_phy_exit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) static struct phy *brcm_usb_phy_xlate(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) struct of_phandle_args *args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) struct brcm_usb_phy_data *data = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * values 0 and 1 are for backward compatibility with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * device tree nodes from older bootloaders.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) switch (args->args[0]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) case PHY_TYPE_USB2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (data->phys[BRCM_USB_PHY_2_0].phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) return data->phys[BRCM_USB_PHY_2_0].phy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) dev_warn(dev, "Error, 2.0 Phy not found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) case PHY_TYPE_USB3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (data->phys[BRCM_USB_PHY_3_0].phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) return data->phys[BRCM_USB_PHY_3_0].phy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) dev_warn(dev, "Error, 3.0 Phy not found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) return ERR_PTR(-ENODEV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) static int name_to_value(const struct value_to_name_map *table, int count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) const char *name, int *value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) int x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) *value = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) for (x = 0; x < count; x++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (sysfs_streq(name, table[x].name)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) *value = x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) static const char *value_to_name(const struct value_to_name_map *table, int count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (value >= count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) return "unknown";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) return table[value].name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) static ssize_t dr_mode_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) return sprintf(buf, "%s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) value_to_name(&brcm_dr_mode_to_name[0],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) ARRAY_SIZE(brcm_dr_mode_to_name),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) priv->ini.mode));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) static DEVICE_ATTR_RO(dr_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) static ssize_t dual_select_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) int value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) int res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) mutex_lock(&sysfs_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) res = name_to_value(&brcm_dual_mode_to_name[0],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) ARRAY_SIZE(brcm_dual_mode_to_name), buf, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if (!res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) brcm_usb_set_dual_select(&priv->ini, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) res = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) mutex_unlock(&sysfs_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) static ssize_t dual_select_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) int value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) mutex_lock(&sysfs_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) value = brcm_usb_get_dual_select(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) mutex_unlock(&sysfs_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) return sprintf(buf, "%s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) value_to_name(&brcm_dual_mode_to_name[0],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) ARRAY_SIZE(brcm_dual_mode_to_name),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) value));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) static DEVICE_ATTR_RW(dual_select);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) static struct attribute *brcm_usb_phy_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) &dev_attr_dr_mode.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) &dev_attr_dual_select.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) static const struct attribute_group brcm_usb_phy_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) .attrs = brcm_usb_phy_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) static const struct match_chip_info chip_info_7216 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) .init_func = &brcm_usb_dvr_init_7216,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) .required_regs = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) BRCM_REGS_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) BRCM_REGS_XHCI_EC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) BRCM_REGS_XHCI_GBL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) static const struct match_chip_info chip_info_7211b0 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) .init_func = &brcm_usb_dvr_init_7211b0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) .required_regs = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) BRCM_REGS_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) BRCM_REGS_XHCI_EC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) BRCM_REGS_XHCI_GBL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) BRCM_REGS_USB_PHY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) BRCM_REGS_USB_MDIO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) .optional_reg = BRCM_REGS_BDC_EC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) static const struct match_chip_info chip_info_7445 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) .init_func = &brcm_usb_dvr_init_7445,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) .required_regs = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) BRCM_REGS_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) BRCM_REGS_XHCI_EC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) static const struct of_device_id brcm_usb_dt_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) .compatible = "brcm,bcm7216-usb-phy",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) .data = &chip_info_7216,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) .compatible = "brcm,bcm7211-usb-phy",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) .data = &chip_info_7211b0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) .compatible = "brcm,brcmstb-usb-phy",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) .data = &chip_info_7445,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) { /* sentinel */ }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) static int brcm_usb_get_regs(struct platform_device *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) enum brcmusb_reg_sel regs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) struct brcm_usb_init_params *ini,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) bool optional)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) /* Older DT nodes have ctrl and optional xhci_ec by index only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) node_reg_names[regs]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) if (res == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) if (regs == BRCM_REGS_CTRL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) } else if (regs == BRCM_REGS_XHCI_EC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) /* XHCI_EC registers are optional */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (res == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) if (res == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (optional) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) dev_dbg(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) "Optional reg %s not found\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) node_reg_names[regs]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) dev_err(&pdev->dev, "can't get %s base addr\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) node_reg_names[regs]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) ini->regs[regs] = devm_ioremap_resource(&pdev->dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) if (IS_ERR(ini->regs[regs])) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) dev_err(&pdev->dev, "can't map %s register space\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) node_reg_names[regs]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) static int brcm_usb_phy_dvr_init(struct platform_device *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) struct brcm_usb_phy_data *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) struct device_node *dn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) struct phy *gphy = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) priv->usb_20_clk = of_clk_get_by_name(dn, "sw_usb");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) if (IS_ERR(priv->usb_20_clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) if (PTR_ERR(priv->usb_20_clk) == -EPROBE_DEFER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) return -EPROBE_DEFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) dev_info(dev, "Clock not found in Device Tree\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) priv->usb_20_clk = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) err = clk_prepare_enable(priv->usb_20_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) if (priv->has_eohci) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) gphy = devm_phy_create(dev, NULL, &brcm_usb_phy_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) if (IS_ERR(gphy)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) dev_err(dev, "failed to create EHCI/OHCI PHY\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) return PTR_ERR(gphy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) priv->phys[BRCM_USB_PHY_2_0].phy = gphy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) priv->phys[BRCM_USB_PHY_2_0].id = BRCM_USB_PHY_2_0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) phy_set_drvdata(gphy, &priv->phys[BRCM_USB_PHY_2_0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) if (priv->has_xhci) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) gphy = devm_phy_create(dev, NULL, &brcm_usb_phy_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) if (IS_ERR(gphy)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) dev_err(dev, "failed to create XHCI PHY\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) return PTR_ERR(gphy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) priv->phys[BRCM_USB_PHY_3_0].phy = gphy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) priv->phys[BRCM_USB_PHY_3_0].id = BRCM_USB_PHY_3_0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) phy_set_drvdata(gphy, &priv->phys[BRCM_USB_PHY_3_0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) priv->usb_30_clk = of_clk_get_by_name(dn, "sw_usb3");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) if (IS_ERR(priv->usb_30_clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) if (PTR_ERR(priv->usb_30_clk) == -EPROBE_DEFER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) return -EPROBE_DEFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) dev_info(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) "USB3.0 clock not found in Device Tree\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) priv->usb_30_clk = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) err = clk_prepare_enable(priv->usb_30_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) priv->suspend_clk = clk_get(dev, "usb0_freerun");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) if (IS_ERR(priv->suspend_clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) if (PTR_ERR(priv->suspend_clk) == -EPROBE_DEFER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) return -EPROBE_DEFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) dev_err(dev, "Suspend Clock not found in Device Tree\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) priv->suspend_clk = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) priv->wake_irq = platform_get_irq_byname(pdev, "wake");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) if (priv->wake_irq < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) priv->wake_irq = platform_get_irq_byname(pdev, "wakeup");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) if (priv->wake_irq >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) err = devm_request_irq(dev, priv->wake_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) brcm_usb_phy_wake_isr, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) dev_name(dev), gphy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) device_set_wakeup_capable(dev, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) dev_info(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) "Wake interrupt missing, system wake not supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) static int brcm_usb_phy_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) struct brcm_usb_phy_data *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) struct phy_provider *phy_provider;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) struct device_node *dn = pdev->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) const char *mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) const struct of_device_id *match;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) void (*dvr_init)(struct brcm_usb_init_params *params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) const struct match_chip_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) struct regmap *rmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) int x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) if (!priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) platform_set_drvdata(pdev, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) priv->ini.family_id = brcmstb_get_family_id();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) priv->ini.product_id = brcmstb_get_product_id();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) match = of_match_node(brcm_usb_dt_ids, dev->of_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) info = match->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) dvr_init = info->init_func;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) (*dvr_init)(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) dev_dbg(dev, "Best mapping table is for %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) priv->ini.family_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) of_property_read_u32(dn, "brcm,ipp", &priv->ini.ipp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) of_property_read_u32(dn, "brcm,ioc", &priv->ini.ioc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) priv->ini.mode = USB_CTLR_MODE_HOST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) err = of_property_read_string(dn, "dr_mode", &mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) if (err == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) name_to_value(&brcm_dr_mode_to_name[0],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) ARRAY_SIZE(brcm_dr_mode_to_name),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) mode, &priv->ini.mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (of_property_read_bool(dn, "brcm,has-xhci"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) priv->has_xhci = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) if (of_property_read_bool(dn, "brcm,has-eohci"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) priv->has_eohci = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) for (x = 0; x < BRCM_REGS_MAX; x++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) if (info->required_regs[x] >= BRCM_REGS_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) err = brcm_usb_get_regs(pdev, info->required_regs[x],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) &priv->ini, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) if (info->optional_reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) err = brcm_usb_get_regs(pdev, info->optional_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) &priv->ini, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) err = brcm_usb_phy_dvr_init(pdev, priv, dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) priv->pm_notifier.notifier_call = brcm_pm_notifier;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) register_pm_notifier(&priv->pm_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) mutex_init(&priv->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) /* make sure invert settings are correct */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) brcm_usb_init_ipp(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) * Create sysfs entries for mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) * Remove "dual_select" attribute if not in dual mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) if (priv->ini.mode != USB_CTLR_MODE_DRD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) brcm_usb_phy_attrs[1] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) err = sysfs_create_group(&dev->kobj, &brcm_usb_phy_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) dev_warn(dev, "Error creating sysfs attributes\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) /* Get piarbctl syscon if it exists */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) rmap = syscon_regmap_lookup_by_phandle(dev->of_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) "syscon-piarbctl");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) if (IS_ERR(rmap))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) rmap = syscon_regmap_lookup_by_phandle(dev->of_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) "brcm,syscon-piarbctl");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) if (!IS_ERR(rmap))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) priv->ini.syscon_piarbctl = rmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) /* start with everything off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) if (priv->has_xhci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) brcm_usb_uninit_xhci(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) if (priv->has_eohci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) brcm_usb_uninit_eohci(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) brcm_usb_uninit_common(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) clk_disable_unprepare(priv->usb_20_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) clk_disable_unprepare(priv->usb_30_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) phy_provider = devm_of_phy_provider_register(dev, brcm_usb_phy_xlate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) return PTR_ERR_OR_ZERO(phy_provider);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) static int brcm_usb_phy_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) struct brcm_usb_phy_data *priv = dev_get_drvdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) sysfs_remove_group(&pdev->dev.kobj, &brcm_usb_phy_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) unregister_pm_notifier(&priv->pm_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) static int brcm_usb_phy_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) if (priv->init_count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) dev_dbg(dev, "SUSPEND\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) priv->ini.wake_enabled = device_may_wakeup(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) if (priv->phys[BRCM_USB_PHY_3_0].inited)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) brcm_usb_uninit_xhci(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) if (priv->phys[BRCM_USB_PHY_2_0].inited)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) brcm_usb_uninit_eohci(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) brcm_usb_uninit_common(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) * Handle the clocks unless needed for wake. This has
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) * to work for both older XHCI->3.0-clks, EOHCI->2.0-clks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) * and newer XHCI->2.0-clks/3.0-clks.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) if (!priv->ini.suspend_with_clocks) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) if (priv->phys[BRCM_USB_PHY_3_0].inited)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) clk_disable_unprepare(priv->usb_30_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) if (priv->phys[BRCM_USB_PHY_2_0].inited ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) !priv->has_eohci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) clk_disable_unprepare(priv->usb_20_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) if (priv->wake_irq >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) enable_irq_wake(priv->wake_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) static int brcm_usb_phy_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) clk_prepare_enable(priv->usb_20_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) clk_prepare_enable(priv->usb_30_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) brcm_usb_init_ipp(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) * Initialize anything that was previously initialized.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) * Uninitialize anything that wasn't previously initialized.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) if (priv->init_count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) dev_dbg(dev, "RESUME\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) if (priv->wake_irq >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) disable_irq_wake(priv->wake_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) brcm_usb_init_common(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) if (priv->phys[BRCM_USB_PHY_2_0].inited) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) brcm_usb_init_eohci(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) } else if (priv->has_eohci) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) brcm_usb_uninit_eohci(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) clk_disable_unprepare(priv->usb_20_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) if (priv->phys[BRCM_USB_PHY_3_0].inited) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) brcm_usb_init_xhci(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) } else if (priv->has_xhci) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) brcm_usb_uninit_xhci(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) clk_disable_unprepare(priv->usb_30_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) if (!priv->has_eohci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) clk_disable_unprepare(priv->usb_20_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) if (priv->has_xhci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) brcm_usb_uninit_xhci(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) if (priv->has_eohci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) brcm_usb_uninit_eohci(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) brcm_usb_uninit_common(&priv->ini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) clk_disable_unprepare(priv->usb_20_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) clk_disable_unprepare(priv->usb_30_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) priv->ini.wake_enabled = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) #endif /* CONFIG_PM_SLEEP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) static const struct dev_pm_ops brcm_usb_phy_pm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) SET_LATE_SYSTEM_SLEEP_PM_OPS(brcm_usb_phy_suspend, brcm_usb_phy_resume)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) MODULE_DEVICE_TABLE(of, brcm_usb_dt_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) static struct platform_driver brcm_usb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) .probe = brcm_usb_phy_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) .remove = brcm_usb_phy_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) .name = "brcmstb-usb-phy",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) .pm = &brcm_usb_phy_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) .of_match_table = brcm_usb_dt_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) module_platform_driver(brcm_usb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) MODULE_ALIAS("platform:brcmstb-usb-phy");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) MODULE_AUTHOR("Al Cooper <acooper@broadcom.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) MODULE_DESCRIPTION("BRCM USB PHY driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) MODULE_LICENSE("GPL v2");