17597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter/* 27597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter * phy-bcm-kona-usb2.c - Broadcom Kona USB2 Phy Driver 37597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter * 47597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter * Copyright (C) 2013 Linaro Limited 57597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter * Matt Porter <mporter@linaro.org> 67597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter * 77597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter * This software is licensed under the terms of the GNU General Public 87597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter * License version 2, as published by the Free Software Foundation, and 97597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter * may be copied, distributed, and modified under those terms. 107597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter * 117597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter * This program is distributed in the hope that it will be useful, 127597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter * but WITHOUT ANY WARRANTY; without even the implied warranty of 137597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 147597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter * GNU General Public License for more details. 157597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter */ 167597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 177597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter#include <linux/clk.h> 187597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter#include <linux/delay.h> 197597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter#include <linux/err.h> 207597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter#include <linux/io.h> 217597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter#include <linux/module.h> 227597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter#include <linux/of.h> 237597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter#include <linux/phy/phy.h> 247597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter#include <linux/platform_device.h> 257597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 267597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter#define OTGCTL (0) 277597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter#define OTGCTL_OTGSTAT2 BIT(31) 287597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter#define OTGCTL_OTGSTAT1 BIT(30) 297597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter#define OTGCTL_PRST_N_SW BIT(11) 307597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter#define OTGCTL_HRESET_N BIT(10) 317597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter#define OTGCTL_UTMI_LINE_STATE1 BIT(9) 327597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter#define OTGCTL_UTMI_LINE_STATE0 BIT(8) 337597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 347597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter#define P1CTL (8) 357597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter#define P1CTL_SOFT_RESET BIT(1) 367597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter#define P1CTL_NON_DRIVING BIT(0) 377597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 387597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porterstruct bcm_kona_usb { 397597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter void __iomem *regs; 407597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter}; 417597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 427597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porterstatic void bcm_kona_usb_phy_power(struct bcm_kona_usb *phy, int on) 437597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter{ 447597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter u32 val; 457597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 467597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter val = readl(phy->regs + OTGCTL); 477597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter if (on) { 487597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter /* Configure and power PHY */ 497597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter val &= ~(OTGCTL_OTGSTAT2 | OTGCTL_OTGSTAT1 | 507597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter OTGCTL_UTMI_LINE_STATE1 | OTGCTL_UTMI_LINE_STATE0); 517597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter val |= OTGCTL_PRST_N_SW | OTGCTL_HRESET_N; 527597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter } else { 537597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter val &= ~(OTGCTL_PRST_N_SW | OTGCTL_HRESET_N); 547597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter } 557597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter writel(val, phy->regs + OTGCTL); 567597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter} 577597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 587597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porterstatic int bcm_kona_usb_phy_init(struct phy *gphy) 597597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter{ 607597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter struct bcm_kona_usb *phy = phy_get_drvdata(gphy); 617597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter u32 val; 627597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 637597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter /* Soft reset PHY */ 647597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter val = readl(phy->regs + P1CTL); 657597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter val &= ~P1CTL_NON_DRIVING; 667597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter val |= P1CTL_SOFT_RESET; 677597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter writel(val, phy->regs + P1CTL); 687597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter writel(val & ~P1CTL_SOFT_RESET, phy->regs + P1CTL); 697597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter /* Reset needs to be asserted for 2ms */ 707597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter mdelay(2); 717597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter writel(val | P1CTL_SOFT_RESET, phy->regs + P1CTL); 727597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 737597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter return 0; 747597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter} 757597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 767597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porterstatic int bcm_kona_usb_phy_power_on(struct phy *gphy) 777597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter{ 787597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter struct bcm_kona_usb *phy = phy_get_drvdata(gphy); 797597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 807597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter bcm_kona_usb_phy_power(phy, 1); 817597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 827597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter return 0; 837597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter} 847597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 857597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porterstatic int bcm_kona_usb_phy_power_off(struct phy *gphy) 867597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter{ 877597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter struct bcm_kona_usb *phy = phy_get_drvdata(gphy); 887597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 897597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter bcm_kona_usb_phy_power(phy, 0); 907597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 917597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter return 0; 927597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter} 937597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 947597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porterstatic struct phy_ops ops = { 957597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter .init = bcm_kona_usb_phy_init, 967597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter .power_on = bcm_kona_usb_phy_power_on, 977597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter .power_off = bcm_kona_usb_phy_power_off, 987597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter .owner = THIS_MODULE, 997597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter}; 1007597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 1017597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porterstatic int bcm_kona_usb2_probe(struct platform_device *pdev) 1027597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter{ 1037597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter struct device *dev = &pdev->dev; 1047597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter struct bcm_kona_usb *phy; 1057597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter struct resource *res; 1067597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter struct phy *gphy; 1077597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter struct phy_provider *phy_provider; 1087597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 1097597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); 1107597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter if (!phy) 1117597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter return -ENOMEM; 1127597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 1137597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1147597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter phy->regs = devm_ioremap_resource(&pdev->dev, res); 1157597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter if (IS_ERR(phy->regs)) 1167597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter return PTR_ERR(phy->regs); 1177597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 1187597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter platform_set_drvdata(pdev, phy); 1197597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 120f0ed817638b59aa927f1f7e9564dd8796b18dc4fKishon Vijay Abraham I gphy = devm_phy_create(dev, NULL, &ops, NULL); 1217597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter if (IS_ERR(gphy)) 1227597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter return PTR_ERR(gphy); 1237597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 1247597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter /* The Kona PHY supports an 8-bit wide UTMI interface */ 1257597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter phy_set_bus_width(gphy, 8); 1267597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 1277597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter phy_set_drvdata(gphy, phy); 1287597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 1297597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter phy_provider = devm_of_phy_provider_register(dev, 1307597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter of_phy_simple_xlate); 1317597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 132e4b9f782fe923e75cf47d369b770c49c33dfb39dSachin Kamat return PTR_ERR_OR_ZERO(phy_provider); 1337597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter} 1347597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 1357597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porterstatic const struct of_device_id bcm_kona_usb2_dt_ids[] = { 1367597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter { .compatible = "brcm,kona-usb2-phy" }, 1377597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter { /* sentinel */ } 1387597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter}; 1397597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 1407597fdfca983025a3de91d4b3cf7b21ba452003cMatt PorterMODULE_DEVICE_TABLE(of, bcm_kona_usb2_dt_ids); 1417597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 1427597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porterstatic struct platform_driver bcm_kona_usb2_driver = { 1437597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter .probe = bcm_kona_usb2_probe, 1447597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter .driver = { 1457597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter .name = "bcm-kona-usb2", 1467597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter .of_match_table = bcm_kona_usb2_dt_ids, 1477597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter }, 1487597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter}; 1497597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 1507597fdfca983025a3de91d4b3cf7b21ba452003cMatt Portermodule_platform_driver(bcm_kona_usb2_driver); 1517597fdfca983025a3de91d4b3cf7b21ba452003cMatt Porter 1527597fdfca983025a3de91d4b3cf7b21ba452003cMatt PorterMODULE_ALIAS("platform:bcm-kona-usb2"); 1537597fdfca983025a3de91d4b3cf7b21ba452003cMatt PorterMODULE_AUTHOR("Matt Porter <mporter@linaro.org>"); 1547597fdfca983025a3de91d4b3cf7b21ba452003cMatt PorterMODULE_DESCRIPTION("BCM Kona USB 2.0 PHY driver"); 1557597fdfca983025a3de91d4b3cf7b21ba452003cMatt PorterMODULE_LICENSE("GPL v2"); 156