|  | /* | 
|  | * phy-keystone - USB PHY, talking to dwc3 controller in Keystone. | 
|  | * | 
|  | * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com | 
|  | * This program is free software; you can redistribute it and/or modify | 
|  | * it under the terms of the GNU General Public License as published by | 
|  | * the Free Software Foundation; either version 2 of the License, or | 
|  | * (at your option) any later version. | 
|  | * | 
|  | * Author: WingMan Kwok <w-kwok2@ti.com> | 
|  | * | 
|  | * This program is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | * GNU General Public License for more details. | 
|  | * | 
|  | */ | 
|  |  | 
|  | #include <linux/module.h> | 
|  | #include <linux/platform_device.h> | 
|  | #include <linux/usb/usb_phy_generic.h> | 
|  | #include <linux/io.h> | 
|  | #include <linux/of.h> | 
|  |  | 
|  | #include "phy-generic.h" | 
|  |  | 
|  | /* USB PHY control register offsets */ | 
|  | #define USB_PHY_CTL_UTMI		0x0000 | 
|  | #define USB_PHY_CTL_PIPE		0x0004 | 
|  | #define USB_PHY_CTL_PARAM_1		0x0008 | 
|  | #define USB_PHY_CTL_PARAM_2		0x000c | 
|  | #define USB_PHY_CTL_CLOCK		0x0010 | 
|  | #define USB_PHY_CTL_PLL			0x0014 | 
|  |  | 
|  | #define PHY_REF_SSP_EN			BIT(29) | 
|  |  | 
|  | struct keystone_usbphy { | 
|  | struct usb_phy_generic	usb_phy_gen; | 
|  | void __iomem			*phy_ctrl; | 
|  | }; | 
|  |  | 
|  | static inline u32 keystone_usbphy_readl(void __iomem *base, u32 offset) | 
|  | { | 
|  | return readl(base + offset); | 
|  | } | 
|  |  | 
|  | static inline void keystone_usbphy_writel(void __iomem *base, | 
|  | u32 offset, u32 value) | 
|  | { | 
|  | writel(value, base + offset); | 
|  | } | 
|  |  | 
|  | static int keystone_usbphy_init(struct usb_phy *phy) | 
|  | { | 
|  | struct keystone_usbphy *k_phy = dev_get_drvdata(phy->dev); | 
|  | u32 val; | 
|  |  | 
|  | val  = keystone_usbphy_readl(k_phy->phy_ctrl, USB_PHY_CTL_CLOCK); | 
|  | keystone_usbphy_writel(k_phy->phy_ctrl, USB_PHY_CTL_CLOCK, | 
|  | val | PHY_REF_SSP_EN); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void keystone_usbphy_shutdown(struct usb_phy *phy) | 
|  | { | 
|  | struct keystone_usbphy *k_phy = dev_get_drvdata(phy->dev); | 
|  | u32 val; | 
|  |  | 
|  | val  = keystone_usbphy_readl(k_phy->phy_ctrl, USB_PHY_CTL_CLOCK); | 
|  | keystone_usbphy_writel(k_phy->phy_ctrl, USB_PHY_CTL_CLOCK, | 
|  | val &= ~PHY_REF_SSP_EN); | 
|  | } | 
|  |  | 
|  | static int keystone_usbphy_probe(struct platform_device *pdev) | 
|  | { | 
|  | struct device		*dev = &pdev->dev; | 
|  | struct keystone_usbphy	*k_phy; | 
|  | struct resource		*res; | 
|  | int ret; | 
|  |  | 
|  | k_phy = devm_kzalloc(dev, sizeof(*k_phy), GFP_KERNEL); | 
|  | if (!k_phy) | 
|  | return -ENOMEM; | 
|  |  | 
|  | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 
|  | k_phy->phy_ctrl = devm_ioremap_resource(dev, res); | 
|  | if (IS_ERR(k_phy->phy_ctrl)) | 
|  | return PTR_ERR(k_phy->phy_ctrl); | 
|  |  | 
|  | ret = usb_phy_gen_create_phy(dev, &k_phy->usb_phy_gen, NULL); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | k_phy->usb_phy_gen.phy.init = keystone_usbphy_init; | 
|  | k_phy->usb_phy_gen.phy.shutdown = keystone_usbphy_shutdown; | 
|  |  | 
|  | platform_set_drvdata(pdev, k_phy); | 
|  |  | 
|  | return usb_add_phy_dev(&k_phy->usb_phy_gen.phy); | 
|  | } | 
|  |  | 
|  | static int keystone_usbphy_remove(struct platform_device *pdev) | 
|  | { | 
|  | struct keystone_usbphy *k_phy = platform_get_drvdata(pdev); | 
|  |  | 
|  | usb_remove_phy(&k_phy->usb_phy_gen.phy); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static const struct of_device_id keystone_usbphy_ids[] = { | 
|  | { .compatible = "ti,keystone-usbphy" }, | 
|  | { } | 
|  | }; | 
|  | MODULE_DEVICE_TABLE(of, keystone_usbphy_ids); | 
|  |  | 
|  | static struct platform_driver keystone_usbphy_driver = { | 
|  | .probe          = keystone_usbphy_probe, | 
|  | .remove         = keystone_usbphy_remove, | 
|  | .driver         = { | 
|  | .name   = "keystone-usbphy", | 
|  | .of_match_table = keystone_usbphy_ids, | 
|  | }, | 
|  | }; | 
|  |  | 
|  | module_platform_driver(keystone_usbphy_driver); | 
|  |  | 
|  | MODULE_ALIAS("platform:keystone-usbphy"); | 
|  | MODULE_AUTHOR("Texas Instruments Inc."); | 
|  | MODULE_DESCRIPTION("Keystone USB phy driver"); | 
|  | MODULE_LICENSE("GPL v2"); |