phy-bcm-kona-usb2.c (3373B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * phy-bcm-kona-usb2.c - Broadcom Kona USB2 Phy Driver 4 * 5 * Copyright (C) 2013 Linaro Limited 6 * Matt Porter <mporter@linaro.org> 7 */ 8 9#include <linux/clk.h> 10#include <linux/delay.h> 11#include <linux/err.h> 12#include <linux/io.h> 13#include <linux/module.h> 14#include <linux/of.h> 15#include <linux/phy/phy.h> 16#include <linux/platform_device.h> 17 18#define OTGCTL (0) 19#define OTGCTL_OTGSTAT2 BIT(31) 20#define OTGCTL_OTGSTAT1 BIT(30) 21#define OTGCTL_PRST_N_SW BIT(11) 22#define OTGCTL_HRESET_N BIT(10) 23#define OTGCTL_UTMI_LINE_STATE1 BIT(9) 24#define OTGCTL_UTMI_LINE_STATE0 BIT(8) 25 26#define P1CTL (8) 27#define P1CTL_SOFT_RESET BIT(1) 28#define P1CTL_NON_DRIVING BIT(0) 29 30struct bcm_kona_usb { 31 void __iomem *regs; 32}; 33 34static void bcm_kona_usb_phy_power(struct bcm_kona_usb *phy, int on) 35{ 36 u32 val; 37 38 val = readl(phy->regs + OTGCTL); 39 if (on) { 40 /* Configure and power PHY */ 41 val &= ~(OTGCTL_OTGSTAT2 | OTGCTL_OTGSTAT1 | 42 OTGCTL_UTMI_LINE_STATE1 | OTGCTL_UTMI_LINE_STATE0); 43 val |= OTGCTL_PRST_N_SW | OTGCTL_HRESET_N; 44 } else { 45 val &= ~(OTGCTL_PRST_N_SW | OTGCTL_HRESET_N); 46 } 47 writel(val, phy->regs + OTGCTL); 48} 49 50static int bcm_kona_usb_phy_init(struct phy *gphy) 51{ 52 struct bcm_kona_usb *phy = phy_get_drvdata(gphy); 53 u32 val; 54 55 /* Soft reset PHY */ 56 val = readl(phy->regs + P1CTL); 57 val &= ~P1CTL_NON_DRIVING; 58 val |= P1CTL_SOFT_RESET; 59 writel(val, phy->regs + P1CTL); 60 writel(val & ~P1CTL_SOFT_RESET, phy->regs + P1CTL); 61 /* Reset needs to be asserted for 2ms */ 62 mdelay(2); 63 writel(val | P1CTL_SOFT_RESET, phy->regs + P1CTL); 64 65 return 0; 66} 67 68static int bcm_kona_usb_phy_power_on(struct phy *gphy) 69{ 70 struct bcm_kona_usb *phy = phy_get_drvdata(gphy); 71 72 bcm_kona_usb_phy_power(phy, 1); 73 74 return 0; 75} 76 77static int bcm_kona_usb_phy_power_off(struct phy *gphy) 78{ 79 struct bcm_kona_usb *phy = phy_get_drvdata(gphy); 80 81 bcm_kona_usb_phy_power(phy, 0); 82 83 return 0; 84} 85 86static const struct phy_ops ops = { 87 .init = bcm_kona_usb_phy_init, 88 .power_on = bcm_kona_usb_phy_power_on, 89 .power_off = bcm_kona_usb_phy_power_off, 90 .owner = THIS_MODULE, 91}; 92 93static int bcm_kona_usb2_probe(struct platform_device *pdev) 94{ 95 struct device *dev = &pdev->dev; 96 struct bcm_kona_usb *phy; 97 struct phy *gphy; 98 struct phy_provider *phy_provider; 99 100 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); 101 if (!phy) 102 return -ENOMEM; 103 104 phy->regs = devm_platform_ioremap_resource(pdev, 0); 105 if (IS_ERR(phy->regs)) 106 return PTR_ERR(phy->regs); 107 108 platform_set_drvdata(pdev, phy); 109 110 gphy = devm_phy_create(dev, NULL, &ops); 111 if (IS_ERR(gphy)) 112 return PTR_ERR(gphy); 113 114 /* The Kona PHY supports an 8-bit wide UTMI interface */ 115 phy_set_bus_width(gphy, 8); 116 117 phy_set_drvdata(gphy, phy); 118 119 phy_provider = devm_of_phy_provider_register(dev, 120 of_phy_simple_xlate); 121 122 return PTR_ERR_OR_ZERO(phy_provider); 123} 124 125static const struct of_device_id bcm_kona_usb2_dt_ids[] = { 126 { .compatible = "brcm,kona-usb2-phy" }, 127 { /* sentinel */ } 128}; 129 130MODULE_DEVICE_TABLE(of, bcm_kona_usb2_dt_ids); 131 132static struct platform_driver bcm_kona_usb2_driver = { 133 .probe = bcm_kona_usb2_probe, 134 .driver = { 135 .name = "bcm-kona-usb2", 136 .of_match_table = bcm_kona_usb2_dt_ids, 137 }, 138}; 139 140module_platform_driver(bcm_kona_usb2_driver); 141 142MODULE_ALIAS("platform:bcm-kona-usb2"); 143MODULE_AUTHOR("Matt Porter <mporter@linaro.org>"); 144MODULE_DESCRIPTION("BCM Kona USB 2.0 PHY driver"); 145MODULE_LICENSE("GPL v2");